FirestormDynamicGeometryInfoUpdate.cpp 13 KB

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