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.

404 lines
13 KiB

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