LaserUpdate.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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: LaserUpdate.cpp //////////////////////////////////////////////////////////////////////////
  24. // Author: Kris Morness, July 2002
  25. // Desc: Handles laser update processing for render purposes and game control.
  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 "Common/DrawModule.h"
  31. #include "GameClient/Drawable.h"
  32. #include "GameClient/GameClient.h"
  33. #include "GameClient/ParticleSys.h"
  34. #include "GameLogic/GameLogic.h"
  35. #include "GameLogic/Object.h"
  36. #include "GameLogic/Module/LaserUpdate.h"
  37. #include "WWMath/Vector3.h"
  38. //-------------------------------------------------------------------------------------------------
  39. //-------------------------------------------------------------------------------------------------
  40. LaserUpdateModuleData::LaserUpdateModuleData()
  41. {
  42. m_parentFireBoneOnTurret = FALSE;
  43. }
  44. //-------------------------------------------------------------------------------------------------
  45. /*static*/ void LaserUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
  46. {
  47. ModuleData::buildFieldParse(p);
  48. static const FieldParse dataFieldParse[] =
  49. {
  50. { "MuzzleParticleSystem", INI::parseAsciiString, NULL, offsetof( LaserUpdateModuleData, m_particleSystemName ) },
  51. { "TargetParticleSystem", INI::parseAsciiString, NULL, offsetof( LaserUpdateModuleData, m_targetParticleSystemName ) },
  52. { "ParentFireBoneName", INI::parseAsciiString, NULL, offsetof( LaserUpdateModuleData, m_parentFireBoneName ) },
  53. { "ParentFireBoneOnTurret", INI::parseAsciiString, NULL, offsetof( LaserUpdateModuleData, m_parentFireBoneOnTurret ) },
  54. { 0, 0, 0, 0 }
  55. };
  56. p.add(dataFieldParse);
  57. }
  58. //-------------------------------------------------------------------------------------------------
  59. //-------------------------------------------------------------------------------------------------
  60. LaserUpdate::LaserUpdate( Thing *thing, const ModuleData* moduleData ) : ClientUpdateModule( thing, moduleData )
  61. {
  62. //Added By Sadullah Nader
  63. //Initialization missing and needed
  64. m_dirty = FALSE;
  65. m_endPos.zero();
  66. m_startPos.zero();
  67. //
  68. m_particleSystemID = INVALID_PARTICLE_SYSTEM_ID;
  69. m_targetParticleSystemID = INVALID_PARTICLE_SYSTEM_ID;
  70. m_widening = false;
  71. m_widenStartFrame = 0;
  72. m_widenFinishFrame = 0;
  73. m_currentWidthScalar = 1.0f;
  74. m_decaying = false;
  75. m_decayStartFrame = 0;
  76. m_decayFinishFrame = 0;
  77. }
  78. //-------------------------------------------------------------------------------------------------
  79. //-------------------------------------------------------------------------------------------------
  80. LaserUpdate::~LaserUpdate( void )
  81. {
  82. if( m_particleSystemID )
  83. TheParticleSystemManager->destroyParticleSystemByID( m_particleSystemID );
  84. if( m_targetParticleSystemID )
  85. TheParticleSystemManager->destroyParticleSystemByID( m_targetParticleSystemID );
  86. }
  87. //-------------------------------------------------------------------------------------------------
  88. /** The update callback. */
  89. //-------------------------------------------------------------------------------------------------
  90. void LaserUpdate::clientUpdate( void )
  91. {
  92. /// @todo srj use SLEEPY_UPDATE here
  93. if( m_decaying )
  94. {
  95. UnsignedInt now = TheGameLogic->getFrame();
  96. m_currentWidthScalar = 1.0f - (Real)(now - m_decayStartFrame) / (Real)(m_decayFinishFrame - m_decayStartFrame);
  97. m_dirty = true;
  98. if( m_currentWidthScalar <= 0.0f )
  99. {
  100. m_currentWidthScalar = 0.0f;
  101. //When decay is finished... delete the laser.
  102. //TheGameLogic->destroyObject( getObject() );
  103. return;
  104. }
  105. }
  106. else if( m_widening )
  107. {
  108. //We need to resize our laser width based on the growth ratio completed.
  109. UnsignedInt now = TheGameLogic->getFrame();
  110. m_currentWidthScalar = (Real)(now - m_widenStartFrame) / (Real)(m_widenFinishFrame - m_widenStartFrame);
  111. m_dirty = true;
  112. if( m_currentWidthScalar >= 1.0f )
  113. {
  114. m_currentWidthScalar = 1.0f;
  115. m_widening = false;
  116. }
  117. }
  118. return;
  119. }
  120. void LaserUpdate::setDecayFrames( UnsignedInt decayFrames )
  121. {
  122. if( decayFrames > 0 )
  123. {
  124. m_decaying = true;
  125. m_decayStartFrame = TheGameLogic->getFrame();
  126. m_decayFinishFrame = m_decayStartFrame + decayFrames;
  127. m_currentWidthScalar = 1.0f;
  128. }
  129. }
  130. //-------------------------------------------------------------------------------------------------
  131. void LaserUpdate::initLaser( const Object *parent, const Coord3D *startPos, const Coord3D *endPos, Int sizeDeltaFrames )
  132. {
  133. const LaserUpdateModuleData *data = getLaserUpdateModuleData();
  134. ParticleSystem *system;
  135. if( sizeDeltaFrames > 0 )
  136. {
  137. m_widening = true;
  138. m_widenStartFrame = TheGameLogic->getFrame();
  139. m_widenFinishFrame = m_widenStartFrame + sizeDeltaFrames;
  140. m_currentWidthScalar = 0.0f;
  141. }
  142. else if( sizeDeltaFrames < 0 )
  143. {
  144. m_decaying = true;
  145. m_decayStartFrame = TheGameLogic->getFrame();
  146. m_decayFinishFrame = m_decayStartFrame - sizeDeltaFrames;
  147. m_currentWidthScalar = 1.0f;
  148. }
  149. //Compute startPos
  150. if( parent && data->m_parentFireBoneName.isNotEmpty() )
  151. {
  152. // Override startPos with the logic bone position
  153. if( data->m_parentFireBoneOnTurret )
  154. {
  155. if( !parent->getSingleLogicalBonePositionOnTurret( TURRET_MAIN, data->m_parentFireBoneName.str(), &m_startPos, NULL ) )
  156. {
  157. // failed to find the required bone, so just die
  158. TheGameClient->destroyDrawable( getDrawable() );
  159. return;
  160. }
  161. }
  162. else
  163. {
  164. if( !parent->getSingleLogicalBonePosition( data->m_parentFireBoneName.str(), &m_startPos, NULL ) )
  165. {
  166. // failed to find the required bone, so just die
  167. TheGameClient->destroyDrawable( getDrawable() );
  168. return;
  169. }
  170. }
  171. }
  172. else if( startPos )
  173. {
  174. // or just use what they gave
  175. m_startPos = *startPos;
  176. }
  177. else
  178. {
  179. // if they gave nothing, then we are screwed
  180. TheGameClient->destroyDrawable( getDrawable() );
  181. return;
  182. }
  183. //Compute endPos
  184. if( endPos != NULL )
  185. {
  186. // just use what they gave, no override here
  187. m_endPos = *endPos;
  188. }
  189. else
  190. {
  191. // if they gave nothing, then we are screwed
  192. TheGameClient->destroyDrawable( getDrawable() );
  193. return;
  194. }
  195. if( !m_particleSystemID )
  196. {
  197. //If we don't have a particle system for the lense flare (muzzle flare), create it.
  198. if( data->m_particleSystemName.isNotEmpty() )
  199. {
  200. const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate( data->m_particleSystemName );
  201. if( tmp )
  202. {
  203. system = TheParticleSystemManager->createParticleSystem( tmp );
  204. if( system )
  205. {
  206. m_particleSystemID = system->getSystemID();
  207. }
  208. }
  209. }
  210. //If we don't have a particle system for the target effect, create it.
  211. if( data->m_targetParticleSystemName.isNotEmpty() )
  212. {
  213. const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate( data->m_targetParticleSystemName );
  214. if( tmp )
  215. {
  216. system = TheParticleSystemManager->createParticleSystem( tmp );
  217. if( system )
  218. {
  219. m_targetParticleSystemID = system->getSystemID();
  220. }
  221. }
  222. }
  223. }
  224. //Adjust the position of any existing particle system.
  225. if( m_particleSystemID )
  226. {
  227. system = TheParticleSystemManager->findParticleSystem( m_particleSystemID );
  228. if( system )
  229. {
  230. system->setPosition( &m_startPos );
  231. }
  232. }
  233. if( m_targetParticleSystemID )
  234. {
  235. system = TheParticleSystemManager->findParticleSystem( m_targetParticleSystemID );
  236. if( system )
  237. {
  238. system->setPosition( &m_endPos );
  239. }
  240. }
  241. //Important! Set the laser position to the average of both points or else
  242. //it probably won't get rendered!!!
  243. Coord3D avgPos;
  244. avgPos.set( startPos );
  245. avgPos.add( endPos );
  246. avgPos.scale( 0.5 );
  247. getDrawable()->setPosition( &avgPos );
  248. Object *laser = getDrawable()->getObject();
  249. if( laser )
  250. {
  251. laser->setPosition( &avgPos );
  252. }
  253. m_dirty = true;
  254. }
  255. //-------------------------------------------------------------------------------------------------
  256. Real LaserUpdate::getCurrentLaserRadius() const
  257. {
  258. const Drawable *draw = getDrawable();
  259. const LaserDrawInterface* ldi = NULL;
  260. for( const DrawModule** d = draw->getDrawModules(); *d; ++d )
  261. {
  262. ldi = (*d)->getLaserDrawInterface();
  263. if( ldi )
  264. {
  265. //***NOTE***
  266. //While it appears the logic is accessing client data, it is actually accessing template module
  267. //data from the client. This value is INI constant thus can't change. It's grouped with other
  268. //laser defining attributes and having it there makes it easier for artists.
  269. return ldi->getLaserTemplateWidth() * m_currentWidthScalar;
  270. }
  271. }
  272. return 0.0f;
  273. }
  274. // ------------------------------------------------------------------------------------------------
  275. /** CRC */
  276. // ------------------------------------------------------------------------------------------------
  277. void LaserUpdate::crc( Xfer *xfer )
  278. {
  279. // extend base class
  280. ClientUpdateModule::crc( xfer );
  281. } // end crc
  282. // ------------------------------------------------------------------------------------------------
  283. /** Xfer method
  284. * Version Info:
  285. * 1: Initial version */
  286. // ------------------------------------------------------------------------------------------------
  287. void LaserUpdate::xfer( Xfer *xfer )
  288. {
  289. // version
  290. XferVersion currentVersion = 1;
  291. XferVersion version = currentVersion;
  292. xfer->xferVersion( &version, currentVersion );
  293. // extend base class
  294. ClientUpdateModule::xfer( xfer );
  295. // start pos
  296. xfer->xferCoord3D( &m_startPos );
  297. // end pos
  298. xfer->xferCoord3D( &m_endPos );
  299. // dirty
  300. xfer->xferBool( &m_dirty );
  301. // particle system ID
  302. xfer->xferUser( &m_particleSystemID, sizeof( ParticleSystemID ) );
  303. // target particle system id
  304. xfer->xferUser( &m_targetParticleSystemID, sizeof( ParticleSystemID ) );
  305. // widening
  306. xfer->xferBool( &m_widening );
  307. // decaying
  308. xfer->xferBool( &m_decaying );
  309. // widen start frame
  310. xfer->xferUnsignedInt( &m_widenStartFrame );
  311. // widen finish frame
  312. xfer->xferUnsignedInt( &m_widenFinishFrame );
  313. // current width scalar
  314. xfer->xferReal( &m_currentWidthScalar );
  315. // decay start frame
  316. xfer->xferUnsignedInt( &m_decayStartFrame );
  317. // decay finish frame
  318. xfer->xferUnsignedInt( &m_decayFinishFrame );
  319. } // end xfer
  320. // ------------------------------------------------------------------------------------------------
  321. /** Load post process */
  322. // ------------------------------------------------------------------------------------------------
  323. void LaserUpdate::loadPostProcess( void )
  324. {
  325. // extend base class
  326. ClientUpdateModule::loadPostProcess();
  327. } // end loadPostProcess