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.

158 lines
4.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: static_prop - don't move, don't animate, don't do anything.
  4. // physics_prop - move, take damage, but don't animate
  5. //
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "tf_gamerules.h"
  9. #include "tf_props.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. ConVar tf_soccer_ball_up_max( "tf_soccer_ball_up_max", "350", FCVAR_CHEAT );
  13. ConVar tf_soccer_ball_multiplier( "tf_soccer_ball_multiplier", "4", FCVAR_CHEAT );
  14. ConVar tf_soccer_ball_min_speed( "tf_soccer_ball_min_speed", "30", FCVAR_CHEAT );
  15. // Ranges from ~ .3 (side swipe) to 1 (full head on hit). When it's >= this value,
  16. // treat the hit as a full frontal 1.0 collision.
  17. ConVar tf_soccer_front_hit_range( "tf_soccer_front_hit_range", ".95", FCVAR_CHEAT );
  18. extern ConVar tf_halloween_kart_dash_speed;
  19. extern ConVar tf_halloween_kart_normal_speed;
  20. LINK_ENTITY_TO_CLASS( prop_soccer_ball, CPropSoccerBall );
  21. BEGIN_DATADESC( CPropSoccerBall )
  22. DEFINE_KEYFIELD( m_iszTriggers, FIELD_STRING, "trigger_name" ),
  23. END_DATADESC()
  24. void CPropSoccerBall::Precache()
  25. {
  26. PrecacheScriptSound( "BumperCar.HitBall" );
  27. }
  28. void CPropSoccerBall::Spawn()
  29. {
  30. BaseClass::Spawn();
  31. SetSolid( SOLID_VPHYSICS ); // Use our vphys model for collision
  32. SetSolidFlags( FSOLID_TRIGGER ); // Generate Touch functions, but dont collide
  33. SetCollisionGroup( TFCOLLISION_GROUP_ROCKETS ); // Need this one too so players dont get stopped
  34. SetTouch( &CPropSoccerBall::BallTouch );
  35. SetContextThink( &CPropSoccerBall::TriggerTouchThink, gpGlobals->curtime + 0.2f, "TriggerTouchThink" );
  36. }
  37. // Here's the deal. The ball is a trigger, but triggers are not allowed to touch other triggers. To get around this,
  38. // we're going to specify the names of the triggers we actually want to touch and then we're going to manually try to
  39. // touch them. Our collision system is a vortex of insanity.
  40. void CPropSoccerBall::TriggerTouchThink()
  41. {
  42. FOR_EACH_VEC( m_vecTriggers, i )
  43. {
  44. if ( m_vecTriggers[i]->PointIsWithin( GetAbsOrigin() ) )
  45. {
  46. m_vecTriggers[i]->StartTouch( this );
  47. m_vecTriggers[i]->EndTouch( this );
  48. }
  49. }
  50. SetContextThink( &CPropSoccerBall::TriggerTouchThink, gpGlobals->curtime + 0.2f, "TriggerTouchThink" );
  51. }
  52. void CPropSoccerBall::Activate()
  53. {
  54. CBaseTrigger* pTrigger = NULL;
  55. do
  56. {
  57. pTrigger = dynamic_cast<CBaseTrigger *> ( gEntList.FindEntityByName( pTrigger, m_iszTriggers.ToCStr() ) );
  58. if ( pTrigger )
  59. {
  60. m_vecTriggers.AddToTail( pTrigger );
  61. }
  62. } while ( pTrigger );
  63. BaseClass::Activate();
  64. }
  65. bool CPropSoccerBall::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
  66. {
  67. TestHitboxes( ray, 0xFFFFFFFF, trace );
  68. if ( trace.DidHit() )
  69. {
  70. IPhysicsObject *pObj = VPhysicsGetObject();
  71. if ( pObj )
  72. pObj->Wake();
  73. }
  74. return false;
  75. }
  76. void CPropSoccerBall::BallTouch( CBaseEntity *pOther )
  77. {
  78. if ( gpGlobals->curtime < m_flNextAllowedImpactTime )
  79. return;
  80. CTFPlayer *pTFPlayer = ToTFPlayer( pOther );
  81. if ( pTFPlayer )
  82. {
  83. const float flSoccerBallMultiplier = tf_soccer_ball_multiplier.GetFloat();
  84. // Get player direction and speed.
  85. Vector vPlayer( pOther->GetAbsVelocity().x, pOther->GetAbsVelocity().y, 0.0f );
  86. float flSpeed = vPlayer.Length2D();
  87. vPlayer.NormalizeInPlace();
  88. // Linearly scale up based on kart speed.
  89. float fUp = tf_soccer_ball_up_max.GetFloat();
  90. float fUpScale = flSpeed / tf_halloween_kart_dash_speed.GetFloat();
  91. fUp = Clamp( fUp * fUpScale, 5.0f, fUp ) * flSoccerBallMultiplier;
  92. // Get vector to ball from player.
  93. Vector vToBall = GetAbsOrigin() - pOther->GetAbsOrigin();
  94. vToBall.z = 0.0f;
  95. vToBall.NormalizeInPlace();
  96. // cosTheta ranges from about .3 (side swipe) to 1 (full head on hit).
  97. float cosTheta = Max( 0.1f, vToBall.Dot( vPlayer ) );
  98. // Scale speed based on incident angle and soccer ball multiplier hack.
  99. flSpeed = Max( flSpeed * cosTheta, tf_soccer_ball_min_speed.GetFloat() );
  100. flSpeed *= flSoccerBallMultiplier;
  101. Vector vecVelocity;
  102. if ( cosTheta >= tf_soccer_front_hit_range.GetFloat() )
  103. {
  104. // Front hit - snag player velocity and direction and use that.
  105. //DevMsg( "%s cosTheta: %.2f front hit\n", __FUNCTION__, cosTheta );
  106. vecVelocity = vPlayer;
  107. }
  108. else
  109. {
  110. // Side swipe. Scale vector by player speed and hit angle.
  111. //DevMsg( "%s cosTheta: %.2f side hit\n", __FUNCTION__, cosTheta );
  112. vecVelocity = vToBall;
  113. }
  114. vecVelocity *= flSpeed;
  115. vecVelocity.z = fUp;
  116. IPhysicsObject *pObj = VPhysicsGetObject();
  117. pObj->Wake();
  118. pObj->AddVelocity( &vecVelocity, NULL );
  119. m_flNextAllowedImpactTime = gpGlobals->curtime + 0.1f;
  120. EmitSound( "BumperCar.HitBall" );
  121. ChangeTeam( pTFPlayer->GetTeamNumber() );
  122. m_hLastToucher = pTFPlayer;
  123. }
  124. }