Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4827 lines
121 KiB

/***
9 years ago
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
/*
===== player.cpp ========================================================
functions dealing with the player
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
#include "trains.h"
#include "nodes.h"
#include "weapons.h"
#include "monsters.h"
#include "shake.h"
#include "decals.h"
#include "gamerules.h"
#include "game.h"
#include "pm_shared.h"
9 years ago
#include "hltv.h"
#include "quake_gun.h"
9 years ago
// #define DUCKFIX
extern bool g_bHaveMOTD;
#include "pm_shared.h"
8 years ago
extern DLL_GLOBAL ULONG g_ulModelIndexPlayer;
extern DLL_GLOBAL BOOL g_fGameOver;
extern DLL_GLOBAL BOOL g_fDrawLines;
extern unsigned short g_sTeleport;
extern unsigned short g_usPowerUp;
Vector g_vecTeleMins[MAX_TELES];
Vector g_vecTeleMaxs[MAX_TELES];
int g_iTeleNum;
9 years ago
int gEvilImpulse101;
8 years ago
extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle;
9 years ago
extern "C" int g_bhopcap;
9 years ago
BOOL gInitHUD = TRUE;
8 years ago
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, bool bCheckDM );
extern bool g_bIsThreeWave;
9 years ago
// the world node graph
8 years ago
extern CGraph WorldGraph;
9 years ago
8 years ago
#define TRAIN_ACTIVE 0x80
9 years ago
#define TRAIN_NEW 0xc0
#define TRAIN_OFF 0x00
8 years ago
#define TRAIN_NEUTRAL 0x01
9 years ago
#define TRAIN_SLOW 0x02
8 years ago
#define TRAIN_MEDIUM 0x03
#define TRAIN_FAST 0x04
9 years ago
#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)
// Global Savedata for player
TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] =
9 years ago
{
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 ),
9 years ago
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 ),
9 years ago
//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 gmsgServerName = 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 gmsgTeamNames = 0;
int gmsgBhopcap = 0;
9 years ago
// QUAKECLASSIC
int gmsgQItems = 0;
9 years ago
int gmsgStatusText = 0;
8 years ago
int gmsgStatusValue = 0;
9 years ago
//++ BulliT
int gmsgAllowSpec = 0;
int gmsgSpectator = 0;
//-- Martin Webrant
// ThreeWave
int gmsgFlagStatus = 0;
int gmsgFlagCarrier = 0;
int gmsgRuneStatus = 0;
int gmsgCTFMsgs = 0;
9 years ago
void LinkUserMessages( void )
{
// Already taken care of?
8 years ago
if( gmsgSelAmmo )
9 years ago
{
return;
}
8 years ago
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 );
9 years ago
gmsgHealth = REG_USER_MSG( "Health", 1 );
gmsgDamage = REG_USER_MSG( "Damage", 12 );
gmsgBattery = REG_USER_MSG( "Battery", 2);
8 years ago
gmsgTrain = REG_USER_MSG( "Train", 1 );
//gmsgHudText = REG_USER_MSG( "HudTextPro", -1 );
gmsgHudText = REG_USER_MSG( "HudText", -1 ); // we don't use the message but 3rd party addons may!
9 years ago
gmsgSayText = REG_USER_MSG( "SayText", -1 );
gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );
8 years ago
gmsgWeaponList = REG_USER_MSG( "WeaponList", -1 );
gmsgResetHUD = REG_USER_MSG( "ResetHUD", 1 ); // called every respawn
gmsgInitHUD = REG_USER_MSG( "InitHUD", -1 ); // called every time a new player joins the server
8 years ago
gmsgShowGameTitle = REG_USER_MSG( "GameTitle", 1 );
9 years ago
gmsgDeathMsg = REG_USER_MSG( "DeathMsg", -1 );
gmsgScoreInfo = REG_USER_MSG( "ScoreInfo", 7 );
9 years ago
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 );
gmsgServerName = REG_USER_MSG( "ServerName", -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 );
8 years ago
gmsgShake = REG_USER_MSG( "ScreenShake", sizeof(ScreenShake) );
gmsgFade = REG_USER_MSG( "ScreenFade", sizeof(ScreenFade) );
gmsgAmmoX = REG_USER_MSG( "AmmoX", 2 );
9 years ago
gmsgTeamNames = REG_USER_MSG( "TeamNames", -1 );
gmsgQItems = REG_USER_MSG( "QItems", 4 );
8 years ago
gmsgStatusText = REG_USER_MSG( "StatusText", -1 );
gmsgStatusValue = REG_USER_MSG( "StatusValue", 3 );
if( g_bIsThreeWave )
{
gmsgCTFMsgs = REG_USER_MSG( "Bonus", -1 );
gmsgFlagStatus = REG_USER_MSG( "FlagStat", 5 );
gmsgRuneStatus = REG_USER_MSG( "RuneStat", 1 );
gmsgFlagCarrier = REG_USER_MSG( "FlagCarrier", 2 );
}
//++ BulliT
gmsgAllowSpec = REG_USER_MSG( "AllowSpec", 1 ); //Allow spectator button message.
gmsgSpectator = REG_USER_MSG( "Spectator", 2 ); //Spectator message.
//-- Martin Webrant
gmsgBhopcap = REG_USER_MSG( "Bhopcap", 1 );
9 years ago
}
LINK_ENTITY_TO_CLASS( player, CBasePlayer )
9 years ago
// QUAKECLASSIC: Play pain sounds
8 years ago
void CBasePlayer::Pain( CBaseEntity *pAttacker )
9 years ago
{
if( pev->health < 0 )
return;
9 years ago
if( FClassnameIs( pAttacker->pev, "teledeath" ) )
{
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/teledth1.wav", 1, ATTN_NORM );
return;
}
// water pain sounds
if( pev->watertype == CONTENT_WATER && pev->waterlevel == 3 )
{
UTIL_Bubbles( pev->mins, pev->maxs, 3 );
if( RANDOM_FLOAT( 0, 1 ) > 0.5 )
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/drown1.wav", 1, ATTN_NORM );
else
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/drown2.wav", 1, ATTN_NORM );
return;
}
// slime pain sounds
if( pev->watertype == CONTENT_SLIME )
{
if( RANDOM_FLOAT( 0, 1 ) > 0.5 )
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM );
else
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM );
return;
}
// lava pain sounds
if( pev->watertype == CONTENT_LAVA )
{
if( RANDOM_FLOAT( 0, 1 ) > 0.5 )
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM );
else
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM );
return;
}
// don't make multiple pain sounds right after each other
if( m_flPainSoundFinished > gpGlobals->time )
{
m_bAxHitMe = 0;
return;
}
m_flPainSoundFinished = gpGlobals->time + 0.5;
// ax pain sound
if( m_bAxHitMe == 1 )
{
m_bAxHitMe = 0;
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/axhitbod.wav", 1, ATTN_NORM );
return;
}
// play random sound
switch( (int)( RANDOM_FLOAT( 0, 1 ) * 6 ) )
{
case 0:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/pain1.wav", 1, ATTN_NORM );
break;
case 1:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/pain2.wav", 1, ATTN_NORM );
break;
case 2:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/pain3.wav", 1, ATTN_NORM );
break;
case 3:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/pain4.wav", 1, ATTN_NORM );
break;
case 4:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/pain5.wav", 1, ATTN_NORM );
break;
case 5:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/pain6.wav", 1, ATTN_NORM );
break;
}
9 years ago
}
8 years ago
Vector VecVelocityForDamage( float flDamage )
9 years ago
{
8 years ago
Vector vec( RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( 200, 300 ) );
9 years ago
8 years ago
if( flDamage > -50 )
9 years ago
vec = vec * 0.7;
8 years ago
else if( flDamage > -200 )
9 years ago
vec = vec * 2;
else
vec = vec * 10;
9 years ago
return vec;
}
8 years ago
#if 0
static void ThrowGib( entvars_t *pev, char *szGibModel, float flDamage )
9 years ago
{
edict_t *pentNew = CREATE_ENTITY();
8 years ago
entvars_t *pevNew = VARS( pentNew );
9 years ago
pevNew->origin = pev->origin;
8 years ago
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;
9 years ago
}
8 years ago
static void ThrowHead( entvars_t *pev, char *szGibModel, floatflDamage )
9 years ago
{
8 years ago
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 );
9 years ago
pev->origin.z -= 24;
8 years ago
ClearBits( pev->flags, FL_ONGROUND );
9 years ago
}
#endif
8 years ago
int TrainSpeed( int iSpeed, int iMax )
9 years ago
{
float fSpeed, fMax;
int iRet = 0;
fMax = (float)iMax;
fSpeed = iSpeed;
fSpeed = fSpeed/fMax;
8 years ago
if( iSpeed < 0 )
9 years ago
iRet = TRAIN_BACK;
8 years ago
else if( iSpeed == 0 )
9 years ago
iRet = TRAIN_NEUTRAL;
8 years ago
else if( fSpeed < 0.33 )
9 years ago
iRet = TRAIN_SLOW;
8 years ago
else if( fSpeed < 0.66 )
9 years ago
iRet = TRAIN_MEDIUM;
else
iRet = TRAIN_FAST;
return iRet;
}
8 years ago
void CBasePlayer::DeathSound( void )
9 years ago
{
// water death sounds
8 years ago
if( pev->waterlevel == 3 )
9 years ago
{
8 years ago
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE );
9 years ago
return;
}
// play random sound
switch( (int)( RANDOM_FLOAT( 0, 1 ) * 5 ) )
9 years ago
{
case 0:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/death1.wav", 1, ATTN_NORM );
break;
case 1:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/death2.wav", 1, ATTN_NORM );
break;
case 2:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/death3.wav", 1, ATTN_NORM );
break;
case 3:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/death4.wav", 1, ATTN_NORM );
break;
case 4:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/death5.wav", 1, ATTN_NORM );
break;
9 years ago
}
}
// override takehealth
// bitsDamageType indicates type of damage healed.
8 years ago
int CBasePlayer::TakeHealth( float flHealth, int bitsDamageType )
9 years ago
{
// QUAKECLASSIC
if( pev->health <= 0 )
return 0;
if( !( bitsDamageType & DMG_IGNORE_MAXHEALTH ) && ( pev->health >= pev->max_health ) )
return 0;
int iHealAmount = ceil( flHealth );
pev->health += iHealAmount;
if( !( bitsDamageType & DMG_IGNORE_MAXHEALTH ) && ( pev->health >= pev->max_health ) )
pev->health = pev->max_health;
if( pev->health > 250 )
pev->health = 250;
return 1;
9 years ago
}
8 years ago
Vector CBasePlayer::GetGunPosition()
9 years ago
{
8 years ago
//UTIL_MakeVectors( pev->v_angle );
//m_HackedGunPos = pev->view_ofs;
9 years ago
Vector origin;
9 years ago
origin = pev->origin + pev->view_ofs;
return origin;
}
//=========================================================
// TraceAttack
//=========================================================
8 years ago
void CBasePlayer::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
9 years ago
{
8 years ago
if( pev->takedamage )
9 years ago
{
8 years ago
SpawnBlood( ptr->vecEndPos, BloodColor(), flDamage );// a little surface blood.
9 years ago
TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType );
}
}
void CBasePlayer::RemoveAllItems( BOOL removeSuit )
{
int i;
CBasePlayerItem *pPendingItem;
8 years ago
if( m_pActiveItem )
9 years ago
{
8 years ago
ResetAutoaim();
m_pActiveItem->Holster();
9 years ago
m_pActiveItem = NULL;
}
m_pLastItem = NULL;
if( m_pTank != 0 )
m_pTank->Use( this, this, USE_OFF, 0 );
m_iTrain = TRAIN_NEW; // turn off train
8 years ago
for( i = 0; i < MAX_ITEM_TYPES; i++ )
9 years ago
{
m_pActiveItem = m_rgpPlayerItems[i];
m_rgpPlayerItems[i] = NULL;
8 years ago
while( m_pActiveItem )
9 years ago
{
pPendingItem = m_pActiveItem->m_pNext;
8 years ago
m_pActiveItem->Drop();
9 years ago
m_pActiveItem = pPendingItem;
}
}
m_pActiveItem = NULL;
8 years ago
pev->viewmodel = 0;
pev->weaponmodel = 0;
8 years ago
if( removeSuit )
9 years ago
pev->weapons = 0;
else
pev->weapons &= ~WEAPON_ALLWEAPONS;
// Turn off flashlight
ClearBits( pev->effects, EF_DIMLIGHT );
8 years ago
for( i = 0; i < MAX_AMMO_SLOTS; i++ )
9 years ago
m_rgAmmo[i] = 0;
UpdateClientData();
9 years ago
// send Selected Weapon Message to our client
MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev );
8 years ago
WRITE_BYTE( 0 );
WRITE_BYTE( 0 );
WRITE_BYTE( 0 );
9 years ago
MESSAGE_END();
}
/*
* GLOBALS ASSUMED SET: g_ulModelIndexPlayer
*
* ENTITY_METHOD(PlayerDie)
*/
entvars_t *g_pevLastInflictor; // Set in combat.cpp. Used to pass the damage inflictor for death messages.
// Better solution: Add as parameter to all Killed() functions.
9 years ago
void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib )
{
// Holster weapon immediately, to allow it to cleanup
8 years ago
if( m_pActiveItem )
m_pActiveItem->Holster();
9 years ago
g_pGameRules->PlayerKilled( this, pevAttacker, g_pevLastInflictor );
if( m_pTank != 0 )
9 years ago
m_pTank->Use( this, this, USE_OFF, 0 );
//Remove all powerups and powerup timers
m_flInvincibleFinished = m_flRadsuitFinished = m_flInvisibleFinished = m_flSuperDamageFinished = 0.0;
PowerUpThink();
9 years ago
SetAnimation( PLAYER_DIE );
9 years ago
m_iRespawnFrames = 0;
pev->modelindex = g_ulModelIndexPlayer; // don't use eyes
8 years ago
pev->deadflag = DEAD_DYING;
pev->movetype = MOVETYPE_TOSS;
9 years ago
ClearBits( pev->flags, FL_ONGROUND );
if( m_iQuakeWeapon == IT_LIGHTNING )
{
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usLightning, 0, (float *)&pev->origin, (float *)&pev->angles, 0.0, 0.0, 0, 1, 0, 0 );
if( m_pActiveItem )
( (CQuakeGun*)m_pActiveItem )->DestroyEffect();
}
8 years ago
if( pev->velocity.z < 10 )
pev->velocity.z += RANDOM_FLOAT( 0, 300 );
9 years ago
// clear out the suit message cache so we don't keep chattering
8 years ago
SetSuitUpdate( NULL, FALSE, 0 );
9 years ago
// 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 );
8 years ago
WRITE_BYTE( 0 );
WRITE_BYTE( 0XFF );
WRITE_BYTE( 0xFF );
9 years ago
MESSAGE_END();
// UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12
8 years ago
// UTIL_ScreenFade( edict(), Vector( 128, 0, 0 ), 6, 15, 255, FFADE_OUT | FFADE_MODULATE );
9 years ago
//Quake Player always gibs
if( pev->health < -40 )
9 years ago
{
8 years ago
pev->solid = SOLID_NOT;
9 years ago
GibMonster(); // This clears pev->model
pev->effects |= EF_NODRAW;
return;
}
DeathSound();
9 years ago
pev->angles.x = 0;
pev->angles.z = 0;
//++ BulliT
if( !g_bIsThreeWave && g_pGameRules->m_iGameMode >= ARENA )
m_iQuakeWeapon = 0;
//-- Martin Webrant
SetThink( &CBasePlayer::PlayerDeathThink );
9 years ago
pev->nextthink = gpGlobals->time + 0.1;
}
// Set the activity based on an event or current state
void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
{
int animDesired;
float speed;
char szAnim[64];
speed = pev->velocity.Length2D();
8 years ago
if( pev->flags & FL_FROZEN )
9 years ago
{
speed = 0;
playerAnim = PLAYER_IDLE;
}
8 years ago
switch( playerAnim )
9 years ago
{
case PLAYER_JUMP:
m_IdealActivity = ACT_HOP;
break;
case PLAYER_SUPERJUMP:
m_IdealActivity = ACT_LEAP;
break;
case PLAYER_DIE:
m_IdealActivity = ACT_DIESIMPLE;
8 years ago
m_IdealActivity = GetDeathActivity();
9 years ago
break;
8 years ago
case PLAYER_ATTACK1:
9 years ago
switch( m_Activity )
{
case ACT_HOVER:
case ACT_SWIM:
case ACT_HOP:
case ACT_LEAP:
case ACT_DIESIMPLE:
m_IdealActivity = m_Activity;
break;
default:
m_IdealActivity = ACT_RANGE_ATTACK1;
break;
}
break;
case PLAYER_IDLE:
case PLAYER_WALK:
8 years ago
if( !FBitSet( pev->flags, FL_ONGROUND ) && ( m_Activity == ACT_HOP || m_Activity == ACT_LEAP ) ) // Still jumping
9 years ago
{
m_IdealActivity = m_Activity;
}
8 years ago
else if( pev->waterlevel > 1 )
9 years ago
{
8 years ago
if( speed == 0 )
9 years ago
m_IdealActivity = ACT_HOVER;
else
m_IdealActivity = ACT_SWIM;
}
else
{
m_IdealActivity = ACT_WALK;
}
break;
}
8 years ago
switch( m_IdealActivity )
9 years ago
{
case ACT_HOVER:
case ACT_LEAP:
case ACT_SWIM:
case ACT_HOP:
case ACT_DIESIMPLE:
default:
8 years ago
if( m_Activity == m_IdealActivity )
9 years ago
return;
m_Activity = m_IdealActivity;
animDesired = LookupActivity( m_Activity );
9 years ago
// Already using the desired animation?
8 years ago
if( pev->sequence == animDesired )
9 years ago
return;
pev->gaitsequence = 0;
8 years ago
pev->sequence = animDesired;
pev->frame = 0;
ResetSequenceInfo();
9 years ago
return;
case ACT_RANGE_ATTACK1:
8 years ago
if( FBitSet( pev->flags, FL_DUCKING ) ) // crouching
9 years ago
strcpy( szAnim, "crouch_shoot_" );
else
strcpy( szAnim, "ref_shoot_" );
strcat( szAnim, m_pszAnimExtention );
9 years ago
animDesired = LookupSequence( szAnim );
8 years ago
if( animDesired == -1 )
9 years ago
animDesired = 0;
8 years ago
if( pev->sequence != animDesired || !m_fSequenceLoops )
9 years ago
{
pev->frame = 0;
}
8 years ago
if( !m_fSequenceLoops )
9 years ago
{
pev->effects |= EF_NOINTERP;
}
m_Activity = m_IdealActivity;
8 years ago
pev->sequence = animDesired;
ResetSequenceInfo();
9 years ago
break;
case ACT_WALK:
8 years ago
if( m_Activity != ACT_RANGE_ATTACK1 || m_fSequenceFinished )
9 years ago
{
8 years ago
if( FBitSet( pev->flags, FL_DUCKING ) ) // crouching
9 years ago
strcpy( szAnim, "crouch_aim_" );
else
strcpy( szAnim, "ref_aim_" );
strcat( szAnim, m_pszAnimExtention );
9 years ago
animDesired = LookupSequence( szAnim );
8 years ago
if( animDesired == -1 )
9 years ago
animDesired = 0;
m_Activity = ACT_WALK;
}
else
{
animDesired = pev->sequence;
}
}
8 years ago
if( FBitSet( pev->flags, FL_DUCKING ) )
9 years ago
{
8 years ago
if( speed == 0 )
9 years ago
{
8 years ago
pev->gaitsequence = LookupActivity( ACT_CROUCHIDLE );
// pev->gaitsequence = LookupActivity( ACT_CROUCH );
9 years ago
}
else
{
8 years ago
pev->gaitsequence = LookupActivity( ACT_CROUCH );
9 years ago
}
}
8 years ago
else if( speed > 220 )
9 years ago
{
8 years ago
pev->gaitsequence = LookupActivity( ACT_RUN );
9 years ago
}
8 years ago
else if( speed > 0 )
9 years ago
{
8 years ago
pev->gaitsequence = LookupActivity( ACT_WALK );
9 years ago
}
else
{
8 years ago
// pev->gaitsequence = LookupActivity( ACT_WALK );
pev->gaitsequence = LookupSequence( "deep_idle" );
9 years ago
}
// Already using the desired animation?
8 years ago
if( pev->sequence == animDesired )
9 years ago
return;
//ALERT( at_console, "Set animation to %d\n", animDesired );
// Reset to first frame of desired animation
8 years ago
pev->sequence = animDesired;
pev->frame = 0;
ResetSequenceInfo();
9 years ago
}
/*
===========
WaterMove
============
*/
#define AIRTIME 12 // lung full of air lasts this many seconds
void CBasePlayer::WaterMove()
{
int air;
8 years ago
if( pev->movetype == MOVETYPE_NOCLIP )
9 years ago
return;
8 years ago
if( pev->health < 0 )
9 years ago
return;
// waterlevel 0 - not in water
// waterlevel 1 - feet in water
// waterlevel 2 - waist in water
// waterlevel 3 - head in water
8 years ago
if( pev->waterlevel != 3 )
9 years ago
{
// not underwater
9 years ago
// play 'up for air' sound
8 years ago
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 );
9 years ago
pev->air_finished = gpGlobals->time + AIRTIME;
pev->dmg = 2;
// if we took drowning damage, give it back slowly
8 years ago
if( m_idrowndmg > m_idrownrestored )
9 years ago
{
// 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.
9 years ago
// NOTE: this actually causes the count to continue restarting
// until all drowning damage is healed.
//m_bitsDamageType |= DMG_DROWNRECOVER;
9 years ago
m_bitsDamageType &= ~DMG_DROWN;
//m_rgbTimeBasedDamage[itbd_DrownRecover] = 0;
9 years ago
}
}
else
{ // fully under water
// stop restoring damage while underwater
m_bitsDamageType &= ~DMG_DROWNRECOVER;
m_rgbTimeBasedDamage[itbd_DrownRecover] = 0;
8 years ago
if( pev->air_finished < gpGlobals->time ) // drown!
9 years ago
{
8 years ago
if( pev->pain_finished < gpGlobals->time )
9 years ago
{
// take drowning damage
pev->dmg += 1;
8 years ago
if( pev->dmg > 5 )
9 years ago
pev->dmg = 5;
8 years ago
TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), pev->dmg, DMG_DROWN );
9 years ago
pev->pain_finished = gpGlobals->time + 1;
9 years ago
// track drowning damage, give it back when
// player finally takes a breath
m_idrowndmg += (int)pev->dmg;
9 years ago
}
}
else
{
m_bitsDamageType &= ~DMG_DROWN;
}
}
8 years ago
if( !pev->waterlevel )
9 years ago
{
8 years ago
if( FBitSet( pev->flags, FL_INWATER ) )
{
ClearBits( pev->flags, FL_INWATER );
9 years ago
}
return;
}
// make bubbles
8 years ago
air = (int)( pev->air_finished - gpGlobals->time );
if( !RANDOM_LONG( 0, 0x1f ) && RANDOM_LONG( 0, AIRTIME - 1 ) >= air )
9 years ago
{
8 years ago
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;
9 years ago
}
}
8 years ago
if( pev->watertype == CONTENT_LAVA ) // do damage
9 years ago
{
8 years ago
if( pev->dmgtime < gpGlobals->time )
{
if( m_iQuakeItems & IT_SUIT )
pev->dmgtime = gpGlobals->time + 1.0;
else
pev->dmgtime = gpGlobals->time + 0.2;
8 years ago
TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), 10 * pev->waterlevel, DMG_BURN );
}
9 years ago
}
8 years ago
else if( pev->watertype == CONTENT_SLIME ) // do damage
9 years ago
{
if( pev->dmgtime < gpGlobals->time )
{
pev->dmgtime = gpGlobals->time + 1.0;
TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), 4 * pev->waterlevel, DMG_ACID );
}
9 years ago
}
8 years ago
if( !FBitSet( pev->flags, FL_INWATER ) )
9 years ago
{
8 years ago
SetBits( pev->flags, FL_INWATER );
9 years ago
pev->dmgtime = 0;
}
}
// TRUE if the player is attached to a ladder
BOOL CBasePlayer::IsOnLadder( void )
{
return ( pev->movetype == MOVETYPE_FLY );
}
8 years ago
void CBasePlayer::PlayerDeathThink( void )
9 years ago
{
float flForward;
8 years ago
if( FBitSet( pev->flags, FL_ONGROUND ) )
9 years ago
{
flForward = pev->velocity.Length() - 20;
8 years ago
if( flForward <= 0 )
9 years ago
pev->velocity = g_vecZero;
else
pev->velocity = flForward * pev->velocity.Normalize();
}
if( m_iQuakeWeapon )
9 years ago
{
DropBackpack();
9 years ago
}
8 years ago
if( pev->modelindex && ( !m_fSequenceFinished ) && ( pev->deadflag == DEAD_DYING ) )
9 years ago
{
8 years ago
StudioFrameAdvance();
9 years ago
m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands
8 years ago
if( m_iRespawnFrames < 120 ) // Animations should be no longer than this
9 years ago
return;
}
// once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore
// this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn
8 years ago
if( pev->movetype != MOVETYPE_NONE && FBitSet( pev->flags, FL_ONGROUND ) )
9 years ago
pev->movetype = MOVETYPE_NONE;
if( m_fSequenceFinished == 0 )
{
StudioFrameAdvance();
return;
}
8 years ago
if( pev->deadflag == DEAD_DYING )
9 years ago
pev->deadflag = DEAD_DEAD;
9 years ago
StopAnimation();
pev->effects |= EF_NOINTERP;
pev->framerate = 0.0;
//++ BulliT
//Remove sticky dead models.
pev->solid = SOLID_NOT;
//-- Martin Webrant
8 years ago
BOOL fAnyButtonDown = ( pev->button & ~IN_SCORE );
9 years ago
// wait for all buttons released
8 years ago
if( pev->deadflag == DEAD_DEAD )
9 years ago
{
8 years ago
if( fAnyButtonDown )
9 years ago
return;
8 years ago
if( g_pGameRules->FPlayerCanRespawn( this ) )
9 years ago
{
m_fDeadTime = gpGlobals->time;
pev->deadflag = DEAD_RESPAWNABLE;
}
9 years ago
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 ) )
9 years ago
{
// go to dead camera.
StartDeathCam();
}*/
if( pev->iuser1 ) // player is in spectator mode
return;
// wait for any button down, or mp_forcerespawn is set and the respawn time is up
8 years ago
if( !fAnyButtonDown && !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && ( gpGlobals->time > ( m_fDeadTime + 5 ) ) ) )
9 years ago
return;
pev->button = 0;
m_iRespawnFrames = 0;
8 years ago
//ALERT( at_console, "Respawn\n" );
9 years ago
8 years ago
respawn( pev, !( m_afPhysicsFlags & PFLAG_OBSERVER ) );// don't copy a corpse if we're in deathcam.
9 years ago
pev->nextthink = -1;
}
//=========================================================
// StartDeathCam - find an intermission spot and send the
// player off into observer mode
//=========================================================
void CBasePlayer::StartDeathCam( void )
{
edict_t *pSpot, *pNewSpot;
int iRand;
8 years ago
if( pev->view_ofs == g_vecZero )
9 years ago
{
// don't accept subsequent attempts to StartDeathCam()
return;
}
8 years ago
pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission" );
9 years ago
8 years ago
if( !FNullEnt( pSpot ) )
9 years ago
{
// at least one intermission spot in the world.
iRand = RANDOM_LONG( 0, 3 );
8 years ago
while( iRand > 0 )
9 years ago
{
8 years ago
pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission" );
8 years ago
if( pNewSpot )
9 years ago
{
pSpot = pNewSpot;
}
iRand--;
}
CopyToBodyQue( pev );
UTIL_SetOrigin( pev, pSpot->v.origin );
pev->angles = pev->v_angle = pSpot->v.v_angle;
9 years ago
}
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 );
UTIL_SetOrigin( pev, tr.vecEndPos );
pev->angles = pev->v_angle = UTIL_VecToAngles( tr.vecEndPos - pev->origin );
9 years ago
}
// start death cam
m_afPhysicsFlags |= PFLAG_OBSERVER;
pev->view_ofs = g_vecZero;
pev->fixangle = TRUE;
pev->solid = SOLID_NOT;
pev->takedamage = DAMAGE_NO;
pev->movetype = MOVETYPE_NONE;
pev->modelindex = 0;
9 years ago
}
void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle )
{
m_iHideHUD |= ( HIDEHUD_HEALTH | HIDEHUD_WEAPONS );
9 years ago
m_afPhysicsFlags |= PFLAG_OBSERVER;
// clear any clientside entities attached to this player
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_KILLPLAYERATTACHMENTS );
WRITE_BYTE( (BYTE)entindex() );
MESSAGE_END();
// Holster weapon immediately, to allow it to cleanup
if( m_pActiveItem )
m_pActiveItem->Holster();
if( m_pTank != 0 )
m_pTank->Use( this, this, USE_OFF, 0 );
9 years ago
// clear out the suit message cache so we don't keep chattering
SetSuitUpdate( NULL, FALSE, 0 );
// Tell Ammo Hud that the player is dead
MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev );
WRITE_BYTE( 0 );
WRITE_BYTE( 0XFF );
WRITE_BYTE( 0xFF );
MESSAGE_END();
// reset FOV
m_iFOV = m_iClientFOV = 0;
pev->fov = m_iFOV;
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE( 0 );
MESSAGE_END();
// Setup flags
m_iHideHUD = ( HIDEHUD_HEALTH | HIDEHUD_WEAPONS );
m_afPhysicsFlags |= PFLAG_OBSERVER;
pev->effects = EF_NODRAW;
9 years ago
pev->view_ofs = g_vecZero;
pev->angles = pev->v_angle = vecViewAngle;
pev->fixangle = TRUE;
pev->solid = SOLID_NOT;
pev->takedamage = DAMAGE_NO;
pev->movetype = MOVETYPE_NONE;
ClearBits( m_afPhysicsFlags, PFLAG_DUCKING );
ClearBits( pev->flags, FL_DUCKING );
pev->deadflag = DEAD_RESPAWNABLE;
pev->health = 1;
// Clear out the status bar
m_fInitHUD = TRUE;
pev->team = 0;
MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo );
WRITE_BYTE( ENTINDEX(edict()) );
WRITE_STRING( "" );
MESSAGE_END();
// Remove all the player's stuff
RemoveAllItems( FALSE );
// Move them to the new position
9 years ago
UTIL_SetOrigin( pev, vecPosition );
ClearBits( m_afPhysicsFlags, PFLAG_DUCKING );
ClearBits( pev->flags, FL_DUCKING );
// pev->flags = FL_CLIENT | FL_SPECTATOR; // Should we set Spectator flag? Or is it reserver for people connecting with spectator 1?
pev->deadflag = DEAD_RESPAWNABLE;
// Tell the physics code that this player's now in observer mode
Observer_SetMode( OBS_CHASE_LOCKED );
m_flNextObserverInput = 0;
// Find a player to watch
// Observer_SetMode( m_iObserverLastMode );
9 years ago
}
//
9 years ago
// PlayerUse - handles USE keypress
//
#define PLAYER_SEARCH_RADIUS (float)64
8 years ago
void CBasePlayer::PlayerUse( void )
9 years ago
{
if( IsObserver() )
return;
9 years ago
// Was use pressed or released?
8 years ago
if( !( ( pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE ) )
9 years ago
return;
// Hit Use on a train?
8 years ago
if( m_afButtonPressed & IN_USE )
9 years ago
{
if( m_pTank != 0 )
9 years ago
{
// Stop controlling the tank
// TODO: Send HUD Update
m_pTank->Use( this, this, USE_OFF, 0 );
return;
}
else
{
8 years ago
if( m_afPhysicsFlags & PFLAG_ONTRAIN )
9 years ago
{
m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
m_iTrain = TRAIN_NEW|TRAIN_OFF;
return;
}
else
{ // Start controlling the train!
CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity );
8 years ago
if( pTrain && !( pev->button & IN_JUMP ) && FBitSet( pev->flags, FL_ONGROUND ) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE ) && pTrain->OnControls( pev ) )
9 years ago
{
m_afPhysicsFlags |= PFLAG_ONTRAIN;
m_iTrain = TrainSpeed( (int)pTrain->pev->speed, pTrain->pev->impulse );
9 years ago
m_iTrain |= TRAIN_NEW;
8 years ago
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM );
9 years ago
return;
}
}
}
}
CBaseEntity *pObject = NULL;
CBaseEntity *pClosest = NULL;
8 years ago
Vector vecLOS;
9 years ago
float flMaxDot = VIEW_FIELD_NARROW;
float flDot;
8 years ago
UTIL_MakeVectors( pev->v_angle );// so we know which way we are facing
8 years ago
while( ( pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS ) ) != NULL )
9 years ago
{
8 years ago
if( pObject->ObjectCaps() & ( FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE ) )
9 years ago
{
// !!!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)
8 years ago
vecLOS = ( VecBModelOrigin( pObject->pev ) - ( pev->origin + pev->view_ofs ) );
9 years ago
// 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 );
8 years ago
flDot = DotProduct( vecLOS , gpGlobals->v_forward );
if( flDot > flMaxDot )
{
// only if the item is in front of the user
9 years ago
pClosest = pObject;
flMaxDot = flDot;
//ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot );
9 years ago
}
//ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot );
9 years ago
}
}
pObject = pClosest;
// Found an object
8 years ago
if( pObject )
9 years ago
{
//!!!UNDONE: traceline here to prevent USEing buttons through walls
int caps = pObject->ObjectCaps();
8 years ago
if( m_afButtonPressed & IN_USE )
EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_select.wav", 0.4, ATTN_NORM );
9 years ago
8 years ago
if( ( ( pev->button & IN_USE ) && ( caps & FCAP_CONTINUOUS_USE ) ) ||
( ( m_afButtonPressed & IN_USE ) && ( caps & ( FCAP_IMPULSE_USE | FCAP_ONOFF_USE ) ) ) )
9 years ago
{
8 years ago
if( caps & FCAP_CONTINUOUS_USE )
9 years ago
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
8 years ago
else if( ( m_afButtonReleased & IN_USE ) && ( pObject->ObjectCaps() & FCAP_ONOFF_USE ) ) // BUGBUG This is an "off" use
9 years ago
{
pObject->Use( this, this, USE_SET, 0 );
}
}
else
{
8 years ago
if( m_afButtonPressed & IN_USE )
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "common/wpn_denyselect.wav", 0.4, ATTN_NORM );
9 years ago
}
}
void CBasePlayer::Jump()
{
8 years ago
Vector vecWallCheckDir;// direction we're tracing a line to find a wall when walljumping
Vector vecAdjustedVelocity;
Vector vecSpot;
TraceResult tr;
8 years ago
if( FBitSet( pev->flags, FL_WATERJUMP ) )
9 years ago
return;
8 years ago
if( pev->waterlevel >= 2 )
9 years ago
{
return;
}
// jump velocity is sqrt( height * gravity * 2)
// If this isn't the first frame pressing the jump button, break out.
8 years ago
if( !FBitSet( m_afButtonPressed, IN_JUMP ) )
9 years ago
return; // don't pogo stick
8 years ago
if( !( pev->flags & FL_ONGROUND ) || !pev->groundentity )
9 years ago
{
return;
}
// many features in this function use v_forward, so makevectors now.
8 years ago
UTIL_MakeVectors( pev->angles );
9 years ago
8 years ago
// ClearBits( pev->flags, FL_ONGROUND ); // don't stairwalk
9 years ago
SetAnimation( PLAYER_JUMP );
8 years ago
if( m_fLongJump &&
( pev->button & IN_DUCK ) &&
9 years ago
( pev->flDuckTime > 0 ) &&
pev->velocity.Length() > 50 )
{
// If jump pressed within a second of duck while moving, long jump!
9 years ago
SetAnimation( PLAYER_SUPERJUMP );
}
// If you're standing on a conveyor, add it's velocity to yours (for momentum)
8 years ago
entvars_t *pevGround = VARS( pev->groundentity );
if( pevGround && ( pevGround->flags & FL_CONVEYOR ) )
9 years ago
{
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.
8 years ago
for( int i = 0; i < 18; i++ )
9 years ago
{
UTIL_TraceHull( pPlayer->v.origin, pPlayer->v.origin, dont_ignore_monsters, head_hull, pPlayer, &trace );
8 years ago
if( trace.fStartSolid )
pPlayer->v.origin.z++;
9 years ago
else
break;
}
}
8 years ago
void CBasePlayer::Duck()
9 years ago
{
8 years ago
if( pev->button & IN_DUCK )
9 years ago
{
8 years ago
if( m_IdealActivity != ACT_LEAP )
9 years ago
{
SetAnimation( PLAYER_WALK );
}
}
}
//
// ID's player as such.
//
8 years ago
int CBasePlayer::Classify( void )
9 years ago
{
return CLASS_PLAYER;
}
void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore )
{
// Positive score always adds
8 years ago
if( score < 0 )
9 years ago
{
8 years ago
if( !bAllowNegativeScore )
9 years ago
{
8 years ago
if( pev->frags < 0 ) // Can't go more negative
9 years ago
return;
8 years ago
if( -score > pev->frags ) // Will this go negative?
9 years ago
{
score = (int)( -pev->frags ); // Sum will be 0
9 years ago
}
}
}
pev->frags += score;
MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo );
8 years ago
WRITE_BYTE( ENTINDEX( edict() ) );
WRITE_SHORT( (int)pev->frags );
9 years ago
WRITE_SHORT( m_iDeaths );
WRITE_SHORT( g_pGameRules->GetTeamIndex( m_szTeamName ) + 1 );
MESSAGE_END();
}
void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore )
{
int index = entindex();
8 years ago
for( int i = 1; i <= gpGlobals->maxClients; i++ )
9 years ago
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );
8 years ago
if( pPlayer && i != index )
9 years ago
{
8 years ago
if( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE )
9 years ago
{
pPlayer->AddPoints( score, bAllowNegativeScore );
}
}
}
}
void CBasePlayer::PowerUpThink( void )
{
int iPowerUp = 0;
bool bUpdate = FALSE;
//Quad time ran out
if( m_iQuakeItems & IT_QUAD && m_flSuperDamageFinished < gpGlobals->time )
{
//Clear the glowing shell effect
pev->renderfx = kRenderFxNone;
//Reset quad timer
m_flSuperDamageFinished = 0.0;
m_bPlayedQuadSound = FALSE;
//Remove the powerup
m_iQuakeItems &= ~IT_QUAD;
//We have other powerups, choose the one with more time remaining
if( m_iQuakeItems & IT_INVISIBILITY || m_iQuakeItems & IT_INVULNERABILITY )
{
if( m_iQuakeItems & IT_INVULNERABILITY )
{
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 255, 128, 0 ); // RGB
pev->renderamt = 100; // Shell size
iPowerUp = 2;
}
if( m_iQuakeItems & IT_INVISIBILITY )
{
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 128, 128, 128 ); // RGB
pev->renderamt = 5; // Shell size
}
}
bUpdate = TRUE;
}
if( m_iQuakeItems & IT_QUAD && m_flSuperDamageFinished <= gpGlobals->time + 3 && !m_bPlayedQuadSound )
{
ClientPrint( pev, HUD_PRINTNOTIFY, "#Quad_Damage_Off" );
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/damage2.wav", 1, ATTN_NORM );
m_bPlayedQuadSound = TRUE;
}
//Env Suit time ran out
if( m_iQuakeItems & IT_SUIT && m_flRadsuitFinished < gpGlobals->time )
{
m_flRadsuitFinished = 0.0;
m_bPlayedEnvSound = FALSE;
//Remove the powerup
m_iQuakeItems &= ~IT_SUIT;
//We have other powerups, choose the one with more time remaining
if( m_iQuakeItems & IT_QUAD || m_iQuakeItems & IT_INVULNERABILITY )
{
if( m_iQuakeItems & IT_INVULNERABILITY && m_iQuakeItems & IT_QUAD )
{
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 255, 125, 255 ); // RGB
pev->renderamt = 100; // Shell size
}
else if( m_flSuperDamageFinished > m_flInvincibleFinished )
{
pev->renderfx = kRenderFxNone;
pev->rendermode = kRenderNormal;
pev->renderamt = 255;
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 128, 128, 255 ); // RGB
pev->renderamt = 100; // Shell size
}
else
{
pev->renderfx = kRenderFxNone;
pev->rendermode = kRenderNormal;
pev->renderamt = 255;
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 255, 128, 0 ); // RGB
pev->renderamt = 100; // Shell size
}
}
else //Clear the invisi screen effect
{
pev->renderfx = kRenderFxNone;
pev->rendermode = kRenderNormal;
pev->renderamt = 255;
}
}
if( m_iQuakeItems & IT_SUIT && m_flRadsuitFinished <= gpGlobals->time + 3 && !m_bPlayedEnvSound )
{
ClientPrint( pev, HUD_PRINTNOTIFY, "#BioSuit_Off" );
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/suit2.wav", 1, ATTN_NORM );
9 years ago
m_bPlayedEnvSound = TRUE;
}
9 years ago
//Invisibility time ran out
if( m_iQuakeItems & IT_INVISIBILITY && m_flInvisibleFinished < gpGlobals->time )
9 years ago
{
//Reset the invi timer
m_flInvisibleFinished = 0.0;
m_bPlayedProtectSound = FALSE;
9 years ago
//Remove the powerup
m_iQuakeItems &= ~IT_INVISIBILITY;
9 years ago
pev->renderfx = kRenderFxNone;
pev->rendermode = kRenderNormal;
pev->renderamt = 255;
9 years ago
//We have other powerups, choose the one with more time remaining
if( m_iQuakeItems & IT_QUAD || m_iQuakeItems & IT_INVULNERABILITY )
{
if( m_iQuakeItems & IT_QUAD && m_iQuakeItems & IT_INVULNERABILITY )
{
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 255, 125, 255 ); // RGB
pev->renderamt = 100; // Shell size
}
else if( m_flSuperDamageFinished > m_flInvincibleFinished )
{
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 128, 128, 255 ); // RGB
pev->renderamt = 100; // Shell size
}
else
{
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 255, 128, 0 ); // RGB
pev->renderamt = 100; // Shell size
9 years ago
}
}
else //Clear the invisi screen effect
9 years ago
{
pev->renderfx = kRenderFxNone;
pev->rendermode = kRenderNormal;
pev->renderamt = 255;
9 years ago
}
//Forces our view model to re-appear
W_SetCurrentAmmo();
9 years ago
}
if( m_iQuakeItems & IT_INVISIBILITY && m_flInvisibleFinished <= gpGlobals->time + 3 && !m_bPlayedInvSound )
{
ClientPrint( pev, HUD_PRINTNOTIFY, "#Ring_Shadows_Off" );
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/inv2.wav", 1, ATTN_NORM );
9 years ago
m_bPlayedInvSound = TRUE;
}
//666 time ran out
if( m_iQuakeItems & IT_INVULNERABILITY && m_flInvincibleFinished < gpGlobals->time )
9 years ago
{
//Clear the glowing shell effect
pev->renderfx = kRenderFxNone;
//Reset 666 timer
m_flInvincibleFinished = 0.0;
m_bPlayedProtectSound = FALSE;
9 years ago
//Remove the powerup
m_iQuakeItems &= ~IT_INVULNERABILITY;
9 years ago
//We have other powerups, choose the one with more time remaining
if( m_iQuakeItems & IT_QUAD || m_iQuakeItems & IT_INVISIBILITY )
{
if( m_flSuperDamageFinished > m_flInvisibleFinished )
{
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 128, 128, 255 ); // RGB
pev->renderamt = 100; // Shell size
iPowerUp = 1;
}
else
{
pev->renderfx = kRenderFxGlowShell;
pev->rendercolor = Vector( 128, 128, 128 ); // RGB
pev->renderamt = 5; // Shell size
}
}
bUpdate = TRUE;
9 years ago
}
if( m_iQuakeItems & IT_INVULNERABILITY && m_flInvincibleFinished <= gpGlobals->time + 3 && !m_bPlayedProtectSound )
9 years ago
{
ClientPrint( pev, HUD_PRINTNOTIFY, "#Protection_Off" );
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/protect2.wav", 1, ATTN_NORM );
9 years ago
m_bPlayedProtectSound = TRUE;
9 years ago
}
if( bUpdate )
9 years ago
{
W_SetCurrentAmmo();
9 years ago
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE,
edict(), g_usPowerUp, 0, (float *)&g_vecZero, (float *)&g_vecZero,
(float)iPowerUp, 0.0, entindex(), pev->team, 1, 0 );
9 years ago
}
}
8 years ago
#define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing
9 years ago
#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
8 years ago
void CBasePlayer::PreThink( void )
9 years ago
{
8 years ago
int buttonsChanged = ( m_afButtonLast ^ pev->button ); // These buttons have changed this frame
9 years ago
// Debounced button codes for pressed/released
// UNDONE: Do we need auto-repeat?
m_afButtonPressed = buttonsChanged & pev->button; // The changed ones still down are "pressed"
8 years ago
m_afButtonReleased = buttonsChanged & ( ~pev->button ); // The ones not down are "released"
9 years ago
g_pGameRules->PlayerThink( this );
8 years ago
if( g_fGameOver )
9 years ago
return; // intermission or finale
8 years ago
UTIL_MakeVectors( pev->v_angle ); // is this still used?
8 years ago
ItemPreFrame();
9 years ago
WaterMove();
8 years ago
if( g_pGameRules && g_pGameRules->FAllowFlashlight() )
9 years ago
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();
9 years ago
CheckTimeBasedDamage();
CheckSuitUpdate();
// Observer Button Handling
if( pev->iuser1 != 0 )
{
Observer_HandleButtons();
return;
}
//Run Powerup think (removes powerups over time, etc)
PowerUpThink();
// Dead think only if they're not an observer
/*if( IsObserver() )
{
Observer_HandleButtons();
Observer_CheckTarget();
Observer_CheckProperties();
pev->impulse = 0;
return;
}*/
8 years ago
if( pev->deadflag >= DEAD_DYING )
9 years ago
{
PlayerDeathThink();
return;
}
// So the correct flags get sent to client asap.
//
8 years ago
if( m_afPhysicsFlags & PFLAG_ONTRAIN )
9 years ago
pev->flags |= FL_ONTRAIN;
else
pev->flags &= ~FL_ONTRAIN;
// Train speed control
8 years ago
if( m_afPhysicsFlags & PFLAG_ONTRAIN )
9 years ago
{
CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity );
float vel;
int iGearId; // Vit_amiN: keeps the train control HUD in sync
8 years ago
if( !pTrain )
9 years ago
{
TraceResult trainTrace;
// Maybe this is on the other side of a level transition
8 years ago
UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -38 ), ignore_monsters, ENT( pev ), &trainTrace );
9 years ago
// HACKHACK - Just look for the func_tracktrain classname
8 years ago
if( trainTrace.flFraction != 1.0 && trainTrace.pHit )
9 years ago
pTrain = CBaseEntity::Instance( trainTrace.pHit );
8 years ago
if( !pTrain || !( pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE ) || !pTrain->OnControls( pev ) )
9 years ago
{
//ALERT( at_error, "In train mode with no train!\n" );
m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
m_iTrain = TRAIN_NEW|TRAIN_OFF;
return;
}
}
8 years ago
else if( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || ( pev->button & ( IN_MOVELEFT | IN_MOVERIGHT ) ) )
9 years ago
{
// Turn off the train if you jump, strafe, or the train controls go dead
m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
8 years ago
m_iTrain = TRAIN_NEW | TRAIN_OFF;
9 years ago
return;
}
pev->velocity = g_vecZero;
vel = 0;
8 years ago
if( m_afButtonPressed & IN_FORWARD )
9 years ago
{
vel = 1;
pTrain->Use( this, this, USE_SET, (float)vel );
}
8 years ago
else if( m_afButtonPressed & IN_BACK )
9 years ago
{
vel = -1;
pTrain->Use( this, this, USE_SET, (float)vel );
}
iGearId = TrainSpeed( pTrain->pev->speed, pTrain->pev->impulse );
if( iGearId != ( m_iTrain & 0x0F ) ) // Vit_amiN: speed changed
9 years ago
{
m_iTrain = iGearId;
m_iTrain |= TRAIN_ACTIVE | TRAIN_NEW;
9 years ago
}
}
else if( m_iTrain & TRAIN_ACTIVE )
9 years ago
m_iTrain = TRAIN_NEW; // turn off train
8 years ago
if( pev->button & IN_JUMP )
9 years ago
{
// If on a ladder, jump off the ladder
// else Jump
Jump();
}
// QUAKECLASSIC
// Duck removed
9 years ago
8 years ago
if( !FBitSet( pev->flags, FL_ONGROUND ) )
9 years ago
{
m_flFallVelocity = -pev->velocity.z;
}
8 years ago
// StudioFrameAdvance();//!!!HACKHACK!!! Can't be hit by traceline when not animating?
9 years ago
// Clear out ladder pointer
m_hEnemy = NULL;
8 years ago
if( m_afPhysicsFlags & PFLAG_ONBARNACLE )
9 years ago
{
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
8 years ago
#define DMG_POISON (1 << 16) // blood poisioning
9 years ago
#define DMG_RADIATION (1 << 17) // radiation exposure
#define DMG_DROWNRECOVER (1 << 18) // drown recovery
8 years ago
#define DMG_ACID (1 << 19) // toxic chemicals or acid burns
9 years ago
#define DMG_SLOWBURN (1 << 20) // in an oven
#define DMG_SLOWFREEZE (1 << 21) // in a subzero freezer
2) A new hit inflicting tbd restarts the tbd counter - each monster has an 8bit counter,
per damage type. The counter is decremented every second, so the maximum time
an effect will last is 255/60 = 4.25 minutes. Of course, staying within the radius
of a damaging effect like fire, nervegas, radiation will continually reset the counter to max.
3) Every second that a tbd counter is running, the player takes damage. The damage
is determined by the type of tdb.
Paralyze - 1/2 movement rate, 30 second duration.
Nervegas - 5 points per second, 16 second duration = 80 points max dose.
Poison - 2 points per second, 25 second duration = 50 points max dose.
Radiation - 1 point per second, 50 second duration = 50 points max dose.
Drown - 5 points per second, 2 second duration.
Acid/Chemical - 5 points per second, 10 second duration = 50 points max.
Burn - 10 points per second, 2 second duration.
Freeze - 3 points per second, 10 second duration = 30 points max.
4) Certain actions or countermeasures counteract the damaging effects of tbds:
Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body
- recharged by suit recharger
Air In Lungs - drowning damage is done to air in lungs first, then to body
- recharged by poking head out of water
- 10 seconds if swiming fast
Air In SCUBA - drowning damage is done to air in tanks first, then to body
- 2 minutes in tanks. Need new tank once empty.
Radiation Syringe - Each syringe full provides protection vs one radiation dosage
Antitoxin Syringe - Each syringe full provides protection vs one poisoning (nervegas or poison).
Health kit - Immediate stop to acid/chemical, fire or freeze damage.
Radiation Shower - Immediate stop to radiation damage, acid/chemical or fire damage.
*/
// If player is taking time based damage, continue doing damage to player -
// this simulates the effect of being poisoned, gassed, dosed with radiation etc -
// anything that continues to do damage even after the initial contact stops.
// Update all time based damage counters, and shut off any that are done.
// The m_bitsDamageType bit MUST be set if any damage is to be taken.
// This routine will detect the initial on value of the m_bitsDamageType
// and init the appropriate counter. Only processes damage every second.
8 years ago
//#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage
9 years ago
//#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval
8 years ago
//#define NERVEGAS_DURATION 16
9 years ago
//#define NERVEGAS_DAMAGE 5.0
//#define POISON_DURATION 25
8 years ago
//#define POISON_DAMAGE 2.0
9 years ago
8 years ago
//#define RADIATION_DURATION 50
//#define RADIATION_DAMAGE 1.0
9 years ago
8 years ago
//#define ACID_DURATION 10
9 years ago
//#define ACID_DAMAGE 5.0
8 years ago
//#define SLOWBURN_DURATION 2
9 years ago
//#define SLOWBURN_DAMAGE 1.0
8 years ago
//#define SLOWFREEZE_DURATION 1.0
//#define SLOWFREEZE_DAMAGE 3.0
9 years ago
void CBasePlayer::CheckTimeBasedDamage()
{
int i;
BYTE bDuration = 0;
//static float gtbdPrev = 0.0;
9 years ago
8 years ago
if( !( m_bitsDamageType & DMG_TIMEBASED ) )
9 years ago
return;
// only check for time based damage approx. every 2 seconds
8 years ago
if( fabs( gpGlobals->time - m_tbdPrev ) < 2.0 )
9 years ago
return;
9 years ago
m_tbdPrev = gpGlobals->time;
8 years ago
for( i = 0; i < CDMG_TIMEBASED; i++ )
9 years ago
{
// make sure bit is set for damage type
8 years ago
if( m_bitsDamageType & ( DMG_PARALYZE << i ) )
9 years ago
{
8 years ago
switch( i )
9 years ago
{
case itbd_Paralyze:
// UNDONE - flag movement as half-speed
bDuration = PARALYZE_DURATION;
break;
case itbd_NerveGas:
8 years ago
//TakeDamage( pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC );
9 years ago
bDuration = NERVEGAS_DURATION;
break;
case itbd_Poison:
8 years ago
TakeDamage( pev, pev, POISON_DAMAGE, DMG_GENERIC );
9 years ago
bDuration = POISON_DURATION;
break;
case itbd_Radiation:
8 years ago
//TakeDamage( pev, pev, RADIATION_DAMAGE, DMG_GENERIC );
9 years ago
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
8 years ago
if( m_idrowndmg > m_idrownrestored )
9 years ago
{
int idif = Q_min( m_idrowndmg - m_idrownrestored, 10 );
9 years ago
8 years ago
TakeHealth( idif, DMG_GENERIC );
9 years ago
m_idrownrestored += idif;
}
bDuration = 4; // get up to 5*10 = 50 points back
break;
case itbd_Acid:
8 years ago
//TakeDamage( pev, pev, ACID_DAMAGE, DMG_GENERIC );
9 years ago
bDuration = ACID_DURATION;
break;
case itbd_SlowBurn:
8 years ago
//TakeDamage( pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC );
9 years ago
bDuration = SLOWBURN_DURATION;
break;
case itbd_SlowFreeze:
8 years ago
//TakeDamage( pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC );
9 years ago
bDuration = SLOWFREEZE_DURATION;
break;
default:
bDuration = 0;
}
8 years ago
if( m_rgbTimeBasedDamage[i] )
9 years ago
{
// use up an antitoxin on poison or nervegas after a few seconds of damage
8 years ago
if( ( ( i == itbd_NerveGas ) && ( m_rgbTimeBasedDamage[i] < NERVEGAS_DURATION ) ) ||
( ( i == itbd_Poison ) && ( m_rgbTimeBasedDamage[i] < POISON_DURATION ) ) )
9 years ago
{
8 years ago
if( m_rgItems[ITEM_ANTIDOTE] )
9 years ago
{
m_rgbTimeBasedDamage[i] = 0;
m_rgItems[ITEM_ANTIDOTE]--;
8 years ago
SetSuitUpdate( "!HEV_HEAL4", FALSE, SUIT_REPEAT_OK );
9 years ago
}
}
// decrement damage duration, detect when done.
8 years ago
if( !m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0 )
9 years ago
{
m_rgbTimeBasedDamage[i] = 0;
9 years ago
// if we're done, clear damage bits
8 years ago
m_bitsDamageType &= ~( DMG_PARALYZE << i );
9 years ago
}
}
else
// first time taking this damage type - init damage duration
m_rgbTimeBasedDamage[i] = bDuration;
}
}
}
/*
THE POWER SUIT
The Suit provides 3 main functions: Protection, Notification and Augmentation.
Some functions are automatic, some require power.
The player gets the suit shortly after getting off the train in C1A0 and it stays
with him for the entire game.
Protection
Heat/Cold
When the player enters a hot/cold area, the heating/cooling indicator on the suit
will come on and the battery will drain while the player stays in the area.
After the battery is dead, the player starts to take damage.
This feature is built into the suit and is automatically engaged.
Radiation Syringe
This will cause the player to be immune from the effects of radiation for N seconds. Single use item.
Anti-Toxin Syringe
This will cure the player from being poisoned. Single use item.
Health
Small (1st aid kits, food, etc.)
Large (boxes on walls)
Armor
The armor works using energy to create a protective field that deflects a
percentage of damage projectile and explosive attacks. After the armor has been deployed,
it will attempt to recharge itself to full capacity with the energy reserves from the battery.
It takes the armor N seconds to fully charge.
Notification (via the HUD)
x Health
x Ammo
x Automatic Health Care
Notifies the player when automatic healing has been engaged.
x Geiger counter
Classic Geiger counter sound and status bar at top of HUD
alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal.
x Poison
Armor
Displays the current level of armor.
Augmentation
Reanimation (w/adrenaline)
Causes the player to come back to life after he has been dead for 3 seconds.
Will not work if player was gibbed. Single use.
Long Jump
Used by hitting the ??? key(s). Caused the player to further than normal.
SCUBA
Used automatically after picked up and after player enters the water.
Works for N seconds. Single use.
Things powered by the battery
Armor
Uses N watts for every M units of damage.
Heat/Cool
Uses N watts for every second in hot/cold area.
Long Jump
Uses N watts for every jump.
Alien Cloak
Uses N watts for each use. Each use lasts M seconds.
Alien Shield
Augments armor. Reduces Armor drain by one half
*/
// if in range of radiation source, ping geiger counter
#define GEIGERDELAY 0.25
8 years ago
void CBasePlayer::UpdateGeigerCounter( void )
9 years ago
{
BYTE range;
// delay per update ie: don't flood net with these msgs
8 years ago
if( gpGlobals->time < m_flgeigerDelay )
9 years ago
return;
m_flgeigerDelay = gpGlobals->time + GEIGERDELAY;
// send range to radition source to client
8 years ago
range = (BYTE)( m_flgeigerRange / 4 );
9 years ago
8 years ago
if( range != m_igeigerRangePrev )
9 years ago
{
m_igeigerRangePrev = range;
MESSAGE_BEGIN( MSG_ONE, gmsgGeigerRange, NULL, pev );
WRITE_BYTE( range );
MESSAGE_END();
}
// reset counter and semaphore
8 years ago
if( !RANDOM_LONG( 0, 3 ) )
9 years ago
m_flgeigerRange = 1000;
}
/*
================
CheckSuitUpdate
Play suit update if it's time
================
*/
8 years ago
#define SUITUPDATETIME 3.5
#define SUITFIRSTUPDATETIME 0.1
9 years ago
void CBasePlayer::CheckSuitUpdate()
{
int i;
int isentence = 0;
int isearch = m_iSuitPlayNext;
9 years ago
// Ignore suit updates if no suit
if( !( pev->weapons & ( 1 << IT_AXE ) ) )
9 years ago
return;
// if in range of radiation source, ping geiger counter
UpdateGeigerCounter();
8 years ago
if( g_pGameRules->IsMultiplayer() )
9 years ago
{
// don't bother updating HEV voice in multiplayer.
return;
}
8 years ago
if( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0 )
9 years ago
{
// play a sentence off of the end of the queue
8 years ago
for( i = 0; i < CSUITPLAYLIST; i++ )
{
8 years ago
if( ( isentence = m_rgSuitPlayList[isearch] ) )
9 years ago
break;
8 years ago
if( ++isearch == CSUITPLAYLIST )
9 years ago
isearch = 0;
}
9 years ago
8 years ago
if( isentence )
9 years ago
{
m_rgSuitPlayList[isearch] = 0;
8 years ago
if( isentence > 0 )
9 years ago
{
// play sentence number
char sentence[CBSENTENCENAME_MAX + 1];
8 years ago
strcpy( sentence, "!" );
strcat( sentence, gszallsentencenames[isentence] );
EMIT_SOUND_SUIT( ENT( pev ), sentence );
9 years ago
}
else
{
// play sentence group
8 years ago
EMIT_GROUPID_SUIT( ENT( pev ), -isentence );
9 years ago
}
m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME;
9 years ago
}
else
// queue is empty, don't check
m_flSuitUpdate = 0;
}
}
9 years ago
// add sentence to suit playlist queue. if fgroup is true, then
// name is a sentence group (HEV_AA), otherwise name is a specific
// sentence name ie: !HEV_AA0. If iNoRepeat is specified in
// seconds, then we won't repeat playback of this word or sentence
// for at least that number of seconds.
void CBasePlayer::SetSuitUpdate( const char *name, int fgroup, int iNoRepeatTime )
9 years ago
{
int i;
int isentence;
int iempty = -1;
9 years ago
// Ignore suit updates if no suit
if( !( pev->weapons & ( 1 << IT_AXE ) ) )
9 years ago
return;
8 years ago
if( g_pGameRules->IsMultiplayer() )
9 years ago
{
// 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
8 years ago
if( !name )
9 years ago
{
8 years ago
for( i = 0; i < CSUITPLAYLIST; i++ )
9 years ago
m_rgSuitPlayList[i] = 0;
return;
}
9 years ago
// get sentence or group number
8 years ago
if( !fgroup )
9 years ago
{
8 years ago
isentence = SENTENCEG_Lookup( name, NULL );
if( isentence < 0 )
9 years ago
return;
}
else
// mark group number as negative
8 years ago
isentence = -SENTENCEG_GetIndex( name );
9 years ago
// check norepeat list - this list lets us cancel
// the playback of words or sentences that have already
// been played within a certain time.
8 years ago
for( i = 0; i < CSUITNOREPEAT; i++ )
9 years ago
{
8 years ago
if( isentence == m_rgiSuitNoRepeat[i] )
{
9 years ago
// this sentence or group is already in
// the norepeat list
8 years ago
if( m_rgflSuitNoRepeatTime[i] < gpGlobals->time )
{
9 years ago
// norepeat time has expired, clear it out
m_rgiSuitNoRepeat[i] = 0;
m_rgflSuitNoRepeatTime[i] = 0.0;
iempty = i;
break;
}
9 years ago
else
{
9 years ago
// don't play, still marked as norepeat
return;
}
}
9 years ago
// keep track of empty slot
8 years ago
if( !m_rgiSuitNoRepeat[i] )
9 years ago
iempty = i;
}
// sentence is not in norepeat list, save if norepeat time was given
8 years ago
if( iNoRepeatTime )
9 years ago
{
8 years ago
if( iempty < 0 )
iempty = RANDOM_LONG( 0, CSUITNOREPEAT - 1 ); // pick random slot to take over
9 years ago
m_rgiSuitNoRepeat[iempty] = isentence;
m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->time;
}
// find empty spot in queue, or overwrite last spot
m_rgSuitPlayList[m_iSuitPlayNext++] = isentence;
8 years ago
if( m_iSuitPlayNext == CSUITPLAYLIST )
9 years ago
m_iSuitPlayNext = 0;
8 years ago
if( m_flSuitUpdate <= gpGlobals->time )
9 years ago
{
8 years ago
if( m_flSuitUpdate == 0 )
9 years ago
// 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
================
*/
8 years ago
static void CheckPowerups( entvars_t *pev )
9 years ago
{
8 years ago
if( pev->health <= 0 )
9 years ago
return;
pev->modelindex = g_ulModelIndexPlayer; // don't use eyes
}
void CBasePlayer::PostThink()
{
8 years ago
if( g_fGameOver )
goto pt_end; // intermission or finale
9 years ago
8 years ago
if( !IsAlive() )
9 years ago
goto pt_end;
// Handle Tank controlling
if( m_pTank != 0 )
{
// if they've moved too far from the gun, or selected a weapon, unuse the gun
8 years ago
if( m_pTank->OnControls( pev ) && !pev->weaponmodel )
9 years ago
{
m_pTank->Use( this, this, USE_SET, 2 ); // try fire the gun
}
else
{
// they've moved off the platform
9 years ago
m_pTank->Use( this, this, USE_OFF, 0 );
}
}
// do weapon stuff
8 years ago
ItemPostFrame();
9 years ago
8 years ago
// 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
9 years ago
8 years ago
if( ( FBitSet( pev->flags, FL_ONGROUND ) ) && ( pev->health > 0 ) && m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD )
9 years ago
{
8 years ago
// ALERT( at_console, "%f\n", m_flFallVelocity );
if( pev->watertype == CONTENT_WATER )
9 years ago
{
// 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
8 years ago
// if( !pev->groundentity || VARS(pev->groundentity )->velocity.z == 0 )
// EMIT_SOUND( ENT( pev ), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM );
9 years ago
}
8 years ago
else if( m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED )
{
// after this point, we start doing damage
9 years ago
float flFallDamage = g_pGameRules->FlPlayerFallDamage( this );
8 years ago
if( flFallDamage > pev->health )
{
//splat
9 years ago
// note: play on item channel because we play footstep landing on body channel
8 years ago
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "common/bodysplat.wav", 1, ATTN_NORM );
9 years ago
}
8 years ago
if( flFallDamage > 0 )
9 years ago
{
8 years ago
TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), flFallDamage, DMG_FALL );
9 years ago
pev->punchangle.x = 0;
}
}
8 years ago
if( IsAlive() )
9 years ago
{
SetAnimation( PLAYER_WALK );
}
}
9 years ago
8 years ago
if( FBitSet( pev->flags, FL_ONGROUND ) )
{
//if( m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer() )
// TODO Make noise
9 years ago
m_flFallVelocity = 0;
}
// select the proper animation for the player character
8 years ago
if( IsAlive() )
9 years ago
{
8 years ago
if( !pev->velocity.x && !pev->velocity.y )
9 years ago
SetAnimation( PLAYER_IDLE );
8 years ago
else if( ( pev->velocity.x || pev->velocity.y ) && ( FBitSet( pev->flags, FL_ONGROUND ) ) )
9 years ago
SetAnimation( PLAYER_WALK );
8 years ago
else if( pev->waterlevel > 1 )
9 years ago
SetAnimation( PLAYER_WALK );
}
8 years ago
StudioFrameAdvance();
CheckPowerups( pev );
9 years ago
// Track button info so we can detect 'pressed' and 'released' buttons next frame
m_afButtonLast = pev->button;
pt_end:
if( pev->deadflag == DEAD_NO )
m_vecLastViewAngles = pev->angles;
else
pev->angles = m_vecLastViewAngles;
9 years ago
#if defined( CLIENT_WEAPONS )
// Decay timers on weapons
9 years ago
// go through all of the weapons and make a list of the ones to pack
8 years ago
for( int i = 0; i < MAX_ITEM_TYPES; i++ )
9 years ago
{
8 years ago
if( m_rgpPlayerItems[i] )
9 years ago
{
8 years ago
CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[i];
9 years ago
8 years ago
while( pPlayerItem )
9 years ago
{
CBasePlayerWeapon *gun;
gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr();
8 years ago
if( gun && gun->UseDecrement() )
9 years ago
{
gun->m_flNextPrimaryAttack = Q_max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 );
gun->m_flNextSecondaryAttack = Q_max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001 );
9 years ago
8 years ago
if( gun->m_flTimeWeaponIdle != 1000 )
9 years ago
{
gun->m_flTimeWeaponIdle = Q_max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 );
9 years ago
}
}
pPlayerItem = pPlayerItem->m_pNext;
}
}
}
m_flNextAttack -= gpGlobals->frametime;
8 years ago
if( m_flNextAttack < -0.001 )
9 years ago
m_flNextAttack = -0.001;
#else
return;
#endif
}
// checks if the spot is clear of players
BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot )
{
CBaseEntity *ent = NULL;
8 years ago
if( !pSpot->IsTriggered( pPlayer ) )
9 years ago
{
return FALSE;
}
while( ( ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 96 ) ) != NULL )
9 years ago
{
// if ent is a client, don't spawn on 'em
8 years ago
if( ent->IsPlayer() && ent != pPlayer )
9 years ago
return FALSE;
}
return TRUE;
}
DLL_GLOBAL CBaseEntity *g_pLastSpawn;
8 years ago
inline int FNullEnt( CBaseEntity *ent ) { return ( ent == NULL ) || FNullEnt( ent->edict() ); }
9 years ago
/*
============
EntSelectSpawnPoint
Returns the entity to spawn at
USES AND SETS GLOBAL g_pLastSpawn
============
*/
edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer, bool bCheckDM )
9 years ago
{
CBaseEntity *pSpot;
8 years ago
edict_t *player;
const char *pszName;
9 years ago
player = pPlayer->edict();
// choose a info_player_deathmatch point
/*if( g_pGameRules->IsCoOp() )
9 years ago
{
8 years ago
pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_coop" );
if( !FNullEnt( pSpot ) )
9 years ago
goto ReturnSpot;
8 years ago
pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_start" );
if( !FNullEnt(pSpot) )
9 years ago
goto ReturnSpot;
}
else if( g_pGameRules->IsDeathmatch() )*/
9 years ago
{
pSpot = g_pLastSpawn;
// Randomize the start spot
8 years ago
for( int i = RANDOM_LONG( 1, 5 ); i > 0; i-- )
{
if( !bCheckDM )
{
if( player->v.team == 1 )
pszName = "info_player_team1";
else if( player->v.team == 2 )
pszName = "info_player_team2";
else
pszName = "info_player_deathmatch";
}
else
pszName = "info_player_deathmatch";
pSpot = UTIL_FindEntityByClassname( pSpot, pszName );
}
8 years ago
if( FNullEnt( pSpot ) ) // skip over the null point
{
if( !bCheckDM )
{
if( player->v.team == 1 )
pszName = "info_player_team1";
else if( player->v.team == 2 )
pszName = "info_player_team2";
else
pszName = "info_player_deathmatch";
}
else
pszName = "info_player_deathmatch";
pSpot = UTIL_FindEntityByClassname( pSpot, pszName );
}
9 years ago
CBaseEntity *pFirstSpot = pSpot;
do
{
8 years ago
if( pSpot )
9 years ago
{
// check if pSpot is valid
8 years ago
if( IsSpawnPointValid( pPlayer, pSpot ) )
9 years ago
{
8 years ago
if( pSpot->pev->origin == Vector( 0, 0, 0 ) )
9 years ago
{
if( !bCheckDM )
{
if( player->v.team == 1 )
pszName = "info_player_team1";
else if( player->v.team == 2 )
pszName = "info_player_team2";
else
pszName = "info_player_deathmatch";
}
else
pszName = "info_player_deathmatch";
pSpot = UTIL_FindEntityByClassname( pSpot, pszName );
9 years ago
continue;
}
// if so, go to pSpot
goto ReturnSpot;
}
}
// increment pSpot
if( !bCheckDM )
{
if( player->v.team == 1 )
pszName = "info_player_team1";
else if( player->v.team == 2 )
pszName = "info_player_team2";
else
pszName = "info_player_deathmatch";
}
else
pszName = "info_player_deathmatch";
pSpot = UTIL_FindEntityByClassname( pSpot, pszName );
8 years ago
} while( pSpot != pFirstSpot ); // loop if we're not back to the start
9 years ago
// we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
8 years ago
if( !FNullEnt( pSpot ) )
9 years ago
{
CBaseEntity *ent = NULL;
8 years ago
while( ( ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 ) ) != NULL )
9 years ago
{
// if ent is a client, kill em (unless they are ourselves)
8 years ago
if( ent->IsPlayer() && !(ent->edict() == player) )
ent->TakeDamage( VARS( INDEXENT( 0 ) ), VARS( INDEXENT( 0 ) ), 300, DMG_GENERIC );
9 years ago
}
goto ReturnSpot;
}
}
// If startspot is set, (re)spawn there.
8 years ago
if( FStringNull( gpGlobals->startspot ) || !strlen(STRING( gpGlobals->startspot ) ) )
9 years ago
{
8 years ago
pSpot = UTIL_FindEntityByClassname( NULL, "info_player_start" );
if( !FNullEnt( pSpot ) )
9 years ago
goto ReturnSpot;
}
else
{
8 years ago
pSpot = UTIL_FindEntityByTargetname( NULL, STRING( gpGlobals->startspot ) );
if( !FNullEnt( pSpot ) )
9 years ago
goto ReturnSpot;
}
ReturnSpot:
8 years ago
if( FNullEnt( pSpot ) )
9 years ago
{
8 years ago
ALERT( at_error, "PutClientInServer: no info_player_start on level" );
return INDEXENT( 0 );
9 years ago
}
g_pLastSpawn = pSpot;
return pSpot->edict();
}
void CBasePlayer::Spawn( void )
{
8 years ago
pev->classname = MAKE_STRING( "player" );
pev->health = 100;
pev->armorvalue = 0;
pev->takedamage = DAMAGE_AIM;
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_WALK;
pev->max_health = pev->health;
pev->flags &= FL_PROXY; // keep proxy flag sey by engine
pev->flags |= FL_CLIENT;
pev->air_finished = gpGlobals->time + 12;
pev->dmg = 2; // initial water damage
pev->effects = 0;
pev->deadflag = DEAD_NO;
pev->dmg_take = 0;
pev->dmg_save = 0;
pev->friction = 1.0;
pev->gravity = 1.0;
m_bitsHUDDamage = -1;
m_bitsDamageType = 0;
m_afPhysicsFlags = 0;
m_fLongJump = FALSE;// no longjump module.
9 years ago
g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" );
g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" );
8 years ago
m_flNextDecalTime = 0;// let this player decal as soon as he spawns.
9 years ago
m_flgeigerDelay = gpGlobals->time + 2.0; // wait a few seconds until user-defined message registrations
// are recieved by all clients
8 years ago
m_flTimeStepSound = 0;
9 years ago
m_iStepLeft = 0;
8 years ago
m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them.
9 years ago
8 years ago
m_bloodColor = BLOOD_COLOR_RED;
m_flNextAttack = UTIL_WeaponTimeBase();
9 years ago
StartSneaking();
m_iFlashBattery = 99;
m_flFlashLightTime = 1; // force first message
// dont let uninitialized value here hurt the player
9 years ago
m_flFallVelocity = 0;
//g_pGameRules->SetDefaultPlayerTeam( this );
9 years ago
g_pGameRules->GetPlayerSpawnSpot( this );
8 years ago
SET_MODEL( ENT( pev ), "models/player.mdl" );
g_ulModelIndexPlayer = pev->modelindex;
8 years ago
pev->sequence = LookupActivity( ACT_IDLE );
9 years ago
UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX );
9 years ago
pev->view_ofs = VEC_VIEW;
9 years ago
Precache();
8 years ago
m_HackedGunPos = Vector( 0, 32, 0 );
9 years ago
m_fNoPlayerSound = FALSE;// normal sound behavior.
m_pLastItem = NULL;
m_fInitHUD = TRUE;
m_iClientHideHUD = -1; // force this to be recalculated
m_fWeapon = FALSE;
m_pClientActiveItem = NULL;
m_iClientBattery = -1;
m_flLightningTime = 0.0;
InitStatusBar();
m_iQuakeItems = 0;
9 years ago
// reset all ammo values to 0
8 years ago
for( int i = 0; i < MAX_AMMO_SLOTS; i++ )
9 years ago
{
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;
8 years ago
9 years ago
m_flNextChatTime = gpGlobals->time;
if( !m_bHadFirstSpawn && g_bHaveMOTD )
{
pev->effects |= EF_NODRAW;
pev->solid = SOLID_NOT;
pev->takedamage = DAMAGE_NO;
pev->movetype = MOVETYPE_NONE;
//++ BulliT
pev->deadflag = DEAD_RESPAWNABLE;
//-- Martin Webrant
g_engfuncs.pfnSetClientMaxspeed( ENT( pev ), 1 );
m_iHideHUD |= HIDEHUD_WEAPONS | HIDEHUD_FLASHLIGHT | HIDEHUD_HEALTH;
}
else
{
g_engfuncs.pfnSetClientMaxspeed( ENT( pev ), PLAYER_MAX_SPEED );
m_iHideHUD &= ~( HIDEHUD_WEAPONS | HIDEHUD_HEALTH );
pev->effects &= ~EF_NODRAW;
g_pGameRules->PlayerSpawn( this );
//++ BulliT
Spectate_UpdatePosition();
//-- Martin Webrant
PLAYBACK_EVENT_FULL( FEV_GLOBAL, edict(), g_sTeleport, 0.0, (float *)&pev->origin, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 );
m_fKnownItem = false;
}
9 years ago
}
8 years ago
void CBasePlayer::Precache( void )
9 years ago
{
// 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.
8 years ago
9 years ago
// !!!BUGBUG - now that we have multiplayer, this needs to be moved!
8 years ago
if( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet )
9 years ago
{
8 years ago
if( !WorldGraph.FSetGraphPointers() )
9 years ago
{
8 years ago
ALERT( at_console, "**Graph pointers were not set!\n" );
9 years ago
}
else
{
8 years ago
ALERT( at_console, "**Graph Pointers Set!\n" );
}
9 years ago
}
// SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific)
// because they need to precache before any clients have connected
m_usShotgunSingle = PRECACHE_EVENT( 1, "events/shotgun1.sc" );
m_usShotgunDouble = PRECACHE_EVENT( 1, "events/shotgun2.sc" );
m_usAxe = PRECACHE_EVENT( 1, "events/axe.sc" );
m_usAxeSwing = PRECACHE_EVENT( 1, "events/axeswing.sc" );
m_usRocket = PRECACHE_EVENT( 1, "events/rocket.sc" );
m_usGrenade = PRECACHE_EVENT( 1, "events/grenade.sc" );
m_usLightning = PRECACHE_EVENT( 1, "events/lightning.sc" );
m_usSpike = PRECACHE_EVENT( 1, "events/spike.sc" );
m_usSuperSpike = PRECACHE_EVENT( 1, "events/superspike.sc" );
9 years ago
// 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_flFlashLightTime = 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
8 years ago
if( gInitHUD )
9 years ago
m_fInitHUD = TRUE;
pev->fov = m_iFOV; // Vit_amiN: restore the FOV on level change or map/saved game load
9 years ago
}
int CBasePlayer::Save( CSave &save )
{
8 years ago
if( !CBaseMonster::Save( save ) )
9 years ago
return 0;
8 years ago
return save.WriteFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE( m_playerSaveData ) );
9 years ago
}
//
// Marks everything as new so the player will resend this to the hud.
//
8 years ago
void CBasePlayer::RenewItems( void )
9 years ago
{
}
int CBasePlayer::Restore( CRestore &restore )
{
8 years ago
if( !CBaseMonster::Restore( restore ) )
9 years ago
return 0;
8 years ago
int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE( m_playerSaveData ) );
9 years ago
SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData;
// landmark isn't present.
8 years ago
if( !pSaveData->fUseLandmark )
9 years ago
{
ALERT( at_console, "No Landmark:%s\n", pSaveData->szLandmarkName );
// default to normal spawn
edict_t *pentSpawnSpot = EntSelectSpawnPoint( this, TRUE );
8 years ago
pev->origin = VARS( pentSpawnSpot )->origin + Vector( 0, 0, 1 );
pev->angles = VARS( pentSpawnSpot )->angles;
9 years ago
}
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
8 years ago
m_bloodColor = BLOOD_COLOR_RED;
9 years ago
g_ulModelIndexPlayer = pev->modelindex;
9 years ago
/*if( FBitSet( pev->flags, FL_DUCKING ) )
9 years ago
{
// Use the crouch HACK
//FixPlayerCrouchStuck( edict() );
// Don't need to do this with new player prediction code.
8 years ago
UTIL_SetSize( pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
9 years ago
}
else
{
8 years ago
UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX );
}*/
9 years ago
RenewItems();
#if defined( CLIENT_WEAPONS )
// HACK: This variable is saved/restored in CBaseMonster as a time variable, but we're using it
// as just a counter. Ideally, this needs its own variable that's saved as a plain float.
// Barring that, we clear it out here instead of using the incorrect restored time value.
m_flNextAttack = UTIL_WeaponTimeBase();
#endif
return status;
}
void CBasePlayer::SelectNextItem( int iItem )
{
CBasePlayerItem *pItem;
8 years ago
pItem = m_rgpPlayerItems[iItem];
if( !pItem )
9 years ago
return;
8 years ago
if( pItem == m_pActiveItem )
9 years ago
{
// select the next one in the chain
pItem = m_pActiveItem->m_pNext;
8 years ago
if( !pItem )
9 years ago
{
return;
}
CBasePlayerItem *pLast;
pLast = pItem;
8 years ago
while( pLast->m_pNext )
9 years ago
pLast = pLast->m_pNext;
// relink chain
pLast->m_pNext = m_pActiveItem;
m_pActiveItem->m_pNext = NULL;
8 years ago
m_rgpPlayerItems[iItem] = pItem;
9 years ago
}
8 years ago
ResetAutoaim();
9 years ago
// FIX, this needs to queue them up and delay
8 years ago
if( m_pActiveItem )
9 years ago
{
8 years ago
m_pActiveItem->Holster();
9 years ago
}
8 years ago
9 years ago
m_pActiveItem = pItem;
8 years ago
if( m_pActiveItem )
9 years ago
{
8 years ago
m_pActiveItem->Deploy();
m_pActiveItem->UpdateItemInfo();
9 years ago
}
}
8 years ago
void CBasePlayer::SelectItem( const char *pstr )
9 years ago
{
8 years ago
if( !pstr )
9 years ago
return;
CBasePlayerItem *pItem = NULL;
8 years ago
for( int i = 0; i < MAX_ITEM_TYPES; i++ )
9 years ago
{
8 years ago
if( m_rgpPlayerItems[i] )
9 years ago
{
pItem = m_rgpPlayerItems[i];
8 years ago
while( pItem )
9 years ago
{
8 years ago
if( FClassnameIs( pItem->pev, pstr ) )
9 years ago
break;
pItem = pItem->m_pNext;
}
}
8 years ago
if( pItem )
9 years ago
break;
}
8 years ago
if( !pItem )
9 years ago
return;
8 years ago
if( pItem == m_pActiveItem )
9 years ago
return;
8 years ago
ResetAutoaim();
9 years ago
// FIX, this needs to queue them up and delay
8 years ago
if( m_pActiveItem )
m_pActiveItem->Holster();
9 years ago
m_pLastItem = m_pActiveItem;
m_pActiveItem = pItem;
8 years ago
if( m_pActiveItem )
9 years ago
{
8 years ago
m_pActiveItem->Deploy();
m_pActiveItem->UpdateItemInfo();
9 years ago
}
}
8 years ago
void CBasePlayer::SelectLastItem( void )
9 years ago
{
8 years ago
if( !m_pLastItem )
9 years ago
{
return;
}
8 years ago
if( m_pActiveItem && !m_pActiveItem->CanHolster() )
9 years ago
{
return;
}
8 years ago
ResetAutoaim();
9 years ago
// FIX, this needs to queue them up and delay
8 years ago
if( m_pActiveItem )
m_pActiveItem->Holster();
9 years ago
CBasePlayerItem *pTemp = m_pActiveItem;
m_pActiveItem = m_pLastItem;
m_pLastItem = pTemp;
8 years ago
m_pActiveItem->Deploy();
m_pActiveItem->UpdateItemInfo();
9 years ago
}
//==============================================
// HasWeapons - do I have any weapons at all?
//==============================================
BOOL CBasePlayer::HasWeapons( void )
{
int i;
8 years ago
for( i = 0; i < MAX_ITEM_TYPES; i++ )
9 years ago
{
8 years ago
if( m_rgpPlayerItems[i] )
9 years ago
{
return TRUE;
}
}
return FALSE;
}
void CBasePlayer::SelectPrevItem( int iItem )
{
}
const char *CBasePlayer::TeamID( void )
{
8 years ago
if( pev == NULL ) // Not fully connected yet
9 years ago
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:
8 years ago
void Spawn( entvars_t *pevOwner );
void Think( void );
9 years ago
8 years ago
virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; }
9 years ago
};
8 years ago
void CSprayCan::Spawn( entvars_t *pevOwner )
9 years ago
{
8 years ago
pev->origin = pevOwner->origin + Vector( 0, 0, 32 );
9 years ago
pev->angles = pevOwner->v_angle;
8 years ago
pev->owner = ENT( pevOwner );
9 years ago
pev->frame = 0;
pev->nextthink = gpGlobals->time + 0.1;
8 years ago
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "player/sprayer.wav", 1, ATTN_NORM );
9 years ago
}
void CSprayCan::Think( void )
{
8 years ago
TraceResult tr;
9 years ago
int playernum;
int nFrames;
CBasePlayer *pPlayer;
8 years ago
pPlayer = (CBasePlayer *)GET_PRIVATE( pev->owner );
if( pPlayer )
9 years ago
nFrames = pPlayer->GetCustomDecalFrames();
else
nFrames = -1;
8 years ago
playernum = ENTINDEX( pev->owner );
// ALERT( at_console, "Spray by player %i, %i of %i\n", playernum, (int)( pev->frame + 1 ), nFrames );
9 years ago
8 years ago
UTIL_MakeVectors( pev->angles );
UTIL_TraceLine( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr );
9 years ago
// No customization present.
8 years ago
if( nFrames == -1 )
9 years ago
{
UTIL_DecalTrace( &tr, DECAL_LAMBDA6 );
UTIL_Remove( this );
}
else
{
UTIL_PlayerDecalTrace( &tr, playernum, (int)pev->frame, TRUE );
9 years ago
// Just painted last custom frame.
8 years ago
if( pev->frame++ >= ( nFrames - 1 ) )
9 years ago
UTIL_Remove( this );
}
pev->nextthink = gpGlobals->time + 0.1;
}
8 years ago
class CBloodSplat : public CBaseEntity
9 years ago
{
public:
8 years ago
void Spawn( entvars_t *pevOwner );
void Spray( void );
9 years ago
};
8 years ago
void CBloodSplat::Spawn( entvars_t *pevOwner )
9 years ago
{
8 years ago
pev->origin = pevOwner->origin + Vector( 0, 0, 32 );
9 years ago
pev->angles = pevOwner->v_angle;
8 years ago
pev->owner = ENT( pevOwner );
9 years ago
SetThink( &CBloodSplat::Spray );
pev->nextthink = gpGlobals->time + 0.1;
}
8 years ago
void CBloodSplat::Spray( void )
9 years ago
{
8 years ago
TraceResult tr;
8 years ago
if( g_Language != LANGUAGE_GERMAN )
9 years ago
{
8 years ago
UTIL_MakeVectors( pev->angles );
UTIL_TraceLine( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr );
9 years ago
UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED );
}
SetThink( &CBaseEntity::SUB_Remove );
pev->nextthink = gpGlobals->time + 0.1;
}
//==============================================
void CBasePlayer::GiveNamedItem( const char *pszName )
{
edict_t *pent;
8 years ago
int istr = MAKE_STRING( pszName );
9 years ago
8 years ago
pent = CREATE_NAMED_ENTITY( istr );
if( FNullEnt( pent ) )
9 years ago
{
8 years ago
ALERT( at_console, "NULL Ent in GiveNamedItem!\n" );
9 years ago
return;
}
VARS( pent )->origin = pev->origin;
pent->v.spawnflags |= SF_NORESPAWN;
DispatchSpawn( pent );
DispatchTouch( pent, ENT( pev ) );
}
CBaseEntity *FindEntityForward( CBaseEntity *pMe )
{
TraceResult tr;
8 years ago
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 ) )
9 years ago
{
CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit );
return pHit;
}
return NULL;
}
8 years ago
BOOL CBasePlayer::FlashlightIsOn( void )
9 years ago
{
8 years ago
return FBitSet( pev->effects, EF_DIMLIGHT );
9 years ago
}
8 years ago
void CBasePlayer::FlashlightTurnOn( void )
9 years ago
{
8 years ago
if( !g_pGameRules->FAllowFlashlight() )
9 years ago
{
return;
}
if( (pev->weapons & ( 1 << IT_AXE ) ) )
9 years ago
{
8 years ago
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, SOUND_FLASHLIGHT_ON, 1.0, ATTN_NORM, 0, PITCH_NORM );
SetBits( pev->effects, EF_DIMLIGHT );
9 years ago
MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev );
8 years ago
WRITE_BYTE( 1 );
WRITE_BYTE( m_iFlashBattery );
9 years ago
MESSAGE_END();
m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time;
}
}
8 years ago
void CBasePlayer::FlashlightTurnOff( void )
9 years ago
{
8 years ago
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, SOUND_FLASHLIGHT_OFF, 1.0, ATTN_NORM, 0, PITCH_NORM );
ClearBits( pev->effects, EF_DIMLIGHT );
9 years ago
MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev );
8 years ago
WRITE_BYTE( 0 );
WRITE_BYTE( m_iFlashBattery );
9 years ago
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.
===============
*/
8 years ago
void CBasePlayer::ForceClientDllUpdate( void )
9 years ago
{
8 years ago
m_iClientHealth = -1;
9 years ago
m_iClientBattery = -1;
m_iClientQuakeItems = -1;
m_iClientQuakeWeapon = -1;
m_iClientHideHUD = -1; // Vit_amiN: forcing to update
m_iClientFOV = -1; // Vit_amiN: force client weapons to be sent
9 years ago
m_iTrain |= TRAIN_NEW; // Force new train message.
m_fWeapon = FALSE; // Force weapon send
m_fKnownItem = FALSE; // Force weaponinit messages.
m_fInitHUD = TRUE; // Force HUD gmsgResetHUD message
m_bSentBhopcap = true; // a1ba: Update bhopcap state
memset( m_rgAmmoLast, 0, sizeof( m_rgAmmoLast )); // a1ba: Force update AmmoX
9 years ago
// Now force all the necessary messages
// to be sent.
UpdateClientData();
}
/*
============
ImpulseCommands
============
*/
extern float g_flWeaponCheat;
8 years ago
void CBasePlayer::ImpulseCommands()
9 years ago
{
8 years ago
TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs
9 years ago
// Handle use events
PlayerUse();
9 years ago
int iImpulse = (int)pev->impulse;
// QUAKECLASSIC
// Handle weapon switches first
/*if( iImpulse >= 1 && iImpulse <= 8 )
{
W_ChangeWeapon( iImpulse );
}
else
{*/
8 years ago
switch( iImpulse )
9 years ago
{
// QUAKECLASSIC
case 10:
W_CycleWeaponCommand();
break;
case 12:
W_CycleWeaponReverseCommand();
break;
9 years ago
case 99:
int iOn;
8 years ago
if( !gmsgLogo )
9 years ago
{
iOn = 1;
8 years ago
gmsgLogo = REG_USER_MSG( "Logo", 1 );
9 years ago
}
else
{
iOn = 0;
}
9 years ago
ASSERT( gmsgLogo > 0 );
9 years ago
// send "health" update message
MESSAGE_BEGIN( MSG_ONE, gmsgLogo, NULL, pev );
8 years ago
WRITE_BYTE( iOn );
9 years ago
MESSAGE_END();
if(!iOn)
gmsgLogo = 0;
break;
/*case 100:
9 years ago
// temporary flashlight for level designers
8 years ago
if( FlashlightIsOn() )
9 years ago
{
FlashlightTurnOff();
}
8 years ago
else
9 years ago
{
FlashlightTurnOn();
}
break;*/
case 201:
// paint decal
8 years ago
if( gpGlobals->time < m_flNextDecalTime )
9 years ago
{
// too early!
break;
}
8 years ago
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 );
9 years ago
8 years ago
if( tr.flFraction != 1.0 )
{
// line hit something, so paint a decal
9 years ago
m_flNextDecalTime = gpGlobals->time + decalfrequency.value;
8 years ago
CSprayCan *pCan = GetClassPtr( (CSprayCan *)NULL );
9 years ago
pCan->Spawn( pev );
}
break;
default:
// check all of the cheat impulse commands now
CheatImpulseCommands( iImpulse );
break;
}
//}
9 years ago
pev->impulse = 0;
}
//=========================================================
//=========================================================
void CBasePlayer::CheatImpulseCommands( int iImpulse )
{
#if !defined( HLDEMO_BUILD )
8 years ago
if( g_flWeaponCheat == 0.0 )
9 years ago
{
return;
}
CBaseEntity *pEntity;
TraceResult tr;
8 years ago
switch( iImpulse )
9 years ago
{
case 76:
8 years ago
if( !giPrecacheGrunt )
9 years ago
{
8 years ago
giPrecacheGrunt = 1;
ALERT( at_console, "You must now restart to use Grunt-o-matic.\n" );
9 years ago
}
8 years ago
else
{
UTIL_MakeVectors( Vector( 0, pev->v_angle.y, 0 ) );
Create( "monster_human_grunt", pev->origin + gpGlobals->v_forward * 128, pev->angles );
}
break;
9 years ago
case 101:
gEvilImpulse101 = TRUE;
m_iAmmoNails = 200;
m_iAmmoShells = 100;
m_iAmmoRockets = 100;
m_iAmmoCells = 100;
m_iQuakeItems |= IT_NAILGUN | IT_SUPER_NAILGUN | IT_SUPER_SHOTGUN | IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER | IT_LIGHTNING;
CheckAmmo();
W_SetCurrentAmmo();
9 years ago
gEvilImpulse101 = FALSE;
break;
case 102:
// Gibbage!!!
CGib::SpawnRandomGibs( pev, 1, 1 );
break;
case 103:
// What the hell are you doing?
pEntity = FindEntityForward( this );
8 years ago
if( pEntity )
9 years ago
{
CBaseMonster *pMonster = pEntity->MyMonsterPointer();
8 years ago
if( pMonster )
9 years ago
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.
8 years ago
if( m_fNoPlayerSound )
9 years ago
{
8 years ago
ALERT( at_console, "Player is audible\n" );
m_fNoPlayerSound = FALSE;
}
else
{
ALERT( at_console, "Player is silent\n" );
m_fNoPlayerSound = TRUE;
9 years ago
}
8 years ago
break;
9 years ago
case 106:
// Give me the classname and targetname of this entity.
pEntity = FindEntityForward( this );
8 years ago
if( pEntity )
9 years ago
{
8 years ago
ALERT( at_console, "Classname: %s", STRING( pEntity->pev->classname ) );
if( !FStringNull( pEntity->pev->targetname ) )
9 years ago
{
8 years ago
ALERT( at_console, " - Targetname: %s\n", STRING( pEntity->pev->targetname ) );
9 years ago
}
else
{
8 years ago
ALERT( at_console, " - TargetName: No Targetname\n" );
9 years ago
}
8 years ago
ALERT( at_console, "Model: %s\n", STRING( pEntity->pev->model ) );
if( pEntity->pev->globalname )
ALERT( at_console, "Globalname: %s\n", STRING( pEntity->pev->globalname ) );
9 years ago
}
break;
case 107:
{
//TraceResult tr;
8 years ago
edict_t *pWorld = g_engfuncs.pfnPEntityOfEntIndex( 0 );
9 years ago
Vector start = pev->origin + pev->view_ofs;
Vector end = start + gpGlobals->v_forward * 1024;
UTIL_TraceLine( start, end, ignore_monsters, edict(), &tr );
8 years ago
if( tr.pHit )
9 years ago
pWorld = tr.pHit;
const char *pTextureName = TRACE_TEXTURE( pWorld, start, end );
8 years ago
if( pTextureName )
9 years ago
ALERT( at_console, "Texture: %s\n", pTextureName );
}
break;
8 years ago
case 195:
// show shortest paths for entire level to nearest node
9 years ago
{
8 years ago
Create( "node_viewer_fly", pev->origin, pev->angles );
9 years ago
}
break;
8 years ago
case 196:
// show shortest paths for entire level to nearest node
9 years ago
{
8 years ago
Create( "node_viewer_large", pev->origin, pev->angles );
9 years ago
}
break;
8 years ago
case 197:
// show shortest paths for entire level to nearest node
9 years ago
{
8 years ago
Create( "node_viewer_human", pev->origin, pev->angles );
9 years ago
}
break;
8 years ago
case 199:
// show nearest node and all connections
9 years ago
{
8 years ago
ALERT( at_console, "%d\n", WorldGraph.FindNearestNode( pev->origin, bits_NODE_GROUP_REALM ) );
WorldGraph.ShowNodeConnections( WorldGraph.FindNearestNode( pev->origin, bits_NODE_GROUP_REALM ) );
9 years ago
}
break;
8 years ago
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 );
9 years ago
8 years ago
if( tr.flFraction != 1.0 )
{
// line hit something, so paint a decal
8 years ago
CBloodSplat *pBlood = GetClassPtr( (CBloodSplat *)NULL );
9 years ago
pBlood->Spawn( pev );
}
break;
8 years ago
case 203:
// remove creature.
9 years ago
pEntity = FindEntityForward( this );
8 years ago
if( pEntity )
9 years ago
{
8 years ago
if( pEntity->pev->takedamage )
pEntity->SetThink( &CBaseEntity::SUB_Remove );
9 years ago
}
break;
}
#endif // HLDEMO_BUILD
}
//
// Add a weapon to the player (Item == Weapon == Selectable Object)
//
int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem )
{
CBasePlayerItem *pInsert;
9 years ago
pInsert = m_rgpPlayerItems[pItem->iItemSlot()];
8 years ago
while( pInsert )
9 years ago
{
8 years ago
if( FClassnameIs( pInsert->pev, STRING( pItem->pev->classname ) ) )
9 years ago
{
8 years ago
if( pItem->AddDuplicate( pInsert ) )
9 years ago
{
8 years ago
g_pGameRules->PlayerGotWeapon( this, pItem );
9 years ago
pItem->CheckRespawn();
// ugly hack to update clip w/o an update clip message
8 years ago
pInsert->UpdateItemInfo();
if( m_pActiveItem )
m_pActiveItem->UpdateItemInfo();
9 years ago
8 years ago
pItem->Kill();
9 years ago
}
8 years ago
else if( gEvilImpulse101 )
9 years ago
{
// FIXME: remove anyway for deathmatch testing
8 years ago
pItem->Kill();
9 years ago
}
return FALSE;
}
pInsert = pInsert->m_pNext;
}
8 years ago
if( pItem->AddToPlayer( this ) )
9 years ago
{
8 years ago
g_pGameRules->PlayerGotWeapon( this, pItem );
9 years ago
pItem->CheckRespawn();
pItem->m_pNext = m_rgpPlayerItems[pItem->iItemSlot()];
m_rgpPlayerItems[pItem->iItemSlot()] = pItem;
// should we switch to this item?
8 years ago
if( g_pGameRules->FShouldSwitchWeapon( this, pItem ) )
9 years ago
{
SwitchWeapon( pItem );
}
return TRUE;
}
8 years ago
else if( gEvilImpulse101 )
9 years ago
{
// FIXME: remove anyway for deathmatch testing
8 years ago
pItem->Kill();
9 years ago
}
return FALSE;
}
int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem, bool bCallHolster )
9 years ago
{
pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc.
pItem->SetThink( NULL );
8 years ago
if( m_pActiveItem == pItem )
9 years ago
{
8 years ago
ResetAutoaim();
if( bCallHolster )
pItem->Holster();
9 years ago
m_pActiveItem = NULL;
pev->viewmodel = 0;
pev->weaponmodel = 0;
}
// In some cases an item can be both the active and last item, like for instance dropping all weapons and only having an exhaustible weapon left. - Solokiller
if( m_pLastItem == pItem )
9 years ago
m_pLastItem = NULL;
CBasePlayerItem *pPrev = m_rgpPlayerItems[pItem->iItemSlot()];
8 years ago
if( pPrev == pItem )
9 years ago
{
m_rgpPlayerItems[pItem->iItemSlot()] = pItem->m_pNext;
return TRUE;
}
else
{
8 years ago
while( pPrev && pPrev->m_pNext != pItem )
9 years ago
{
pPrev = pPrev->m_pNext;
}
8 years ago
if( pPrev )
9 years ago
{
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, const char *szName, int iMax )
9 years ago
{
8 years ago
if( !szName )
9 years ago
{
// no ammo.
return -1;
}
8 years ago
if( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) )
9 years ago
{
// game rules say I can't have any more of this ammo type.
return -1;
}
int i = 0;
i = GetAmmoIndex( szName );
8 years ago
if( i < 0 || i >= MAX_AMMO_SLOTS )
9 years ago
return -1;
int iAdd = Q_min( iCount, iMax - m_rgAmmo[i] );
8 years ago
if( iAdd < 1 )
9 years ago
return i;
8 years ago
m_rgAmmo[i] += iAdd;
9 years ago
8 years ago
if( gmsgAmmoPickup ) // make sure the ammo messages have been linked first
9 years ago
{
// Send the message that ammo has been picked up
MESSAGE_BEGIN( MSG_ONE, gmsgAmmoPickup, NULL, pev );
8 years ago
WRITE_BYTE( GetAmmoIndex( szName ) ); // ammo ID
9 years ago
WRITE_BYTE( iAdd ); // amount
MESSAGE_END();
}
return i;
}
/*
============
ItemPreFrame
Called every frame by the player PreThink
============
*/
void CBasePlayer::ItemPreFrame()
{
#if defined( CLIENT_WEAPONS )
8 years ago
if( m_flNextAttack > 0 )
9 years ago
#else
8 years ago
if( gpGlobals->time < m_flNextAttack )
9 years ago
#endif
{
return;
}
8 years ago
if( !m_pActiveItem )
9 years ago
return;
8 years ago
m_pActiveItem->ItemPreFrame();
9 years ago
}
/*
============
ItemPostFrame
Called every frame by the player PostThink
============
*/
void CBasePlayer::ItemPostFrame()
{
//static int fInSelect = FALSE;
9 years ago
// check if the player is using a tank
if( m_pTank != 0 )
9 years ago
return;
#if defined( CLIENT_WEAPONS )
// HACKHACK: To make the axe fire 0.3 sec after fire is pressed
// See if the axe should fire now
if( m_flAxeFire && m_flAxeFire <= gpGlobals->time )
{
m_flAxeFire = 0;
W_FireAxe();
}
8 years ago
if( m_flNextAttack > 0 )
9 years ago
#else
8 years ago
if( gpGlobals->time < m_flNextAttack )
9 years ago
#endif
{
return;
}
ImpulseCommands();
8 years ago
if( !m_pActiveItem )
9 years ago
return;
8 years ago
m_pActiveItem->ItemPostFrame();
9 years ago
}
int CBasePlayer::AmmoInventory( int iAmmoIndex )
{
8 years ago
if( iAmmoIndex == -1 )
9 years ago
{
return -1;
}
8 years ago
return m_rgAmmo[iAmmoIndex];
9 years ago
}
8 years ago
int CBasePlayer::GetAmmoIndex( const char *psz )
9 years ago
{
int i;
8 years ago
if( !psz )
9 years ago
return -1;
8 years ago
for( i = 1; i < MAX_AMMO_SLOTS; i++ )
9 years ago
{
8 years ago
if( !CBasePlayerItem::AmmoInfoArray[i].pszName )
9 years ago
continue;
8 years ago
if( stricmp( psz, CBasePlayerItem::AmmoInfoArray[i].pszName ) == 0 )
9 years ago
return i;
}
return -1;
}
// Called from UpdateClientData
// makes sure the client has all the necessary ammo info, if values have changed
8 years ago
void CBasePlayer::SendAmmoUpdate( void )
9 years ago
{
8 years ago
for( int i = 0; i < MAX_AMMO_SLOTS; i++ )
9 years ago
{
8 years ago
if( m_rgAmmo[i] != m_rgAmmoLast[i] )
9 years ago
{
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( Q_max( Q_min( m_rgAmmo[i], 254 ), 0 ) ); // clamp the value to one byte
9 years ago
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.
=========================================================
*/
8 years ago
void CBasePlayer::UpdateClientData( void )
9 years ago
{
8 years ago
if( m_fInitHUD )
9 years ago
{
m_fInitHUD = FALSE;
gInitHUD = FALSE;
MESSAGE_BEGIN( MSG_ONE, gmsgResetHUD, NULL, pev );
WRITE_BYTE( 0 );
MESSAGE_END();
8 years ago
if( !m_fGameHUDInitialized )
9 years ago
{
MESSAGE_BEGIN( MSG_ONE, gmsgInitHUD, NULL, pev );
WRITE_BYTE( g_iTeleNum );
for( int i = 0; i < g_iTeleNum; i++ )
{
WRITE_COORD( g_vecTeleMins[i].x );
WRITE_COORD( g_vecTeleMins[i].y );
WRITE_COORD( g_vecTeleMins[i].z );
WRITE_COORD( g_vecTeleMaxs[i].x );
WRITE_COORD( g_vecTeleMaxs[i].y );
WRITE_COORD( g_vecTeleMaxs[i].z );
}
CBaseEntity *pEntity = NULL;
pEntity = UTIL_FindEntityByClassname( pEntity, "env_fog" );
if( pEntity )
{
ALERT( at_console, "Map has fog!\n" );
CClientFog *pFog = (CClientFog *)pEntity;
//Send as bytes?.
WRITE_SHORT( pFog->pev->rendercolor.x );
WRITE_SHORT( pFog->pev->rendercolor.y );
WRITE_SHORT( pFog->pev->rendercolor.z );
WRITE_SHORT( pFog->m_iStartDist );
WRITE_SHORT( pFog->m_iEndDist );
}
else
ALERT( at_console, "Map doesn't have any fog!\n" );
9 years ago
MESSAGE_END();
g_pGameRules->InitHUD( this );
m_fGameHUDInitialized = TRUE;
//m_iObserverLastMode = OBS_ROAMING;
8 years ago
if( g_pGameRules->IsMultiplayer() )
9 years ago
{
FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 );
}
}
FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 );
/*
// Send flashlight status
MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev );
WRITE_BYTE( FlashlightIsOn() ? 1 : 0 );
WRITE_BYTE( m_iFlashBattery );
MESSAGE_END();
// Vit_amiN: the geiger state could run out of sync, too
MESSAGE_BEGIN( MSG_ONE, gmsgGeigerRange, NULL, pev );
WRITE_BYTE( 0 );
MESSAGE_END();
*/
9 years ago
InitStatusBar();
}
8 years ago
if( m_iHideHUD != m_iClientHideHUD )
9 years ago
{
MESSAGE_BEGIN( MSG_ONE, gmsgHideWeapon, NULL, pev );
WRITE_BYTE( m_iHideHUD );
MESSAGE_END();
m_iClientHideHUD = m_iHideHUD;
}
8 years ago
if( m_iFOV != m_iClientFOV )
9 years ago
{
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
8 years ago
if( gDisplayTitle )
9 years ago
{
MESSAGE_BEGIN( MSG_ONE, gmsgShowGameTitle, NULL, pev );
WRITE_BYTE( 0 );
MESSAGE_END();
gDisplayTitle = 0;
}
8 years ago
if( pev->health != m_iClientHealth )
9 years ago
{
#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;
9 years ago
// send "health" update message
MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev );
WRITE_BYTE( iHealth );
MESSAGE_END();
m_iClientHealth = (int)pev->health;
9 years ago
}
// QUAKECLASSIC
// Send down the state of the QuakeItems
if( m_iQuakeItems != m_iClientQuakeItems )
{
// send "items" update message
MESSAGE_BEGIN( MSG_ONE, gmsgQItems, NULL, pev );
WRITE_LONG( m_iQuakeItems );
MESSAGE_END();
m_iClientQuakeItems = m_iQuakeItems;
}
if( (int)pev->armorvalue != m_iClientBattery )
9 years ago
{
m_iClientBattery = (int)pev->armorvalue;
9 years ago
ASSERT( gmsgBattery > 0 );
9 years ago
// send "health" update message
MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, pev );
8 years ago
WRITE_SHORT( (int)pev->armorvalue );
9 years ago
MESSAGE_END();
}
8 years ago
if( pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType )
9 years ago
{
// 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 && UTIL_IsValidEntity( other ) )
9 years ago
{
8 years ago
CBaseEntity *pEntity = CBaseEntity::Instance( other );
if( pEntity )
9 years ago
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( (int)pev->dmg_save );
WRITE_BYTE( (int)pev->dmg_take );
9 years ago
WRITE_LONG( visibleDamageBits );
WRITE_COORD( damageOrigin.x );
WRITE_COORD( damageOrigin.y );
WRITE_COORD( damageOrigin.z );
MESSAGE_END();
8 years ago
9 years ago
pev->dmg_take = 0;
pev->dmg_save = 0;
m_bitsHUDDamage = m_bitsDamageType;
8 years ago
9 years ago
// Clear off non-time-based damage indicators
m_bitsDamageType &= DMG_TIMEBASED;
}
8 years ago
if( m_iTrain & TRAIN_NEW )
9 years ago
{
ASSERT( gmsgTrain > 0 );
9 years ago
// send "health" update message
MESSAGE_BEGIN( MSG_ONE, gmsgTrain, NULL, pev );
8 years ago
WRITE_BYTE( m_iTrain & 0xF );
9 years ago
MESSAGE_END();
m_iTrain &= ~TRAIN_NEW;
}
int iShellIndex = GetAmmoIndex( "shells" );
int iNailIndex = GetAmmoIndex( "nails" );
int iRocketIndex = GetAmmoIndex( "rockets" );
int iCellIndex = GetAmmoIndex( "cells" );
9 years ago
//
// New Weapon?
//
8 years ago
if( !m_fKnownItem )
9 years ago
{
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
8 years ago
// byte flags
9 years ago
// ???? Icons
9 years ago
// Send ALL the weapon info now
// QUAKECLASSIC
// Tell the client about the Quake weapons
for( int i = 1; i < 10; i++ )
9 years ago
{
const char *pszName;
int iAmmoIndex = 0;
int iMaxAmmo = 0;
int iCurrentAmmo = 0;
int iBit = 0;
switch( i )
{
case 1:
iBit = IT_AXE;
break;
case 2:
iBit = IT_SHOTGUN;
break;
case 3:
iBit = IT_SUPER_SHOTGUN;
break;
case 4:
iBit = IT_NAILGUN;
break;
case 5:
iBit = IT_SUPER_NAILGUN;
break;
case 6:
iBit = IT_GRENADE_LAUNCHER;
break;
case 7:
iBit = IT_ROCKET_LAUNCHER;
break;
case 8:
iBit = IT_LIGHTNING;
break;
case 9:
iBit = IT_EXTRA_WEAPON;
break;
default:
9 years ago
pszName = "Empty";
break;
}
9 years ago
if( !( m_iQuakeItems & iBit ) )
continue;
switch( i )
{
case 1:
pszName = "weapon_axe";
iAmmoIndex = -1;
iBit |= IT_AXE;
break;
case 2:
pszName = "weapon_shotgun";
iAmmoIndex = iShellIndex;
iBit |= IT_SHOTGUN;
iCurrentAmmo = m_iAmmoShells;
iMaxAmmo = 100;
break;
case 3:
pszName = "weapon_doubleshotgun";
iAmmoIndex = iShellIndex;
iBit |= IT_SUPER_SHOTGUN;
iCurrentAmmo = m_iAmmoShells;
iMaxAmmo = 100;
break;
case 4:
pszName = "weapon_nailgun";
iAmmoIndex = iNailIndex;
iBit |= IT_NAILGUN;
iCurrentAmmo = m_iAmmoNails;
iMaxAmmo = 200;
break;
case 5:
pszName = "weapon_supernail";
iAmmoIndex = iNailIndex;
iBit |= IT_SUPER_NAILGUN;
iCurrentAmmo = m_iAmmoNails;
iMaxAmmo = 200;
break;
case 6:
pszName = "weapon_grenadel";
iAmmoIndex = iRocketIndex;
iBit |= IT_GRENADE_LAUNCHER;
iCurrentAmmo = m_iAmmoRockets;
iMaxAmmo = 100;
break;
case 7:
pszName = "weapon_rocketl";
iAmmoIndex = iRocketIndex;
iBit |= IT_ROCKET_LAUNCHER;
iCurrentAmmo = m_iAmmoRockets;
iMaxAmmo = 100;
break;
case 8:
pszName = "weapon_lightning";
iAmmoIndex = iCellIndex;
iBit |= IT_LIGHTNING;
iCurrentAmmo = m_iAmmoCells;
iMaxAmmo = 100;
break;
case 9:
pszName = "weapon_grapple";
iAmmoIndex = -1;
iBit |= IT_EXTRA_WEAPON;
break;
default:
pszName = "Empty";
break;
}
MESSAGE_BEGIN( MSG_ONE, gmsgWeaponList, NULL, pev );
WRITE_STRING( pszName ); // string weapon name
WRITE_BYTE( iAmmoIndex ); // byte Ammo Type
WRITE_BYTE( iMaxAmmo ); // byte Max Ammo 1
WRITE_BYTE( -1 ); // byte Ammo2 Type
WRITE_BYTE( iCurrentAmmo ); // byte Max Ammo 2
WRITE_BYTE( i ); // byte bucket
WRITE_BYTE( 0 ); // byte bucket pos
WRITE_LONG( iBit ); // byte id (bit index into pev->weapons)
if( i == 1 || i == 9 )
WRITE_BYTE( 1 ); // We can select this one on empty
else
WRITE_BYTE( 0 ); // Can't select it when empty.
MESSAGE_END();
}
}
// QUAKECLASSIC
// HACKHACK: Make the HL ammo types equal the Quake ammo
m_rgAmmo[iShellIndex] = m_iAmmoShells;
m_rgAmmo[iNailIndex] = m_iAmmoNails;
m_rgAmmo[iRocketIndex] = m_iAmmoRockets;
m_rgAmmo[iCellIndex] = m_iAmmoCells;
9 years ago
SendAmmoUpdate();
// Update all the items
8 years ago
for( int i = 0; i < MAX_ITEM_TYPES; i++ )
9 years ago
{
8 years ago
if( m_rgpPlayerItems[i] ) // each item updates it's successors
9 years ago
m_rgpPlayerItems[i]->UpdateClientData( this );
}
// Cache and client weapon change
m_pClientActiveItem = m_pActiveItem;
m_iClientFOV = m_iFOV;
// Update Status Bar
8 years ago
if( m_flNextSBarUpdateTime < gpGlobals->time )
9 years ago
{
UpdateStatusBar();
m_flNextSBarUpdateTime = gpGlobals->time + 0.2;
}
// QUAKECLASSIC
m_iClientQuakeWeapon = m_iQuakeWeapon;
// Send the current bhopcap state.
if( !m_bSentBhopcap )
{
m_bSentBhopcap = true;
MESSAGE_BEGIN( MSG_ONE, gmsgBhopcap, NULL, pev );
WRITE_BYTE( g_bhopcap );
MESSAGE_END();
}
9 years ago
}
//=========================================================
// FBecomeProne - Overridden for the player to set the proper
// physics flags when a barnacle grabs player.
//=========================================================
8 years ago
BOOL CBasePlayer::FBecomeProne( void )
9 years ago
{
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.
//=========================================================
8 years ago
void CBasePlayer::BarnacleVictimBitten( entvars_t *pevBarnacle )
9 years ago
{
8 years ago
TakeDamage( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB );
9 years ago
}
//=========================================================
// BarnacleVictimReleased - overridden for player who has
// physics flags concerns.
//=========================================================
8 years ago
void CBasePlayer::BarnacleVictimReleased( void )
9 years ago
{
m_afPhysicsFlags &= ~PFLAG_ONBARNACLE;
}
//=========================================================
// Illumination
// return player light level plus virtual muzzle flash
//=========================================================
8 years ago
int CBasePlayer::Illumination( void )
9 years ago
{
8 years ago
int iIllum = CBaseEntity::Illumination();
9 years ago
iIllum += m_iWeaponFlash;
8 years ago
if( iIllum > 255 )
9 years ago
return 255;
return iIllum;
}
8 years ago
void CBasePlayer::EnableControl( BOOL fControl )
9 years ago
{
8 years ago
if( !fControl )
9 years ago
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
//=========================================================
8 years ago
Vector CBasePlayer::GetAutoaimVector( float flDelta )
9 years ago
{
8 years ago
if( g_iSkillLevel == SKILL_HARD )
9 years ago
{
UTIL_MakeVectors( pev->v_angle + pev->punchangle );
return gpGlobals->v_forward;
}
8 years ago
Vector vecSrc = GetGunPosition();
9 years ago
float flDist = 8192;
// always use non-sticky autoaim
// UNDONE: use sever variable to chose!
8 years ago
if( 1 || g_iSkillLevel == SKILL_MEDIUM )
9 years ago
{
m_vecAutoAim = Vector( 0, 0, 0 );
// flDelta *= 0.5;
}
BOOL m_fOldTargeting = m_fOnTarget;
Vector angles = AutoaimDeflection(vecSrc, flDist, flDelta );
// update ontarget if changed
8 years ago
if( !g_pGameRules->AllowAutoTargetCrosshair() )
9 years ago
m_fOnTarget = 0;
8 years ago
else if( m_fOldTargeting != m_fOnTarget )
9 years ago
{
8 years ago
m_pActiveItem->UpdateItemInfo();
9 years ago
}
8 years ago
if( angles.x > 180 )
9 years ago
angles.x -= 360;
8 years ago
if( angles.x < -180 )
9 years ago
angles.x += 360;
8 years ago
if( angles.y > 180 )
9 years ago
angles.y -= 360;
8 years ago
if( angles.y < -180 )
9 years ago
angles.y += 360;
8 years ago
if( angles.x > 25 )
9 years ago
angles.x = 25;
8 years ago
if( angles.x < -25 )
9 years ago
angles.x = -25;
8 years ago
if( angles.y > 12 )
9 years ago
angles.y = 12;
8 years ago
if( angles.y < -12 )
9 years ago
angles.y = -12;
// always use non-sticky autoaim
// UNDONE: use sever variable to chose!
8 years ago
if( 0 || g_iSkillLevel == SKILL_EASY )
9 years ago
{
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
8 years ago
if( g_psv_aim->value != 0 )
9 years ago
{
8 years ago
if( m_vecAutoAim.x != m_lastx || m_vecAutoAim.y != m_lasty )
9 years ago
{
SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y );
8 years ago
m_lastx = (int)m_vecAutoAim.x;
m_lasty = (int)m_vecAutoAim.y;
9 years ago
}
}
// ALERT( at_console, "%f %f\n", angles.x, angles.y );
UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim );
return gpGlobals->v_forward;
}
8 years ago
Vector CBasePlayer::AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta )
9 years ago
{
8 years ago
edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 );
CBaseEntity *pEntity;
float bestdot;
Vector bestdir;
edict_t *bestent;
9 years ago
TraceResult tr;
8 years ago
if( g_psv_aim->value == 0 )
9 years ago
{
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 );
8 years ago
if( tr.pHit && tr.pHit->v.takedamage != DAMAGE_NO )
9 years ago
{
// don't look through water
8 years ago
if( !( ( pev->waterlevel != 3 && tr.pHit->v.waterlevel == 3 ) || ( pev->waterlevel == 3 && tr.pHit->v.waterlevel == 0 ) ) )
9 years ago
{
8 years ago
if( tr.pHit->v.takedamage == DAMAGE_AIM )
9 years ago
m_fOnTarget = TRUE;
return m_vecAutoAim;
}
}
8 years ago
for( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ )
9 years ago
{
Vector center;
Vector dir;
float dot;
8 years ago
if( pEdict->free ) // Not in use
9 years ago
continue;
8 years ago
if( pEdict->v.takedamage != DAMAGE_AIM )
9 years ago
continue;
8 years ago
if( pEdict == edict() )
9 years ago
continue;
8 years ago
//if( pev->team > 0 && pEdict->v.team == pev->team )
// continue; // don't aim at teammate
8 years ago
if( !g_pGameRules->ShouldAutoAim( this, pEdict ) )
9 years ago
continue;
pEntity = Instance( pEdict );
8 years ago
if( pEntity == NULL )
9 years ago
continue;
8 years ago
if( !pEntity->IsAlive() )
9 years ago
continue;
// don't look through water
8 years ago
if( ( pev->waterlevel != 3 && pEntity->pev->waterlevel == 3 ) || ( pev->waterlevel == 3 && pEntity->pev->waterlevel == 0 ) )
9 years ago
continue;
center = pEntity->BodyTarget( vecSrc );
8 years ago
dir = ( center - vecSrc ).Normalize();
9 years ago
// make sure it's in front of the player
8 years ago
if( DotProduct( dir, gpGlobals->v_forward ) < 0 )
9 years ago
continue;
8 years ago
dot = fabs( DotProduct( dir, gpGlobals->v_right ) ) + fabs( DotProduct( dir, gpGlobals->v_up ) ) * 0.5;
9 years ago
// tweek for distance
8 years ago
dot *= 1.0 + 0.2 * ( ( center - vecSrc ).Length() / flDist );
9 years ago
8 years ago
if( dot > bestdot )
9 years ago
continue; // to far to turn
UTIL_TraceLine( vecSrc, center, dont_ignore_monsters, edict(), &tr );
8 years ago
if( tr.flFraction != 1.0 && tr.pHit != pEdict )
9 years ago
{
// 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
8 years ago
if( IRelationship( pEntity ) < 0 )
9 years ago
{
8 years ago
if( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch() )
// ALERT( at_console, "friend\n" );
9 years ago
continue;
}
// can shoot at this one
bestdot = dot;
bestent = pEdict;
bestdir = dir;
}
8 years ago
if( bestent )
9 years ago
{
8 years ago
bestdir = UTIL_VecToAngles( bestdir );
9 years ago
bestdir.x = -bestdir.x;
bestdir = bestdir - pev->v_angle - pev->punchangle;
8 years ago
if( bestent->v.takedamage == DAMAGE_AIM )
9 years ago
m_fOnTarget = TRUE;
return bestdir;
}
return Vector( 0, 0, 0 );
}
8 years ago
void CBasePlayer::ResetAutoaim()
9 years ago
{
8 years ago
if( m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0 )
9 years ago
{
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.
=============
*/
8 years ago
void CBasePlayer::SetCustomDecalFrames( int nFrames )
9 years ago
{
8 years ago
if( nFrames > 0 && nFrames < 8 )
9 years ago
m_nCustomSprayFrames = nFrames;
else
m_nCustomSprayFrames = -1;
}
/*
=============
GetCustomDecalFrames
Returns the # of custom frames this player's custom clan logo contains.
=============
*/
8 years ago
int CBasePlayer::GetCustomDecalFrames( void )
9 years ago
{
return m_nCustomSprayFrames;
}
//=========================================================
// DropPlayerItem - drop the named item, or if no name,
// the active item.
//=========================================================
8 years ago
void CBasePlayer::DropPlayerItem( char *pszItemName )
9 years ago
{
8 years ago
if( !g_pGameRules->IsMultiplayer() || ( weaponstay.value > 0 ) )
9 years ago
{
// no dropping in single player.
return;
}
8 years ago
if( !strlen( pszItemName ) )
9 years ago
{
// if this string has no length, the client didn't type a name!
// assume player wants to drop the active item.
// make the string null to make future operations in this function easier
pszItemName = NULL;
}
CBasePlayerItem *pWeapon;
int i;
8 years ago
for( i = 0; i < MAX_ITEM_TYPES; i++ )
9 years ago
{
8 years ago
pWeapon = m_rgpPlayerItems[i];
9 years ago
8 years ago
while( pWeapon )
9 years ago
{
8 years ago
if( pszItemName )
9 years ago
{
// try to match by name.
8 years ago
if( !strcmp( pszItemName, STRING( pWeapon->pev->classname ) ) )
9 years ago
{
// match!
break;
}
}
else
{
// trying to drop active item
8 years ago
if( pWeapon == m_pActiveItem )
9 years ago
{
// active item!
break;
}
}
pWeapon = pWeapon->m_pNext;
}
// if we land here with a valid pWeapon pointer, that's because we found the
// item we want to drop and hit a BREAK; pWeapon is the item.
8 years ago
if( pWeapon )
9 years ago
{
if( !g_pGameRules->GetNextBestWeapon( this, pWeapon ) )
return; // can't drop the item they asked for, may be our last item or something we can't holster
9 years ago
8 years ago
UTIL_MakeVectors( pev->angles );
9 years ago
8 years ago
pev->weapons &= ~( 1 << pWeapon->m_iId );// take item off hud
9 years ago
CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict() );
pWeaponBox->pev->angles.x = 0;
pWeaponBox->pev->angles.z = 0;
pWeaponBox->PackWeapon( pWeapon );
pWeaponBox->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100;
// drop half of the ammo for this weapon.
8 years ago
int iAmmoIndex;
9 years ago
8 years ago
iAmmoIndex = GetAmmoIndex( pWeapon->pszAmmo1() ); // ???
if( iAmmoIndex != -1 )
9 years ago
{
// this weapon weapon uses ammo, so pack an appropriate amount.
8 years ago
if( pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE )
9 years ago
{
// pack up all the ammo, this weapon is its own ammo type
8 years ago
pWeaponBox->PackAmmo( MAKE_STRING( pWeapon->pszAmmo1() ), m_rgAmmo[iAmmoIndex] );
m_rgAmmo[iAmmoIndex] = 0;
9 years ago
}
else
{
// pack half of the ammo
8 years ago
pWeaponBox->PackAmmo( MAKE_STRING( pWeapon->pszAmmo1() ), m_rgAmmo[iAmmoIndex] / 2 );
m_rgAmmo[iAmmoIndex] /= 2;
9 years ago
}
}
return;// we're done, so stop searching with the FOR loop.
}
}
}
//=========================================================
// HasPlayerItem Does the player already have this item?
//=========================================================
BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem )
{
CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()];
8 years ago
while( pItem )
9 years ago
{
8 years ago
if( FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname ) ) )
9 years ago
{
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;
8 years ago
for( i = 0; i < MAX_ITEM_TYPES; i++ )
9 years ago
{
8 years ago
pItem = m_rgpPlayerItems[i];
while( pItem )
9 years ago
{
8 years ago
if( !strcmp( pszItemName, STRING( pItem->pev->classname ) ) )
9 years ago
{
return TRUE;
}
pItem = pItem->m_pNext;
}
}
return FALSE;
}
//=========================================================
//
//=========================================================
8 years ago
BOOL CBasePlayer::SwitchWeapon( CBasePlayerItem *pWeapon )
9 years ago
{
8 years ago
if( !pWeapon->CanDeploy() )
9 years ago
{
return FALSE;
}
8 years ago
ResetAutoaim();
if( m_pActiveItem )
9 years ago
{
8 years ago
m_pActiveItem->Holster();
9 years ago
}
m_pActiveItem = pWeapon;
8 years ago
pWeapon->Deploy();
9 years ago
return TRUE;
}
//=========================================================
// Dead HEV suit prop
//=========================================================
class CDeadHEV : public CBaseMonster
{
public:
void Spawn( void );
8 years ago
int Classify( void )
{
return CLASS_HUMAN_MILITARY;
}
9 years ago
void KeyValue( KeyValueData *pkvd );
8 years ago
int m_iPose;// which sequence to display -- temporary, don't need to save
static const char *m_szPoses[4];
9 years ago
};
const char *CDeadHEV::m_szPoses[] =
8 years ago
{
"deadback",
"deadsitting",
"deadstomach",
"deadtable"
};
9 years ago
void CDeadHEV::KeyValue( KeyValueData *pkvd )
{
8 years ago
if( FStrEq( pkvd->szKeyName, "pose" ) )
9 years ago
{
8 years ago
m_iPose = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else
9 years ago
CBaseMonster::KeyValue( pkvd );
}
LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV )
9 years ago
//=========================================================
// ********** DeadHEV SPAWN **********
//=========================================================
8 years ago
void CDeadHEV::Spawn( void )
9 years ago
{
8 years ago
PRECACHE_MODEL( "models/player.mdl" );
SET_MODEL( ENT( pev ), "models/player.mdl" );
9 years ago
8 years ago
pev->effects = 0;
pev->yaw_speed = 8;
pev->sequence = 0;
pev->body = 1;
m_bloodColor = BLOOD_COLOR_RED;
9 years ago
pev->sequence = LookupSequence( m_szPoses[m_iPose] );
8 years ago
if( pev->sequence == -1 )
9 years ago
{
8 years ago
ALERT( at_console, "Dead hevsuit with bad pose\n" );
9 years ago
pev->sequence = 0;
pev->effects = EF_BRIGHTFIELD;
}
// Corpses have less health
8 years ago
pev->health = 8;
9 years ago
MonsterInitDead();
}
class CStripWeapons : public CPointEntity
{
public:
8 years ago
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
9 years ago
private:
};
LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons )
9 years ago
8 years ago
void CStripWeapons::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
9 years ago
{
CBasePlayer *pPlayer = NULL;
8 years ago
if( pActivator && pActivator->IsPlayer() )
9 years ago
{
pPlayer = (CBasePlayer *)pActivator;
}
8 years ago
else if( !g_pGameRules->IsDeathmatch() )
9 years ago
{
pPlayer = (CBasePlayer *)CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) );
}
8 years ago
if( pPlayer )
9 years ago
pPlayer->RemoveAllItems( FALSE );
}
class CRevertSaved : public CPointEntity
{
public:
8 years ago
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT MessageThink( void );
void EXPORT LoadThink( void );
void KeyValue( KeyValueData *pkvd );
9 years ago
8 years ago
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
9 years ago
8 years ago
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; }
9 years ago
8 years ago
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; }
9 years ago
private:
8 years ago
float m_messageTime;
float m_loadTime;
9 years ago
};
LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved )
9 years ago
TYPEDESCRIPTION CRevertSaved::m_SaveData[] =
9 years ago
{
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 )
9 years ago
8 years ago
void CRevertSaved::KeyValue( KeyValueData *pkvd )
9 years ago
{
8 years ago
if( FStrEq( pkvd->szKeyName, "duration" ) )
9 years ago
{
8 years ago
SetDuration( atof( pkvd->szValue ) );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "holdtime" ) )
9 years ago
{
8 years ago
SetHoldTime( atof( pkvd->szValue ) );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "messagetime" ) )
9 years ago
{
8 years ago
SetMessageTime( atof( pkvd->szValue ) );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "loadtime" ) )
9 years ago
{
8 years ago
SetLoadTime( atof( pkvd->szValue ) );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else
9 years ago
CPointEntity::KeyValue( pkvd );
}
8 years ago
void CRevertSaved::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
9 years ago
{
UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), (int)pev->renderamt, FFADE_OUT );
9 years ago
pev->nextthink = gpGlobals->time + MessageTime();
SetThink( &CRevertSaved::MessageThink );
}
8 years ago
void CRevertSaved::MessageThink( void )
9 years ago
{
8 years ago
UTIL_ShowMessageAll( STRING( pev->message ) );
9 years ago
float nextThink = LoadTime() - MessageTime();
8 years ago
if( nextThink > 0 )
9 years ago
{
pev->nextthink = gpGlobals->time + nextThink;
SetThink( &CRevertSaved::LoadThink );
}
else
LoadThink();
}
8 years ago
void CRevertSaved::LoadThink( void )
9 years ago
{
8 years ago
if( !gpGlobals->deathmatch )
9 years ago
{
8 years ago
SERVER_COMMAND( "reload\n" );
9 years ago
}
}
//=========================================================
// 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!
}
8 years ago
void CInfoIntermission::Think( void )
9 years ago
{
edict_t *pTarget;
// find my target
8 years ago
pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->target ) );
9 years ago
8 years ago
if( !FNullEnt( pTarget ) )
9 years ago
{
8 years ago
pev->v_angle = UTIL_VecToAngles( ( pTarget->v.origin - pev->origin ).Normalize() );
9 years ago
pev->v_angle.x = -pev->v_angle.x;
}
}
LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission )
//++ BulliT
void CBasePlayer::Init()
{
m_bReady = true;
m_bIngame = ( g_bIsThreeWave || g_pGameRules->m_iGameMode < ARENA );
if( g_bIsThreeWave )
return;
if( g_pGameRules->m_iGameMode >= LMS )
g_pGameRules->m_LMS.ClientConnected( this );
else if( g_pGameRules->m_iGameMode == ARENA )
g_pGameRules->m_Arena.ClientConnected( this );
}
void CBasePlayer::RemoveAllItemsNoClientMessage()
{
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;
pev->weapons &= ~WEAPON_ALLWEAPONS;
for( i = 0; i < MAX_AMMO_SLOTS;i++ )
m_rgAmmo[i] = 0;
// 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();
}
//Special spawn - removes all entites attached to the player.
bool CBasePlayer::RespawnMatch()
{
/*
// clear any clientside entities attached to this player
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_KILLPLAYERATTACHMENTS );
WRITE_BYTE( (BYTE)entindex() );
MESSAGE_END();
*/
//Remove all weapons/items
RemoveAllItemsNoClientMessage();
7 years ago
if( m_pTank != 0 )
{
m_pTank->Use( this, this, USE_OFF, 0 );
m_pTank = NULL;
}
//Make sure hud is shown correctly
m_iHideHUD &= ~HIDEHUD_WEAPONS;
m_iHideHUD &= ~HIDEHUD_FLASHLIGHT;
m_iHideHUD &= ~HIDEHUD_HEALTH;
// clear out the suit message cache so we don't keep chattering
SetSuitUpdate( NULL, FALSE, 0 );
m_iTrain |= TRAIN_NEW; // Force new train message.
m_fKnownItem = FALSE; // Force weaponinit messages.
//Respawn player
m_bHadFirstSpawn = true;
UpdateClientData();
Spawn();
return true;
}
void CBasePlayer::ResetScore()
{
//Reset score
pev->frags = 0.0;
m_iDeaths = 0;
MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo );
WRITE_BYTE( ENTINDEX( edict() ) );
WRITE_SHORT( pev->frags );
WRITE_SHORT( m_iDeaths );
WRITE_SHORT( pev->team );
MESSAGE_END();
}
//-- Martin Webrant