SlowDeathBehavior.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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: SlowDeathBehavior.cpp ///////////////////////////////////////////////////////////////////////
  24. // Author:
  25. // Desc:
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #define DEFINE_SLOWDEATHPHASE_NAMES
  30. #include "Common/GameLOD.h"
  31. #include "Common/INI.h"
  32. #include "Common/RandomValue.h"
  33. #include "Common/Thing.h"
  34. #include "Common/ThingTemplate.h"
  35. #include "Common/Xfer.h"
  36. #include "GameClient/Drawable.h"
  37. #include "GameClient/FXList.h"
  38. #include "GameClient/InGameUI.h"
  39. #include "GameLogic/GameLogic.h"
  40. #include "GameLogic/Module/BodyModule.h"
  41. #include "GameLogic/Module/PhysicsUpdate.h"
  42. #include "GameLogic/Module/SlowDeathBehavior.h"
  43. #include "GameLogic/Module/AIUpdate.h"
  44. #include "GameLogic/Module/SlavedUpdate.h"
  45. #include "GameLogic/Object.h"
  46. #include "GameLogic/ObjectCreationList.h"
  47. #include "GameLogic/Weapon.h"
  48. #include "GameClient/Drawable.h"
  49. #ifdef _INTERNAL
  50. // for occasional debugging...
  51. //#pragma optimize("", off)
  52. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  53. #endif
  54. const Real BEGIN_MIDPOINT_RATIO = 0.35f;
  55. const Real END_MIDPOINT_RATIO = 0.65f;
  56. //-------------------------------------------------------------------------------------------------
  57. SlowDeathBehaviorModuleData::SlowDeathBehaviorModuleData()
  58. {
  59. m_sinkRate = 0;
  60. m_probabilityModifier = 10;
  61. m_modifierBonusPerOverkillPercent = 0;
  62. m_sinkDelay = 0;
  63. m_sinkDelayVariance = 0;
  64. m_destructionDelay = 0;
  65. m_destructionDelayVariance = 0;
  66. m_destructionAltitude = -10;
  67. m_maskOfLoadedEffects = 0; //assume no ocl, fx, or weapons.
  68. m_flingForce = 0;
  69. m_flingForceVariance = 0;
  70. m_flingPitch = 0;
  71. m_flingPitchVariance = 0;
  72. // redundant.
  73. //m_fx.clear();
  74. //m_ocls.clear();
  75. //m_weapons.clear();
  76. }
  77. //-------------------------------------------------------------------------------------------------
  78. static void parseFX( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ )
  79. {
  80. SlowDeathBehaviorModuleData* self = (SlowDeathBehaviorModuleData*)instance;
  81. SlowDeathPhaseType sdphase = (SlowDeathPhaseType)INI::scanIndexList(ini->getNextToken(), TheSlowDeathPhaseNames);
  82. for (const char* token = ini->getNextToken(); token != NULL; token = ini->getNextTokenOrNull())
  83. {
  84. const FXList *fxl = TheFXListStore->findFXList((token)); // could be null! this is OK!
  85. self->m_fx[sdphase].push_back(fxl);
  86. if (fxl)
  87. self->m_maskOfLoadedEffects |= SlowDeathBehaviorModuleData::HAS_FX;
  88. }
  89. }
  90. //-------------------------------------------------------------------------------------------------
  91. static void parseOCL( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ )
  92. {
  93. SlowDeathBehaviorModuleData* self = (SlowDeathBehaviorModuleData*)instance;
  94. SlowDeathPhaseType sdphase = (SlowDeathPhaseType)INI::scanIndexList(ini->getNextToken(), TheSlowDeathPhaseNames);
  95. for (const char* token = ini->getNextToken(); token != NULL; token = ini->getNextTokenOrNull())
  96. {
  97. const ObjectCreationList *ocl = TheObjectCreationListStore->findObjectCreationList(token); // could be null! this is OK!
  98. self->m_ocls[sdphase].push_back(ocl);
  99. if (ocl)
  100. self->m_maskOfLoadedEffects |= SlowDeathBehaviorModuleData::HAS_OCL;
  101. }
  102. }
  103. //-------------------------------------------------------------------------------------------------
  104. static void parseWeapon( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ )
  105. {
  106. SlowDeathBehaviorModuleData* self = (SlowDeathBehaviorModuleData*)instance;
  107. SlowDeathPhaseType sdphase = (SlowDeathPhaseType)INI::scanIndexList(ini->getNextToken(), TheSlowDeathPhaseNames);
  108. for (const char* token = ini->getNextToken(); token != NULL; token = ini->getNextTokenOrNull())
  109. {
  110. const WeaponTemplate *wt = TheWeaponStore->findWeaponTemplate(token); // could be null! this is OK!
  111. self->m_weapons[sdphase].push_back(wt);
  112. if (wt)
  113. self->m_maskOfLoadedEffects |= SlowDeathBehaviorModuleData::HAS_WEAPON;
  114. }
  115. }
  116. //-------------------------------------------------------------------------------------------------
  117. /*static*/ void SlowDeathBehaviorModuleData::buildFieldParse(MultiIniFieldParse& p)
  118. {
  119. UpdateModuleData::buildFieldParse(p);
  120. static const FieldParse dataFieldParse[] =
  121. {
  122. { "SinkRate", INI::parseVelocityReal, NULL, offsetof( SlowDeathBehaviorModuleData, m_sinkRate ) },
  123. { "ProbabilityModifier", INI::parseInt, NULL, offsetof( SlowDeathBehaviorModuleData, m_probabilityModifier ) },
  124. { "ModifierBonusPerOverkillPercent", INI::parsePercentToReal, NULL, offsetof( SlowDeathBehaviorModuleData, m_modifierBonusPerOverkillPercent ) },
  125. { "SinkDelay", INI::parseDurationUnsignedInt, NULL, offsetof( SlowDeathBehaviorModuleData, m_sinkDelay ) },
  126. { "SinkDelayVariance", INI::parseDurationUnsignedInt, NULL, offsetof( SlowDeathBehaviorModuleData, m_sinkDelayVariance ) },
  127. { "DestructionDelay", INI::parseDurationUnsignedInt, NULL, offsetof( SlowDeathBehaviorModuleData, m_destructionDelay ) },
  128. { "DestructionDelayVariance", INI::parseDurationUnsignedInt, NULL, offsetof( SlowDeathBehaviorModuleData, m_destructionDelayVariance ) },
  129. { "DestructionAltitude", INI::parseReal, NULL, offsetof( SlowDeathBehaviorModuleData, m_destructionAltitude ) },
  130. { "FX", parseFX, NULL, 0 },
  131. { "OCL", parseOCL, NULL, 0 },
  132. { "Weapon", parseWeapon, NULL, 0 },
  133. { "FlingForce", INI::parseReal, NULL, offsetof( SlowDeathBehaviorModuleData, m_flingForce) },
  134. { "FlingForceVariance", INI::parseReal, NULL, offsetof( SlowDeathBehaviorModuleData, m_flingForceVariance) },
  135. { "FlingPitch", INI::parseAngleReal, NULL, offsetof( SlowDeathBehaviorModuleData, m_flingPitch) },
  136. { "FlingPitchVariance", INI::parseAngleReal, NULL, offsetof( SlowDeathBehaviorModuleData, m_flingPitchVariance) },
  137. { 0, 0, 0, 0 }
  138. };
  139. p.add(dataFieldParse);
  140. p.add(DieMuxData::getFieldParse(), offsetof( SlowDeathBehaviorModuleData, m_dieMuxData ));
  141. }
  142. //-------------------------------------------------------------------------------------------------
  143. //-------------------------------------------------------------------------------------------------
  144. SlowDeathBehavior::SlowDeathBehavior( Thing *thing, const ModuleData* moduleData ) : UpdateModule( thing, moduleData )
  145. {
  146. m_flags = 0;
  147. m_sinkFrame = 0;
  148. m_midpointFrame = 0;
  149. m_destructionFrame = 0;
  150. m_acceleratedTimeScale = 1.0f;
  151. if (getSlowDeathBehaviorModuleData()->m_probabilityModifier < 1)
  152. {
  153. DEBUG_CRASH(("ProbabilityModifer must be >= 1.\n"));
  154. throw INI_INVALID_DATA;
  155. }
  156. setWakeFrame(getObject(), UPDATE_SLEEP_FOREVER);
  157. }
  158. //-------------------------------------------------------------------------------------------------
  159. //-------------------------------------------------------------------------------------------------
  160. SlowDeathBehavior::~SlowDeathBehavior( void )
  161. {
  162. }
  163. //-------------------------------------------------------------------------------------------------
  164. //-------------------------------------------------------------------------------------------------
  165. Int SlowDeathBehavior::getProbabilityModifier( const DamageInfo *damageInfo ) const
  166. {
  167. // Calculating how far past dead we were allows us to pick more spectacular deaths when
  168. // severly killed, and more sedate ones when only slightly killed.
  169. // eg ( 200 hp max, had 10 left, took 50 damage, 40 overkill, (40/200) * 100 = 20 overkill %)
  170. Int overkillDamage = damageInfo->out.m_actualDamageDealt - damageInfo->out.m_actualDamageClipped;
  171. Real overkillPercent = (float)overkillDamage / (float)getObject()->getBodyModule()->getMaxHealth();
  172. Int overkillModifier = overkillPercent * getSlowDeathBehaviorModuleData()->m_modifierBonusPerOverkillPercent;
  173. return max( getSlowDeathBehaviorModuleData()->m_probabilityModifier + overkillModifier, 1 );
  174. }
  175. //-------------------------------------------------------------------------------------------------
  176. static void calcRandomForce(Real minMag, Real maxMag, Real minPitch, Real maxPitch, Coord3D& force)
  177. {
  178. Real angle = GameLogicRandomValueReal(-PI, PI);
  179. Real pitch = GameLogicRandomValueReal(minPitch, maxPitch);
  180. Real mag = GameLogicRandomValueReal(minMag, maxMag);
  181. Matrix3D mtx(1);
  182. mtx.Scale(mag);
  183. mtx.Rotate_Z(angle);
  184. mtx.Rotate_Y(-pitch);
  185. Vector3 v = mtx.Get_X_Vector();
  186. force.x = v.X;
  187. force.y = v.Y;
  188. force.z = v.Z;
  189. }
  190. //-------------------------------------------------------------------------------------------------
  191. //-------------------------------------------------------------------------------------------------
  192. void SlowDeathBehavior::beginSlowDeath(const DamageInfo *damageInfo)
  193. {
  194. if (!isSlowDeathActivated())
  195. {
  196. const SlowDeathBehaviorModuleData* d = getSlowDeathBehaviorModuleData();
  197. Object* obj = getObject();
  198. if (d->m_sinkRate && obj->isKindOf(KINDOF_INFANTRY))
  199. {
  200. Drawable *draw = getObject()->getDrawable();
  201. if ( draw )
  202. {
  203. // this object sinks slowly after it dies so don't draw a
  204. // floating shadow decal on the ground above it.
  205. obj->getDrawable()->setShadowsEnabled(false);
  206. draw->setTerrainDecalFadeTarget( 0.0f, -0.2f );
  207. }
  208. }
  209. // Ask game detail manager if we need to speedup all deaths to improve performance
  210. Real timeScale = TheGameLODManager->getSlowDeathScale();
  211. m_acceleratedTimeScale = 1.0f; // assume normal death speed.
  212. if (timeScale == 0.0f && !d->hasNonLodEffects())
  213. {
  214. // Deaths happen instantly so just delete the object and return
  215. TheGameLogic->destroyObject(obj);
  216. return;
  217. }
  218. else
  219. {
  220. // timescale is some non-zero value so we may need to speed up death
  221. if( getObject()->isKindOf( KINDOF_HULK ) && TheGameLogic->getHulkMaxLifetimeOverride() != -1 )
  222. {
  223. //Scripts don't want hulks around, so start sinking immediately!
  224. m_sinkFrame = 1;
  225. m_midpointFrame = (LOGICFRAMES_PER_SECOND/2) + 1;
  226. m_destructionFrame = LOGICFRAMES_PER_SECOND + 1;
  227. m_acceleratedTimeScale = 1.0f;
  228. }
  229. else
  230. {
  231. m_sinkFrame = timeScale * (d->m_sinkDelay + GameLogicRandomValue(0, d->m_sinkDelayVariance));
  232. m_destructionFrame = timeScale * (d->m_destructionDelay + GameLogicRandomValue(0, d->m_destructionDelayVariance));
  233. m_midpointFrame = GameLogicRandomValue( BEGIN_MIDPOINT_RATIO * m_destructionFrame, END_MIDPOINT_RATIO * m_destructionFrame );
  234. m_acceleratedTimeScale = timeScale;
  235. }
  236. }
  237. UnsignedInt now = TheGameLogic->getFrame();
  238. if (d->m_flingForce > 0)
  239. {
  240. //Just in case this is a stingersoldier or other HELD object, lets set them free so they will fly
  241. // with their own physics during slow death
  242. if( obj->isDisabledByType( DISABLED_HELD ) )
  243. {
  244. static NameKeyType key_SlavedUpdate = NAMEKEY( "SlavedUpdate" );
  245. SlavedUpdate* slave = (SlavedUpdate*)obj->findUpdateModule( key_SlavedUpdate );
  246. if( slave )
  247. {
  248. slave->onSlaverDie( NULL );
  249. }
  250. }
  251. PhysicsBehavior* physics = obj->getPhysics();
  252. if (physics)
  253. {
  254. // make sure we are at least a bit above the ground
  255. const Real MIN_ALTITUDE = 1.0f;
  256. Real altitude = obj->getHeightAboveTerrain();
  257. if (altitude < MIN_ALTITUDE)
  258. {
  259. Coord3D pos = *obj->getPosition();
  260. pos.z += MIN_ALTITUDE;
  261. obj->setPosition(&pos);
  262. }
  263. Coord3D force;
  264. calcRandomForce(d->m_flingForce, d->m_flingForce + d->m_flingForceVariance,
  265. d->m_flingPitch, d->m_flingPitch + d->m_flingPitchVariance, force);
  266. physics->setAllowToFall(true);
  267. physics->applyForce(&force);
  268. physics->setExtraBounciness(-1.0); // we don't want this guy to bounce at all
  269. physics->setExtraFriction(-3 * SECONDS_PER_LOGICFRAME_REAL); // reduce his ground friction a bit
  270. physics->setAllowBouncing(true);
  271. Real orientation = atan2(force.y, force.x);
  272. physics->setAngles(orientation, 0, 0);
  273. obj->getDrawable()->setModelConditionState(MODELCONDITION_EXPLODED_FLAILING);
  274. m_flags |= (1<<FLUNG_INTO_AIR);
  275. }
  276. setWakeFrame(obj, UPDATE_SLEEP_NONE);
  277. }
  278. else
  279. {
  280. // we don't need to wake up immediately, but only when the first of these
  281. // counters wants to trigger....
  282. Int whenToWakeTime = m_sinkFrame;
  283. if (whenToWakeTime > m_destructionFrame)
  284. whenToWakeTime = m_destructionFrame;
  285. if (whenToWakeTime > m_midpointFrame)
  286. whenToWakeTime = m_midpointFrame;
  287. setWakeFrame(obj, UPDATE_SLEEP(whenToWakeTime));
  288. }
  289. m_sinkFrame += now;
  290. m_destructionFrame += now;
  291. m_midpointFrame += now;
  292. m_flags |= (1<<SLOW_DEATH_ACTIVATED);
  293. doPhaseStuff(SDPHASE_INITIAL);
  294. }
  295. }
  296. //-------------------------------------------------------------------------------------------------
  297. //-------------------------------------------------------------------------------------------------
  298. void SlowDeathBehavior::doPhaseStuff(SlowDeathPhaseType sdphase)
  299. {
  300. const SlowDeathBehaviorModuleData* d = getSlowDeathBehaviorModuleData();
  301. Int idx, listSize;
  302. if (!d->m_maskOfLoadedEffects)
  303. return; //has no ocl, fx, or weapons.
  304. listSize = d->m_fx[sdphase].size();
  305. if (listSize > 0)
  306. {
  307. idx = GameLogicRandomValue(0, listSize-1);
  308. const FXListVec& v = d->m_fx[sdphase];
  309. DEBUG_ASSERTCRASH(idx>=0&&idx<v.size(),("bad idx"));
  310. const FXList* fxl = v[idx];
  311. FXList::doFXObj(fxl, getObject(), NULL);
  312. }
  313. listSize = d->m_ocls[sdphase].size();
  314. if (listSize > 0)
  315. {
  316. idx = GameLogicRandomValue(0, listSize-1);
  317. const OCLVec& v = d->m_ocls[sdphase];
  318. DEBUG_ASSERTCRASH(idx>=0&&idx<v.size(),("bad idx"));
  319. const ObjectCreationList* ocl = v[idx];
  320. ObjectCreationList::create(ocl, getObject(), NULL);
  321. }
  322. listSize = d->m_weapons[sdphase].size();
  323. if (listSize > 0)
  324. {
  325. idx = GameLogicRandomValue(0, listSize-1);
  326. const WeaponTemplateVec& v = d->m_weapons[sdphase];
  327. DEBUG_ASSERTCRASH(idx>=0&&idx<v.size(),("bad idx"));
  328. const WeaponTemplate* wt = v[idx];
  329. if (wt)
  330. {
  331. TheWeaponStore->createAndFireTempWeapon(wt, getObject(), getObject()->getPosition());
  332. }
  333. }
  334. }
  335. //-------------------------------------------------------------------------------------------------
  336. //-------------------------------------------------------------------------------------------------
  337. UpdateSleepTime SlowDeathBehavior::update()
  338. {
  339. //DEBUG_LOG(("updating SlowDeathBehavior %08lx\n",this));
  340. DEBUG_ASSERTCRASH(isSlowDeathActivated(), ("hmm, this should not be possible"));
  341. const SlowDeathBehaviorModuleData* d = getSlowDeathBehaviorModuleData();
  342. Object* obj = getObject();
  343. Real timeScale = TheGameLODManager->getSlowDeathScale();
  344. // Check if we have normal time scale but LODManager is requeseting acceleration
  345. if (timeScale != 1.0f && m_acceleratedTimeScale == 1.0f && !d->hasNonLodEffects())
  346. {
  347. // speed of deaths has been increased since beginning of death
  348. // so adjust it to current levels.
  349. if (timeScale == 0)
  350. {
  351. // instant death
  352. TheGameLogic->destroyObject(obj);
  353. return UPDATE_SLEEP_NONE;
  354. }
  355. m_sinkFrame = (Real)m_sinkFrame * timeScale;
  356. m_midpointFrame = (Real)m_midpointFrame * timeScale;
  357. m_destructionFrame = (Real)m_destructionFrame * timeScale;
  358. m_acceleratedTimeScale = timeScale;
  359. };
  360. UnsignedInt now = TheGameLogic->getFrame();
  361. if ((m_flags & (1<<FLUNG_INTO_AIR)) != 0)
  362. {
  363. if ((m_flags & (1<<BOUNCED)) == 0)
  364. {
  365. ++m_sinkFrame;
  366. ++m_midpointFrame;
  367. ++m_destructionFrame;
  368. if (!obj->isAboveTerrain())
  369. {
  370. obj->clearAndSetModelConditionFlags(MAKE_MODELCONDITION_MASK(MODELCONDITION_EXPLODED_FLAILING),
  371. MAKE_MODELCONDITION_MASK(MODELCONDITION_EXPLODED_BOUNCING));
  372. m_flags |= (1<<BOUNCED);
  373. }
  374. // Here we want to make sure we die if we collide with a tree on the way down
  375. PhysicsBehavior *phys = obj->getPhysics();
  376. if ( phys )
  377. {
  378. ObjectID treeID = phys->getLastCollidee();
  379. Object *tree = TheGameLogic->findObjectByID( treeID );
  380. if ( tree )
  381. {
  382. if (tree->isKindOf( KINDOF_SHRUBBERY ) )
  383. {
  384. obj->setDisabled( DISABLED_HELD );
  385. obj->clearModelConditionFlags( MAKE_MODELCONDITION_MASK(MODELCONDITION_EXPLODED_FLAILING) );
  386. obj->clearModelConditionFlags( MAKE_MODELCONDITION_MASK(MODELCONDITION_EXPLODED_BOUNCING) );
  387. obj->setModelConditionFlags( MAKE_MODELCONDITION_MASK(MODELCONDITION_PARACHUTING) ); //looks like he is snagged in a tree
  388. obj->setPositionZ( obj->getPosition()->z - (d->m_sinkRate * 50.0f) );// make him sink faster
  389. if ( !obj->isAboveTerrain() )
  390. TheGameLogic->destroyObject(obj);
  391. }
  392. }
  393. }
  394. }
  395. }
  396. if ( (now >= m_sinkFrame && d->m_sinkRate > 0.0f) )
  397. {
  398. // disable Physics (if any) so that we can control the sink...
  399. obj->setDisabled( DISABLED_HELD );
  400. Coord3D pos = *obj->getPosition();
  401. pos.z -= d->m_sinkRate / m_acceleratedTimeScale;
  402. obj->setPosition( &pos );
  403. }
  404. if( now >= m_midpointFrame && (m_flags & (1<<MIDPOINT_EXECUTED)) == 0 )
  405. {
  406. doPhaseStuff(SDPHASE_MIDPOINT);
  407. m_flags |= (1<<MIDPOINT_EXECUTED);
  408. }
  409. if (now >= m_destructionFrame)
  410. {
  411. doPhaseStuff(SDPHASE_FINAL);
  412. TheGameLogic->destroyObject(obj);
  413. }
  414. return UPDATE_SLEEP_NONE;
  415. }
  416. //-------------------------------------------------------------------------------------------------
  417. void SlowDeathBehavior::onDie( const DamageInfo *damageInfo )
  418. {
  419. Object *obj = getObject();
  420. if (!isDieApplicable(damageInfo))
  421. return;
  422. AIUpdateInterface *ai = obj->getAIUpdateInterface();
  423. if (ai)
  424. {
  425. // has another AI already handled us. (hopefully another SlowDeathBehavior)
  426. if (ai->isAiInDeadState())
  427. return;
  428. ai->markAsDead();
  429. }
  430. // deselect this unit for all players.
  431. TheGameLogic->deselectObject(obj, PLAYERMASK_ALL, TRUE);
  432. Int total = 0;
  433. for (BehaviorModule** update = obj->getBehaviorModules(); *update; ++update)
  434. {
  435. SlowDeathBehaviorInterface* sdu = (*update)->getSlowDeathBehaviorInterface();
  436. if (sdu != NULL && sdu->isDieApplicable(damageInfo))
  437. {
  438. total += sdu->getProbabilityModifier( damageInfo );
  439. }
  440. }
  441. DEBUG_ASSERTCRASH(total > 0, ("Hmm, this is wrong"));
  442. // this returns a value from 1...total, inclusive
  443. Int roll = GameLogicRandomValue(1, total);
  444. for (/* UpdateModuleInterface** */ update = obj->getBehaviorModules(); *update; ++update)
  445. {
  446. SlowDeathBehaviorInterface* sdu = (*update)->getSlowDeathBehaviorInterface();
  447. if (sdu != NULL && sdu->isDieApplicable(damageInfo))
  448. {
  449. roll -= sdu->getProbabilityModifier( damageInfo );
  450. if (roll <= 0)
  451. {
  452. sdu->beginSlowDeath(damageInfo);
  453. return;
  454. }
  455. }
  456. }
  457. DEBUG_CRASH(("We should never get here"));
  458. }
  459. // ------------------------------------------------------------------------------------------------
  460. /** CRC */
  461. // ------------------------------------------------------------------------------------------------
  462. void SlowDeathBehavior::crc( Xfer *xfer )
  463. {
  464. // extend base class
  465. UpdateModule::crc( xfer );
  466. } // end crc
  467. // ------------------------------------------------------------------------------------------------
  468. /** Xfer method
  469. * Version Info:
  470. * 1: Initial version */
  471. // ------------------------------------------------------------------------------------------------
  472. void SlowDeathBehavior::xfer( Xfer *xfer )
  473. {
  474. // version
  475. XferVersion currentVersion = 1;
  476. XferVersion version = currentVersion;
  477. xfer->xferVersion( &version, currentVersion );
  478. // extend base class
  479. UpdateModule::xfer( xfer );
  480. // sink frame
  481. xfer->xferUnsignedInt( &m_sinkFrame );
  482. // midpoint frame
  483. xfer->xferUnsignedInt( &m_midpointFrame );
  484. // destruction frame
  485. xfer->xferUnsignedInt( &m_destructionFrame );
  486. // accelerated time scale
  487. xfer->xferReal( &m_acceleratedTimeScale );
  488. // flags
  489. xfer->xferUnsignedInt( &m_flags );
  490. } // end xfer
  491. // ------------------------------------------------------------------------------------------------
  492. /** Load post process */
  493. // ------------------------------------------------------------------------------------------------
  494. void SlowDeathBehavior::loadPostProcess( void )
  495. {
  496. // extend base class
  497. UpdateModule::loadPostProcess();
  498. } // end loadPostProcess