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.

577 lines
19 KiB

  1. //===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
  2. //
  3. //===========================================================================//
  4. #include "cbase.h"
  5. #include "paint_power_user.h"
  6. #ifdef CLIENT_DLL
  7. #include "c_projectedwallentity.h"
  8. #include "c_portal_player.h"
  9. #include "c_physicsprop.h"
  10. #define CPhysicsProp C_PhysicsProp
  11. #else
  12. #include "projectedwallentity.h"
  13. #include "portal_player.h"
  14. #include "props.h" // for CPhysicsProp def
  15. extern void WallPainted( int colorIndex, int nSegment, CBaseEntity *pWall );
  16. #endif
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. #if defined( GAME_DLL )
  20. ConVar wall_debug_time("wall_debug_time", "5.f");
  21. ConVar wall_debug("wall_debug", "0");
  22. #endif
  23. ConVar debug_paintable_projected_wall("debug_paintable_projected_wall", "0", FCVAR_REPLICATED);
  24. ConVar sv_thinnerprojectedwalls( "sv_thinnerprojectedwalls", "0", FCVAR_CHEAT | FCVAR_REPLICATED );
  25. void CProjectedWallEntity::Touch( CBaseEntity* pOther )
  26. {
  27. //Check if the touched entity is a paint power user
  28. IPaintPowerUser* pPowerUser = dynamic_cast< IPaintPowerUser* >( pOther );
  29. if( engine->HasPaintmap() && pPowerUser )
  30. {
  31. //Get the up vector of the wall
  32. Vector vecWallUp;
  33. #if defined( GAME_DLL )
  34. AngleVectors( GetLocalAngles(), NULL, NULL, &vecWallUp );
  35. #else
  36. AngleVectors( GetNetworkAngles(), NULL, NULL, &vecWallUp );
  37. #endif
  38. const trace_t& trace = BaseClass::GetTouchTrace();
  39. float flDot = DotProduct( vecWallUp, trace.plane.normal );
  40. //Get the segment of the wall that the power user touched
  41. Vector vecWorldSpaceCenter = pOther->WorldSpaceCenter();
  42. Vector vecTouchPoint = UTIL_ProjectPointOntoPlane( vecWorldSpaceCenter, trace.plane );
  43. const int nSegment = ComputeSegmentIndex( vecTouchPoint );
  44. if( nSegment >= m_nNumSegments )
  45. {
  46. return;
  47. }
  48. //Get the paint power at the current segment
  49. PaintPowerType power = m_PaintPowers[nSegment];
  50. if( debug_paintable_projected_wall.GetBool() )
  51. {
  52. DevMsg( "Segment: %d, Power: %d\n", nSegment, power );
  53. }
  54. // We dont want to give power to the user if they're touching the side of a projected wall
  55. if( !CloseEnough( flDot, 0.0f ) )
  56. {
  57. pPowerUser->AddSurfacePaintPowerInfo( PaintPowerInfo_t( trace.plane.normal,
  58. trace.endpos,
  59. this,
  60. power ) );
  61. }
  62. }
  63. }
  64. int CProjectedWallEntity::ComputeSegmentIndex( const Vector& vWorldPositionOnWall ) const
  65. {
  66. const Vector& startPoint = m_vecStartPoint;
  67. const Vector& endPoint = m_vecEndPoint;
  68. const Vector wallVector = endPoint - startPoint;
  69. const Vector contactOffset = vWorldPositionOnWall - startPoint;
  70. const float distance = DotProduct( wallVector, contactOffset ) / m_flLength;
  71. Assert( distance + 0.5f > 0.0f && distance < m_flLength + 0.5f );
  72. return clamp( distance / m_flSegmentLength, 0, m_nNumSegments - 1 );
  73. }
  74. PaintPowerType CProjectedWallEntity::GetPaintPowerAtPoint( const Vector& worldContactPt ) const
  75. {
  76. return m_PaintPowers[ComputeSegmentIndex(worldContactPt)];
  77. }
  78. void CProjectedWallEntity::Paint( PaintPowerType type, const Vector& worldContactPt )
  79. {
  80. const int nSegment = ComputeSegmentIndex( worldContactPt );
  81. if( nSegment < m_PaintPowers.Count() )
  82. {
  83. m_PaintPowers[nSegment] = type;
  84. #ifndef CLIENT_DLL
  85. //Send the event to the client
  86. WallPainted( type, nSegment, this );
  87. #endif
  88. }
  89. }
  90. void CProjectedWallEntity::CleansePaint()
  91. {
  92. for( int i = 0; i < m_nNumSegments; ++i )
  93. {
  94. // come back to this - MTW
  95. /*
  96. #if defined( CLIENT_DLL )
  97. if ( m_PaintPowers[i] != NO_POWER && m_PaintParticles[i] && m_PaintParticles[i]->IsValid() )
  98. {
  99. ParticleProp()->StopEmissionAndDestroyImmediately( m_PaintParticles[i] );
  100. }
  101. m_PaintParticles[i] = NULL;
  102. #endif
  103. */
  104. m_PaintPowers[i] = NO_POWER;
  105. }
  106. }
  107. class CProjectorCollideList : public IEntityEnumerator
  108. {
  109. public:
  110. CProjectorCollideList( Ray_t *pRay, CProjectedWallEntity* pIgnoreEntity, int nContentsMask ) :
  111. m_Entities( 0, 32 ), m_pIgnoreEntity( pIgnoreEntity ),
  112. m_nContentsMask( nContentsMask ), m_pRay(pRay) {}
  113. virtual bool EnumEntity( IHandleEntity *pHandleEntity )
  114. {
  115. // Don't bother with the ignore entity.
  116. if ( pHandleEntity == m_pIgnoreEntity )
  117. return true;
  118. Assert( pHandleEntity );
  119. if ( !pHandleEntity )
  120. return true;
  121. #if defined( GAME_DLL )
  122. CBaseEntity *pEntity = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() );
  123. #else
  124. CBaseEntity *pEntity = C_BaseEntity::Instance( pHandleEntity->GetRefEHandle() );
  125. #endif
  126. Assert( pEntity );
  127. if ( !pEntity )
  128. return true;
  129. // Only interested in physics objects, the player and turret npcs
  130. if ( pEntity->IsPlayer() ||
  131. dynamic_cast<CPhysicsProp*>( pEntity ) )
  132. {
  133. Ray_t ray;
  134. ray.Init( pEntity->GetAbsOrigin(), pEntity->GetAbsOrigin(), pEntity->CollisionProp()->OBBMins(), pEntity->CollisionProp()->OBBMaxs() ) ;
  135. trace_t tr;
  136. m_pIgnoreEntity->TestCollision( ray, MASK_SHOT, tr );
  137. // add if their AABB is overlapping the collideable
  138. if ( tr.DidHit() )
  139. {
  140. m_Entities.AddToTail( pEntity );
  141. }
  142. }
  143. return true;
  144. }
  145. CUtlVector<CBaseEntity*> m_Entities;
  146. private:
  147. CProjectedWallEntity *m_pIgnoreEntity;
  148. int m_nContentsMask;
  149. Ray_t *m_pRay;
  150. };
  151. void CProjectedWallEntity::DisplaceObstructingEntity( CBaseEntity *pEntity, bool bIgnoreStuck )
  152. {
  153. #if defined( GAME_DLL )
  154. Vector vOrigin = GetLocalOrigin();
  155. #else
  156. Vector vOrigin = GetNetworkOrigin();
  157. #endif
  158. Vector vWallForward, vWallRight, vWallUp;
  159. GetVectors( &vWallForward, &vWallRight, &vWallUp );
  160. Ray_t ray;
  161. Vector vLength = GetLengthVector();
  162. Vector vWallSweptBoxMins, vWallSweptBoxMaxs;
  163. GetExtents( vWallSweptBoxMins, vWallSweptBoxMaxs );
  164. ray.Init( vOrigin, vOrigin + vWallForward*vLength.Length(), vWallSweptBoxMins, vWallSweptBoxMaxs );
  165. CTraceFilterOnlyHitThis filter( pEntity );
  166. trace_t tr;
  167. UTIL_TraceRay( ray, MASK_ALL, &filter, &tr );
  168. if ( tr.DidHit() )
  169. {
  170. DisplaceObstructingEntity( pEntity, vOrigin, vWallUp, vWallRight, bIgnoreStuck );
  171. }
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose: Attempts to smooth over the frequent physics-stuck properties of the wall.
  175. //-----------------------------------------------------------------------------
  176. void CProjectedWallEntity::DisplaceObstructingEntities( void )
  177. {
  178. // Walls size needs to be set up before we test for obstructing objects
  179. Assert ( !VectorsAreEqual( m_vWorldSpace_WallMins, m_vWorldSpace_WallMaxs ) );
  180. #if defined( GAME_DLL )
  181. Vector vOrigin = GetLocalOrigin();
  182. #else
  183. Vector vOrigin = GetNetworkOrigin();
  184. #endif
  185. Vector vWallForward, vWallRight, vWallUp;
  186. GetVectors( &vWallForward, &vWallRight, &vWallUp );
  187. Ray_t ray;
  188. Vector vLength = GetLengthVector();
  189. Vector vWallSweptBoxMins, vWallSweptBoxMaxs;
  190. GetExtents( vWallSweptBoxMins, vWallSweptBoxMaxs );
  191. ray.Init( vOrigin, vOrigin + vWallForward*vLength.Length(), vWallSweptBoxMins, vWallSweptBoxMaxs );
  192. CProjectorCollideList enumerator( &ray, this, MASK_SHOT );
  193. enginetrace->EnumerateEntities( ray, false, &enumerator );
  194. for( int iEntity = enumerator.m_Entities.Count(); --iEntity >= 0; )
  195. {
  196. CBaseEntity *pEntity = enumerator.m_Entities[iEntity];
  197. DisplaceObstructingEntity( pEntity, vOrigin, vWallUp, vWallRight, false );
  198. }
  199. }
  200. CEG_NOINLINE void CProjectedWallEntity::DisplaceObstructingEntity( CBaseEntity *pEntity, const Vector &vOrigin, const Vector &vWallUp, const Vector &vWallRight, bool bIgnoreStuck )
  201. {
  202. #ifdef CLIENT_DLL
  203. if ( !pEntity->GetPredictable() )
  204. return;
  205. #endif
  206. Vector vObstructionMaxs = pEntity->CollisionProp()->OBBMins();
  207. Vector vObstructionMins = pEntity->CollisionProp()->OBBMaxs();
  208. Vector vNewPos = pEntity->GetAbsOrigin();
  209. QAngle vNewAngles = pEntity->GetAbsAngles();
  210. Vector vNewVel = pEntity->GetAbsVelocity();
  211. // TODO:
  212. // - get 8 corner points out of the OBB
  213. // - find max distances PointVSPlane for both sides of the plane
  214. // - use the least distance of the two maxs as distance to push off the entity in the direction of normal of the greater max
  215. Vector vEntForward, vEntRight, vEntUp;
  216. AngleVectors( pEntity->CollisionProp()->GetCollisionAngles(), &vEntForward, &vEntRight, &vEntUp );
  217. Vector ptOBBCenter = pEntity->CollisionProp()->GetCollisionOrigin() + pEntity->CollisionProp()->OBBCenter();
  218. Vector vExtents = ( vObstructionMaxs - vObstructionMins ) * 0.5f;
  219. vEntForward *= vExtents.x;
  220. vEntRight *= vExtents.y;
  221. vEntUp *= vExtents.z;
  222. Vector ptOBB[8];
  223. ptOBB[0] = ptOBBCenter - vEntForward - vEntRight - vEntUp;
  224. ptOBB[1] = ptOBBCenter - vEntForward - vEntRight + vEntUp;
  225. ptOBB[2] = ptOBBCenter - vEntForward + vEntRight + vEntUp;
  226. ptOBB[3] = ptOBBCenter - vEntForward + vEntRight - vEntUp;
  227. ptOBB[4] = ptOBBCenter + vEntForward - vEntRight - vEntUp;
  228. ptOBB[5] = ptOBBCenter + vEntForward - vEntRight + vEntUp;
  229. ptOBB[6] = ptOBBCenter + vEntForward + vEntRight + vEntUp;
  230. ptOBB[7] = ptOBBCenter + vEntForward + vEntRight - vEntUp;
  231. #if defined( GAME_DLL )
  232. if ( wall_debug.GetBool() )
  233. {
  234. NDebugOverlay::Sphere( ptOBBCenter, 5, 255, 0, 0, true, wall_debug_time.GetFloat() );
  235. for ( int i=0; i<8; ++i )
  236. {
  237. NDebugOverlay::Sphere( ptOBB[i], 2, 255, 0, 0, true, wall_debug_time.GetFloat() );
  238. }
  239. NDebugOverlay::VertArrow( GetAbsOrigin(), GetAbsOrigin() + 50.f*vWallUp, 2, 255, 0, 0, 128, true, wall_debug_time.GetFloat() );
  240. }
  241. CEG_PROTECT_MEMBER_FUNCTION( CProjectedWallEntity_DisplaceObstructingEntity );
  242. #endif
  243. VPlane plWallPlane( vWallUp, DotProduct( vWallUp, vOrigin ) );
  244. float flFrontMax = 0.f;
  245. float flBackMax = 0.f;
  246. Vector vFrontMaxPos, vBackMaxPos;
  247. for ( int i=0; i<8; ++i )
  248. {
  249. float flDistToPlane = fabsf( plWallPlane.DistTo( ptOBB[i] ) );
  250. if ( plWallPlane.GetPointSide( ptOBB[i] ) == SIDE_FRONT )
  251. {
  252. if ( flDistToPlane > flFrontMax )
  253. {
  254. flFrontMax = flDistToPlane;
  255. vFrontMaxPos = ptOBB[i];
  256. }
  257. }
  258. else
  259. {
  260. if ( flDistToPlane > flBackMax )
  261. {
  262. flBackMax = flDistToPlane;
  263. vBackMaxPos = ptOBB[i];
  264. }
  265. }
  266. }
  267. // always try to push the entity up or down along Z-axis if the wall is horizontal (walkable)
  268. // else push the entity to the side of the bridge in the direction of bridge UP vector projected onto XY-plane
  269. float flHalfWallWidth = m_flWidth / 2.f;
  270. Vector side1 = vOrigin + flHalfWallWidth * vWallRight;
  271. Vector side2 = vOrigin - flHalfWallWidth * vWallRight;
  272. Vector vBumpAxis;
  273. float flBumpAmount;
  274. float flInvBumpAmount;
  275. if ( m_bIsHorizontal )
  276. {
  277. vBumpAxis = Vector( 0, 0, 1 );
  278. // compute the bump amount
  279. float flDot = fabs( clamp( DotProduct( vWallUp, vBumpAxis ), -1.f, 1.f ) );
  280. Assert( flDot != 0.0f );
  281. flBumpAmount = MIN( flBackMax / flDot, MAX( fabs( DotProduct( side1 - vBackMaxPos, vBumpAxis ) ), fabs( DotProduct( side2 - vBackMaxPos, vBumpAxis ) ) ) );
  282. flInvBumpAmount = MIN( flFrontMax / flDot, MAX( fabs( DotProduct( side1 - vFrontMaxPos, vBumpAxis ) ), fabs( DotProduct( side2 - vFrontMaxPos, vBumpAxis ) ) ) );
  283. if ( vWallUp.z < 0.f )
  284. {
  285. V_swap( flBumpAmount, flInvBumpAmount );
  286. }
  287. }
  288. else
  289. {
  290. vBumpAxis = Vector( vWallUp.x, vWallUp.y, 0.f );
  291. VectorNormalize( vBumpAxis );
  292. // compute the bump amount
  293. float flDot = fabs( clamp( DotProduct( vWallUp, vBumpAxis ), -1.f, 1.f ) );
  294. Assert( flDot != 0.0f );
  295. flBumpAmount = MIN( flBackMax / flDot, MAX( fabs( DotProduct( side1 - vBackMaxPos, vBumpAxis ) ), fabs( DotProduct( side2 - vBackMaxPos, vBumpAxis ) ) ) );
  296. flInvBumpAmount = MIN( flFrontMax / flDot, MAX( fabs( DotProduct( side1 - vFrontMaxPos, vBumpAxis ) ), fabs( DotProduct( side2 - vFrontMaxPos, vBumpAxis ) ) ) );
  297. #if defined( GAME_DLL )
  298. if ( wall_debug.GetBool() )
  299. {
  300. // front side push
  301. NDebugOverlay::VertArrow( vFrontMaxPos - flFrontMax * vWallUp, vFrontMaxPos, 2, 255, 0, 0, 255, true, wall_debug_time.GetFloat() );
  302. NDebugOverlay::VertArrow( vFrontMaxPos, vFrontMaxPos - flInvBumpAmount * vBumpAxis, 2, 255, 0, 0, 255, true, wall_debug_time.GetFloat() );
  303. // back side push
  304. NDebugOverlay::VertArrow( vBackMaxPos + flBackMax * vWallUp, vBackMaxPos, 2, 0, 0, 255, 255, true, wall_debug_time.GetFloat() );
  305. NDebugOverlay::VertArrow( vBackMaxPos, vBackMaxPos + flBumpAmount * vBumpAxis, 2, 0, 0, 255, 255, true, wall_debug_time.GetFloat() );
  306. }
  307. #endif
  308. // push in the negative direction of the projected normal
  309. if ( flFrontMax < flBackMax )
  310. {
  311. VectorNegate( vBumpAxis );
  312. V_swap( flBumpAmount, flInvBumpAmount );
  313. }
  314. }
  315. // add epsilon
  316. flBumpAmount += 0.1f;
  317. flInvBumpAmount += 0.1f;
  318. vNewPos += flBumpAmount * vBumpAxis;
  319. #if defined( GAME_DLL )
  320. if ( wall_debug.GetBool() )
  321. {
  322. Vector vPosOffset = vNewPos - pEntity->GetAbsOrigin();
  323. NDebugOverlay::Sphere( ptOBBCenter + vPosOffset, 5, 0, 0, 255, true, wall_debug_time.GetFloat() );
  324. for ( int i=0; i<8; ++i )
  325. {
  326. NDebugOverlay::Sphere( ptOBB[i] + vPosOffset, 2, 0, 0, 255, true, wall_debug_time.GetFloat() );
  327. }
  328. NDebugOverlay::BoxAngles( pEntity->GetAbsOrigin() , vObstructionMins, vObstructionMaxs, pEntity->CollisionProp()->GetCollisionAngles(), 0, 255, 255, 64, wall_debug_time.GetFloat() );
  329. NDebugOverlay::BoxAngles( vNewPos , vObstructionMins, vObstructionMaxs, pEntity->CollisionProp()->GetCollisionAngles(), 255, 255, 0, 64, wall_debug_time.GetFloat() );
  330. }
  331. #endif
  332. // check if the entity gets stuck at the new pos
  333. CTraceFilterSimple filter( pEntity, COLLISION_GROUP_NONE );
  334. trace_t stuckTrace;
  335. enginetrace->SweepCollideable( pEntity->GetCollideable(), vNewPos, vNewPos, vNewAngles, MASK_SOLID, &filter, &stuckTrace );
  336. // If safe, teleport. Otherwise, we're better off being stuck by the wall.
  337. if ( !stuckTrace.startsolid || bIgnoreStuck )
  338. {
  339. //EASY_DIFFPRINT( this, "CProjectedWallEntity::DisplaceObstructingEntities() teleport up" );
  340. // TODO: Some smoothing of the player's view or effect when this happens?
  341. pEntity->Teleport( &vNewPos, &vNewAngles, &vNewVel );
  342. return;
  343. }
  344. // the entity got stuck with horizontal bridge
  345. else if ( pEntity->IsPlayer() && m_bIsHorizontal )
  346. {
  347. // if success, move on
  348. CPortal_Player* pPlayer = ToPortalPlayer( pEntity );
  349. Assert ( pPlayer );
  350. if ( !pPlayer )
  351. return;
  352. // 1. If player wasn't crouching already, try to crouch and move player up
  353. if ( !pPlayer->m_Local.m_bDucked )
  354. {
  355. // If ducking stops the intersection, force them to duck
  356. TracePlayerBoxAgainstCollidables( stuckTrace, pPlayer, vNewPos, vNewPos, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
  357. if ( !stuckTrace.startsolid )
  358. {
  359. //EASY_DIFFPRINT( this, "CProjectedWallEntity::DisplaceObstructingEntities() force duck up" );
  360. pPlayer->ForceDuckThisFrame();
  361. pPlayer->Teleport( &vNewPos, &vNewAngles, &vNewVel );
  362. #if defined( GAME_DLL )
  363. if ( wall_debug.GetBool() )
  364. {
  365. NDebugOverlay::BoxAngles( vNewPos , VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pEntity->CollisionProp()->GetCollisionAngles(), 255, 0, 0, 64, wall_debug_time.GetFloat() );
  366. }
  367. #endif
  368. return;
  369. }
  370. }
  371. // 2. If pushing up failed, try to move the player to the opposite side
  372. vNewPos = pEntity->GetAbsOrigin() - flInvBumpAmount * vBumpAxis;
  373. if ( !pPlayer->m_Local.m_bDucked )
  374. {
  375. TracePlayerBoxAgainstCollidables( stuckTrace, pPlayer, vNewPos, vNewPos, VEC_HULL_MIN, VEC_HULL_MAX );
  376. if ( !stuckTrace.startsolid )
  377. {
  378. //EASY_DIFFPRINT( this, "CProjectedWallEntity::DisplaceObstructingEntities() teleport down" );
  379. pPlayer->Teleport( &vNewPos, &vNewAngles, &vNewVel );
  380. #if defined( GAME_DLL )
  381. if ( wall_debug.GetBool() )
  382. {
  383. NDebugOverlay::BoxAngles( vNewPos , VEC_HULL_MIN, VEC_HULL_MAX, pEntity->CollisionProp()->GetCollisionAngles(), 255, 0, 0, 64, wall_debug_time.GetFloat() );
  384. }
  385. #endif
  386. return;
  387. }
  388. // check duck
  389. vNewPos += 36.f * Vector( 0, 0, 1 );
  390. TracePlayerBoxAgainstCollidables( stuckTrace, pPlayer, vNewPos, vNewPos, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
  391. if ( !stuckTrace.startsolid )
  392. {
  393. //EASY_DIFFPRINT( this, "CProjectedWallEntity::DisplaceObstructingEntities() force duck down" );
  394. pPlayer->ForceDuckThisFrame();
  395. pPlayer->Teleport( &vNewPos, &vNewAngles, &vNewVel );
  396. #if defined( GAME_DLL )
  397. if ( wall_debug.GetBool() )
  398. {
  399. NDebugOverlay::BoxAngles( vNewPos , VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pEntity->CollisionProp()->GetCollisionAngles(), 255, 0, 0, 64, wall_debug_time.GetFloat() );
  400. }
  401. #endif
  402. return;
  403. }
  404. }
  405. else
  406. {
  407. TracePlayerBoxAgainstCollidables( stuckTrace, pPlayer, vNewPos, vNewPos, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
  408. if ( !stuckTrace.startsolid )
  409. {
  410. //EASY_DIFFPRINT( this, "CProjectedWallEntity::DisplaceObstructingEntities() double duck down" );
  411. pPlayer->ForceDuckThisFrame();
  412. pPlayer->Teleport( &vNewPos, &vNewAngles, &vNewVel );
  413. #if defined( GAME_DLL )
  414. if ( wall_debug.GetBool() )
  415. {
  416. NDebugOverlay::BoxAngles( vNewPos , VEC_HULL_MIN, VEC_HULL_MAX, pEntity->CollisionProp()->GetCollisionAngles(), 255, 0, 0, 64, wall_debug_time.GetFloat() );
  417. }
  418. #endif
  419. return;
  420. }
  421. }
  422. }
  423. // player stuck in not-horizontal bridge OR entity is stuck in a bridge
  424. else
  425. {
  426. vNewPos = pEntity->GetAbsOrigin() - flInvBumpAmount * vBumpAxis;
  427. UTIL_ClearTrace( stuckTrace );
  428. enginetrace->SweepCollideable( pEntity->GetCollideable(), vNewPos, vNewPos, vNewAngles, MASK_SOLID, &filter, &stuckTrace );
  429. if ( !stuckTrace.startsolid || bIgnoreStuck )
  430. {
  431. pEntity->Teleport( &vNewPos, &vNewAngles, &vNewVel );
  432. #if defined( GAME_DLL )
  433. if ( wall_debug.GetBool() )
  434. {
  435. NDebugOverlay::BoxAngles( vNewPos , vObstructionMins, vObstructionMaxs, pEntity->CollisionProp()->GetCollisionAngles(), 255, 0, 0, 64, wall_debug_time.GetFloat() );
  436. }
  437. STEAMWORKS_SELFCHECK();
  438. #endif
  439. return;
  440. }
  441. #if defined( GAME_DLL )
  442. if ( wall_debug.GetBool() )
  443. {
  444. NDebugOverlay::BoxAngles( vNewPos , vObstructionMins, vObstructionMaxs, pEntity->CollisionProp()->GetCollisionAngles(), 255, 0, 0, 64, wall_debug_time.GetFloat() );
  445. }
  446. #endif
  447. }
  448. // The entity is stuck at super rare case if we get here.
  449. {
  450. AssertMsg( 0, "Rare case for the entity getting stuck with projected bridge. Investigate at CProjectedWallEntity::DisplaceObstructingEntities()." );
  451. }
  452. }
  453. void CProjectedWallEntity::GetExtents( Vector &outMins, Vector &outMaxs, float flWidthScale )
  454. {
  455. // Get current orientation
  456. Vector vecForward, vecRight, vecUp;
  457. #if defined( GAME_DLL )
  458. QAngle qAngles = GetLocalAngles();
  459. #else
  460. QAngle qAngles = GetNetworkAngles();
  461. #endif
  462. AngleVectors( qAngles, &vecForward, &vecRight, &vecUp );
  463. #if defined( GAME_DLL ) && !defined( _PS3 )
  464. // we're assuming it's oblong, and that height is the larger
  465. COMPILE_TIME_ASSERT( WALL_PROJECTOR_THICKNESS > WALL_PROJECTOR_HEIGHT );
  466. #endif
  467. // Set up mins/maxes to trace along
  468. float flHalfHeight = m_flHeight / 2.f;
  469. float flHalfWidth = ( m_flWidth * flWidthScale ) / 2.f;
  470. Vector vTmpExtent1 = ( -vecForward * FLT_EPSILON ) - ( vecUp * flHalfHeight ) - ( vecRight * flHalfWidth );
  471. Vector vTmpExtent2 = ( vecForward * FLT_EPSILON ) + ( vecUp * flHalfHeight ) + ( vecRight * flHalfWidth );
  472. // align the mins and maxs
  473. Vector vWallSweptBoxMins, vWallSweptBoxMaxs;
  474. VectorMin( vTmpExtent1, vTmpExtent2, vWallSweptBoxMins );
  475. VectorMax( vTmpExtent1, vTmpExtent2, vWallSweptBoxMaxs );
  476. outMins = vWallSweptBoxMins;
  477. outMaxs = vWallSweptBoxMaxs;
  478. }