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.

393 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "env_headcrabcanister_shared.h"
  9. #include "mapdata_shared.h"
  10. #include "sharedInterface.h"
  11. #include "mathlib/vmatrix.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. #define ROTATION_SPEED 90.0f
  15. BEGIN_SIMPLE_DATADESC( CEnvHeadcrabCanisterShared )
  16. DEFINE_FIELD( m_vecStartPosition, FIELD_POSITION_VECTOR ),
  17. DEFINE_FIELD( m_vecEnterWorldPosition, FIELD_POSITION_VECTOR ),
  18. DEFINE_FIELD( m_vecDirection, FIELD_VECTOR ),
  19. DEFINE_FIELD( m_vecStartAngles, FIELD_VECTOR ),
  20. DEFINE_KEYFIELD( m_flLaunchHeight, FIELD_FLOAT, "StartingHeight" ),
  21. DEFINE_KEYFIELD( m_flFlightSpeed, FIELD_FLOAT, "FlightSpeed" ),
  22. DEFINE_KEYFIELD( m_flFlightTime, FIELD_FLOAT, "FlightTime" ),
  23. DEFINE_FIELD( m_flLaunchTime, FIELD_TIME ),
  24. DEFINE_FIELD( m_flWorldEnterTime, FIELD_FLOAT ),
  25. DEFINE_FIELD( m_flInitialZSpeed, FIELD_FLOAT ),
  26. DEFINE_FIELD( m_flZAcceleration, FIELD_FLOAT ),
  27. DEFINE_FIELD( m_flHorizSpeed, FIELD_FLOAT ),
  28. DEFINE_FIELD( m_bLaunchedFromWithinWorld, FIELD_BOOLEAN ),
  29. DEFINE_FIELD( m_vecSkyboxOrigin, FIELD_VECTOR ),
  30. DEFINE_FIELD( m_vecParabolaDirection, FIELD_VECTOR ),
  31. DEFINE_FIELD( m_flSkyboxScale, FIELD_FLOAT ),
  32. DEFINE_FIELD( m_bInSkybox, FIELD_BOOLEAN ),
  33. END_DATADESC()
  34. BEGIN_NETWORK_TABLE_NOBASE( CEnvHeadcrabCanisterShared, DT_EnvHeadcrabCanisterShared )
  35. #if !defined( CLIENT_DLL )
  36. SendPropFloat ( SENDINFO( m_flFlightSpeed ), 0, SPROP_NOSCALE ),
  37. SendPropTime ( SENDINFO( m_flLaunchTime ) ),
  38. SendPropVector ( SENDINFO( m_vecParabolaDirection ), 0, SPROP_NOSCALE ),
  39. SendPropFloat ( SENDINFO( m_flFlightTime ), 0, SPROP_NOSCALE ),
  40. SendPropFloat ( SENDINFO( m_flWorldEnterTime ), 0, SPROP_NOSCALE ),
  41. SendPropFloat ( SENDINFO( m_flInitialZSpeed ), 0, SPROP_NOSCALE ),
  42. SendPropFloat ( SENDINFO( m_flZAcceleration ), 0, SPROP_NOSCALE ),
  43. SendPropFloat ( SENDINFO( m_flHorizSpeed ), 0, SPROP_NOSCALE ),
  44. SendPropBool ( SENDINFO( m_bLaunchedFromWithinWorld ) ),
  45. SendPropVector ( SENDINFO( m_vecStartPosition ), 0, SPROP_NOSCALE ),
  46. SendPropVector ( SENDINFO( m_vecEnterWorldPosition ), 0, SPROP_NOSCALE ),
  47. SendPropVector ( SENDINFO( m_vecDirection ), 0, SPROP_NOSCALE ),
  48. SendPropVector ( SENDINFO( m_vecStartAngles ), 0, SPROP_NOSCALE ),
  49. SendPropVector ( SENDINFO( m_vecSkyboxOrigin ), 0, SPROP_NOSCALE ),
  50. SendPropFloat ( SENDINFO( m_flSkyboxScale ), 0, SPROP_NOSCALE ),
  51. SendPropBool ( SENDINFO( m_bInSkybox ) ),
  52. #else
  53. RecvPropFloat ( RECVINFO( m_flFlightSpeed ) ),
  54. RecvPropTime ( RECVINFO( m_flLaunchTime ) ),
  55. RecvPropVector ( RECVINFO( m_vecParabolaDirection ) ),
  56. RecvPropFloat ( RECVINFO( m_flFlightTime ) ),
  57. RecvPropFloat ( RECVINFO( m_flWorldEnterTime ) ),
  58. RecvPropFloat ( RECVINFO( m_flInitialZSpeed ) ),
  59. RecvPropFloat ( RECVINFO( m_flZAcceleration ) ),
  60. RecvPropFloat ( RECVINFO( m_flHorizSpeed ) ),
  61. RecvPropBool ( RECVINFO( m_bLaunchedFromWithinWorld ) ),
  62. RecvPropVector ( RECVINFO( m_vecStartPosition ) ),
  63. RecvPropVector ( RECVINFO( m_vecEnterWorldPosition ) ),
  64. RecvPropVector ( RECVINFO( m_vecDirection ) ),
  65. RecvPropVector ( RECVINFO( m_vecStartAngles ) ),
  66. RecvPropVector ( RECVINFO( m_vecSkyboxOrigin ) ),
  67. RecvPropFloat ( RECVINFO( m_flSkyboxScale ) ),
  68. RecvPropBool ( RECVINFO( m_bInSkybox ) ),
  69. #endif
  70. END_NETWORK_TABLE()
  71. //=============================================================================
  72. //
  73. // HeadcrabCanister Functions.
  74. //
  75. //-----------------------------------------------------------------------------
  76. // Constructor
  77. //-----------------------------------------------------------------------------
  78. CEnvHeadcrabCanisterShared::CEnvHeadcrabCanisterShared()
  79. {
  80. m_vecStartPosition.Init();
  81. m_vecDirection.Init();
  82. m_flFlightSpeed = 0.0f;
  83. // This tells the client DLL to not draw trails, etc.
  84. m_flLaunchTime = -1.0f;
  85. m_flWorldEnterTime = 0.0f;
  86. m_flFlightTime = 0.0f;
  87. m_bInSkybox = false;
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Creates a headcrab canister in the world
  91. //-----------------------------------------------------------------------------
  92. void CEnvHeadcrabCanisterShared::InitInWorld( float flLaunchTime,
  93. const Vector &vecStartPosition, const QAngle &vecStartAngles,
  94. const Vector &vecDirection, const Vector &vecImpactPosition, bool bLaunchedFromWithinWorld )
  95. {
  96. Vector vecActualStartPosition = vecStartPosition;
  97. if ( !bLaunchedFromWithinWorld )
  98. {
  99. // Move the start position inward if it's too close
  100. Vector vecDelta;
  101. VectorSubtract( vecStartPosition, vecImpactPosition, vecDelta );
  102. VectorNormalize( vecDelta );
  103. VectorMA( vecImpactPosition, m_flFlightTime * m_flFlightSpeed, vecDelta, vecActualStartPosition );
  104. }
  105. // Setup initial parametric state.
  106. m_flLaunchTime = flLaunchTime;
  107. m_vecStartPosition = vecActualStartPosition;
  108. m_vecEnterWorldPosition = vecActualStartPosition;
  109. m_vecDirection = vecDirection;
  110. m_vecStartAngles = vecStartAngles;
  111. m_flWorldEnterTime = 0.0f;
  112. m_bInSkybox = false;
  113. m_bLaunchedFromWithinWorld = bLaunchedFromWithinWorld;
  114. if ( m_bLaunchedFromWithinWorld )
  115. {
  116. m_flSkyboxScale = 1;
  117. m_vecSkyboxOrigin = vec3_origin;
  118. float flLength = m_vecDirection.Get().AsVector2D().Length();
  119. VectorSubtract(vecImpactPosition, vecStartPosition, m_vecParabolaDirection.GetForModify());
  120. m_vecParabolaDirection.GetForModify().z = 0;
  121. float flTotalDistance = VectorNormalize( m_vecParabolaDirection.GetForModify() );
  122. m_vecDirection.GetForModify().x = flLength * m_vecParabolaDirection.Get().x;
  123. m_vecDirection.GetForModify().y = flLength * m_vecParabolaDirection.Get().y;
  124. m_flHorizSpeed = flTotalDistance / m_flFlightTime;
  125. m_flWorldEnterTime = 0;
  126. float flFinalZSpeed = m_vecDirection.Get().z * m_flHorizSpeed;
  127. m_flFlightSpeed = sqrt( m_flHorizSpeed * m_flHorizSpeed + flFinalZSpeed * flFinalZSpeed );
  128. m_flInitialZSpeed = (2.0f * ( vecImpactPosition.z - vecStartPosition.z ) - flFinalZSpeed * m_flFlightTime) / m_flFlightTime;
  129. m_flZAcceleration = (flFinalZSpeed - m_flInitialZSpeed) / m_flFlightTime;
  130. }
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Creates a headcrab canister in the skybox
  134. //-----------------------------------------------------------------------------
  135. void CEnvHeadcrabCanisterShared::InitInSkybox( float flLaunchTime,
  136. const Vector &vecStartPosition, const QAngle &vecStartAngles, const Vector &vecDirection,
  137. const Vector &vecImpactPosition, const Vector &vecSkyboxOrigin, float flSkyboxScale )
  138. {
  139. // Compute a horizontal speed (constant)
  140. m_vecParabolaDirection.Init( vecDirection.x, vecDirection.y, 0.0f );
  141. float flLength = VectorNormalize( m_vecParabolaDirection.GetForModify() );
  142. m_flHorizSpeed = flLength * m_flFlightSpeed;
  143. // compute total distance to travel
  144. float flTotalDistance = m_flFlightTime * m_flHorizSpeed;
  145. flTotalDistance -= vecStartPosition.AsVector2D().DistTo( vecImpactPosition.AsVector2D() );
  146. if ( flTotalDistance <= 0.0f )
  147. {
  148. InitInWorld( flLaunchTime, vecStartPosition, vecStartAngles, vecDirection, vecImpactPosition );
  149. return;
  150. }
  151. // Setup initial parametric state.
  152. m_flLaunchTime = flLaunchTime;
  153. m_flWorldEnterTime = flTotalDistance / m_flHorizSpeed;
  154. m_vecSkyboxOrigin = vecSkyboxOrigin;
  155. m_flSkyboxScale = flSkyboxScale;
  156. m_vecEnterWorldPosition = vecStartPosition;
  157. m_vecDirection = vecDirection;
  158. m_vecStartAngles = vecStartAngles;
  159. m_bInSkybox = true;
  160. m_bLaunchedFromWithinWorld = false;
  161. // Compute parabolic course
  162. // Assume the x velocity remains constant.
  163. // Z moves ballistically, as if under gravity
  164. // zf + lh = zo
  165. // vf = vo + a*t
  166. // zf = zo + vo*t + 0.5 * a * t*t
  167. // a*t = vf - vo
  168. // zf = zo + vo*t + 0.5f * (vf - vo) * t
  169. // zf - zo = 0.5f *vo*t + 0.5f * vf * t
  170. // -lh - 0.5f * vf * t = 0.5f * vo * t
  171. // vo = -2.0f * lh / t - vf
  172. // a = (vf - vo) / t
  173. m_flHorizSpeed /= flSkyboxScale;
  174. VectorMA( vecSkyboxOrigin, 1.0f / m_flSkyboxScale, vecStartPosition, m_vecStartPosition.GetForModify() );
  175. VectorMA( m_vecStartPosition.Get(), -m_flHorizSpeed * m_flWorldEnterTime, m_vecParabolaDirection, m_vecStartPosition.GetForModify() );
  176. float flLaunchHeight = m_flLaunchHeight / flSkyboxScale;
  177. float flFinalZSpeed = m_vecDirection.Get().z * m_flFlightSpeed / flSkyboxScale;
  178. m_vecStartPosition.GetForModify().z += flLaunchHeight;
  179. m_flZAcceleration = 2.0f * ( flLaunchHeight + flFinalZSpeed * m_flWorldEnterTime ) / ( m_flWorldEnterTime * m_flWorldEnterTime );
  180. m_flInitialZSpeed = flFinalZSpeed - m_flZAcceleration * m_flWorldEnterTime;
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Convert from skybox to world
  184. //-----------------------------------------------------------------------------
  185. void CEnvHeadcrabCanisterShared::ConvertFromSkyboxToWorld()
  186. {
  187. Assert( m_bInSkybox );
  188. m_bInSkybox = false;
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Returns the time at which it enters the world
  192. //-----------------------------------------------------------------------------
  193. float CEnvHeadcrabCanisterShared::GetEnterWorldTime() const
  194. {
  195. return m_flWorldEnterTime;
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Did we impact?
  199. //-----------------------------------------------------------------------------
  200. bool CEnvHeadcrabCanisterShared::DidImpact( float flTime ) const
  201. {
  202. return (flTime - m_flLaunchTime) >= m_flFlightTime;
  203. }
  204. //-----------------------------------------------------------------------------
  205. // Computes the position of the canister
  206. //-----------------------------------------------------------------------------
  207. void CEnvHeadcrabCanisterShared::GetPositionAtTime( float flTime, Vector &vecPosition, QAngle &vecAngles )
  208. {
  209. float flDeltaTime = flTime - m_flLaunchTime;
  210. if ( flDeltaTime > m_flFlightTime )
  211. {
  212. flDeltaTime = m_flFlightTime;
  213. }
  214. VMatrix initToWorld;
  215. if ( m_bLaunchedFromWithinWorld || m_bInSkybox )
  216. {
  217. VectorMA( m_vecStartPosition, flDeltaTime * m_flHorizSpeed, m_vecParabolaDirection, vecPosition );
  218. vecPosition.z += m_flInitialZSpeed * flDeltaTime + 0.5f * m_flZAcceleration * flDeltaTime * flDeltaTime;
  219. Vector vecLeft;
  220. CrossProduct( m_vecParabolaDirection, Vector( 0, 0, 1 ), vecLeft );
  221. Vector vecForward;
  222. VectorMultiply( m_vecParabolaDirection, -1.0f, vecForward );
  223. vecForward.z = -(m_flInitialZSpeed + m_flZAcceleration * flDeltaTime) / m_flHorizSpeed; // This is -dz/dx.
  224. VectorNormalize( vecForward );
  225. Vector vecUp;
  226. CrossProduct( vecForward, vecLeft, vecUp );
  227. initToWorld.SetBasisVectors( vecForward, vecLeft, vecUp );
  228. }
  229. else
  230. {
  231. flDeltaTime -= m_flWorldEnterTime;
  232. Vector vecVelocity;
  233. VectorMultiply( m_vecDirection, m_flFlightSpeed, vecVelocity );
  234. VectorMA( m_vecEnterWorldPosition, flDeltaTime, vecVelocity, vecPosition );
  235. MatrixFromAngles( m_vecStartAngles.Get(), initToWorld );
  236. }
  237. VMatrix rotation;
  238. MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), flDeltaTime * ROTATION_SPEED );
  239. VMatrix newAngles;
  240. MatrixMultiply( initToWorld, rotation, newAngles );
  241. MatrixToAngles( newAngles, vecAngles );
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Are we in the skybox?
  245. //-----------------------------------------------------------------------------
  246. bool CEnvHeadcrabCanisterShared::IsInSkybox( )
  247. {
  248. // Check to see if we are always in the world!
  249. return m_bInSkybox;
  250. }
  251. //-----------------------------------------------------------------------------
  252. //-----------------------------------------------------------------------------
  253. void CEnvHeadcrabCanisterShared::CalcEnterTime( const Vector &vecTriggerMins,
  254. const Vector &vecTriggerMaxs )
  255. {
  256. /*
  257. #define HEADCRABCANISTER_TRIGGER_EPSILON 0.001f
  258. // Initialize the enter/exit fractions.
  259. float flEnterFrac = 0.0f;
  260. float flExitFrac = 1.0f;
  261. // Create an arbitrarily large end position.
  262. Vector vecEndPosition;
  263. VectorMA( m_vecStartPosition, 32000.0f, m_vecDirection, vecEndPosition );
  264. float flFrac, flDistStart, flDistEnd;
  265. for( int iAxis = 0; iAxis < 3; iAxis++ )
  266. {
  267. // Negative Axis
  268. flDistStart = -m_vecStartPosition[iAxis] + vecTriggerMins[iAxis];
  269. flDistEnd = -vecEndPosition[iAxis] + vecTriggerMins[iAxis];
  270. if ( ( flDistStart > 0.0f ) && ( flDistEnd < 0.0f ) )
  271. {
  272. flFrac = ( flDistStart - HEADCRABCANISTER_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
  273. if ( flFrac > flEnterFrac ) { flEnterFrac = flFrac; }
  274. }
  275. if ( ( flDistStart < 0.0f ) && ( flDistEnd > 0.0f ) )
  276. {
  277. flFrac = ( flDistStart + HEADCRABCANISTER_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
  278. if( flFrac < flExitFrac ) { flExitFrac = flFrac; }
  279. }
  280. if ( ( flDistStart > 0.0f ) && ( flDistEnd > 0.0f ) )
  281. return;
  282. // Positive Axis
  283. flDistStart = m_vecStartPosition[iAxis] - vecTriggerMaxs[iAxis];
  284. flDistEnd = vecEndPosition[iAxis] - vecTriggerMaxs[iAxis];
  285. if ( ( flDistStart > 0.0f ) && ( flDistEnd < 0.0f ) )
  286. {
  287. flFrac = ( flDistStart - HEADCRABCANISTER_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
  288. if ( flFrac > flEnterFrac ) { flEnterFrac = flFrac; }
  289. }
  290. if ( ( flDistStart < 0.0f ) && ( flDistEnd > 0.0f ) )
  291. {
  292. flFrac = ( flDistStart + HEADCRABCANISTER_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
  293. if( flFrac < flExitFrac ) { flExitFrac = flFrac; }
  294. }
  295. if ( ( flDistStart > 0.0f ) && ( flDistEnd > 0.0f ) )
  296. return;
  297. }
  298. // Check for intersection.
  299. if ( flExitFrac >= flEnterFrac )
  300. {
  301. // Check to see if we start in the world or the skybox!
  302. if ( flEnterFrac == 0.0f )
  303. {
  304. m_nLocation = HEADCRABCANISTER_LOCATION_WORLD;
  305. }
  306. else
  307. {
  308. m_nLocation = HEADCRABCANISTER_LOCATION_SKYBOX;
  309. }
  310. // Calculate the enter/exit times.
  311. Vector vecEnterPoint, vecExitPoint, vecDeltaPosition;
  312. VectorSubtract( vecEndPosition, m_vecStartPosition, vecDeltaPosition );
  313. VectorScale( vecDeltaPosition, flEnterFrac, vecEnterPoint );
  314. VectorScale( vecDeltaPosition, flExitFrac, vecExitPoint );
  315. m_flWorldEnterTime = vecEnterPoint.Length() / m_flFlightSpeed;
  316. m_flWorldEnterTime += m_flLaunchTime;
  317. }
  318. */
  319. #undef HEADCRABCANISTER_TRIGGER_EPSILON
  320. }