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.

416 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include <stdarg.h>
  9. #include "gamerules.h"
  10. #include "player.h"
  11. #include "model_types.h"
  12. #include "movehelper_server.h"
  13. #include "shake.h" // For screen fade constants
  14. #include "engine/IEngineSound.h"
  15. //=============================================================================
  16. // HPE_BEGIN
  17. // [dwenger] Necessary for stats tracking
  18. //=============================================================================
  19. #ifdef CSTRIKE_DLL
  20. #include "cs_gamestats.h"
  21. #include "cs_achievement_constants.h"
  22. #endif
  23. //=============================================================================
  24. // HPE_END
  25. //=============================================================================
  26. // memdbgon must be the last include file in a .cpp file!!!
  27. #include "tier0/memdbgon.h"
  28. extern IPhysicsCollision *physcollision;
  29. //-----------------------------------------------------------------------------
  30. // Implementation of the movehelper on the server
  31. //-----------------------------------------------------------------------------
  32. class CMoveHelperServer : public IMoveHelperServer
  33. {
  34. public:
  35. CMoveHelperServer( void );
  36. virtual ~CMoveHelperServer();
  37. // Methods associated with a particular entity
  38. virtual char const* GetName( EntityHandle_t handle ) const;
  39. // Touch list...
  40. virtual void ResetTouchList( void );
  41. virtual bool AddToTouched( const trace_t &tr, const Vector& impactvelocity );
  42. virtual void ProcessImpacts( void );
  43. virtual bool PlayerFallingDamage( void );
  44. virtual void PlayerSetAnimation( PLAYER_ANIM eAnim );
  45. // Numbered line printf
  46. virtual void Con_NPrintf( int idx, char const* fmt, ... );
  47. // These have separate server vs client impementations
  48. virtual void StartSound( const Vector& origin, int channel, char const* sample, float volume, soundlevel_t soundlevel, int fFlags, int pitch );
  49. virtual void StartSound( const Vector& origin, const char *soundname );
  50. virtual void PlaybackEventFull( int flags, int clientindex, unsigned short eventindex, float delay, Vector& origin, Vector& angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
  51. virtual IPhysicsSurfaceProps *GetSurfaceProps( void );
  52. void SetHost( CBasePlayer *host );
  53. virtual bool IsWorldEntity( const CBaseHandle &handle );
  54. private:
  55. CBasePlayer* m_pHostPlayer;
  56. // results, tallied on client and server, but only used by server to run SV_Impact.
  57. // we store off our velocity in the trace_t structure so that we can determine results
  58. // of shoving boxes etc. around.
  59. struct touchlist_t
  60. {
  61. Vector deltavelocity;
  62. trace_t trace;
  63. };
  64. CUtlVector<touchlist_t> m_TouchList;
  65. };
  66. //-----------------------------------------------------------------------------
  67. // Singleton
  68. //-----------------------------------------------------------------------------
  69. IMPLEMENT_MOVEHELPER();
  70. IMoveHelperServer* MoveHelperServer()
  71. {
  72. static CMoveHelperServer s_MoveHelperServer;
  73. return &s_MoveHelperServer;
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Converts the entity handle into a edict_t
  77. //-----------------------------------------------------------------------------
  78. static inline edict_t* GetEdict( EntityHandle_t handle )
  79. {
  80. return gEntList.GetEdict( handle );
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Constructor
  84. //-----------------------------------------------------------------------------
  85. CMoveHelperServer::CMoveHelperServer( void ) : m_TouchList( 0, 128 )
  86. {
  87. m_pHostPlayer = 0;
  88. SetSingleton( this );
  89. }
  90. CMoveHelperServer::~CMoveHelperServer( void )
  91. {
  92. SetSingleton( 0 );
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Indicates which player we're going to move
  96. //-----------------------------------------------------------------------------
  97. void CMoveHelperServer::SetHost( CBasePlayer *host )
  98. {
  99. m_pHostPlayer = host;
  100. // In case any stuff is ever left over, sigh...
  101. ResetTouchList();
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Returns the name for debugging purposes
  105. //-----------------------------------------------------------------------------
  106. char const* CMoveHelperServer::GetName( EntityHandle_t handle ) const
  107. {
  108. // This ain't pertickulerly fast, but it's for debugging anyways
  109. edict_t* pEdict = GetEdict(handle);
  110. CBaseEntity *ent = CBaseEntity::Instance( pEdict );
  111. // Is it the world?
  112. if (ENTINDEX(pEdict) == 0)
  113. return STRING(gpGlobals->mapname);
  114. // Is it a model?
  115. if ( ent && ent->GetModelName() != NULL_STRING )
  116. return STRING( ent->GetModelName() );
  117. if ( ent->GetClassname() != NULL )
  118. {
  119. return ent->GetClassname();
  120. }
  121. return "?";
  122. }
  123. //-----------------------------------------------------------------------------
  124. // When we do a collision test, we report everything we hit..
  125. //-----------------------------------------------------------------------------
  126. void CMoveHelperServer::ResetTouchList( void )
  127. {
  128. m_TouchList.RemoveAll();
  129. }
  130. //-----------------------------------------------------------------------------
  131. // When a collision occurs, we add it to the touched list
  132. //-----------------------------------------------------------------------------
  133. bool CMoveHelperServer::AddToTouched( const trace_t &tr, const Vector& impactvelocity )
  134. {
  135. Assert( m_pHostPlayer );
  136. // Trace missed
  137. if ( !tr.m_pEnt )
  138. return false;
  139. if ( tr.m_pEnt == m_pHostPlayer )
  140. {
  141. Assert( !"CMoveHelperServer::AddToTouched: Tried to add self to touchlist!!!" );
  142. return false;
  143. }
  144. // Check for duplicate entities
  145. for ( int j = m_TouchList.Size(); --j >= 0; )
  146. {
  147. if ( m_TouchList[j].trace.m_pEnt == tr.m_pEnt )
  148. {
  149. return false;
  150. }
  151. }
  152. int i = m_TouchList.AddToTail();
  153. m_TouchList[i].trace = tr;
  154. VectorCopy( impactvelocity, m_TouchList[i].deltavelocity );
  155. return true;
  156. }
  157. //-----------------------------------------------------------------------------
  158. // After we built the touch list, deal with all the impacts...
  159. //-----------------------------------------------------------------------------
  160. void CMoveHelperServer::ProcessImpacts( void )
  161. {
  162. Assert( m_pHostPlayer );
  163. // Relink in order to build absorigin and absmin/max to reflect any changes
  164. // from prediction. Relink will early out on SOLID_NOT
  165. m_pHostPlayer->PhysicsTouchTriggers();
  166. // Don't bother if the player ain't solid
  167. if ( m_pHostPlayer->IsSolidFlagSet( FSOLID_NOT_SOLID ) )
  168. return;
  169. // Save off the velocity, cause we need to temporarily reset it
  170. Vector vel = m_pHostPlayer->GetAbsVelocity();
  171. // Touch other objects that were intersected during the movement.
  172. for (int i = 0 ; i < m_TouchList.Size(); i++)
  173. {
  174. CBaseHandle entindex = m_TouchList[i].trace.m_pEnt->GetRefEHandle();
  175. // We should have culled negative indices by now
  176. Assert( entindex.IsValid() );
  177. edict_t* ent = GetEdict( entindex );
  178. if (!ent)
  179. continue;
  180. // Run the impact function as if we had run it during movement.
  181. CBaseEntity *entity = GetContainingEntity( ent );
  182. if ( !entity )
  183. continue;
  184. Assert( entity != m_pHostPlayer );
  185. // Don't ever collide with self!!!!
  186. if ( entity == m_pHostPlayer )
  187. continue;
  188. // Reconstruct trace results.
  189. m_TouchList[i].trace.m_pEnt = CBaseEntity::Instance( ent );
  190. // Use the velocity we had when we collided, so boxes will move, etc.
  191. m_pHostPlayer->SetAbsVelocity( m_TouchList[i].deltavelocity );
  192. entity->PhysicsImpact( m_pHostPlayer, m_TouchList[i].trace );
  193. }
  194. // Restore the velocity
  195. m_pHostPlayer->SetAbsVelocity( vel );
  196. // So no stuff is ever left over, sigh...
  197. ResetTouchList();
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Purpose:
  201. // Input : origin -
  202. // *soundname -
  203. //-----------------------------------------------------------------------------
  204. void CMoveHelperServer::StartSound( const Vector& origin, const char *soundname )
  205. {
  206. //MDB - Changing this to send to PAS, as the overloaded function below has done.
  207. //Also removed the UsePredictionRules, client does not yet play the equivalent sound
  208. CRecipientFilter filter;
  209. filter.AddRecipientsByPAS( origin );
  210. CBaseEntity::EmitSound( filter, m_pHostPlayer->entindex(), soundname );
  211. }
  212. //-----------------------------------------------------------------------------
  213. // plays a sound
  214. //-----------------------------------------------------------------------------
  215. void CMoveHelperServer::StartSound( const Vector& origin, int channel, char const* sample,
  216. float volume, soundlevel_t soundlevel, int fFlags, int pitch )
  217. {
  218. CRecipientFilter filter;
  219. filter.AddRecipientsByPAS( origin );
  220. // FIXME, these sounds should not go to the host entity ( SND_NOTHOST )
  221. if ( gpGlobals->maxClients == 1 )
  222. {
  223. // Always send sounds down in SP
  224. EmitSound_t ep;
  225. ep.m_nChannel = channel;
  226. ep.m_pSoundName = sample;
  227. ep.m_flVolume = volume;
  228. ep.m_SoundLevel = soundlevel;
  229. ep.m_nFlags = fFlags;
  230. ep.m_nPitch = pitch;
  231. ep.m_pOrigin = &origin;
  232. CBaseEntity::EmitSound( filter, m_pHostPlayer->entindex(), ep );
  233. }
  234. else
  235. {
  236. filter.UsePredictionRules();
  237. EmitSound_t ep;
  238. ep.m_nChannel = channel;
  239. ep.m_pSoundName = sample;
  240. ep.m_flVolume = volume;
  241. ep.m_SoundLevel = soundlevel;
  242. ep.m_nFlags = fFlags;
  243. ep.m_nPitch = pitch;
  244. ep.m_pOrigin = &origin;
  245. CBaseEntity::EmitSound( filter, m_pHostPlayer->entindex(), ep );
  246. }
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Umm...
  250. //-----------------------------------------------------------------------------
  251. void CMoveHelperServer::PlaybackEventFull( int flags, int clientindex, unsigned short eventindex, float delay, Vector& origin, Vector& angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 )
  252. {
  253. // FIXME, Redo with new event system parameter stuff
  254. }
  255. IPhysicsSurfaceProps *CMoveHelperServer::GetSurfaceProps( void )
  256. {
  257. extern IPhysicsSurfaceProps *physprops;
  258. return physprops;
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Purpose: Note that this only works on a listen server (since it requires graphical output)
  262. // *pFormat -
  263. // ... -
  264. //-----------------------------------------------------------------------------
  265. void CMoveHelperServer::Con_NPrintf( int idx, char const* pFormat, ...)
  266. {
  267. va_list marker;
  268. char msg[8192];
  269. va_start(marker, pFormat);
  270. Q_vsnprintf(msg, sizeof( msg ), pFormat, marker);
  271. va_end(marker);
  272. engine->Con_NPrintf( idx, msg );
  273. }
  274. //-----------------------------------------------------------------------------
  275. // Purpose: Called when the player falls onto a surface fast enough to take
  276. // damage, according to the rules in CGameMovement::CheckFalling.
  277. // Output : Returns true if the player survived the fall, false if they died.
  278. //-----------------------------------------------------------------------------
  279. bool CMoveHelperServer::PlayerFallingDamage( void )
  280. {
  281. float flFallDamage = g_pGameRules->FlPlayerFallDamage( m_pHostPlayer );
  282. if ( flFallDamage > 0 )
  283. {
  284. m_pHostPlayer->TakeDamage( CTakeDamageInfo( GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), flFallDamage, DMG_FALL ) );
  285. StartSound( m_pHostPlayer->GetAbsOrigin(), "Player.FallDamage" );
  286. //=============================================================================
  287. // HPE_BEGIN:
  288. // [dwenger] Needed for fun-fact implementation
  289. //=============================================================================
  290. #ifdef CSTRIKE_DLL
  291. // Increment the stat for fall damage
  292. CCSPlayer* pPlayer = ToCSPlayer(m_pHostPlayer);
  293. if ( pPlayer )
  294. {
  295. CCS_GameStats.IncrementStat( pPlayer, CSSTAT_FALL_DAMAGE, (int)flFallDamage );
  296. }
  297. #endif
  298. //=============================================================================
  299. // HPE_END
  300. //=============================================================================
  301. }
  302. if ( m_pHostPlayer->m_iHealth <= 0 )
  303. {
  304. if ( g_pGameRules->FlPlayerFallDeathDoesScreenFade( m_pHostPlayer ) )
  305. {
  306. color32 black = {0, 0, 0, 255};
  307. UTIL_ScreenFade( m_pHostPlayer, black, 0, 9999, FFADE_OUT | FFADE_STAYOUT );
  308. }
  309. return(false);
  310. }
  311. return(true);
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Purpose: Sets an animation in the player.
  315. // Input : eAnim - Animation to set.
  316. //-----------------------------------------------------------------------------
  317. void CMoveHelperServer::PlayerSetAnimation( PLAYER_ANIM eAnim )
  318. {
  319. m_pHostPlayer->SetAnimation( eAnim );
  320. }
  321. bool CMoveHelperServer::IsWorldEntity( const CBaseHandle &handle )
  322. {
  323. return handle == CBaseEntity::Instance( 0 );
  324. }