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.

399 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "env_meteor_shared.h"
  9. #include "mapdata_shared.h"
  10. #include "sharedInterface.h"
  11. //=============================================================================
  12. //
  13. // Meteor Functions.
  14. //
  15. //-----------------------------------------------------------------------------
  16. //-----------------------------------------------------------------------------
  17. CEnvMeteorShared::CEnvMeteorShared()
  18. {
  19. m_nID = 0;
  20. m_vecStartPosition.Init();
  21. m_vecDirection.Init();
  22. m_flSpeed = 0.0f;
  23. m_flDamageRadius = 0.0f;
  24. m_flStartTime = METEOR_INVALID_TIME;
  25. m_flPassiveTime = METEOR_INVALID_TIME;
  26. m_flWorldEnterTime = METEOR_INVALID_TIME;
  27. m_flWorldExitTime = METEOR_INVALID_TIME;
  28. m_nLocation = METEOR_LOCATION_INVALID;
  29. }
  30. //-----------------------------------------------------------------------------
  31. //-----------------------------------------------------------------------------
  32. void CEnvMeteorShared::Init( int nID, float flStartTime, float flPassiveTime,
  33. const Vector &vecStartPosition,
  34. const Vector &vecDirection, float flSpeed, float flDamageRadius,
  35. const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
  36. {
  37. // Setup initial parametric state.
  38. m_nID = nID;
  39. VectorCopy( vecStartPosition, m_vecStartPosition );
  40. VectorCopy( vecStartPosition, m_vecPos );
  41. VectorCopy( vecDirection, m_vecDirection );
  42. m_flSpeed = flSpeed;
  43. m_flDamageRadius = flDamageRadius;
  44. m_flStartTime = flPassiveTime + flStartTime;
  45. m_flPassiveTime = flPassiveTime;
  46. m_flPosTime = m_flStartTime;
  47. // Calculate the enter/exit times.
  48. CalcEnterAndExitTimes( vecTriggerMins, vecTriggerMaxs );
  49. }
  50. //-----------------------------------------------------------------------------
  51. //-----------------------------------------------------------------------------
  52. void CEnvMeteorShared::GetPositionAtTime( float flTime, Vector &vecPosition )
  53. {
  54. float flDeltaTime = flTime - m_flPosTime;
  55. Vector vecVelocity( m_vecDirection.x * m_flSpeed, m_vecDirection.y * m_flSpeed, m_vecDirection.z * m_flSpeed );
  56. VectorMA( m_vecPos, flDeltaTime, vecVelocity, vecPosition );
  57. }
  58. //-----------------------------------------------------------------------------
  59. //-----------------------------------------------------------------------------
  60. void CEnvMeteorShared::ConvertFromSkyboxToWorld( void )
  61. {
  62. // The new start position is the position at which the meteor enters
  63. // the skybox.
  64. Vector vecSkyboxOrigin;
  65. g_pMapData->Get3DSkyboxOrigin( vecSkyboxOrigin );
  66. float flSkyboxScale = g_pMapData->Get3DSkyboxScale();
  67. m_vecPos += ( m_flSpeed * m_vecDirection ) * ( m_flWorldEnterTime - m_flStartTime );
  68. m_vecPos -= vecSkyboxOrigin;
  69. m_vecPos *= flSkyboxScale;
  70. // Scale the speed.
  71. m_flSpeed *= flSkyboxScale;
  72. // Reset the start time.
  73. m_flPosTime = m_flWorldEnterTime;
  74. // Set the location to world.
  75. m_nLocation = METEOR_LOCATION_WORLD;
  76. }
  77. //-----------------------------------------------------------------------------
  78. //-----------------------------------------------------------------------------
  79. void CEnvMeteorShared::ConvertFromWorldToSkybox( void )
  80. {
  81. // Scale the speed.
  82. float flSkyboxScale = g_pMapData->Get3DSkyboxScale();
  83. m_flSpeed /= flSkyboxScale;
  84. float flDeltaTime = m_flWorldExitTime - m_flStartTime;
  85. Vector vecVelocity( m_vecDirection.x * m_flSpeed, m_vecDirection.y * m_flSpeed, m_vecDirection.z * m_flSpeed );
  86. VectorMA( m_vecStartPosition, flDeltaTime, vecVelocity, m_vecPos );
  87. // Reset the start time.
  88. m_flPosTime = m_flWorldExitTime;
  89. // Set the location to skybox.
  90. m_nLocation = METEOR_LOCATION_SKYBOX;
  91. }
  92. //-----------------------------------------------------------------------------
  93. //-----------------------------------------------------------------------------
  94. bool CEnvMeteorShared::IsInSkybox( float flTime )
  95. {
  96. // Check to see if we are always in the skybox!
  97. if ( m_flWorldEnterTime == METEOR_INVALID_TIME )
  98. return true;
  99. return ( ( flTime < m_flWorldEnterTime ) || ( flTime > m_flWorldExitTime ) );
  100. }
  101. //-----------------------------------------------------------------------------
  102. //-----------------------------------------------------------------------------
  103. bool CEnvMeteorShared::IsPassive( float flTime )
  104. {
  105. return ( flTime < m_flPassiveTime );
  106. }
  107. //-----------------------------------------------------------------------------
  108. //-----------------------------------------------------------------------------
  109. bool CEnvMeteorShared::WillTransition( void )
  110. {
  111. return ( m_flWorldEnterTime == METEOR_INVALID_TIME );
  112. }
  113. //-----------------------------------------------------------------------------
  114. //-----------------------------------------------------------------------------
  115. float CEnvMeteorShared::GetDamageRadius( void )
  116. {
  117. return m_flDamageRadius;
  118. }
  119. //-----------------------------------------------------------------------------
  120. //-----------------------------------------------------------------------------
  121. void CEnvMeteorShared::CalcEnterAndExitTimes( const Vector &vecTriggerMins,
  122. const Vector &vecTriggerMaxs )
  123. {
  124. #define METEOR_TRIGGER_EPSILON 0.001f
  125. // Initialize the enter/exit fractions.
  126. float flEnterFrac = 0.0f;
  127. float flExitFrac = 1.0f;
  128. // Create an arbitrarily large end position.
  129. Vector vecEndPosition;
  130. VectorMA( m_vecStartPosition, 32000.0f, m_vecDirection, vecEndPosition );
  131. float flFrac, flDistStart, flDistEnd;
  132. for( int iAxis = 0; iAxis < 3; iAxis++ )
  133. {
  134. // Negative Axis
  135. flDistStart = -m_vecStartPosition[iAxis] + vecTriggerMins[iAxis];
  136. flDistEnd = -vecEndPosition[iAxis] + vecTriggerMins[iAxis];
  137. if ( ( flDistStart > 0.0f ) && ( flDistEnd < 0.0f ) )
  138. {
  139. flFrac = ( flDistStart - METEOR_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
  140. if ( flFrac > flEnterFrac ) { flEnterFrac = flFrac; }
  141. }
  142. if ( ( flDistStart < 0.0f ) && ( flDistEnd > 0.0f ) )
  143. {
  144. flFrac = ( flDistStart + METEOR_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
  145. if( flFrac < flExitFrac ) { flExitFrac = flFrac; }
  146. }
  147. if ( ( flDistStart > 0.0f ) && ( flDistEnd > 0.0f ) )
  148. return;
  149. // Positive Axis
  150. flDistStart = m_vecStartPosition[iAxis] - vecTriggerMaxs[iAxis];
  151. flDistEnd = vecEndPosition[iAxis] - vecTriggerMaxs[iAxis];
  152. if ( ( flDistStart > 0.0f ) && ( flDistEnd < 0.0f ) )
  153. {
  154. flFrac = ( flDistStart - METEOR_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
  155. if ( flFrac > flEnterFrac ) { flEnterFrac = flFrac; }
  156. }
  157. if ( ( flDistStart < 0.0f ) && ( flDistEnd > 0.0f ) )
  158. {
  159. flFrac = ( flDistStart + METEOR_TRIGGER_EPSILON ) / ( flDistStart - flDistEnd );
  160. if( flFrac < flExitFrac ) { flExitFrac = flFrac; }
  161. }
  162. if ( ( flDistStart > 0.0f ) && ( flDistEnd > 0.0f ) )
  163. return;
  164. }
  165. // Check for intersection.
  166. if ( flExitFrac >= flEnterFrac )
  167. {
  168. // Check to see if we start in the world or the skybox!
  169. if ( flEnterFrac == 0.0f )
  170. {
  171. m_nLocation = METEOR_LOCATION_WORLD;
  172. }
  173. else
  174. {
  175. m_nLocation = METEOR_LOCATION_SKYBOX;
  176. }
  177. // Calculate the enter/exit times.
  178. Vector vecEnterPoint, vecExitPoint, vecDeltaPosition;
  179. VectorSubtract( vecEndPosition, m_vecStartPosition, vecDeltaPosition );
  180. VectorScale( vecDeltaPosition, flEnterFrac, vecEnterPoint );
  181. VectorScale( vecDeltaPosition, flExitFrac, vecExitPoint );
  182. m_flWorldEnterTime = vecEnterPoint.Length() / m_flSpeed;
  183. m_flWorldExitTime = vecExitPoint.Length() / m_flSpeed;
  184. m_flWorldEnterTime += m_flStartTime;
  185. m_flWorldExitTime += m_flStartTime;
  186. }
  187. #undef METEOR_TRIGGER_EPSILON
  188. }
  189. //=============================================================================
  190. //
  191. // Meteor Spawner Functions.
  192. //
  193. //-----------------------------------------------------------------------------
  194. //-----------------------------------------------------------------------------
  195. CEnvMeteorSpawnerShared::CEnvMeteorSpawnerShared()
  196. {
  197. m_pFactory = NULL;
  198. m_nMeteorCount = 0;
  199. m_flStartTime = 0.0f;
  200. m_nRandomSeed = 0;
  201. m_iMeteorType = -1;
  202. m_flMeteorDamageRadius = 0.0f;
  203. m_bSkybox = true;
  204. m_flMinSpawnTime = 0.0f;
  205. m_flMaxSpawnTime = 0.0f;
  206. m_nMinSpawnCount = 0;
  207. m_nMaxSpawnCount = 0;
  208. m_vecMinBounds.Init();
  209. m_vecMaxBounds.Init();
  210. m_flMinSpeed = 0.0f;
  211. m_flMaxSpeed = 0.0f;
  212. m_flNextSpawnTime = 0.0f;
  213. m_vecTriggerMins.Init();
  214. m_vecTriggerMaxs.Init();
  215. m_vecTriggerCenter.Init();
  216. // Debug!
  217. m_nRandomCallCount = 0;
  218. m_aTargets.Purge();
  219. }
  220. //-----------------------------------------------------------------------------
  221. //-----------------------------------------------------------------------------
  222. void CEnvMeteorSpawnerShared::Init( IMeteorFactory *pFactory, int nRandomSeed, float flTime,
  223. const Vector &vecMinBounds, const Vector &vecMaxBounds,
  224. const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
  225. {
  226. // Factory.
  227. m_pFactory = pFactory;
  228. // Setup the random number stream.
  229. m_nRandomSeed = nRandomSeed;
  230. m_NumberStream.SetSeed( nRandomSeed );
  231. // Start time.
  232. m_flStartTime = flTime;
  233. // Copy the spawner bounds.
  234. m_vecMinBounds = vecMinBounds;
  235. m_vecMaxBounds = vecMaxBounds;
  236. // Copy the trigger bounds.
  237. m_vecTriggerMins = vecTriggerMins;
  238. m_vecTriggerMaxs = vecTriggerMaxs;
  239. // Get the center of the trigger bounds.
  240. m_vecTriggerCenter = ( m_vecTriggerMins + m_vecTriggerMaxs ) * 0.5f;
  241. // Setup spawn time.
  242. m_flNextSpawnTime = m_flStartTime + m_flMaxSpawnTime;
  243. }
  244. //-----------------------------------------------------------------------------
  245. //-----------------------------------------------------------------------------
  246. int CEnvMeteorSpawnerShared::GetRandomInt( int nMin, int nMax )
  247. {
  248. m_nRandomCallCount++;
  249. return m_NumberStream.RandomInt( nMin, nMax );
  250. }
  251. //-----------------------------------------------------------------------------
  252. //-----------------------------------------------------------------------------
  253. float CEnvMeteorSpawnerShared::GetRandomFloat( float flMin, float flMax )
  254. {
  255. m_nRandomCallCount++;
  256. return m_NumberStream.RandomFloat( flMin, flMax );
  257. }
  258. //-----------------------------------------------------------------------------
  259. //-----------------------------------------------------------------------------
  260. float CEnvMeteorSpawnerShared::MeteorThink( float flTime )
  261. {
  262. // Check for spawn.
  263. if ( flTime < m_flNextSpawnTime )
  264. return m_flNextSpawnTime;
  265. while ( m_flNextSpawnTime < flTime )
  266. {
  267. // Get a random number of meteors to spawn and spawn them.
  268. int nMeteorCount = GetRandomInt( m_nMinSpawnCount, m_nMaxSpawnCount );
  269. for ( int iMeteor = 0; iMeteor < nMeteorCount; iMeteor++ )
  270. {
  271. // Increment the number of meteors created (starting with 1).
  272. m_nMeteorCount++;
  273. // Get a random meteor position.
  274. Vector meteorOrigin( GetRandomFloat( m_vecMinBounds.GetX(), m_vecMaxBounds.GetX() ) /* x */,
  275. GetRandomFloat( m_vecMinBounds.GetY(), m_vecMaxBounds.GetY() ) /* y */,
  276. GetRandomFloat( m_vecMinBounds.GetZ(), m_vecMaxBounds.GetZ() ) /* z */ );
  277. // Calculate the direction of the meteor based on "targets."
  278. Vector vecDirection( 0.0f, 0.0f, -1.0f );
  279. if ( m_aTargets.Count() > 0 )
  280. {
  281. float flFreq = 1.0f / m_aTargets.Count();
  282. float flFreqAccum = flFreq;
  283. int iTarget;
  284. for( iTarget = 0; iTarget < m_aTargets.Count(); ++iTarget )
  285. {
  286. float flRandom = GetRandomFloat( 0.0f, 1.0f );
  287. if ( flRandom < flFreqAccum )
  288. break;
  289. flFreqAccum += flFreq;
  290. }
  291. // Should ever be here!
  292. if ( iTarget == m_aTargets.Count() )
  293. {
  294. iTarget--;
  295. }
  296. // Just set it to the first target for now!!!
  297. // NOTE: Will randomly generate from list of targets when more than 1 in
  298. // the future.
  299. // Move the meteor into the "world."
  300. Vector vecPositionInWorld;
  301. Vector vecSkyboxOrigin;
  302. g_pMapData->Get3DSkyboxOrigin( vecSkyboxOrigin );
  303. vecPositionInWorld = ( meteorOrigin - vecSkyboxOrigin );
  304. vecPositionInWorld *= g_pMapData->Get3DSkyboxScale();
  305. Vector vecTargetPos = m_aTargets[iTarget].m_vecPosition;
  306. vecTargetPos.x += GetRandomFloat( -m_aTargets[iTarget].m_flRadius, m_aTargets[iTarget].m_flRadius );
  307. vecTargetPos.y += GetRandomFloat( -m_aTargets[iTarget].m_flRadius, m_aTargets[iTarget].m_flRadius );
  308. vecTargetPos.z += GetRandomFloat( -m_aTargets[iTarget].m_flRadius, m_aTargets[iTarget].m_flRadius );
  309. vecDirection = vecTargetPos - vecPositionInWorld;
  310. VectorNormalize( vecDirection );
  311. }
  312. // Pass in the randomized position, randomized speed, and start time.
  313. m_pFactory->CreateMeteor( m_nMeteorCount, m_iMeteorType, meteorOrigin,
  314. vecDirection /* direction */,
  315. GetRandomFloat( m_flMinSpeed, m_flMaxSpeed ) /* speed */,
  316. m_flNextSpawnTime, m_flMeteorDamageRadius,
  317. m_vecTriggerMins, m_vecTriggerMaxs );
  318. }
  319. // Set next spawn time.
  320. m_flNextSpawnTime += GetRandomFloat( m_flMinSpawnTime, m_flMaxSpawnTime );
  321. }
  322. // Return the next spawn time.
  323. return ( m_flNextSpawnTime - gpGlobals->curtime );
  324. }
  325. //-----------------------------------------------------------------------------
  326. //-----------------------------------------------------------------------------
  327. void CEnvMeteorSpawnerShared::AddToTargetList( const Vector &vecPosition, float flRadius )
  328. {
  329. int iTarget = m_aTargets.AddToTail();
  330. m_aTargets[iTarget].m_vecPosition = vecPosition;
  331. m_aTargets[iTarget].m_flRadius = flRadius;
  332. }