Counter Strike : Global Offensive Source Code
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.

442 lines
13 KiB

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