FirestormDynamicGeometryInfoUpdate.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: FirestormDynamicGeometryInfoUpdate.cpp //////////////////////////////////////////////////////////////////////////
  24. // Author: Graham Smallwood, April 2002
  25. // Desc: Update module adds the molestation of a particle system to Geometry changing
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/Xfer.h"
  30. #include "GameClient/GameClient.h"
  31. #include "GameClient/InGameUI.h"
  32. #include "GameClient/FXList.h"
  33. #include "GameClient/ParticleSys.h"
  34. #include "GameLogic/Damage.h"
  35. #include "GameLogic/GameLogic.h"
  36. #include "GameLogic/Object.h"
  37. #include "GameLogic/PartitionManager.h"
  38. #include "GameLogic/TerrainLogic.h"
  39. #include "GameLogic/Module/FirestormDynamicGeometryInfoUpdate.h"
  40. //-------------------------------------------------------------------------------------------------
  41. //-------------------------------------------------------------------------------------------------
  42. FirestormDynamicGeometryInfoUpdateModuleData::FirestormDynamicGeometryInfoUpdateModuleData() : DynamicGeometryInfoUpdateModuleData()
  43. {
  44. for( Int i = 0; i < MAX_FIRESTORM_SYSTEMS; i++ )
  45. m_particleSystem[ i ] = NULL;
  46. m_fxList = NULL;
  47. m_particleOffsetZ = 0.0f;
  48. m_scorchSize = 0.0f;
  49. m_delayBetweenDamageFrames = 0.0f;
  50. m_damageAmount = 0.0f;
  51. m_maxHeightForDamage = 20.0f;
  52. }
  53. //-------------------------------------------------------------------------------------------------
  54. /*static*/ void FirestormDynamicGeometryInfoUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
  55. {
  56. DynamicGeometryInfoUpdateModuleData::buildFieldParse(p);
  57. static const FieldParse dataFieldParse[] =
  58. {
  59. { "DelayBetweenDamageFrames", INI::parseDurationReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_delayBetweenDamageFrames ) },
  60. { "DamageAmount", INI::parseReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_damageAmount ) },
  61. { "MaxHeightForDamage", INI::parseReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_maxHeightForDamage ) },
  62. { "ParticleSystem1", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 0 ] ) },
  63. { "ParticleSystem2", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 1 ] ) },
  64. { "ParticleSystem3", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 2 ] ) },
  65. { "ParticleSystem4", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 3 ] ) },
  66. { "ParticleSystem5", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 4 ] ) },
  67. { "ParticleSystem6", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 5 ] ) },
  68. { "ParticleSystem7", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 6 ] ) },
  69. { "ParticleSystem8", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 7 ] ) },
  70. { "ParticleSystem9", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 8 ] ) },
  71. { "ParticleSystem10", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 9 ] ) },
  72. { "ParticleSystem11", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 10 ] ) },
  73. { "ParticleSystem12", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 11 ] ) },
  74. { "ParticleSystem13", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 12 ] ) },
  75. { "ParticleSystem14", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 13 ] ) },
  76. { "ParticleSystem15", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 14 ] ) },
  77. { "ParticleSystem16", INI::parseParticleSystemTemplate, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleSystem[ 15 ] ) },
  78. { "FXList", INI::parseFXList, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_fxList ) },
  79. { "ParticleOffsetZ", INI::parseReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_particleOffsetZ ) },
  80. { "ScorchSize", INI::parseReal, NULL, offsetof( FirestormDynamicGeometryInfoUpdateModuleData, m_scorchSize ) },
  81. { 0, 0, 0, 0 }
  82. };
  83. p.add(dataFieldParse);
  84. }
  85. //-------------------------------------------------------------------------------------------------
  86. FirestormDynamicGeometryInfoUpdate::FirestormDynamicGeometryInfoUpdate( Thing *thing, const ModuleData* moduleData ) : DynamicGeometryInfoUpdate( thing, moduleData )
  87. {
  88. for( Int i = 0; i < MAX_FIRESTORM_SYSTEMS; i++ )
  89. m_myParticleSystemID[ i ] = INVALID_PARTICLE_SYSTEM_ID;
  90. m_effectsFired = FALSE;
  91. m_scorchPlaced = FALSE;
  92. m_lastDamageFrame = 0;
  93. }
  94. //-------------------------------------------------------------------------------------------------
  95. //-------------------------------------------------------------------------------------------------
  96. FirestormDynamicGeometryInfoUpdate::~FirestormDynamicGeometryInfoUpdate( void )
  97. {
  98. }
  99. //-------------------------------------------------------------------------------------------------
  100. /** The update callback. */
  101. //-------------------------------------------------------------------------------------------------
  102. UpdateSleepTime FirestormDynamicGeometryInfoUpdate::update( void )
  103. {
  104. // extend functionality
  105. DynamicGeometryInfoUpdate::update();
  106. // get out of here if we haven't fired yet
  107. if( m_startingDelayCountdown > 0 )
  108. return UPDATE_SLEEP_NONE;
  109. // get the module data
  110. const FirestormDynamicGeometryInfoUpdateModuleData *modData = getFirestormDynamicGeometryInfoUpdateModuleData();
  111. // start effects for the first time
  112. if( m_effectsFired == FALSE )
  113. {
  114. ParticleSystem *sys;
  115. //
  116. // construct a position to play the particle effects ... that is on the ground, but
  117. // note that we add a small amount to it to avoid particles from the system (especially
  118. // flat XY particles) from popping up through the terrain
  119. //
  120. Coord3D pos;
  121. pos.x = getObject()->getPosition()->x;
  122. pos.y = getObject()->getPosition()->y;
  123. pos.z = modData->m_particleOffsetZ + TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  124. // do the particle systems
  125. for( Int i = 0; i < MAX_FIRESTORM_SYSTEMS; i++ )
  126. {
  127. sys = TheParticleSystemManager->createParticleSystem( modData->m_particleSystem[ i ] );
  128. if( sys )
  129. {
  130. sys->setPosition( &pos );
  131. m_myParticleSystemID[ i ] = sys->getSystemID();
  132. } // end if
  133. } // end for i
  134. // do the FX list
  135. FXList::doFXObj( modData->m_fxList, getObject() );
  136. // effects have been fired
  137. m_effectsFired = TRUE;
  138. }
  139. //
  140. // Parent goes first, and we use part of what he did to alter our bound particle system
  141. // get and update our running particle system if we have one
  142. //
  143. for( Int i = 0; i < MAX_FIRESTORM_SYSTEMS; i++ )
  144. {
  145. if( m_myParticleSystemID[ i ] )
  146. {
  147. ParticleSystem *sys = TheParticleSystemManager->findParticleSystem( m_myParticleSystemID[ i ] );
  148. if( sys )
  149. {
  150. ParticleSystemInfo::EmissionVolumeType type = sys->getEmisionVolumeType();
  151. if( type == ParticleSystemInfo::EmissionVolumeType::SPHERE )
  152. sys->setEmissionVolumeSphereRadius( getObject()->getGeometryInfo().getMajorRadius() );
  153. else if( type == ParticleSystemInfo::EmissionVolumeType::CYLINDER )
  154. sys->setEmissionVolumeCylinderRadius( getObject()->getGeometryInfo().getMajorRadius() );
  155. } // end if
  156. else
  157. {
  158. // this system not found (it probably died)... stop trying to find it in the future
  159. m_myParticleSystemID[ i ] = INVALID_PARTICLE_SYSTEM_ID;
  160. } // end else
  161. } // end if
  162. } // end for, i
  163. // when we first start running backward ... make a scorch mark
  164. if( m_switchedDirections == TRUE && m_scorchPlaced == FALSE )
  165. {
  166. TheGameClient->addScorch( getObject()->getPosition(), modData->m_scorchSize, SCORCH_1 );
  167. m_scorchPlaced = TRUE;
  168. } // end if
  169. // scan and do some damage every once in a while
  170. if( TheGameLogic->getFrame() - m_lastDamageFrame >= modData->m_delayBetweenDamageFrames )
  171. {
  172. doDamageScan();
  173. m_lastDamageFrame = TheGameLogic->getFrame();
  174. } // end if
  175. return UPDATE_SLEEP_NONE;
  176. }
  177. // ------------------------------------------------------------------------------------------------
  178. // ------------------------------------------------------------------------------------------------
  179. void FirestormDynamicGeometryInfoUpdate::doDamageScan( void )
  180. {
  181. // get the module data
  182. const FirestormDynamicGeometryInfoUpdateModuleData *modData = getFirestormDynamicGeometryInfoUpdateModuleData();
  183. // get the object and position
  184. Object *firestorm = getObject();
  185. const Coord3D *firestormPos = firestorm->getPosition();
  186. // setup a damage info structure to do some damage
  187. DamageInfo damageInfo;
  188. damageInfo.in.m_damageType = DAMAGE_FLAME;
  189. damageInfo.in.m_deathType = DEATH_BURNED;
  190. damageInfo.in.m_sourceID = firestorm->getID();
  191. damageInfo.in.m_amount = modData->m_damageAmount;
  192. // get the current bounding circle size for the firestorm
  193. Real boundingCircle = firestorm->getGeometryInfo().getBoundingCircleRadius();
  194. // scan objects around us and do damage to objects we have "passed over"
  195. if( boundingCircle )
  196. {
  197. ObjectIterator *iter = ThePartitionManager->iterateObjectsInRange( firestormPos,
  198. boundingCircle,
  199. FROM_BOUNDINGSPHERE_2D,
  200. NULL );
  201. MemoryPoolObjectHolder hold( iter );
  202. Object *other;
  203. for( other = iter->first(); other; other = iter->next() )
  204. {
  205. // it's too high above us. skip it.
  206. if (other->getPosition()->z > firestorm->getPosition()->z + modData->m_maxHeightForDamage)
  207. continue;
  208. // do damage
  209. other->attemptDamage( &damageInfo );
  210. } // end for, other
  211. } // end if, an boundingCircle radius exists
  212. } // end doDamageScan
  213. // ------------------------------------------------------------------------------------------------
  214. /** CRC */
  215. // ------------------------------------------------------------------------------------------------
  216. void FirestormDynamicGeometryInfoUpdate::crc( Xfer *xfer )
  217. {
  218. // extend base class
  219. DynamicGeometryInfoUpdate::crc( xfer );
  220. } // end crc
  221. // ------------------------------------------------------------------------------------------------
  222. /** Xfer method
  223. * Version Info:
  224. * 1: Initial version */
  225. // ------------------------------------------------------------------------------------------------
  226. void FirestormDynamicGeometryInfoUpdate::xfer( Xfer *xfer )
  227. {
  228. // version
  229. XferVersion currentVersion = 1;
  230. XferVersion version = currentVersion;
  231. xfer->xferVersion( &version, currentVersion );
  232. // extend base class
  233. DynamicGeometryInfoUpdate::xfer( xfer );
  234. // particle system ids
  235. xfer->xferUser( m_myParticleSystemID, sizeof( ParticleSystemID ) * MAX_FIRESTORM_SYSTEMS );
  236. // effects fired
  237. xfer->xferBool( &m_effectsFired );
  238. // scorch placed
  239. xfer->xferBool( &m_scorchPlaced );
  240. // last damage frame
  241. xfer->xferUnsignedInt( &m_lastDamageFrame );
  242. } // end xfer
  243. // ------------------------------------------------------------------------------------------------
  244. /** Load post process */
  245. // ------------------------------------------------------------------------------------------------
  246. void FirestormDynamicGeometryInfoUpdate::loadPostProcess( void )
  247. {
  248. // extend base class
  249. DynamicGeometryInfoUpdate::loadPostProcess();
  250. } // end loadPostProcess