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.

335 lines
8.8 KiB

  1. //========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "c_triggers.h"
  9. #include "in_buttons.h"
  10. #include "c_func_brush.h"
  11. #include "collisionutils.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. IMPLEMENT_CLIENTCLASS_DT( C_BaseTrigger, DT_BaseTrigger, CBaseTrigger )
  15. RecvPropBool( RECVINFO( m_bClientSidePredicted ) ),
  16. RecvPropInt( RECVINFO( m_spawnflags ) ),
  17. END_RECV_TABLE()
  18. //-----------------------------------------------------------------------------
  19. // Purpose: Disables auto movement on players that touch it
  20. //-----------------------------------------------------------------------------
  21. class C_TriggerPlayerMovement : public C_BaseTrigger
  22. {
  23. public:
  24. DECLARE_CLASS( C_TriggerPlayerMovement, C_BaseTrigger );
  25. DECLARE_CLIENTCLASS();
  26. C_TriggerPlayerMovement();
  27. ~C_TriggerPlayerMovement();
  28. void StartTouch( C_BaseEntity *pOther );
  29. void EndTouch( C_BaseEntity *pOther );
  30. protected:
  31. virtual void UpdatePartitionListEntry();
  32. public:
  33. C_TriggerPlayerMovement *m_pNext;
  34. };
  35. IMPLEMENT_CLIENTCLASS_DT( C_TriggerPlayerMovement, DT_TriggerPlayerMovement, CTriggerPlayerMovement )
  36. END_RECV_TABLE()
  37. C_EntityClassList< C_TriggerPlayerMovement > g_TriggerPlayerMovementList;
  38. template<> C_TriggerPlayerMovement *C_EntityClassList<C_TriggerPlayerMovement>::m_pClassList = NULL;
  39. C_TriggerPlayerMovement::C_TriggerPlayerMovement()
  40. {
  41. g_TriggerPlayerMovementList.Insert( this );
  42. }
  43. C_TriggerPlayerMovement::~C_TriggerPlayerMovement()
  44. {
  45. g_TriggerPlayerMovementList.Remove( this );
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Little enumeration class used to try touching all triggers
  49. //-----------------------------------------------------------------------------
  50. template< class T >
  51. class CFastTouchTriggers
  52. {
  53. public:
  54. CFastTouchTriggers( C_BaseEntity *pEnt, T *pTriggers ) : m_pEnt( pEnt ), m_pTriggers( pTriggers )
  55. {
  56. m_pCollide = pEnt->GetCollideable();
  57. m_nRequiredTriggerFlags = m_pCollide->GetRequiredTriggerFlags();
  58. Assert( m_pCollide );
  59. Vector vecMins, vecMaxs;
  60. CM_GetCollideableTriggerTestBox( m_pCollide, &vecMins, &vecMaxs );
  61. const Vector &vecStart = m_pCollide->GetCollisionOrigin();
  62. m_Ray.Init( vecStart, vecStart, vecMins, vecMaxs );
  63. }
  64. FORCEINLINE void CM_GetCollideableTriggerTestBox( ICollideable *pCollide, Vector *pMins, Vector *pMaxs )
  65. {
  66. if ( pCollide->GetSolid() == SOLID_BBOX )
  67. {
  68. *pMins = pCollide->OBBMins();
  69. *pMaxs = pCollide->OBBMaxs();
  70. }
  71. else
  72. {
  73. const Vector &vecStart = pCollide->GetCollisionOrigin();
  74. pCollide->WorldSpaceSurroundingBounds( pMins, pMaxs );
  75. *pMins -= vecStart;
  76. *pMaxs -= vecStart;
  77. }
  78. }
  79. FORCEINLINE void Check( T *pEntity, bool bIgnoreTriggerSolidFlags )
  80. {
  81. // Hmmm.. everything in this list should be a trigger....
  82. ICollideable *pTriggerCollideable = pEntity->GetCollideable();
  83. int nTriggerSolidFlags = pTriggerCollideable->GetSolidFlags();
  84. if ( !bIgnoreTriggerSolidFlags
  85. && m_nRequiredTriggerFlags && ( nTriggerSolidFlags & m_nRequiredTriggerFlags ) == m_nRequiredTriggerFlags )
  86. return;
  87. if ( nTriggerSolidFlags & FSOLID_USE_TRIGGER_BOUNDS )
  88. {
  89. Vector vecTriggerMins, vecTriggerMaxs;
  90. pTriggerCollideable->WorldSpaceTriggerBounds( &vecTriggerMins, &vecTriggerMaxs );
  91. if ( !IsBoxIntersectingRay( vecTriggerMins, vecTriggerMaxs, m_Ray ) )
  92. {
  93. return;
  94. }
  95. }
  96. else
  97. {
  98. trace_t tr;
  99. enginetrace->ClipRayToCollideable( m_Ray, MASK_SOLID, pTriggerCollideable, &tr );
  100. if ( !(tr.contents & MASK_SOLID) )
  101. return;
  102. }
  103. trace_t tr;
  104. UTIL_ClearTrace( tr );
  105. tr.endpos = (m_pEnt->GetAbsOrigin() + pEntity->GetAbsOrigin()) * 0.5;
  106. m_pEnt->PhysicsMarkEntitiesAsTouching( pEntity, tr );
  107. }
  108. FORCEINLINE void Run( bool bIgnoreTriggerSolidFlags = false )
  109. {
  110. for ( T *trigger = m_pTriggers; trigger ; trigger = trigger->m_pNext )
  111. {
  112. if ( trigger->IsDormant() )
  113. continue;
  114. Check( trigger, bIgnoreTriggerSolidFlags );
  115. }
  116. }
  117. Ray_t m_Ray;
  118. private:
  119. C_BaseEntity *m_pEnt;
  120. ICollideable *m_pCollide;
  121. uint m_nRequiredTriggerFlags;
  122. T *m_pTriggers;
  123. };
  124. void TouchTriggerPlayerMovement( C_BaseEntity *pEntity )
  125. {
  126. CFastTouchTriggers< C_TriggerPlayerMovement > helper( pEntity, g_TriggerPlayerMovementList.m_pClassList );
  127. helper.Run();
  128. }
  129. void C_TriggerPlayerMovement::UpdatePartitionListEntry()
  130. {
  131. if ( !m_bClientSidePredicted )
  132. {
  133. BaseClass::UpdatePartitionListEntry();
  134. return;
  135. }
  136. ::partition->RemoveAndInsert(
  137. PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, // remove
  138. PARTITION_CLIENT_TRIGGER_ENTITIES, // add
  139. CollisionProp()->GetPartitionHandle() );
  140. }
  141. void C_TriggerPlayerMovement::StartTouch( C_BaseEntity *pOther )
  142. {
  143. C_BasePlayer *pPlayer = ToBasePlayer( pOther );
  144. if ( !pPlayer )
  145. return;
  146. if ( HasSpawnFlags( SF_TRIGGER_AUTO_DUCK ) )
  147. {
  148. pPlayer->ForceButtons( IN_DUCK );
  149. }
  150. if ( HasSpawnFlags( SF_TRIGGER_AUTO_WALK ) )
  151. {
  152. pPlayer->ForceButtons( IN_SPEED );
  153. }
  154. // UNDONE: Currently this is the only operation this trigger can do
  155. if ( HasSpawnFlags( SF_TRIGGER_MOVE_AUTODISABLE ) )
  156. {
  157. pPlayer->m_Local.m_bAllowAutoMovement = false;
  158. }
  159. }
  160. void C_TriggerPlayerMovement::EndTouch( C_BaseEntity *pOther )
  161. {
  162. C_BasePlayer *pPlayer = ToBasePlayer( pOther );
  163. if ( !pPlayer )
  164. return;
  165. if ( HasSpawnFlags( SF_TRIGGER_AUTO_DUCK ) )
  166. {
  167. pPlayer->UnforceButtons( IN_DUCK );
  168. }
  169. if ( HasSpawnFlags( SF_TRIGGER_AUTO_WALK ) )
  170. {
  171. pPlayer->UnforceButtons( IN_SPEED );
  172. }
  173. if ( HasSpawnFlags( SF_TRIGGER_MOVE_AUTODISABLE ) )
  174. {
  175. pPlayer->m_Local.m_bAllowAutoMovement = true;
  176. }
  177. }
  178. IMPLEMENT_CLIENTCLASS_DT( C_BaseVPhysicsTrigger, DT_BaseVPhysicsTrigger, CBaseVPhysicsTrigger )
  179. //RecvPropBool ( RECVINFO( m_bDisabled ) )
  180. END_RECV_TABLE()
  181. //////////////////////////////////////////////////////////////////////////
  182. //
  183. // Sound operator trigger
  184. //
  185. class C_TriggerSoundOperator : public C_BaseTrigger
  186. {
  187. public:
  188. DECLARE_CLASS( C_TriggerSoundOperator, C_BaseTrigger );
  189. DECLARE_CLIENTCLASS();
  190. C_TriggerSoundOperator();
  191. ~C_TriggerSoundOperator();
  192. void StartTouch( C_BaseEntity *pOther );
  193. void EndTouch( C_BaseEntity *pOther );
  194. protected:
  195. virtual void UpdatePartitionListEntry();
  196. int m_nSoundOperator;
  197. void UpdateSosVar( bool bTouchingNow );
  198. public:
  199. C_TriggerSoundOperator *m_pNext;
  200. };
  201. IMPLEMENT_CLIENTCLASS_DT( C_TriggerSoundOperator, DT_TriggerSoundOperator, CTriggerSoundOperator )
  202. RecvPropInt( RECVINFO( m_nSoundOperator ) ),
  203. END_RECV_TABLE()
  204. C_EntityClassList< C_TriggerSoundOperator > g_TriggerSoundOperators;
  205. template<> C_TriggerSoundOperator *C_EntityClassList<C_TriggerSoundOperator>::m_pClassList = NULL;
  206. C_TriggerSoundOperator::C_TriggerSoundOperator()
  207. {
  208. g_TriggerSoundOperators.Insert( this );
  209. m_nSoundOperator = 0;
  210. }
  211. C_TriggerSoundOperator::~C_TriggerSoundOperator()
  212. {
  213. g_TriggerSoundOperators.Remove( this );
  214. }
  215. static char const * g_szTriggerSoundOperatorVariables[] = {
  216. "sosVarCustomVolume1",
  217. "sosVarCustomVolume2"
  218. };
  219. static bool g_bTriggerSoundOperatorVariablesSet[ Q_ARRAYSIZE( g_szTriggerSoundOperatorVariables ) ] = {
  220. };
  221. void TouchTriggerSoundOperator( C_BaseEntity *pEntity )
  222. {
  223. CFastTouchTriggers< C_TriggerSoundOperator > helper( pEntity, g_TriggerSoundOperators.m_pClassList );
  224. helper.Run( true );
  225. }
  226. void UntouchAllTriggerSoundOperator( C_BaseEntity *pEntity )
  227. {
  228. for ( int j = 0; j < Q_ARRAYSIZE( g_szTriggerSoundOperatorVariables ); ++ j )
  229. {
  230. if ( g_bTriggerSoundOperatorVariablesSet[ j ] )
  231. {
  232. g_bTriggerSoundOperatorVariablesSet[ j ] = false;
  233. engine->SOSSetOpvarFloat( g_szTriggerSoundOperatorVariables[ j ], 0.0f );
  234. }
  235. }
  236. }
  237. void C_TriggerSoundOperator::UpdatePartitionListEntry()
  238. {
  239. if ( !m_bClientSidePredicted )
  240. {
  241. BaseClass::UpdatePartitionListEntry();
  242. return;
  243. }
  244. ::partition->RemoveAndInsert(
  245. PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, // remove
  246. PARTITION_CLIENT_TRIGGER_ENTITIES, // add
  247. CollisionProp()->GetPartitionHandle() );
  248. }
  249. void C_TriggerSoundOperator::StartTouch( C_BaseEntity *pOther )
  250. {
  251. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  252. if ( !pLocalPlayer || ( pOther != pLocalPlayer ) )
  253. return;
  254. UpdateSosVar( true );
  255. }
  256. void C_TriggerSoundOperator::EndTouch( C_BaseEntity *pOther )
  257. {
  258. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  259. if ( !pLocalPlayer || ( pOther != pLocalPlayer ) )
  260. return;
  261. UpdateSosVar( false );
  262. }
  263. void C_TriggerSoundOperator::UpdateSosVar( bool bTouchingNow )
  264. {
  265. int nVar = 0;
  266. if ( ( m_nSoundOperator >= 0 )
  267. && ( m_nSoundOperator < Q_ARRAYSIZE( g_szTriggerSoundOperatorVariables ) ) )
  268. nVar = m_nSoundOperator;
  269. char const *szVar = g_szTriggerSoundOperatorVariables[ nVar ];
  270. g_bTriggerSoundOperatorVariablesSet[ nVar ] = bTouchingNow;
  271. engine->SOSSetOpvarFloat( szVar, bTouchingNow ? 1.0f : 0.0f );
  272. }