|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Player for HL1.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tfc_player.h"
#include "tfc_gamerules.h"
#include "KeyValues.h"
#include "viewport_panel_names.h"
#include "client.h"
#include "team.h"
#include "weapon_tfcbase.h"
#include "tfc_client.h"
#include "tfc_mapitems.h"
#include "tfc_timer.h"
#include "tfc_engineer.h"
#include "tfc_team.h"
#define TFC_PLAYER_MODEL "models/player/pyro.mdl"
// -------------------------------------------------------------------------------- //
// Player animation event. Sent to the client when a player fires, jumps, reloads, etc..
// -------------------------------------------------------------------------------- //
class CTEPlayerAnimEvent : public CBaseTempEntity { public: DECLARE_CLASS( CTEPlayerAnimEvent, CBaseTempEntity ); DECLARE_SERVERCLASS();
CTEPlayerAnimEvent( const char *name ) : CBaseTempEntity( name ) { }
CNetworkHandle( CBasePlayer, m_hPlayer ); CNetworkVar( int, m_iEvent ); CNetworkVar( int, m_nData ); };
IMPLEMENT_SERVERCLASS_ST_NOBASE( CTEPlayerAnimEvent, DT_TEPlayerAnimEvent ) SendPropEHandle( SENDINFO( m_hPlayer ) ), SendPropInt( SENDINFO( m_iEvent ), Q_log2( PLAYERANIMEVENT_COUNT ) + 1, SPROP_UNSIGNED ) SendPropInt( SENDINFO( m_nData ), 32 ) END_SEND_TABLE()
static CTEPlayerAnimEvent g_TEPlayerAnimEvent( "PlayerAnimEvent" );
void TE_PlayerAnimEvent( CBasePlayer *pPlayer, PlayerAnimEvent_t event, int nData ) { CPVSFilter filter( pPlayer->EyePosition() ); // The player himself doesn't need to be sent his animation events
// unless cs_showanimstate wants to show them.
if ( !ToolsEnabled() && ( cl_showanimstate.GetInt() == pPlayer->entindex() ) ) { filter.RemoveRecipient( pPlayer ); }
g_TEPlayerAnimEvent.m_hPlayer = pPlayer; g_TEPlayerAnimEvent.m_iEvent = event; g_TEPlayerAnimEvent.m_nData = nData; g_TEPlayerAnimEvent.Create( filter, 0 ); }
// -------------------------------------------------------------------------------- //
// Tables.
// -------------------------------------------------------------------------------- //
LINK_ENTITY_TO_CLASS( player, CTFCPlayer ); PRECACHE_REGISTER(player);
IMPLEMENT_SERVERCLASS_ST( CTFCPlayer, DT_TFCPlayer ) SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ), SendPropExclude( "DT_BaseAnimating", "m_flPlaybackRate" ), SendPropExclude( "DT_BaseAnimating", "m_nSequence" ), SendPropExclude( "DT_BaseEntity", "m_angRotation" ), SendPropExclude( "DT_BaseAnimatingOverlay", "overlay_vars" ), // cs_playeranimstate and clientside animation takes care of these on the client
SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ), SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 0), 11 ), SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 1), 11 ),
SendPropDataTable( SENDINFO_DT( m_Shared ), &REFERENCE_SEND_TABLE( DT_TFCPlayerShared ) ) END_SEND_TABLE()
// -------------------------------------------------------------------------------- //
void cc_CreatePredictionError_f() { CBaseEntity *pEnt = CBaseEntity::Instance( 1 ); pEnt->SetAbsOrigin( pEnt->GetAbsOrigin() + Vector( 63, 0, 0 ) ); }
ConCommand cc_CreatePredictionError( "CreatePredictionError", cc_CreatePredictionError_f, "Create a prediction error", FCVAR_CHEAT );
CTFCPlayer::CTFCPlayer() { m_PlayerAnimState = CreatePlayerAnimState( this ); item_list = 0;
UseClientSideAnimation(); m_angEyeAngles.Init(); m_pCurStateInfo = NULL; m_lifeState = LIFE_DEAD; // Start "dead".
SetViewOffset( TFC_PLAYER_VIEW_OFFSET );
SetContextThink( &CTFCPlayer::TFCPlayerThink, gpGlobals->curtime, "TFCPlayerThink" ); }
void CTFCPlayer::TFCPlayerThink() { if ( m_pCurStateInfo && m_pCurStateInfo->pfnThink ) (this->*m_pCurStateInfo->pfnThink)();
SetContextThink( &CTFCPlayer::TFCPlayerThink, gpGlobals->curtime, "TFCPlayerThink" ); }
CTFCPlayer::~CTFCPlayer() { m_PlayerAnimState->Release(); }
CTFCPlayer *CTFCPlayer::CreatePlayer( const char *className, edict_t *ed ) { CTFCPlayer::s_PlayerEdict = ed; return (CTFCPlayer*)CreateEntityByName( className ); }
void CTFCPlayer::PostThink() { BaseClass::PostThink();
QAngle angles = GetLocalAngles(); angles[PITCH] = 0; SetLocalAngles( angles ); // Store the eye angles pitch so the client can compute its animation state correctly.
m_angEyeAngles = EyeAngles();
m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] ); }
void CTFCPlayer::Precache() { for ( int i=0; i < PC_LASTCLASS; i++ ) PrecacheModel( GetTFCClassInfo( i )->m_pModelName );
PrecacheScriptSound( "Player.Spawn" );
BaseClass::Precache(); }
void CTFCPlayer::InitialSpawn( void ) { BaseClass::InitialSpawn();
State_Enter( STATE_WELCOME ); }
void CTFCPlayer::Spawn() { SetModel( GetTFCClassInfo( m_Shared.GetPlayerClass() )->m_pModelName );
SetMoveType( MOVETYPE_WALK ); m_iLegDamage = 0;
BaseClass::Spawn();
// Kind of lame, but CBasePlayer::Spawn resets a lot of the state that we initially want on.
// So if we're in the welcome state, call its enter function to reset
if ( m_Shared.State_Get() == STATE_WELCOME ) { State_Enter_WELCOME(); }
// If they were dead, then they're respawning. Put them in the active state.
if ( m_Shared.State_Get() == STATE_DYING ) { State_Transition( STATE_ACTIVE ); }
// If they're spawning into the world as fresh meat, give them items and stuff.
if ( m_Shared.State_Get() == STATE_ACTIVE ) { EmitSound( "Player.Spawn" ); GiveDefaultItems(); } }
void CTFCPlayer::ForceRespawn() { //TFCTODO: goldsrc tfc has a big function for this.. doing what I'm doing here may not work.
respawn( this, false ); }
void CTFCPlayer::GiveDefaultItems() { switch( m_Shared.GetPlayerClass() ) { case PC_HWGUY: { GiveNamedItem( "weapon_crowbar" ); GiveNamedItem( "weapon_minigun" ); GiveAmmo( 176, TFC_AMMO_SHELLS ); } break;
case PC_PYRO: { GiveNamedItem( "weapon_crowbar" ); } break;
case PC_ENGINEER: { GiveNamedItem( "weapon_spanner" ); GiveNamedItem( "weapon_super_shotgun" ); GiveAmmo( 20, TFC_AMMO_SHELLS ); } break;
case PC_SCOUT: { GiveNamedItem( "weapon_crowbar" ); GiveNamedItem( "weapon_shotgun" ); GiveNamedItem( "weapon_nailgun" ); GiveAmmo( 25, TFC_AMMO_SHELLS ); GiveAmmo( 100, TFC_AMMO_NAILS ); } break;
case PC_SNIPER: { GiveNamedItem( "weapon_crowbar" ); } break;
case PC_SOLDIER: { GiveNamedItem( "weapon_crowbar" ); } break;
case PC_DEMOMAN: { GiveNamedItem( "weapon_crowbar" ); } break;
case PC_SPY: { GiveNamedItem( "weapon_knife" ); } break;
case PC_MEDIC: { GiveNamedItem( "weapon_medikit" ); GiveNamedItem( "weapon_super_nailgun" ); GiveAmmo( 100, TFC_AMMO_NAILS ); } break; } }
void CTFCPlayer::DoAnimationEvent( PlayerAnimEvent_t event, int nData ) { m_PlayerAnimState->DoAnimationEvent( event, nData ); TE_PlayerAnimEvent( this, event, nData ); // Send to any clients who can see this guy.
}
void CTFCPlayer::State_Transition( TFCPlayerState newState ) { State_Leave(); State_Enter( newState ); }
void CTFCPlayer::State_Enter( TFCPlayerState newState ) { m_Shared.m_iPlayerState = newState; m_pCurStateInfo = State_LookupInfo( newState );
// Initialize the new state.
if ( m_pCurStateInfo && m_pCurStateInfo->pfnEnterState ) (this->*m_pCurStateInfo->pfnEnterState)(); }
void CTFCPlayer::State_Leave() { if ( m_pCurStateInfo && m_pCurStateInfo->pfnLeaveState ) { (this->*m_pCurStateInfo->pfnLeaveState)(); } }
CPlayerStateInfo* CTFCPlayer::State_LookupInfo( TFCPlayerState state ) { // This table MUST match the
static CPlayerStateInfo playerStateInfos[] = { { STATE_ACTIVE, "STATE_ACTIVE", &CTFCPlayer::State_Enter_ACTIVE, NULL, NULL }, { STATE_WELCOME, "STATE_WELCOME", &CTFCPlayer::State_Enter_WELCOME, NULL, NULL }, { STATE_PICKINGTEAM, "STATE_PICKINGTEAM", &CTFCPlayer::State_Enter_PICKINGTEAM, NULL, NULL }, { STATE_PICKINGCLASS, "STATE_PICKINGCLASS", &CTFCPlayer::State_Enter_PICKINGCLASS, NULL, NULL }, { STATE_OBSERVER_MODE, "STATE_OBSERVER_MODE", &CTFCPlayer::State_Enter_OBSERVER_MODE, NULL, NULL }, { STATE_DYING, "STATE_DYING", &CTFCPlayer::State_Enter_DYING, NULL, NULL } };
for ( int i=0; i < ARRAYSIZE( playerStateInfos ); i++ ) { if ( playerStateInfos[i].m_iPlayerState == state ) return &playerStateInfos[i]; }
return NULL; }
void CTFCPlayer::State_Enter_WELCOME() { SetMoveType( MOVETYPE_NONE ); AddEffects( EF_NODRAW ); AddSolidFlags( FSOLID_NOT_SOLID ); PhysObjectSleep(); // Show info panel (if it's not a simple demo map).
KeyValues *data = new KeyValues("data"); data->SetString( "title", "Message of the Day" ); // info panel title
data->SetString( "type", "3" ); // show a file
data->SetString( "msg", "motd.txt" ); // this file
data->SetString( "cmd", "joingame" ); // exec this command if panel closed
ShowViewPortPanel( "info", true, data );
data->deleteThis(); }
void CTFCPlayer::State_Enter_PICKINGTEAM() { ShowViewPortPanel( PANEL_TEAM ); // show the team menu
}
void CTFCPlayer::State_Enter_PICKINGCLASS() { // go to spec mode, if dying keep deathcam
if ( GetObserverMode() == OBS_MODE_DEATHCAM ) { StartObserverMode( OBS_MODE_DEATHCAM ); } else { StartObserverMode( OBS_MODE_ROAMING ); } PhysObjectSleep();
// show the class menu:
ShowViewPortPanel( PANEL_CLASS ); }
void CTFCPlayer::State_Enter_OBSERVER_MODE() { StartObserverMode( m_iObserverLastMode ); PhysObjectSleep(); }
void CTFCPlayer::State_Enter_ACTIVE() { SetMoveType( MOVETYPE_WALK ); RemoveEffects( EF_NODRAW ); RemoveSolidFlags( FSOLID_NOT_SOLID ); m_Local.m_iHideHUD = 0; PhysObjectWake(); }
void CTFCPlayer::State_Enter_DYING() { SetMoveType( MOVETYPE_NONE ); AddSolidFlags( FSOLID_NOT_SOLID ); }
void CTFCPlayer::PhysObjectSleep() { IPhysicsObject *pObj = VPhysicsGetObject(); if ( pObj ) pObj->Sleep(); }
void CTFCPlayer::PhysObjectWake() { IPhysicsObject *pObj = VPhysicsGetObject(); if ( pObj ) pObj->Wake(); }
void CTFCPlayer::HandleCommand_JoinTeam( const char *pTeamName ) { int iTeam = TEAM_RED; if ( stricmp( pTeamName, "auto" ) == 0 ) { iTeam = RandomInt( 0, 1 ) ? TEAM_RED : TEAM_BLUE; } else if ( stricmp( pTeamName, "spectate" ) == 0 ) { iTeam = TEAM_SPECTATOR; } else { for ( int i=0; i < TEAM_MAXCOUNT; i++ ) { if ( stricmp( pTeamName, teamnames[i] ) == 0 ) { iTeam = i; break; } } }
if ( iTeam == TEAM_SPECTATOR ) { // Prevent this is the cvar is set
if ( !mp_allowspectators.GetInt() && !IsHLTV() ) { ClientPrint( this, HUD_PRINTCENTER, "#Cannot_Be_Spectator" ); return; } if ( GetTeamNumber() != TEAM_UNASSIGNED && !IsDead() ) { CommitSuicide();
// add 1 to frags to balance out the 1 subtracted for killing yourself
IncrementFragCount( 1 ); }
ChangeTeam( TEAM_SPECTATOR );
// do we have fadetoblack on? (need to fade their screen back in)
if ( mp_fadetoblack.GetInt() ) { color32_s clr = { 0,0,0,0 }; UTIL_ScreenFade( this, clr, 0.001, 0, FFADE_IN ); } } else { ChangeTeam( iTeam ); State_Transition( STATE_PICKINGCLASS ); } }
void CTFCPlayer::ChangeTeam( int iTeamNum ) { if ( !GetGlobalTeam( iTeamNum ) ) { Warning( "CCSPlayer::ChangeTeam( %d ) - invalid team index.\n", iTeamNum ); return; }
int iOldTeam = GetTeamNumber();
// if this is our current team, just abort
if ( iTeamNum == iOldTeam ) return;
BaseClass::ChangeTeam( iTeamNum );
if ( iTeamNum == TEAM_UNASSIGNED ) { State_Transition( STATE_OBSERVER_MODE ); } else if ( iTeamNum == TEAM_SPECTATOR ) { State_Transition( STATE_OBSERVER_MODE ); } else // active player
{ if ( iOldTeam == TEAM_SPECTATOR ) { // If they're switching from being a spectator to ingame player
GetIntoGame(); }
if ( !IsDead() && iOldTeam != TEAM_UNASSIGNED ) { // Kill player if switching teams while alive
CommitSuicide(); }
// Put up the class selection menu.
State_Transition( STATE_PICKINGCLASS ); } }
void CTFCPlayer::HandleCommand_JoinClass( const char *pClassName ) { int iClass = RandomInt( 0, PC_LAST_NORMAL_CLASS ); if ( stricmp( pClassName, "random" ) != 0 ) { for ( int i=0; i < PC_LASTCLASS; i++ ) { if ( stricmp( pClassName, GetTFCClassInfo( i )->m_pClassName ) == 0 ) { iClass = i; break; } } if ( i == PC_LAST_NORMAL_CLASS ) { Warning( "HandleCommand_JoinClass( %s ) - invalid class name.\n", pClassName ); } }
m_Shared.SetPlayerClass( iClass ); if ( !IsAlive() ) GetIntoGame(); }
void CTFCPlayer::GetIntoGame() { State_Transition( STATE_ACTIVE ); Spawn(); }
bool CTFCPlayer::ClientCommand( const CCommand& args ) { const char *pcmd = args[0]; if ( FStrEq( pcmd, "joingame" ) ) { // player just closed MOTD dialog
if ( m_Shared.m_iPlayerState == STATE_WELCOME ) { State_Transition( STATE_PICKINGTEAM ); } return true; } else if ( FStrEq( pcmd, "jointeam" ) ) { if ( args.ArgC() >= 2 ) { HandleCommand_JoinTeam( args[1] ); return true; } } else if ( FStrEq( pcmd, "joinclass" ) ) { if ( args.ArgC() < 2 ) { Warning( "Player sent bad joinclass syntax\n" ); }
HandleCommand_JoinClass( args[1] ); return true; }
return BaseClass::ClientCommand( args ); }
bool CTFCPlayer::IsAlly( CBaseEntity *pEnt ) const { return pEnt->GetTeamNumber() == GetTeamNumber(); }
void CTFCPlayer::TF_AddFrags( int nFrags ) { // TFCTODO: implement frags
}
void CTFCPlayer::ResetMenu() { current_menu = 0; }
int CTFCPlayer::GetNumFlames() const { // TFCTODO: implement flames
return 0; }
void CTFCPlayer::SetNumFlames( int nFlames ) { // TFCTODO: implement frags
Assert( 0 ); }
int CTFCPlayer::TakeHealth( float flHealth, int bitsDamageType ) { int bResult = false;
// If the bit's set, ignore the monster's max health and add over it
if ( bitsDamageType & DMG_IGNORE_MAXHEALTH ) { int iDamage = g_pGameRules->Damage_GetTimeBased(); m_bitsDamageType &= ~(bitsDamageType & ~iDamage); m_iHealth += flHealth; bResult = true; } else { bResult = BaseClass::TakeHealth( flHealth, bitsDamageType ); }
// Leg Healing
if (m_iLegDamage > 0) { // Allow even at full health
if ( GetHealth() >= (GetMaxHealth() - 5)) m_iLegDamage = 0; else m_iLegDamage -= (GetHealth() + flHealth) / 20; if (m_iLegDamage < 1) m_iLegDamage = 0;
TeamFortress_SetSpeed(); bResult = true; }
return bResult; }
void CTFCPlayer::TeamFortress_SetSpeed() { int playerclass = m_Shared.GetPlayerClass(); float maxfbspeed;
// Spectators can move while in Classic Observer mode
if ( IsObserver() ) { if ( GetObserverMode() == OBS_MODE_ROAMING ) SetMaxSpeed( GetTFCClassInfo( PC_SCOUT )->m_flMaxSpeed ); else SetMaxSpeed( 0 );
return; }
// Check for any reason why they can't move at all
if ( (m_Shared.GetStateFlags() & TFSTATE_CANT_MOVE) || (playerclass == PC_UNDEFINED) ) { SetAbsVelocity( vec3_origin ); SetMaxSpeed( 1 ); return; }
// First, get their max class speed
maxfbspeed = GetTFCClassInfo( playerclass )->m_flMaxSpeed;
// 2nd, see if any GoalItems are slowing them down
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" ); while ( pEnt ) { CTFGoal *pGoal = dynamic_cast<CTFGoal*>( pEnt ); if ( pGoal ) { if ( pGoal->GetOwnerEntity() == this ) { if (pGoal->goal_activation & TFGI_SLOW) { maxfbspeed = maxfbspeed / 2; } else if (pGoal->speed_reduction) { float flPercent = ((float)pGoal->speed_reduction) / 100.0; maxfbspeed = flPercent * maxfbspeed; } } }
pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" ); }
// 3rd, See if they're tranquilised
if (m_Shared.GetStateFlags() & TFSTATE_TRANQUILISED) { maxfbspeed = maxfbspeed / 2; }
// 4th, check for leg wounds
if (m_iLegDamage) { if (m_iLegDamage > 6) m_iLegDamage = 6;
// reduce speed by 10% per leg wound
maxfbspeed = (maxfbspeed * ((10 - m_iLegDamage) / 10)); }
// 5th, if they're a sniper, and they're aiming, their speed must be 80 or less
if (m_Shared.GetStateFlags() & TFSTATE_AIMING) { if (maxfbspeed > 80) maxfbspeed = 80; }
// Set the speed
SetMaxSpeed( maxfbspeed ); }
void CTFCPlayer::Event_Killed( const CTakeDamageInfo &info ) { DoAnimationEvent( PLAYERANIMEVENT_DIE ); State_Transition( STATE_DYING ); // Transition into the dying state.
// Remove all items..
RemoveAllItems( true );
BaseClass::Event_Killed( info );
// Don't overflow the value for this.
m_iHealth = 0; }
void CTFCPlayer::ClientHearVox( const char *pSentence ) { //TFCTODO: implement this.
}
//=========================================================================
// Check all stats to make sure they're good for this class
void CTFCPlayer::TeamFortress_CheckClassStats() { // Check armor
if (armortype > armor_allowed) armortype = armor_allowed; if (ArmorValue() > GetClassInfo()->m_iMaxArmor) SetArmorValue( GetClassInfo()->m_iMaxArmor );
if (ArmorValue() < 0) SetArmorValue( 0 ); if (armortype < 0) armortype = 0; // Check ammo
for ( int iAmmoType=0; iAmmoType < TFC_NUM_AMMO_TYPES; iAmmoType++ ) { if ( GetAmmoCount( iAmmoType ) > GetClassInfo()->m_MaxAmmo[iAmmoType] ) RemoveAmmo( GetAmmoCount( iAmmoType ) - GetClassInfo()->m_MaxAmmo[iAmmoType], iAmmoType ); }
// Check Grenades
Assert( GetAmmoCount( TFC_AMMO_GRENADES1 ) >= 0 ); Assert( GetAmmoCount( TFC_AMMO_GRENADES2 ) >= 0 ); // Limit Nails
if ( no_grenades_1() > g_nMaxGrenades[tp_grenades_1()] ) RemoveAmmo( TFC_AMMO_GRENADES1, no_grenades_1() - g_nMaxGrenades[tp_grenades_1()] );
if ( no_grenades_2() > g_nMaxGrenades[tp_grenades_2()] ) RemoveAmmo( TFC_AMMO_GRENADES2, no_grenades_2() - g_nMaxGrenades[tp_grenades_2()] );
// Check health
if (GetHealth() > GetMaxHealth() && !(m_Shared.GetItemFlags() & IT_SUPERHEALTH)) SetHealth( GetMaxHealth() ); if (GetHealth() < 0) SetHealth( 0 );
// Update armor picture
m_Shared.RemoveItemFlags( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 ); if (armortype >= 0.8) m_Shared.AddItemFlags( IT_ARMOR3 ); else if (armortype >= 0.6) m_Shared.AddItemFlags( IT_ARMOR2 ); else if (armortype >= 0.3) m_Shared.AddItemFlags( IT_ARMOR1 ); }
//======================================================================
// DISGUISE HANDLING
//======================================================================
// Reset spy skin and color or remove invisibility
void CTFCPlayer::Spy_RemoveDisguise() { if (m_Shared.GetPlayerClass() == PC_SPY) { if ( undercover_team || undercover_skin ) ClientPrint( this, HUD_PRINTCENTER, "#Disguise_Lost" );
// Set their color
undercover_team = 0; undercover_skin = 0;
immune_to_check = gpGlobals->curtime + 10; is_undercover = 0;
// undisguise weapon
TeamFortress_SetSkin(); TeamFortress_SpyCalcName();
Spy_ResetExternalWeaponModel();
// get them out of any disguise menus
if ( current_menu == MENU_SPY || current_menu == MENU_SPY_SKIN || current_menu == MENU_SPY_COLOR ) { ResetMenu(); }
// Remove the Disguise timer
CTimer *pTimer = Timer_FindTimer( this, TF_TIMER_DISGUISE ); if (pTimer) { ClientPrint( this, HUD_PRINTCENTER, "#Disguise_stop" ); Timer_Remove( pTimer ); } } }
// when the spy loses disguise reset his weapon
void CTFCPlayer::Spy_ResetExternalWeaponModel( void ) { // we don't show any weapon models if we're feigning
if ( is_feigning ) return;
#ifdef TFCTODO // spy
pev->weaponmodel = MAKE_STRING( m_pszSavedWeaponModel ); strcpy( m_szAnimExtention, m_szSavedAnimExtention ); m_iCurrentAnimationState = 0; // force the current animation sequence to be recalculated
#endif
}
//=========================================================================
// Try and find the player's name who's skin and team closest fit the
// current disguise of the spy
void CTFCPlayer::TeamFortress_SpyCalcName() { CBaseEntity *last_target = undercover_target;// don't redisguise self as this person
undercover_target = NULL; // Find a player on the team the spy is disguised as to pretend to be
if (undercover_team != 0) { CTFCPlayer *pPlayer = NULL;
// Loop through players
int i; for ( i = 1; i <= gpGlobals->maxClients; i++ ) { pPlayer = ToTFCPlayer( UTIL_PlayerByIndex( i ) ); if ( pPlayer ) { if ( pPlayer == last_target ) { // choose someone else, we're trying to rid ourselves of a disguise as this one
continue; }
// First, try to find a player with same color and skins
if (pPlayer->GetTeamNumber() == undercover_team && pPlayer->m_Shared.GetPlayerClass() == undercover_skin) { undercover_target = pPlayer; return; } } }
for ( i = 1; i <= gpGlobals->maxClients; i++ ) { pPlayer = ToTFCPlayer( UTIL_PlayerByIndex( i ) ); if ( pPlayer ) { if (pPlayer->GetTeamNumber() == undercover_team) { undercover_target = pPlayer; return; } } } } }
//=========================================================================
// Set the skin of a player based on his/her class
void CTFCPlayer::TeamFortress_SetSkin() { immune_to_check = gpGlobals->curtime + 10;
// Find out whether we should show our actual class or a disguised class
int iClassToUse = m_Shared.GetPlayerClass(); if (iClassToUse == PC_SPY && undercover_skin != 0) iClassToUse = undercover_skin; int iTeamToUse = GetTeamNumber(); if (m_Shared.GetPlayerClass() == PC_SPY && undercover_team != 0) iTeamToUse = undercover_team;
// TFCTODO: handle replacement_model here.
SetModel( GetTFCClassInfo( iClassToUse )->m_pModelName );
// Skins in the models should be setup using the team IDs in tfc_shareddefs.h, subtracting 1
// so they're 0-based.
m_nSkin = iTeamToUse - 1;
if ( FBitSet(GetFlags(), FL_DUCKING) ) UTIL_SetSize(this, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); else UTIL_SetSize(this, VEC_HULL_MIN, VEC_HULL_MAX); }
//=========================================================================
// Displays the state of the items specified by the Goal passed in
void CTFCPlayer::DisplayLocalItemStatus( CTFGoal *pGoal ) { for (int i = 0; i < 4; i++) { if (pGoal->display_item_status[i] != 0) { CTFGoalItem *pItem = Finditem(pGoal->display_item_status[i]); if (pItem) DisplayItemStatus(pGoal, this, pItem); else ClientPrint( this, HUD_PRINTTALK, "#Item_missing" ); } } }
//=========================================================================
// Removes all the Engineer's buildings
void CTFCPlayer::Engineer_RemoveBuildings() { // If the player's building already, stop
if (is_building == 1) { m_Shared.RemoveStateFlags( TFSTATE_CANT_MOVE ); TeamFortress_SetSpeed();
// Remove the timer
CTimer *pTimer = Timer_FindTimer( this, TF_TIMER_BUILD ); if (pTimer) Timer_Remove(pTimer); // Remove the building
UTIL_Remove( building ); building = NULL; is_building = 0;
// Stop Build Sound
StopSound( "Engineer.Building" ); //STOP_SOUND( ENT(pev), CHAN_STATIC, "weapons/building.wav" );
if ( GetActiveWeapon() ) GetActiveWeapon()->Deploy(); }
DestroyBuilding(this, "building_dispenser"); DestroyBuilding(this, "building_sentrygun"); DestroyTeleporter(this, BUILD_TELEPORTER_ENTRY); DestroyTeleporter(this, BUILD_TELEPORTER_EXIT); }
//=========================================================================
// Removes all grenades that persist for a period of time from the world
void CTFCPlayer::TeamFortress_RemoveLiveGrenades( void ) { RemoveOwnedEnt( "tf_weapon_napalmgrenade" ); RemoveOwnedEnt( "tf_weapon_nailgrenade" ); RemoveOwnedEnt( "tf_weapon_gasgrenade" ); RemoveOwnedEnt( "tf_weapon_caltrop" ); }
//=========================================================================
// Removes all rockets the player has fired into the world
// (this prevents a team kill cheat where players would fire rockets
// then change teams to kill their own team)
void CTFCPlayer::TeamFortress_RemoveRockets( void ) { RemoveOwnedEnt( "tf_rpg_rocket" ); RemoveOwnedEnt( "tf_ic_rocket" ); }
// removes the player's pipebombs with no explosions
void CTFCPlayer::RemovePipebombs( void ) { CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "tf_gl_pipebomb" ); while ( pEnt ) { CTFCPlayer *pOwner = ToTFCPlayer( pEnt->GetOwnerEntity() ); if ( pOwner == this ) { pOwner->m_iPipebombCount--; pEnt->AddFlag( FL_KILLME ); }
pEnt = gEntList.FindEntityByClassname( pEnt, "tf_gl_pipebomb" ); } }
//=========================================================================
// Stops the setting of the detpack
void CTFCPlayer::TeamFortress_DetpackStop( void ) { CTimer *pTimer = Timer_FindTimer( this, TF_TIMER_DETPACKSET );
if (!pTimer) return;
ClientPrint( this, HUD_PRINTNOTIFY, "#Detpack_retrieve" );
// Return the detpack
GiveAmmo( 1, TFC_AMMO_DETPACK ); Timer_Remove(pTimer);
// Release player
m_Shared.RemoveStateFlags( TFSTATE_CANT_MOVE ); is_detpacking = 0; TeamFortress_SetSpeed();
// Return their weapon
if ( GetActiveWeapon() ) GetActiveWeapon()->Deploy(); }
//=========================================================================
// Removes any detpacks the player may have set
BOOL CTFCPlayer::TeamFortress_RemoveDetpacks( void ) { // Remove all detpacks owned by the player
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "detpack" ); while ( pEnt ) { // if the player owns this detpack, remove it
if ( pEnt->GetOwnerEntity() == this ) { UTIL_Remove( pEnt ); return TRUE; }
pEnt = gEntList.FindEntityByClassname( pEnt, "detpack" ); }
return FALSE; }
//=========================================================================
// Remove all of an ent owned by this player
void CTFCPlayer::RemoveOwnedEnt( char *pEntName ) { CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, pEntName ); while ( pEnt ) { // if the player owns this entity, remove it
if ( pEnt->GetOwnerEntity() == this ) pEnt->AddFlag( FL_KILLME ); pEnt = gEntList.FindEntityByClassname( pEnt, pEntName ); } }
|