Team Fortress 2 Source Code as on 22/4/2020
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.

1629 lines
38 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Player for HL2.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "weapon_hl2mpbasehlmpcombatweapon.h"
  8. #include "hl2mp_player.h"
  9. #include "globalstate.h"
  10. #include "game.h"
  11. #include "gamerules.h"
  12. #include "hl2mp_player_shared.h"
  13. #include "predicted_viewmodel.h"
  14. #include "in_buttons.h"
  15. #include "hl2mp_gamerules.h"
  16. #include "KeyValues.h"
  17. #include "team.h"
  18. #include "weapon_hl2mpbase.h"
  19. #include "grenade_satchel.h"
  20. #include "eventqueue.h"
  21. #include "gamestats.h"
  22. #include "engine/IEngineSound.h"
  23. #include "SoundEmitterSystem/isoundemittersystembase.h"
  24. #include "ilagcompensationmanager.h"
  25. int g_iLastCitizenModel = 0;
  26. int g_iLastCombineModel = 0;
  27. CBaseEntity *g_pLastCombineSpawn = NULL;
  28. CBaseEntity *g_pLastRebelSpawn = NULL;
  29. extern CBaseEntity *g_pLastSpawn;
  30. #define HL2MP_COMMAND_MAX_RATE 0.3
  31. void DropPrimedFragGrenade( CHL2MP_Player *pPlayer, CBaseCombatWeapon *pGrenade );
  32. LINK_ENTITY_TO_CLASS( player, CHL2MP_Player );
  33. LINK_ENTITY_TO_CLASS( info_player_combine, CPointEntity );
  34. LINK_ENTITY_TO_CLASS( info_player_rebel, CPointEntity );
  35. IMPLEMENT_SERVERCLASS_ST(CHL2MP_Player, DT_HL2MP_Player)
  36. SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 0), 11, SPROP_CHANGES_OFTEN ),
  37. SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 1), 11, SPROP_CHANGES_OFTEN ),
  38. SendPropEHandle( SENDINFO( m_hRagdoll ) ),
  39. SendPropInt( SENDINFO( m_iSpawnInterpCounter), 4 ),
  40. SendPropInt( SENDINFO( m_iPlayerSoundType), 3 ),
  41. SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ),
  42. SendPropExclude( "DT_BaseFlex", "m_viewtarget" ),
  43. // SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ),
  44. // SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
  45. END_SEND_TABLE()
  46. BEGIN_DATADESC( CHL2MP_Player )
  47. END_DATADESC()
  48. const char *g_ppszRandomCitizenModels[] =
  49. {
  50. "models/humans/group03/male_01.mdl",
  51. "models/humans/group03/male_02.mdl",
  52. "models/humans/group03/female_01.mdl",
  53. "models/humans/group03/male_03.mdl",
  54. "models/humans/group03/female_02.mdl",
  55. "models/humans/group03/male_04.mdl",
  56. "models/humans/group03/female_03.mdl",
  57. "models/humans/group03/male_05.mdl",
  58. "models/humans/group03/female_04.mdl",
  59. "models/humans/group03/male_06.mdl",
  60. "models/humans/group03/female_06.mdl",
  61. "models/humans/group03/male_07.mdl",
  62. "models/humans/group03/female_07.mdl",
  63. "models/humans/group03/male_08.mdl",
  64. "models/humans/group03/male_09.mdl",
  65. };
  66. const char *g_ppszRandomCombineModels[] =
  67. {
  68. "models/combine_soldier.mdl",
  69. "models/combine_soldier_prisonguard.mdl",
  70. "models/combine_super_soldier.mdl",
  71. "models/police.mdl",
  72. };
  73. #define MAX_COMBINE_MODELS 4
  74. #define MODEL_CHANGE_INTERVAL 5.0f
  75. #define TEAM_CHANGE_INTERVAL 5.0f
  76. #define HL2MPPLAYER_PHYSDAMAGE_SCALE 4.0f
  77. #pragma warning( disable : 4355 )
  78. CHL2MP_Player::CHL2MP_Player() : m_PlayerAnimState( this )
  79. {
  80. m_angEyeAngles.Init();
  81. m_iLastWeaponFireUsercmd = 0;
  82. m_flNextModelChangeTime = 0.0f;
  83. m_flNextTeamChangeTime = 0.0f;
  84. m_iSpawnInterpCounter = 0;
  85. m_bEnterObserver = false;
  86. m_bReady = false;
  87. BaseClass::ChangeTeam( 0 );
  88. // UseClientSideAnimation();
  89. }
  90. CHL2MP_Player::~CHL2MP_Player( void )
  91. {
  92. }
  93. void CHL2MP_Player::UpdateOnRemove( void )
  94. {
  95. if ( m_hRagdoll )
  96. {
  97. UTIL_RemoveImmediate( m_hRagdoll );
  98. m_hRagdoll = NULL;
  99. }
  100. BaseClass::UpdateOnRemove();
  101. }
  102. void CHL2MP_Player::Precache( void )
  103. {
  104. BaseClass::Precache();
  105. PrecacheModel ( "sprites/glow01.vmt" );
  106. //Precache Citizen models
  107. int nHeads = ARRAYSIZE( g_ppszRandomCitizenModels );
  108. int i;
  109. for ( i = 0; i < nHeads; ++i )
  110. PrecacheModel( g_ppszRandomCitizenModels[i] );
  111. //Precache Combine Models
  112. nHeads = ARRAYSIZE( g_ppszRandomCombineModels );
  113. for ( i = 0; i < nHeads; ++i )
  114. PrecacheModel( g_ppszRandomCombineModels[i] );
  115. PrecacheFootStepSounds();
  116. PrecacheScriptSound( "NPC_MetroPolice.Die" );
  117. PrecacheScriptSound( "NPC_CombineS.Die" );
  118. PrecacheScriptSound( "NPC_Citizen.die" );
  119. }
  120. void CHL2MP_Player::GiveAllItems( void )
  121. {
  122. EquipSuit();
  123. CBasePlayer::GiveAmmo( 255, "Pistol");
  124. CBasePlayer::GiveAmmo( 255, "AR2" );
  125. CBasePlayer::GiveAmmo( 5, "AR2AltFire" );
  126. CBasePlayer::GiveAmmo( 255, "SMG1");
  127. CBasePlayer::GiveAmmo( 1, "smg1_grenade");
  128. CBasePlayer::GiveAmmo( 255, "Buckshot");
  129. CBasePlayer::GiveAmmo( 32, "357" );
  130. CBasePlayer::GiveAmmo( 3, "rpg_round");
  131. CBasePlayer::GiveAmmo( 1, "grenade" );
  132. CBasePlayer::GiveAmmo( 2, "slam" );
  133. GiveNamedItem( "weapon_crowbar" );
  134. GiveNamedItem( "weapon_stunstick" );
  135. GiveNamedItem( "weapon_pistol" );
  136. GiveNamedItem( "weapon_357" );
  137. GiveNamedItem( "weapon_smg1" );
  138. GiveNamedItem( "weapon_ar2" );
  139. GiveNamedItem( "weapon_shotgun" );
  140. GiveNamedItem( "weapon_frag" );
  141. GiveNamedItem( "weapon_crossbow" );
  142. GiveNamedItem( "weapon_rpg" );
  143. GiveNamedItem( "weapon_slam" );
  144. GiveNamedItem( "weapon_physcannon" );
  145. }
  146. void CHL2MP_Player::GiveDefaultItems( void )
  147. {
  148. EquipSuit();
  149. CBasePlayer::GiveAmmo( 255, "Pistol");
  150. CBasePlayer::GiveAmmo( 45, "SMG1");
  151. CBasePlayer::GiveAmmo( 1, "grenade" );
  152. CBasePlayer::GiveAmmo( 6, "Buckshot");
  153. CBasePlayer::GiveAmmo( 6, "357" );
  154. if ( GetPlayerModelType() == PLAYER_SOUNDS_METROPOLICE || GetPlayerModelType() == PLAYER_SOUNDS_COMBINESOLDIER )
  155. {
  156. GiveNamedItem( "weapon_stunstick" );
  157. }
  158. else if ( GetPlayerModelType() == PLAYER_SOUNDS_CITIZEN )
  159. {
  160. GiveNamedItem( "weapon_crowbar" );
  161. }
  162. GiveNamedItem( "weapon_pistol" );
  163. GiveNamedItem( "weapon_smg1" );
  164. GiveNamedItem( "weapon_frag" );
  165. GiveNamedItem( "weapon_physcannon" );
  166. const char *szDefaultWeaponName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_defaultweapon" );
  167. CBaseCombatWeapon *pDefaultWeapon = Weapon_OwnsThisType( szDefaultWeaponName );
  168. if ( pDefaultWeapon )
  169. {
  170. Weapon_Switch( pDefaultWeapon );
  171. }
  172. else
  173. {
  174. Weapon_Switch( Weapon_OwnsThisType( "weapon_physcannon" ) );
  175. }
  176. }
  177. void CHL2MP_Player::PickDefaultSpawnTeam( void )
  178. {
  179. if ( GetTeamNumber() == 0 )
  180. {
  181. if ( HL2MPRules()->IsTeamplay() == false )
  182. {
  183. if ( GetModelPtr() == NULL )
  184. {
  185. const char *szModelName = NULL;
  186. szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_playermodel" );
  187. if ( ValidatePlayerModel( szModelName ) == false )
  188. {
  189. char szReturnString[512];
  190. Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel models/combine_soldier.mdl\n" );
  191. engine->ClientCommand ( edict(), szReturnString );
  192. }
  193. ChangeTeam( TEAM_UNASSIGNED );
  194. }
  195. }
  196. else
  197. {
  198. CTeam *pCombine = g_Teams[TEAM_COMBINE];
  199. CTeam *pRebels = g_Teams[TEAM_REBELS];
  200. if ( pCombine == NULL || pRebels == NULL )
  201. {
  202. ChangeTeam( random->RandomInt( TEAM_COMBINE, TEAM_REBELS ) );
  203. }
  204. else
  205. {
  206. if ( pCombine->GetNumPlayers() > pRebels->GetNumPlayers() )
  207. {
  208. ChangeTeam( TEAM_REBELS );
  209. }
  210. else if ( pCombine->GetNumPlayers() < pRebels->GetNumPlayers() )
  211. {
  212. ChangeTeam( TEAM_COMBINE );
  213. }
  214. else
  215. {
  216. ChangeTeam( random->RandomInt( TEAM_COMBINE, TEAM_REBELS ) );
  217. }
  218. }
  219. }
  220. }
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose: Sets HL2 specific defaults.
  224. //-----------------------------------------------------------------------------
  225. void CHL2MP_Player::Spawn(void)
  226. {
  227. m_flNextModelChangeTime = 0.0f;
  228. m_flNextTeamChangeTime = 0.0f;
  229. PickDefaultSpawnTeam();
  230. BaseClass::Spawn();
  231. if ( !IsObserver() )
  232. {
  233. pl.deadflag = false;
  234. RemoveSolidFlags( FSOLID_NOT_SOLID );
  235. RemoveEffects( EF_NODRAW );
  236. GiveDefaultItems();
  237. }
  238. SetNumAnimOverlays( 3 );
  239. ResetAnimation();
  240. m_nRenderFX = kRenderNormal;
  241. m_Local.m_iHideHUD = 0;
  242. AddFlag(FL_ONGROUND); // set the player on the ground at the start of the round.
  243. m_impactEnergyScale = HL2MPPLAYER_PHYSDAMAGE_SCALE;
  244. if ( HL2MPRules()->IsIntermission() )
  245. {
  246. AddFlag( FL_FROZEN );
  247. }
  248. else
  249. {
  250. RemoveFlag( FL_FROZEN );
  251. }
  252. m_iSpawnInterpCounter = (m_iSpawnInterpCounter + 1) % 8;
  253. m_Local.m_bDucked = false;
  254. SetPlayerUnderwater(false);
  255. m_bReady = false;
  256. }
  257. void CHL2MP_Player::PickupObject( CBaseEntity *pObject, bool bLimitMassAndSize )
  258. {
  259. }
  260. bool CHL2MP_Player::ValidatePlayerModel( const char *pModel )
  261. {
  262. int iModels = ARRAYSIZE( g_ppszRandomCitizenModels );
  263. int i;
  264. for ( i = 0; i < iModels; ++i )
  265. {
  266. if ( !Q_stricmp( g_ppszRandomCitizenModels[i], pModel ) )
  267. {
  268. return true;
  269. }
  270. }
  271. iModels = ARRAYSIZE( g_ppszRandomCombineModels );
  272. for ( i = 0; i < iModels; ++i )
  273. {
  274. if ( !Q_stricmp( g_ppszRandomCombineModels[i], pModel ) )
  275. {
  276. return true;
  277. }
  278. }
  279. return false;
  280. }
  281. void CHL2MP_Player::SetPlayerTeamModel( void )
  282. {
  283. const char *szModelName = NULL;
  284. szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_playermodel" );
  285. int modelIndex = modelinfo->GetModelIndex( szModelName );
  286. if ( modelIndex == -1 || ValidatePlayerModel( szModelName ) == false )
  287. {
  288. szModelName = "models/Combine_Soldier.mdl";
  289. m_iModelType = TEAM_COMBINE;
  290. char szReturnString[512];
  291. Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", szModelName );
  292. engine->ClientCommand ( edict(), szReturnString );
  293. }
  294. if ( GetTeamNumber() == TEAM_COMBINE )
  295. {
  296. if ( Q_stristr( szModelName, "models/human") )
  297. {
  298. int nHeads = ARRAYSIZE( g_ppszRandomCombineModels );
  299. g_iLastCombineModel = ( g_iLastCombineModel + 1 ) % nHeads;
  300. szModelName = g_ppszRandomCombineModels[g_iLastCombineModel];
  301. }
  302. m_iModelType = TEAM_COMBINE;
  303. }
  304. else if ( GetTeamNumber() == TEAM_REBELS )
  305. {
  306. if ( !Q_stristr( szModelName, "models/human") )
  307. {
  308. int nHeads = ARRAYSIZE( g_ppszRandomCitizenModels );
  309. g_iLastCitizenModel = ( g_iLastCitizenModel + 1 ) % nHeads;
  310. szModelName = g_ppszRandomCitizenModels[g_iLastCitizenModel];
  311. }
  312. m_iModelType = TEAM_REBELS;
  313. }
  314. SetModel( szModelName );
  315. SetupPlayerSoundsByModel( szModelName );
  316. m_flNextModelChangeTime = gpGlobals->curtime + MODEL_CHANGE_INTERVAL;
  317. }
  318. void CHL2MP_Player::SetPlayerModel( void )
  319. {
  320. const char *szModelName = NULL;
  321. const char *pszCurrentModelName = modelinfo->GetModelName( GetModel());
  322. szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_playermodel" );
  323. if ( ValidatePlayerModel( szModelName ) == false )
  324. {
  325. char szReturnString[512];
  326. if ( ValidatePlayerModel( pszCurrentModelName ) == false )
  327. {
  328. pszCurrentModelName = "models/Combine_Soldier.mdl";
  329. }
  330. Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", pszCurrentModelName );
  331. engine->ClientCommand ( edict(), szReturnString );
  332. szModelName = pszCurrentModelName;
  333. }
  334. if ( GetTeamNumber() == TEAM_COMBINE )
  335. {
  336. int nHeads = ARRAYSIZE( g_ppszRandomCombineModels );
  337. g_iLastCombineModel = ( g_iLastCombineModel + 1 ) % nHeads;
  338. szModelName = g_ppszRandomCombineModels[g_iLastCombineModel];
  339. m_iModelType = TEAM_COMBINE;
  340. }
  341. else if ( GetTeamNumber() == TEAM_REBELS )
  342. {
  343. int nHeads = ARRAYSIZE( g_ppszRandomCitizenModels );
  344. g_iLastCitizenModel = ( g_iLastCitizenModel + 1 ) % nHeads;
  345. szModelName = g_ppszRandomCitizenModels[g_iLastCitizenModel];
  346. m_iModelType = TEAM_REBELS;
  347. }
  348. else
  349. {
  350. if ( Q_strlen( szModelName ) == 0 )
  351. {
  352. szModelName = g_ppszRandomCitizenModels[0];
  353. }
  354. if ( Q_stristr( szModelName, "models/human") )
  355. {
  356. m_iModelType = TEAM_REBELS;
  357. }
  358. else
  359. {
  360. m_iModelType = TEAM_COMBINE;
  361. }
  362. }
  363. int modelIndex = modelinfo->GetModelIndex( szModelName );
  364. if ( modelIndex == -1 )
  365. {
  366. szModelName = "models/Combine_Soldier.mdl";
  367. m_iModelType = TEAM_COMBINE;
  368. char szReturnString[512];
  369. Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", szModelName );
  370. engine->ClientCommand ( edict(), szReturnString );
  371. }
  372. SetModel( szModelName );
  373. SetupPlayerSoundsByModel( szModelName );
  374. m_flNextModelChangeTime = gpGlobals->curtime + MODEL_CHANGE_INTERVAL;
  375. }
  376. void CHL2MP_Player::SetupPlayerSoundsByModel( const char *pModelName )
  377. {
  378. if ( Q_stristr( pModelName, "models/human") )
  379. {
  380. m_iPlayerSoundType = (int)PLAYER_SOUNDS_CITIZEN;
  381. }
  382. else if ( Q_stristr(pModelName, "police" ) )
  383. {
  384. m_iPlayerSoundType = (int)PLAYER_SOUNDS_METROPOLICE;
  385. }
  386. else if ( Q_stristr(pModelName, "combine" ) )
  387. {
  388. m_iPlayerSoundType = (int)PLAYER_SOUNDS_COMBINESOLDIER;
  389. }
  390. }
  391. void CHL2MP_Player::ResetAnimation( void )
  392. {
  393. if ( IsAlive() )
  394. {
  395. SetSequence ( -1 );
  396. SetActivity( ACT_INVALID );
  397. if (!GetAbsVelocity().x && !GetAbsVelocity().y)
  398. SetAnimation( PLAYER_IDLE );
  399. else if ((GetAbsVelocity().x || GetAbsVelocity().y) && ( GetFlags() & FL_ONGROUND ))
  400. SetAnimation( PLAYER_WALK );
  401. else if (GetWaterLevel() > 1)
  402. SetAnimation( PLAYER_WALK );
  403. }
  404. }
  405. bool CHL2MP_Player::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex )
  406. {
  407. bool bRet = BaseClass::Weapon_Switch( pWeapon, viewmodelindex );
  408. if ( bRet == true )
  409. {
  410. ResetAnimation();
  411. }
  412. return bRet;
  413. }
  414. void CHL2MP_Player::PreThink( void )
  415. {
  416. QAngle vOldAngles = GetLocalAngles();
  417. QAngle vTempAngles = GetLocalAngles();
  418. vTempAngles = EyeAngles();
  419. if ( vTempAngles[PITCH] > 180.0f )
  420. {
  421. vTempAngles[PITCH] -= 360.0f;
  422. }
  423. SetLocalAngles( vTempAngles );
  424. BaseClass::PreThink();
  425. State_PreThink();
  426. //Reset bullet force accumulator, only lasts one frame
  427. m_vecTotalBulletForce = vec3_origin;
  428. SetLocalAngles( vOldAngles );
  429. }
  430. void CHL2MP_Player::PostThink( void )
  431. {
  432. BaseClass::PostThink();
  433. if ( GetFlags() & FL_DUCKING )
  434. {
  435. SetCollisionBounds( VEC_CROUCH_TRACE_MIN, VEC_CROUCH_TRACE_MAX );
  436. }
  437. m_PlayerAnimState.Update();
  438. // Store the eye angles pitch so the client can compute its animation state correctly.
  439. m_angEyeAngles = EyeAngles();
  440. QAngle angles = GetLocalAngles();
  441. angles[PITCH] = 0;
  442. SetLocalAngles( angles );
  443. }
  444. void CHL2MP_Player::PlayerDeathThink()
  445. {
  446. if( !IsObserver() )
  447. {
  448. BaseClass::PlayerDeathThink();
  449. }
  450. }
  451. void CHL2MP_Player::FireBullets ( const FireBulletsInfo_t &info )
  452. {
  453. // Move other players back to history positions based on local player's lag
  454. lagcompensation->StartLagCompensation( this, this->GetCurrentCommand() );
  455. FireBulletsInfo_t modinfo = info;
  456. CWeaponHL2MPBase *pWeapon = dynamic_cast<CWeaponHL2MPBase *>( GetActiveWeapon() );
  457. if ( pWeapon )
  458. {
  459. modinfo.m_iPlayerDamage = modinfo.m_flDamage = pWeapon->GetHL2MPWpnData().m_iPlayerDamage;
  460. }
  461. NoteWeaponFired();
  462. BaseClass::FireBullets( modinfo );
  463. // Move other players back to history positions based on local player's lag
  464. lagcompensation->FinishLagCompensation( this );
  465. }
  466. void CHL2MP_Player::NoteWeaponFired( void )
  467. {
  468. Assert( m_pCurrentCommand );
  469. if( m_pCurrentCommand )
  470. {
  471. m_iLastWeaponFireUsercmd = m_pCurrentCommand->command_number;
  472. }
  473. }
  474. extern ConVar sv_maxunlag;
  475. bool CHL2MP_Player::WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits ) const
  476. {
  477. // No need to lag compensate at all if we're not attacking in this command and
  478. // we haven't attacked recently.
  479. if ( !( pCmd->buttons & IN_ATTACK ) && (pCmd->command_number - m_iLastWeaponFireUsercmd > 5) )
  480. return false;
  481. // If this entity hasn't been transmitted to us and acked, then don't bother lag compensating it.
  482. if ( pEntityTransmitBits && !pEntityTransmitBits->Get( pPlayer->entindex() ) )
  483. return false;
  484. const Vector &vMyOrigin = GetAbsOrigin();
  485. const Vector &vHisOrigin = pPlayer->GetAbsOrigin();
  486. // get max distance player could have moved within max lag compensation time,
  487. // multiply by 1.5 to to avoid "dead zones" (sqrt(2) would be the exact value)
  488. float maxDistance = 1.5 * pPlayer->MaxSpeed() * sv_maxunlag.GetFloat();
  489. // If the player is within this distance, lag compensate them in case they're running past us.
  490. if ( vHisOrigin.DistTo( vMyOrigin ) < maxDistance )
  491. return true;
  492. // If their origin is not within a 45 degree cone in front of us, no need to lag compensate.
  493. Vector vForward;
  494. AngleVectors( pCmd->viewangles, &vForward );
  495. Vector vDiff = vHisOrigin - vMyOrigin;
  496. VectorNormalize( vDiff );
  497. float flCosAngle = 0.707107f; // 45 degree angle
  498. if ( vForward.Dot( vDiff ) < flCosAngle )
  499. return false;
  500. return true;
  501. }
  502. Activity CHL2MP_Player::TranslateTeamActivity( Activity ActToTranslate )
  503. {
  504. if ( m_iModelType == TEAM_COMBINE )
  505. return ActToTranslate;
  506. if ( ActToTranslate == ACT_RUN )
  507. return ACT_RUN_AIM_AGITATED;
  508. if ( ActToTranslate == ACT_IDLE )
  509. return ACT_IDLE_AIM_AGITATED;
  510. if ( ActToTranslate == ACT_WALK )
  511. return ACT_WALK_AIM_AGITATED;
  512. return ActToTranslate;
  513. }
  514. extern ConVar hl2_normspeed;
  515. // Set the activity based on an event or current state
  516. void CHL2MP_Player::SetAnimation( PLAYER_ANIM playerAnim )
  517. {
  518. int animDesired;
  519. float speed;
  520. speed = GetAbsVelocity().Length2D();
  521. // bool bRunning = true;
  522. //Revisit!
  523. /* if ( ( m_nButtons & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) ) )
  524. {
  525. if ( speed > 1.0f && speed < hl2_normspeed.GetFloat() - 20.0f )
  526. {
  527. bRunning = false;
  528. }
  529. }*/
  530. if ( GetFlags() & ( FL_FROZEN | FL_ATCONTROLS ) )
  531. {
  532. speed = 0;
  533. playerAnim = PLAYER_IDLE;
  534. }
  535. Activity idealActivity = ACT_HL2MP_RUN;
  536. // This could stand to be redone. Why is playerAnim abstracted from activity? (sjb)
  537. if ( playerAnim == PLAYER_JUMP )
  538. {
  539. idealActivity = ACT_HL2MP_JUMP;
  540. }
  541. else if ( playerAnim == PLAYER_DIE )
  542. {
  543. if ( m_lifeState == LIFE_ALIVE )
  544. {
  545. return;
  546. }
  547. }
  548. else if ( playerAnim == PLAYER_ATTACK1 )
  549. {
  550. if ( GetActivity( ) == ACT_HOVER ||
  551. GetActivity( ) == ACT_SWIM ||
  552. GetActivity( ) == ACT_HOP ||
  553. GetActivity( ) == ACT_LEAP ||
  554. GetActivity( ) == ACT_DIESIMPLE )
  555. {
  556. idealActivity = GetActivity( );
  557. }
  558. else
  559. {
  560. idealActivity = ACT_HL2MP_GESTURE_RANGE_ATTACK;
  561. }
  562. }
  563. else if ( playerAnim == PLAYER_RELOAD )
  564. {
  565. idealActivity = ACT_HL2MP_GESTURE_RELOAD;
  566. }
  567. else if ( playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK )
  568. {
  569. if ( !( GetFlags() & FL_ONGROUND ) && GetActivity( ) == ACT_HL2MP_JUMP ) // Still jumping
  570. {
  571. idealActivity = GetActivity( );
  572. }
  573. /*
  574. else if ( GetWaterLevel() > 1 )
  575. {
  576. if ( speed == 0 )
  577. idealActivity = ACT_HOVER;
  578. else
  579. idealActivity = ACT_SWIM;
  580. }
  581. */
  582. else
  583. {
  584. if ( GetFlags() & FL_DUCKING )
  585. {
  586. if ( speed > 0 )
  587. {
  588. idealActivity = ACT_HL2MP_WALK_CROUCH;
  589. }
  590. else
  591. {
  592. idealActivity = ACT_HL2MP_IDLE_CROUCH;
  593. }
  594. }
  595. else
  596. {
  597. if ( speed > 0 )
  598. {
  599. /*
  600. if ( bRunning == false )
  601. {
  602. idealActivity = ACT_WALK;
  603. }
  604. else
  605. */
  606. {
  607. idealActivity = ACT_HL2MP_RUN;
  608. }
  609. }
  610. else
  611. {
  612. idealActivity = ACT_HL2MP_IDLE;
  613. }
  614. }
  615. }
  616. idealActivity = TranslateTeamActivity( idealActivity );
  617. }
  618. if ( idealActivity == ACT_HL2MP_GESTURE_RANGE_ATTACK )
  619. {
  620. RestartGesture( Weapon_TranslateActivity( idealActivity ) );
  621. // FIXME: this seems a bit wacked
  622. Weapon_SetActivity( Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 );
  623. return;
  624. }
  625. else if ( idealActivity == ACT_HL2MP_GESTURE_RELOAD )
  626. {
  627. RestartGesture( Weapon_TranslateActivity( idealActivity ) );
  628. return;
  629. }
  630. else
  631. {
  632. SetActivity( idealActivity );
  633. animDesired = SelectWeightedSequence( Weapon_TranslateActivity ( idealActivity ) );
  634. if (animDesired == -1)
  635. {
  636. animDesired = SelectWeightedSequence( idealActivity );
  637. if ( animDesired == -1 )
  638. {
  639. animDesired = 0;
  640. }
  641. }
  642. // Already using the desired animation?
  643. if ( GetSequence() == animDesired )
  644. return;
  645. m_flPlaybackRate = 1.0;
  646. ResetSequence( animDesired );
  647. SetCycle( 0 );
  648. return;
  649. }
  650. // Already using the desired animation?
  651. if ( GetSequence() == animDesired )
  652. return;
  653. //Msg( "Set animation to %d\n", animDesired );
  654. // Reset to first frame of desired animation
  655. ResetSequence( animDesired );
  656. SetCycle( 0 );
  657. }
  658. extern int gEvilImpulse101;
  659. //-----------------------------------------------------------------------------
  660. // Purpose: Player reacts to bumping a weapon.
  661. // Input : pWeapon - the weapon that the player bumped into.
  662. // Output : Returns true if player picked up the weapon
  663. //-----------------------------------------------------------------------------
  664. bool CHL2MP_Player::BumpWeapon( CBaseCombatWeapon *pWeapon )
  665. {
  666. CBaseCombatCharacter *pOwner = pWeapon->GetOwner();
  667. // Can I have this weapon type?
  668. if ( !IsAllowedToPickupWeapons() )
  669. return false;
  670. if ( pOwner || !Weapon_CanUse( pWeapon ) || !g_pGameRules->CanHavePlayerItem( this, pWeapon ) )
  671. {
  672. if ( gEvilImpulse101 )
  673. {
  674. UTIL_Remove( pWeapon );
  675. }
  676. return false;
  677. }
  678. // Don't let the player fetch weapons through walls (use MASK_SOLID so that you can't pickup through windows)
  679. if( !pWeapon->FVisible( this, MASK_SOLID ) && !(GetFlags() & FL_NOTARGET) )
  680. {
  681. return false;
  682. }
  683. bool bOwnsWeaponAlready = !!Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType());
  684. if ( bOwnsWeaponAlready == true )
  685. {
  686. //If we have room for the ammo, then "take" the weapon too.
  687. if ( Weapon_EquipAmmoOnly( pWeapon ) )
  688. {
  689. pWeapon->CheckRespawn();
  690. UTIL_Remove( pWeapon );
  691. return true;
  692. }
  693. else
  694. {
  695. return false;
  696. }
  697. }
  698. pWeapon->CheckRespawn();
  699. Weapon_Equip( pWeapon );
  700. return true;
  701. }
  702. void CHL2MP_Player::ChangeTeam( int iTeam )
  703. {
  704. /* if ( GetNextTeamChangeTime() >= gpGlobals->curtime )
  705. {
  706. char szReturnString[128];
  707. Q_snprintf( szReturnString, sizeof( szReturnString ), "Please wait %d more seconds before trying to switch teams again.\n", (int)(GetNextTeamChangeTime() - gpGlobals->curtime) );
  708. ClientPrint( this, HUD_PRINTTALK, szReturnString );
  709. return;
  710. }*/
  711. bool bKill = false;
  712. if ( HL2MPRules()->IsTeamplay() != true && iTeam != TEAM_SPECTATOR )
  713. {
  714. //don't let them try to join combine or rebels during deathmatch.
  715. iTeam = TEAM_UNASSIGNED;
  716. }
  717. if ( HL2MPRules()->IsTeamplay() == true )
  718. {
  719. if ( iTeam != GetTeamNumber() && GetTeamNumber() != TEAM_UNASSIGNED )
  720. {
  721. bKill = true;
  722. }
  723. }
  724. BaseClass::ChangeTeam( iTeam );
  725. m_flNextTeamChangeTime = gpGlobals->curtime + TEAM_CHANGE_INTERVAL;
  726. if ( HL2MPRules()->IsTeamplay() == true )
  727. {
  728. SetPlayerTeamModel();
  729. }
  730. else
  731. {
  732. SetPlayerModel();
  733. }
  734. if ( iTeam == TEAM_SPECTATOR )
  735. {
  736. RemoveAllItems( true );
  737. State_Transition( STATE_OBSERVER_MODE );
  738. }
  739. if ( bKill == true )
  740. {
  741. CommitSuicide();
  742. }
  743. }
  744. bool CHL2MP_Player::HandleCommand_JoinTeam( int team )
  745. {
  746. if ( !GetGlobalTeam( team ) || team == 0 )
  747. {
  748. Warning( "HandleCommand_JoinTeam( %d ) - invalid team index.\n", team );
  749. return false;
  750. }
  751. if ( team == TEAM_SPECTATOR )
  752. {
  753. // Prevent this is the cvar is set
  754. if ( !mp_allowspectators.GetInt() )
  755. {
  756. ClientPrint( this, HUD_PRINTCENTER, "#Cannot_Be_Spectator" );
  757. return false;
  758. }
  759. if ( GetTeamNumber() != TEAM_UNASSIGNED && !IsDead() )
  760. {
  761. m_fNextSuicideTime = gpGlobals->curtime; // allow the suicide to work
  762. CommitSuicide();
  763. // add 1 to frags to balance out the 1 subtracted for killing yourself
  764. IncrementFragCount( 1 );
  765. }
  766. ChangeTeam( TEAM_SPECTATOR );
  767. return true;
  768. }
  769. else
  770. {
  771. StopObserverMode();
  772. State_Transition(STATE_ACTIVE);
  773. }
  774. // Switch their actual team...
  775. ChangeTeam( team );
  776. return true;
  777. }
  778. bool CHL2MP_Player::ClientCommand( const CCommand &args )
  779. {
  780. if ( FStrEq( args[0], "spectate" ) )
  781. {
  782. if ( ShouldRunRateLimitedCommand( args ) )
  783. {
  784. // instantly join spectators
  785. HandleCommand_JoinTeam( TEAM_SPECTATOR );
  786. }
  787. return true;
  788. }
  789. else if ( FStrEq( args[0], "jointeam" ) )
  790. {
  791. if ( args.ArgC() < 2 )
  792. {
  793. Warning( "Player sent bad jointeam syntax\n" );
  794. }
  795. if ( ShouldRunRateLimitedCommand( args ) )
  796. {
  797. int iTeam = atoi( args[1] );
  798. HandleCommand_JoinTeam( iTeam );
  799. }
  800. return true;
  801. }
  802. else if ( FStrEq( args[0], "joingame" ) )
  803. {
  804. return true;
  805. }
  806. return BaseClass::ClientCommand( args );
  807. }
  808. void CHL2MP_Player::CheatImpulseCommands( int iImpulse )
  809. {
  810. switch ( iImpulse )
  811. {
  812. case 101:
  813. {
  814. if( sv_cheats->GetBool() )
  815. {
  816. GiveAllItems();
  817. }
  818. }
  819. break;
  820. default:
  821. BaseClass::CheatImpulseCommands( iImpulse );
  822. }
  823. }
  824. bool CHL2MP_Player::ShouldRunRateLimitedCommand( const CCommand &args )
  825. {
  826. int i = m_RateLimitLastCommandTimes.Find( args[0] );
  827. if ( i == m_RateLimitLastCommandTimes.InvalidIndex() )
  828. {
  829. m_RateLimitLastCommandTimes.Insert( args[0], gpGlobals->curtime );
  830. return true;
  831. }
  832. else if ( (gpGlobals->curtime - m_RateLimitLastCommandTimes[i]) < HL2MP_COMMAND_MAX_RATE )
  833. {
  834. // Too fast.
  835. return false;
  836. }
  837. else
  838. {
  839. m_RateLimitLastCommandTimes[i] = gpGlobals->curtime;
  840. return true;
  841. }
  842. }
  843. void CHL2MP_Player::CreateViewModel( int index /*=0*/ )
  844. {
  845. Assert( index >= 0 && index < MAX_VIEWMODELS );
  846. if ( GetViewModel( index ) )
  847. return;
  848. CPredictedViewModel *vm = ( CPredictedViewModel * )CreateEntityByName( "predicted_viewmodel" );
  849. if ( vm )
  850. {
  851. vm->SetAbsOrigin( GetAbsOrigin() );
  852. vm->SetOwner( this );
  853. vm->SetIndex( index );
  854. DispatchSpawn( vm );
  855. vm->FollowEntity( this, false );
  856. m_hViewModel.Set( index, vm );
  857. }
  858. }
  859. bool CHL2MP_Player::BecomeRagdollOnClient( const Vector &force )
  860. {
  861. return true;
  862. }
  863. // -------------------------------------------------------------------------------- //
  864. // Ragdoll entities.
  865. // -------------------------------------------------------------------------------- //
  866. class CHL2MPRagdoll : public CBaseAnimatingOverlay
  867. {
  868. public:
  869. DECLARE_CLASS( CHL2MPRagdoll, CBaseAnimatingOverlay );
  870. DECLARE_SERVERCLASS();
  871. // Transmit ragdolls to everyone.
  872. virtual int UpdateTransmitState()
  873. {
  874. return SetTransmitState( FL_EDICT_ALWAYS );
  875. }
  876. public:
  877. // In case the client has the player entity, we transmit the player index.
  878. // In case the client doesn't have it, we transmit the player's model index, origin, and angles
  879. // so they can create a ragdoll in the right place.
  880. CNetworkHandle( CBaseEntity, m_hPlayer ); // networked entity handle
  881. CNetworkVector( m_vecRagdollVelocity );
  882. CNetworkVector( m_vecRagdollOrigin );
  883. };
  884. LINK_ENTITY_TO_CLASS( hl2mp_ragdoll, CHL2MPRagdoll );
  885. IMPLEMENT_SERVERCLASS_ST_NOBASE( CHL2MPRagdoll, DT_HL2MPRagdoll )
  886. SendPropVector( SENDINFO(m_vecRagdollOrigin), -1, SPROP_COORD ),
  887. SendPropEHandle( SENDINFO( m_hPlayer ) ),
  888. SendPropModelIndex( SENDINFO( m_nModelIndex ) ),
  889. SendPropInt ( SENDINFO(m_nForceBone), 8, 0 ),
  890. SendPropVector ( SENDINFO(m_vecForce), -1, SPROP_NOSCALE ),
  891. SendPropVector( SENDINFO( m_vecRagdollVelocity ) )
  892. END_SEND_TABLE()
  893. void CHL2MP_Player::CreateRagdollEntity( void )
  894. {
  895. if ( m_hRagdoll )
  896. {
  897. UTIL_RemoveImmediate( m_hRagdoll );
  898. m_hRagdoll = NULL;
  899. }
  900. // If we already have a ragdoll, don't make another one.
  901. CHL2MPRagdoll *pRagdoll = dynamic_cast< CHL2MPRagdoll* >( m_hRagdoll.Get() );
  902. if ( !pRagdoll )
  903. {
  904. // create a new one
  905. pRagdoll = dynamic_cast< CHL2MPRagdoll* >( CreateEntityByName( "hl2mp_ragdoll" ) );
  906. }
  907. if ( pRagdoll )
  908. {
  909. pRagdoll->m_hPlayer = this;
  910. pRagdoll->m_vecRagdollOrigin = GetAbsOrigin();
  911. pRagdoll->m_vecRagdollVelocity = GetAbsVelocity();
  912. pRagdoll->m_nModelIndex = m_nModelIndex;
  913. pRagdoll->m_nForceBone = m_nForceBone;
  914. pRagdoll->m_vecForce = m_vecTotalBulletForce;
  915. pRagdoll->SetAbsOrigin( GetAbsOrigin() );
  916. }
  917. // ragdolls will be removed on round restart automatically
  918. m_hRagdoll = pRagdoll;
  919. }
  920. //-----------------------------------------------------------------------------
  921. //-----------------------------------------------------------------------------
  922. int CHL2MP_Player::FlashlightIsOn( void )
  923. {
  924. return IsEffectActive( EF_DIMLIGHT );
  925. }
  926. extern ConVar flashlight;
  927. //-----------------------------------------------------------------------------
  928. //-----------------------------------------------------------------------------
  929. void CHL2MP_Player::FlashlightTurnOn( void )
  930. {
  931. if( flashlight.GetInt() > 0 && IsAlive() )
  932. {
  933. AddEffects( EF_DIMLIGHT );
  934. EmitSound( "HL2Player.FlashlightOn" );
  935. }
  936. }
  937. //-----------------------------------------------------------------------------
  938. //-----------------------------------------------------------------------------
  939. void CHL2MP_Player::FlashlightTurnOff( void )
  940. {
  941. RemoveEffects( EF_DIMLIGHT );
  942. if( IsAlive() )
  943. {
  944. EmitSound( "HL2Player.FlashlightOff" );
  945. }
  946. }
  947. void CHL2MP_Player::Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity )
  948. {
  949. //Drop a grenade if it's primed.
  950. if ( GetActiveWeapon() )
  951. {
  952. CBaseCombatWeapon *pGrenade = Weapon_OwnsThisType("weapon_frag");
  953. if ( GetActiveWeapon() == pGrenade )
  954. {
  955. if ( ( m_nButtons & IN_ATTACK ) || (m_nButtons & IN_ATTACK2) )
  956. {
  957. DropPrimedFragGrenade( this, pGrenade );
  958. return;
  959. }
  960. }
  961. }
  962. BaseClass::Weapon_Drop( pWeapon, pvecTarget, pVelocity );
  963. }
  964. void CHL2MP_Player::DetonateTripmines( void )
  965. {
  966. CBaseEntity *pEntity = NULL;
  967. while ((pEntity = gEntList.FindEntityByClassname( pEntity, "npc_satchel" )) != NULL)
  968. {
  969. CSatchelCharge *pSatchel = dynamic_cast<CSatchelCharge *>(pEntity);
  970. if (pSatchel->m_bIsLive && pSatchel->GetThrower() == this )
  971. {
  972. g_EventQueue.AddEvent( pSatchel, "Explode", 0.20, this, this );
  973. }
  974. }
  975. // Play sound for pressing the detonator
  976. EmitSound( "Weapon_SLAM.SatchelDetonate" );
  977. }
  978. void CHL2MP_Player::Event_Killed( const CTakeDamageInfo &info )
  979. {
  980. //update damage info with our accumulated physics force
  981. CTakeDamageInfo subinfo = info;
  982. subinfo.SetDamageForce( m_vecTotalBulletForce );
  983. SetNumAnimOverlays( 0 );
  984. // Note: since we're dead, it won't draw us on the client, but we don't set EF_NODRAW
  985. // because we still want to transmit to the clients in our PVS.
  986. CreateRagdollEntity();
  987. DetonateTripmines();
  988. BaseClass::Event_Killed( subinfo );
  989. if ( info.GetDamageType() & DMG_DISSOLVE )
  990. {
  991. if ( m_hRagdoll )
  992. {
  993. m_hRagdoll->GetBaseAnimating()->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL );
  994. }
  995. }
  996. CBaseEntity *pAttacker = info.GetAttacker();
  997. if ( pAttacker )
  998. {
  999. int iScoreToAdd = 1;
  1000. if ( pAttacker == this )
  1001. {
  1002. iScoreToAdd = -1;
  1003. }
  1004. GetGlobalTeam( pAttacker->GetTeamNumber() )->AddScore( iScoreToAdd );
  1005. }
  1006. FlashlightTurnOff();
  1007. m_lifeState = LIFE_DEAD;
  1008. RemoveEffects( EF_NODRAW ); // still draw player body
  1009. StopZooming();
  1010. }
  1011. int CHL2MP_Player::OnTakeDamage( const CTakeDamageInfo &inputInfo )
  1012. {
  1013. //return here if the player is in the respawn grace period vs. slams.
  1014. if ( gpGlobals->curtime < m_flSlamProtectTime && (inputInfo.GetDamageType() == DMG_BLAST ) )
  1015. return 0;
  1016. m_vecTotalBulletForce += inputInfo.GetDamageForce();
  1017. gamestats->Event_PlayerDamage( this, inputInfo );
  1018. return BaseClass::OnTakeDamage( inputInfo );
  1019. }
  1020. void CHL2MP_Player::DeathSound( const CTakeDamageInfo &info )
  1021. {
  1022. if ( m_hRagdoll && m_hRagdoll->GetBaseAnimating()->IsDissolving() )
  1023. return;
  1024. char szStepSound[128];
  1025. Q_snprintf( szStepSound, sizeof( szStepSound ), "%s.Die", GetPlayerModelSoundPrefix() );
  1026. const char *pModelName = STRING( GetModelName() );
  1027. CSoundParameters params;
  1028. if ( GetParametersForSound( szStepSound, params, pModelName ) == false )
  1029. return;
  1030. Vector vecOrigin = GetAbsOrigin();
  1031. CRecipientFilter filter;
  1032. filter.AddRecipientsByPAS( vecOrigin );
  1033. EmitSound_t ep;
  1034. ep.m_nChannel = params.channel;
  1035. ep.m_pSoundName = params.soundname;
  1036. ep.m_flVolume = params.volume;
  1037. ep.m_SoundLevel = params.soundlevel;
  1038. ep.m_nFlags = 0;
  1039. ep.m_nPitch = params.pitch;
  1040. ep.m_pOrigin = &vecOrigin;
  1041. EmitSound( filter, entindex(), ep );
  1042. }
  1043. CBaseEntity* CHL2MP_Player::EntSelectSpawnPoint( void )
  1044. {
  1045. CBaseEntity *pSpot = NULL;
  1046. CBaseEntity *pLastSpawnPoint = g_pLastSpawn;
  1047. edict_t *player = edict();
  1048. const char *pSpawnpointName = "info_player_deathmatch";
  1049. if ( HL2MPRules()->IsTeamplay() == true )
  1050. {
  1051. if ( GetTeamNumber() == TEAM_COMBINE )
  1052. {
  1053. pSpawnpointName = "info_player_combine";
  1054. pLastSpawnPoint = g_pLastCombineSpawn;
  1055. }
  1056. else if ( GetTeamNumber() == TEAM_REBELS )
  1057. {
  1058. pSpawnpointName = "info_player_rebel";
  1059. pLastSpawnPoint = g_pLastRebelSpawn;
  1060. }
  1061. if ( gEntList.FindEntityByClassname( NULL, pSpawnpointName ) == NULL )
  1062. {
  1063. pSpawnpointName = "info_player_deathmatch";
  1064. pLastSpawnPoint = g_pLastSpawn;
  1065. }
  1066. }
  1067. pSpot = pLastSpawnPoint;
  1068. // Randomize the start spot
  1069. for ( int i = random->RandomInt(1,5); i > 0; i-- )
  1070. pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
  1071. if ( !pSpot ) // skip over the null point
  1072. pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
  1073. CBaseEntity *pFirstSpot = pSpot;
  1074. do
  1075. {
  1076. if ( pSpot )
  1077. {
  1078. // check if pSpot is valid
  1079. if ( g_pGameRules->IsSpawnPointValid( pSpot, this ) )
  1080. {
  1081. if ( pSpot->GetLocalOrigin() == vec3_origin )
  1082. {
  1083. pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
  1084. continue;
  1085. }
  1086. // if so, go to pSpot
  1087. goto ReturnSpot;
  1088. }
  1089. }
  1090. // increment pSpot
  1091. pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
  1092. } while ( pSpot != pFirstSpot ); // loop if we're not back to the start
  1093. // we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
  1094. if ( pSpot )
  1095. {
  1096. CBaseEntity *ent = NULL;
  1097. for ( CEntitySphereQuery sphere( pSpot->GetAbsOrigin(), 128 ); (ent = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() )
  1098. {
  1099. // if ent is a client, kill em (unless they are ourselves)
  1100. if ( ent->IsPlayer() && !(ent->edict() == player) )
  1101. ent->TakeDamage( CTakeDamageInfo( GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), 300, DMG_GENERIC ) );
  1102. }
  1103. goto ReturnSpot;
  1104. }
  1105. if ( !pSpot )
  1106. {
  1107. pSpot = gEntList.FindEntityByClassname( pSpot, "info_player_start" );
  1108. if ( pSpot )
  1109. goto ReturnSpot;
  1110. }
  1111. ReturnSpot:
  1112. if ( HL2MPRules()->IsTeamplay() == true )
  1113. {
  1114. if ( GetTeamNumber() == TEAM_COMBINE )
  1115. {
  1116. g_pLastCombineSpawn = pSpot;
  1117. }
  1118. else if ( GetTeamNumber() == TEAM_REBELS )
  1119. {
  1120. g_pLastRebelSpawn = pSpot;
  1121. }
  1122. }
  1123. g_pLastSpawn = pSpot;
  1124. m_flSlamProtectTime = gpGlobals->curtime + 0.5;
  1125. return pSpot;
  1126. }
  1127. CON_COMMAND( timeleft, "prints the time remaining in the match" )
  1128. {
  1129. CHL2MP_Player *pPlayer = ToHL2MPPlayer( UTIL_GetCommandClient() );
  1130. int iTimeRemaining = (int)HL2MPRules()->GetMapRemainingTime();
  1131. if ( iTimeRemaining == 0 )
  1132. {
  1133. if ( pPlayer )
  1134. {
  1135. ClientPrint( pPlayer, HUD_PRINTTALK, "This game has no timelimit." );
  1136. }
  1137. else
  1138. {
  1139. Msg( "* No Time Limit *\n" );
  1140. }
  1141. }
  1142. else
  1143. {
  1144. int iMinutes, iSeconds;
  1145. iMinutes = iTimeRemaining / 60;
  1146. iSeconds = iTimeRemaining % 60;
  1147. char minutes[8];
  1148. char seconds[8];
  1149. Q_snprintf( minutes, sizeof(minutes), "%d", iMinutes );
  1150. Q_snprintf( seconds, sizeof(seconds), "%2.2d", iSeconds );
  1151. if ( pPlayer )
  1152. {
  1153. ClientPrint( pPlayer, HUD_PRINTTALK, "Time left in map: %s1:%s2", minutes, seconds );
  1154. }
  1155. else
  1156. {
  1157. Msg( "Time Remaining: %s:%s\n", minutes, seconds );
  1158. }
  1159. }
  1160. }
  1161. void CHL2MP_Player::Reset()
  1162. {
  1163. ResetDeathCount();
  1164. ResetFragCount();
  1165. }
  1166. bool CHL2MP_Player::IsReady()
  1167. {
  1168. return m_bReady;
  1169. }
  1170. void CHL2MP_Player::SetReady( bool bReady )
  1171. {
  1172. m_bReady = bReady;
  1173. }
  1174. void CHL2MP_Player::CheckChatText( char *p, int bufsize )
  1175. {
  1176. //Look for escape sequences and replace
  1177. char *buf = new char[bufsize];
  1178. int pos = 0;
  1179. // Parse say text for escape sequences
  1180. for ( char *pSrc = p; pSrc != NULL && *pSrc != 0 && pos < bufsize-1; pSrc++ )
  1181. {
  1182. // copy each char across
  1183. buf[pos] = *pSrc;
  1184. pos++;
  1185. }
  1186. buf[pos] = '\0';
  1187. // copy buf back into p
  1188. Q_strncpy( p, buf, bufsize );
  1189. delete[] buf;
  1190. const char *pReadyCheck = p;
  1191. HL2MPRules()->CheckChatForReadySignal( this, pReadyCheck );
  1192. }
  1193. void CHL2MP_Player::State_Transition( HL2MPPlayerState newState )
  1194. {
  1195. State_Leave();
  1196. State_Enter( newState );
  1197. }
  1198. void CHL2MP_Player::State_Enter( HL2MPPlayerState newState )
  1199. {
  1200. m_iPlayerState = newState;
  1201. m_pCurStateInfo = State_LookupInfo( newState );
  1202. // Initialize the new state.
  1203. if ( m_pCurStateInfo && m_pCurStateInfo->pfnEnterState )
  1204. (this->*m_pCurStateInfo->pfnEnterState)();
  1205. }
  1206. void CHL2MP_Player::State_Leave()
  1207. {
  1208. if ( m_pCurStateInfo && m_pCurStateInfo->pfnLeaveState )
  1209. {
  1210. (this->*m_pCurStateInfo->pfnLeaveState)();
  1211. }
  1212. }
  1213. void CHL2MP_Player::State_PreThink()
  1214. {
  1215. if ( m_pCurStateInfo && m_pCurStateInfo->pfnPreThink )
  1216. {
  1217. (this->*m_pCurStateInfo->pfnPreThink)();
  1218. }
  1219. }
  1220. CHL2MPPlayerStateInfo *CHL2MP_Player::State_LookupInfo( HL2MPPlayerState state )
  1221. {
  1222. // This table MUST match the
  1223. static CHL2MPPlayerStateInfo playerStateInfos[] =
  1224. {
  1225. { STATE_ACTIVE, "STATE_ACTIVE", &CHL2MP_Player::State_Enter_ACTIVE, NULL, &CHL2MP_Player::State_PreThink_ACTIVE },
  1226. { STATE_OBSERVER_MODE, "STATE_OBSERVER_MODE", &CHL2MP_Player::State_Enter_OBSERVER_MODE, NULL, &CHL2MP_Player::State_PreThink_OBSERVER_MODE }
  1227. };
  1228. for ( int i=0; i < ARRAYSIZE( playerStateInfos ); i++ )
  1229. {
  1230. if ( playerStateInfos[i].m_iPlayerState == state )
  1231. return &playerStateInfos[i];
  1232. }
  1233. return NULL;
  1234. }
  1235. bool CHL2MP_Player::StartObserverMode(int mode)
  1236. {
  1237. //we only want to go into observer mode if the player asked to, not on a death timeout
  1238. if ( m_bEnterObserver == true )
  1239. {
  1240. VPhysicsDestroyObject();
  1241. return BaseClass::StartObserverMode( mode );
  1242. }
  1243. return false;
  1244. }
  1245. void CHL2MP_Player::StopObserverMode()
  1246. {
  1247. m_bEnterObserver = false;
  1248. BaseClass::StopObserverMode();
  1249. }
  1250. void CHL2MP_Player::State_Enter_OBSERVER_MODE()
  1251. {
  1252. int observerMode = m_iObserverLastMode;
  1253. if ( IsNetClient() )
  1254. {
  1255. const char *pIdealMode = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_spec_mode" );
  1256. if ( pIdealMode )
  1257. {
  1258. observerMode = atoi( pIdealMode );
  1259. if ( observerMode <= OBS_MODE_FIXED || observerMode > OBS_MODE_ROAMING )
  1260. {
  1261. observerMode = m_iObserverLastMode;
  1262. }
  1263. }
  1264. }
  1265. m_bEnterObserver = true;
  1266. StartObserverMode( observerMode );
  1267. }
  1268. void CHL2MP_Player::State_PreThink_OBSERVER_MODE()
  1269. {
  1270. // Make sure nobody has changed any of our state.
  1271. // Assert( GetMoveType() == MOVETYPE_FLY );
  1272. Assert( m_takedamage == DAMAGE_NO );
  1273. Assert( IsSolidFlagSet( FSOLID_NOT_SOLID ) );
  1274. // Assert( IsEffectActive( EF_NODRAW ) );
  1275. // Must be dead.
  1276. Assert( m_lifeState == LIFE_DEAD );
  1277. Assert( pl.deadflag );
  1278. }
  1279. void CHL2MP_Player::State_Enter_ACTIVE()
  1280. {
  1281. SetMoveType( MOVETYPE_WALK );
  1282. // md 8/15/07 - They'll get set back to solid when they actually respawn. If we set them solid now and mp_forcerespawn
  1283. // is false, then they'll be spectating but blocking live players from moving.
  1284. // RemoveSolidFlags( FSOLID_NOT_SOLID );
  1285. m_Local.m_iHideHUD = 0;
  1286. }
  1287. void CHL2MP_Player::State_PreThink_ACTIVE()
  1288. {
  1289. //we don't really need to do anything here.
  1290. //This state_prethink structure came over from CS:S and was doing an assert check that fails the way hl2dm handles death
  1291. }
  1292. //-----------------------------------------------------------------------------
  1293. // Purpose:
  1294. //-----------------------------------------------------------------------------
  1295. bool CHL2MP_Player::CanHearAndReadChatFrom( CBasePlayer *pPlayer )
  1296. {
  1297. // can always hear the console unless we're ignoring all chat
  1298. if ( !pPlayer )
  1299. return false;
  1300. return true;
  1301. }