DynamicShroudClearingRangeUpdate.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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: DynamicShroudClearingRangeUpdate.cpp /////////////////////////////////////////////////////////////////////////
  24. // Author: Graham Smallwood, August 2002
  25. // Desc: Changes the Objects Shroud Clearing range
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h"
  29. #include "Common/Xfer.h"
  30. #include "GameLogic/GameLogic.h"
  31. #include "GameLogic/Object.h"
  32. #include "GameLogic/Module/DynamicShroudClearingRangeUpdate.h"
  33. #ifdef _INTERNAL
  34. // for occasional debugging...
  35. //#pragma optimize("", off)
  36. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  37. #endif
  38. //-------------------------------------------------------------------------------------------------
  39. DynamicShroudClearingRangeUpdateModuleData::DynamicShroudClearingRangeUpdateModuleData()
  40. {
  41. m_shrinkDelay = 0;
  42. m_shrinkTime = 0;
  43. m_growDelay = 0;
  44. m_growTime = 0;
  45. m_finalVision = 0.0f;
  46. m_changeInterval = 0;
  47. m_growInterval = 0;
  48. m_doSpySatFX = FALSE;
  49. }
  50. //-------------------------------------------------------------------------------------------------
  51. /*static*/ void DynamicShroudClearingRangeUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
  52. {
  53. UpdateModuleData::buildFieldParse(p);
  54. static const FieldParse dataFieldParse[] =
  55. {
  56. { "ChangeInterval", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_changeInterval ) },
  57. { "GrowInterval", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_growInterval ) },
  58. { "ShrinkDelay", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_shrinkDelay ) },
  59. { "ShrinkTime", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_shrinkTime ) },
  60. { "GrowDelay", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_growDelay ) },
  61. { "GrowTime", INI::parseDurationUnsignedInt, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_growTime ) },
  62. { "FinalVision", INI::parseReal, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_finalVision ) },
  63. { "GridDecalTemplate", RadiusDecalTemplate::parseRadiusDecalTemplate, NULL, offsetof( DynamicShroudClearingRangeUpdateModuleData, m_gridDecalTemplate ) },
  64. { 0, 0, 0, 0 }
  65. };
  66. p.add(dataFieldParse);
  67. }
  68. //-------------------------------------------------------------------------------------------------
  69. //
  70. // doneForeverFrame
  71. // o | shrinkdelay |
  72. // |<-----------------------------------stateCountDown---------------------------------->|
  73. // | shrinktime | | growtime | growdelay |
  74. // | shrinkStartDeadline sustain growStartDeadline|
  75. //
  76. //-------------------------------------------------------------------------------------------------
  77. DynamicShroudClearingRangeUpdate::DynamicShroudClearingRangeUpdate( Thing *thing, const ModuleData* moduleData ) : UpdateModule( thing, moduleData )
  78. {
  79. DynamicShroudClearingRangeUpdateModuleData *md = (DynamicShroudClearingRangeUpdateModuleData *)moduleData;
  80. // m_shrinkStartCountdown = md->m_shrinkDelay;
  81. // m_shrinkDeadline = 0;
  82. m_changeIntervalCountdown = 0;
  83. m_visionChangePerInterval = 0.0f;
  84. m_stateCountDown = md->m_shrinkDelay + md->m_shrinkTime;// total time
  85. m_totalFrames = max(1,m_stateCountDown);
  86. m_shrinkStartDeadline = m_stateCountDown - md->m_shrinkDelay;
  87. m_growStartDeadline = m_stateCountDown - md->m_growDelay;
  88. m_sustainDeadline = m_growStartDeadline - md->m_growTime;
  89. DEBUG_ASSERTCRASH((m_sustainDeadline >= m_shrinkStartDeadline),("DynamicShroudClearingRangeUpdate\nYOU WILL NEVER REACH FULL SHROUD CLEARING RANGE WITH THESE TIMES AND DELAYS"));
  90. DEBUG_ASSERTCRASH((m_growStartDeadline >= m_shrinkStartDeadline),("DynamicShroudClearingRangeUpdate\nYOU WILL NEVER REACH FULL SHROUD CLEARING RANGE WITH THESE TIMES AND DELAYS"));
  91. m_doneForeverFrame = TheGameLogic->getFrame() + m_stateCountDown;// a failsafe to force a shutdown on schedule
  92. // m_shrinkStartDeadline;
  93. // m_doneForeverFrame; //
  94. m_decalsCreated = FALSE;
  95. m_nativeClearingRange = 200;// a sensible default
  96. m_currentClearingRange = 0;
  97. m_state = DSCRU_NOT_STARTED_YET;
  98. // m_shrinkFinished = FALSE;
  99. // m_shrinkStarted = FALSE;
  100. Object* obj = getObject();
  101. if ( ! obj )
  102. return;
  103. Player* controller = obj->getControllingPlayer();
  104. if ( ! controller )
  105. return;
  106. m_nativeClearingRange = obj->getShroudClearingRange();//capture this before we start monkeying with it
  107. for (int d = 0; d < GRID_FX_DECAL_COUNT; ++d)
  108. {
  109. m_gridDecal[d].clear();
  110. }
  111. }
  112. //-------------------------------------------------------------------------------------------------
  113. //-------------------------------------------------------------------------------------------------
  114. DynamicShroudClearingRangeUpdate::~DynamicShroudClearingRangeUpdate( void )
  115. {
  116. killGridDecals();// just in case
  117. }
  118. //-------------------------------------------------------------------------------------------------
  119. void DynamicShroudClearingRangeUpdate::createGridDecals( const RadiusDecalTemplate& tmpl, Real radius, const Coord3D& pos )
  120. {
  121. for (int d = 0; d < GRID_FX_DECAL_COUNT; ++d)
  122. {
  123. m_gridDecal[d].clear();
  124. tmpl.createRadiusDecal(pos, radius, getObject()->getControllingPlayer(), m_gridDecal[d]);
  125. m_gridDecal[d].setPosition(pos);
  126. }
  127. }
  128. //-------------------------------------------------------------------------------------------------
  129. void DynamicShroudClearingRangeUpdate::animateGridDecals( void )
  130. {
  131. const Coord3D *ctr = getObject()->getPosition();
  132. Coord3D pos;
  133. pos.z = 0;
  134. Real radius = m_currentClearingRange + ((m_totalFrames - m_stateCountDown) * 2);
  135. Real angle = 0.0f;
  136. Real angleInc = (PI*2.0f) / (Real)GRID_FX_DECAL_COUNT;
  137. Real opacity = 1.0f - (m_currentClearingRange / m_nativeClearingRange);
  138. for (int d = 0; d < GRID_FX_DECAL_COUNT; ++d)
  139. {
  140. pos.x = ctr->x + (sinf(angle) * radius);
  141. pos.y = ctr->y + (cosf(angle) * radius);
  142. pos.x -= ((Int)pos.x)%23;
  143. pos.y -= ((Int)pos.y)%23;
  144. m_gridDecal[d].setPosition(pos);
  145. m_gridDecal[d].setOpacity( opacity );
  146. angle += angleInc;
  147. }
  148. }
  149. //-------------------------------------------------------------------------------------------------
  150. //-------------------------------------------------------------------------------------------------
  151. void DynamicShroudClearingRangeUpdate::killGridDecals()
  152. {
  153. for (int d = 0; d < GRID_FX_DECAL_COUNT; ++d)
  154. {
  155. m_gridDecal[d].clear();
  156. }
  157. }
  158. //-------------------------------------------------------------------------------------------------
  159. //-------------------------------------------------------------------------------------------------
  160. UpdateSleepTime DynamicShroudClearingRangeUpdate::update( void )
  161. {
  162. if (m_state == DSCRU_SLEEPING) {
  163. return UPDATE_SLEEP_NONE;
  164. }
  165. //Housekeeping-----------------------------------------
  166. Object *me = getObject();
  167. const DynamicShroudClearingRangeUpdateModuleData *md = getDynamicShroudClearingRangeUpdateModuleData();
  168. UnsignedInt currentFrame = TheGameLogic->getFrame();
  169. if ( ! m_decalsCreated )
  170. {
  171. createGridDecals(md->m_gridDecalTemplate, 100, *(me->getPosition()));
  172. m_decalsCreated = TRUE;
  173. }
  174. //-----------------------------------------------------
  175. if( m_stateCountDown <= 0 || currentFrame > m_doneForeverFrame )
  176. m_state = DSCRU_DONE_FOREVER;
  177. else if ( m_stateCountDown <= m_shrinkStartDeadline )
  178. m_state = DSCRU_SHRINKING;
  179. else if ( m_stateCountDown <= m_sustainDeadline )
  180. m_state = DSCRU_SUSTAINING;
  181. else if ( m_stateCountDown <= m_growStartDeadline )
  182. m_state = DSCRU_GROWING;
  183. switch (m_state)
  184. {
  185. case DSCRU_NOT_STARTED_YET :
  186. {
  187. animateGridDecals();
  188. break;
  189. }
  190. case DSCRU_GROWING :
  191. {
  192. animateGridDecals();
  193. m_currentClearingRange += m_nativeClearingRange / max(1.0f, (Real)md->m_growTime);
  194. if (m_currentClearingRange >= m_nativeClearingRange)
  195. m_state = DSCRU_SUSTAINING;
  196. break;
  197. }
  198. case DSCRU_SUSTAINING :
  199. {
  200. m_currentClearingRange = m_nativeClearingRange;
  201. killGridDecals();
  202. break;
  203. }
  204. case DSCRU_SHRINKING :
  205. {
  206. m_currentClearingRange -= (m_nativeClearingRange-md->m_finalVision) / max(1.0f, (Real)md->m_shrinkTime);
  207. break;
  208. }
  209. case DSCRU_DONE_FOREVER :
  210. {
  211. killGridDecals();
  212. m_currentClearingRange = md->m_finalVision;
  213. break;
  214. }
  215. }
  216. if ( m_stateCountDown > 0 ) m_stateCountDown --;// it is important that this gets called every frame without sleeping
  217. //beacuse it handles animation and may need to respond to changing vision range from scripts & stuff
  218. if( m_changeIntervalCountdown > 0 )
  219. m_changeIntervalCountdown--;
  220. else
  221. {// reset per change timer
  222. m_changeIntervalCountdown = ( m_state == DSCRU_GROWING ? md->m_growInterval : md->m_changeInterval);
  223. me->setShroudClearingRange( m_currentClearingRange );
  224. if (m_state == DSCRU_DONE_FOREVER) { // We are done forever, and have done the final update, so sleep.+
  225. m_state = DSCRU_SLEEPING;
  226. }
  227. }
  228. return UPDATE_SLEEP_NONE;
  229. // if( !m_shrinkStarted )
  230. // {
  231. // //To allow a start delay of zero, check before dec, and look for trigger after
  232. // if( m_shrinkStartCountdown > 0 )
  233. // m_shrinkStartCountdown--;
  234. // if( m_shrinkStartCountdown == 0 )
  235. // {
  236. // m_shrinkStarted = TRUE;
  237. //
  238. // // Timer for how often to change
  239. // m_changeIntervalCountdown = md->m_changeInterval;
  240. // // Marker to make sure we end up precisely correct regardless of interval
  241. // m_shrinkDeadline = TheGameLogic->getFrame() + md->m_shrinkTime;
  242. // // Figure out how much to change each interval
  243. // Real visionDiff = me->getShroudClearingRange() - md->m_finalVision;
  244. // m_visionChangePerInterval = -visionDiff/(md->m_shrinkTime/md->m_changeInterval);
  245. // }
  246. // else
  247. // {
  248. // return UPDATE_SLEEP_NONE;// waiting to start
  249. // }
  250. // }
  251. // if( m_changeIntervalCountdown > 0 )
  252. // m_changeIntervalCountdown--;
  253. // if( m_changeIntervalCountdown != 0 )
  254. // return UPDATE_SLEEP_NONE;
  255. // // reset per change timer
  256. // m_changeIntervalCountdown = getDynamicShroudClearingRangeUpdateModuleData()->m_changeInterval;
  257. // UnsignedInt currentFrame = TheGameLogic->getFrame();
  258. // if( currentFrame > m_shrinkDeadline )
  259. // {
  260. // // Time to stop doing anything.
  261. // me->setShroudClearingRange( getDynamicShroudClearingRangeUpdateModuleData()->m_finalVision );
  262. // m_shrinkFinished = TRUE;
  263. // killGridDecals();
  264. // }
  265. // else
  266. // {
  267. // // bump the vision again
  268. // me->setShroudClearingRange( me->getShroudClearingRange() + m_visionChangePerInterval );
  269. // }
  270. // return UPDATE_SLEEP_NONE;
  271. }
  272. // ------------------------------------------------------------------------------------------------
  273. /** CRC */
  274. // ------------------------------------------------------------------------------------------------
  275. void DynamicShroudClearingRangeUpdate::crc( Xfer *xfer )
  276. {
  277. // extend base class
  278. UpdateModule::crc( xfer );
  279. } // end crc
  280. // ------------------------------------------------------------------------------------------------
  281. /** Xfer method
  282. * Version Info:
  283. * 1: Initial version */
  284. // ------------------------------------------------------------------------------------------------
  285. void DynamicShroudClearingRangeUpdate::xfer( Xfer *xfer )
  286. {
  287. // version
  288. XferVersion currentVersion = 1;
  289. XferVersion version = currentVersion;
  290. xfer->xferVersion( &version, currentVersion );
  291. // extend base class
  292. UpdateModule::xfer( xfer );
  293. // shrink start countdown
  294. xfer->xferInt( &m_stateCountDown );
  295. xfer->xferInt( &m_totalFrames );
  296. xfer->xferUnsignedInt( &m_growStartDeadline );
  297. xfer->xferUnsignedInt( &m_sustainDeadline );
  298. xfer->xferUnsignedInt( &m_shrinkStartDeadline );
  299. xfer->xferUnsignedInt( &m_doneForeverFrame );
  300. xfer->xferUnsignedInt( &m_changeIntervalCountdown );
  301. // vision change per interval
  302. xfer->xferBool( &m_decalsCreated );
  303. xfer->xferReal( &m_visionChangePerInterval );
  304. xfer->xferReal( &m_nativeClearingRange );
  305. xfer->xferReal( &m_currentClearingRange );
  306. } // end xfer
  307. // ------------------------------------------------------------------------------------------------
  308. /** Load post process */
  309. // ------------------------------------------------------------------------------------------------
  310. void DynamicShroudClearingRangeUpdate::loadPostProcess( void )
  311. {
  312. // extend base class
  313. UpdateModule::loadPostProcess();
  314. } // end loadPostProcess