PropagandaTowerBehavior.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  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: PropagandaTowerBehavior.cpp //////////////////////////////////////////////////////////////
  24. // Author: Colin Day, August 2002
  25. // Desc: Behavior module for PropagandaTower
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h"
  29. #include "Common/GameState.h"
  30. #include "Common/Player.h"
  31. #include "Common/PlayerList.h"
  32. #include "Common/Upgrade.h"
  33. #include "Common/Xfer.h"
  34. #include "GameClient/Drawable.h"
  35. #include "GameClient/FXList.h"
  36. #include "GameLogic/GameLogic.h"
  37. #include "GameLogic/Object.h"
  38. #include "GameLogic/PartitionManager.h"
  39. #include "GameLogic/Weapon.h"
  40. #include "GameLogic/Module/PropagandaTowerBehavior.h"
  41. #include "GameLogic/Module/BodyModule.h"
  42. #ifdef _INTERNAL
  43. // for occasional debugging...
  44. //#pragma optimize("", off)
  45. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  46. #endif
  47. // FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
  48. enum ObjectID;
  49. // ------------------------------------------------------------------------------------------------
  50. /** This class is used to track objects as they exit our area of influence */
  51. // ------------------------------------------------------------------------------------------------
  52. class ObjectTracker : public MemoryPoolObject
  53. {
  54. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( ObjectTracker, "ObjectTracker" );
  55. public:
  56. ObjectTracker( void ) { objectID = INVALID_ID; next = NULL; }
  57. ObjectID objectID;
  58. ObjectTracker *next;
  59. };
  60. ObjectTracker::~ObjectTracker( void ) { }
  61. ///////////////////////////////////////////////////////////////////////////////////////////////////
  62. ///////////////////////////////////////////////////////////////////////////////////////////////////
  63. ///////////////////////////////////////////////////////////////////////////////////////////////////
  64. // ------------------------------------------------------------------------------------------------
  65. // ------------------------------------------------------------------------------------------------
  66. PropagandaTowerBehaviorModuleData::PropagandaTowerBehaviorModuleData( void )
  67. {
  68. m_scanRadius = 1.0f;
  69. m_scanDelayInFrames = 100;
  70. m_autoHealPercentPerSecond = 0.01f;
  71. m_upgradedAutoHealPercentPerSecond = 0.02f;
  72. m_pulseFX = NULL;
  73. m_upgradeRequired = NULL;
  74. m_upgradedPulseFX = NULL;
  75. m_affectsSelf = FALSE;
  76. } // end PropagandaTowerBehaviorModuleData
  77. // ------------------------------------------------------------------------------------------------
  78. // ------------------------------------------------------------------------------------------------
  79. /*static*/ void PropagandaTowerBehaviorModuleData::buildFieldParse( MultiIniFieldParse &p )
  80. {
  81. UpdateModuleData::buildFieldParse( p );
  82. static const FieldParse dataFieldParse[] =
  83. {
  84. { "Radius", INI::parseReal, NULL, offsetof( PropagandaTowerBehaviorModuleData, m_scanRadius ) },
  85. { "DelayBetweenUpdates", INI::parseDurationUnsignedInt, NULL, offsetof( PropagandaTowerBehaviorModuleData, m_scanDelayInFrames ) },
  86. { "HealPercentEachSecond", INI::parsePercentToReal, NULL, offsetof( PropagandaTowerBehaviorModuleData, m_autoHealPercentPerSecond ) },
  87. { "UpgradedHealPercentEachSecond", INI::parsePercentToReal,NULL, offsetof( PropagandaTowerBehaviorModuleData, m_upgradedAutoHealPercentPerSecond ) },
  88. { "PulseFX", INI::parseFXList, NULL, offsetof( PropagandaTowerBehaviorModuleData, m_pulseFX ) },
  89. { "UpgradeRequired", INI::parseAsciiString, NULL, offsetof( PropagandaTowerBehaviorModuleData, m_upgradeRequired ) },
  90. { "UpgradedPulseFX", INI::parseFXList, NULL, offsetof( PropagandaTowerBehaviorModuleData, m_upgradedPulseFX ) },
  91. { "AffectsSelf", INI::parseBool, NULL, offsetof( PropagandaTowerBehaviorModuleData, m_affectsSelf ) },
  92. { 0, 0, 0, 0 }
  93. };
  94. p.add( dataFieldParse );
  95. } // end buildFieldParse
  96. ///////////////////////////////////////////////////////////////////////////////////////////////////
  97. ///////////////////////////////////////////////////////////////////////////////////////////////////
  98. ///////////////////////////////////////////////////////////////////////////////////////////////////
  99. // ------------------------------------------------------------------------------------------------
  100. // ------------------------------------------------------------------------------------------------
  101. PropagandaTowerBehavior::PropagandaTowerBehavior( Thing *thing, const ModuleData *modData )
  102. : UpdateModule( thing, modData )
  103. {
  104. //Added By Sadullah Nader
  105. //Initializations inserted
  106. m_lastScanFrame = 0;
  107. //
  108. m_insideList = NULL;
  109. setWakeFrame( getObject(), UPDATE_SLEEP_NONE );
  110. } // end PropagandaTowerBehavior
  111. // ------------------------------------------------------------------------------------------------
  112. // ------------------------------------------------------------------------------------------------
  113. PropagandaTowerBehavior::~PropagandaTowerBehavior( void )
  114. {
  115. } // end ~PropagandaTowerBehavior
  116. // ------------------------------------------------------------------------------------------------
  117. /** Module is being deleted */
  118. // ------------------------------------------------------------------------------------------------
  119. void PropagandaTowerBehavior::onDelete( void )
  120. {
  121. // remove any benefits from anybody in our area of influence
  122. removeAllInfluence();
  123. } // end onDelete
  124. // ------------------------------------------------------------------------------------------------
  125. /** Resolve */
  126. // ------------------------------------------------------------------------------------------------
  127. void PropagandaTowerBehavior::onObjectCreated( void )
  128. {
  129. const PropagandaTowerBehaviorModuleData *modData = getPropagandaTowerBehaviorModuleData();
  130. // convert module upgrade name to a pointer
  131. m_upgradeRequired = TheUpgradeCenter->findUpgrade( modData->m_upgradeRequired );
  132. } // end onObjectCreated
  133. // ------------------------------------------------------------------------------------------------
  134. void PropagandaTowerBehavior::onCapture( Player *oldOwner, Player *newOwner )
  135. {
  136. // We don't function for the neutral player.
  137. if( newOwner == ThePlayerList->getNeutralPlayer() )
  138. {
  139. removeAllInfluence();
  140. setWakeFrame( getObject(), UPDATE_SLEEP_FOREVER );
  141. }
  142. else
  143. setWakeFrame( getObject(), UPDATE_SLEEP_NONE );
  144. }
  145. // ------------------------------------------------------------------------------------------------
  146. /** The update callback */
  147. // ------------------------------------------------------------------------------------------------
  148. UpdateSleepTime PropagandaTowerBehavior::update( void )
  149. {
  150. /// @todo srj use SLEEPY_UPDATE here
  151. const PropagandaTowerBehaviorModuleData *modData = getPropagandaTowerBehaviorModuleData();
  152. //Sep 27, 2002 (Kris): Added this code to prevent the tower from working while under construction.
  153. Object *self = getObject();
  154. if( self->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  155. return UPDATE_SLEEP_NONE;
  156. if( self->testStatus(OBJECT_STATUS_SOLD) )
  157. {
  158. removeAllInfluence();
  159. return UPDATE_SLEEP_FOREVER;
  160. }
  161. if( self->isEffectivelyDead() )
  162. return UPDATE_SLEEP_FOREVER;
  163. if( self->isDisabled() )
  164. {
  165. // We need to let go of everyone if we are EMPd or underpowered or yadda, but not if we are only held
  166. DisabledMaskType allButHeld = MAKE_DISABLED_MASK( DISABLED_HELD );
  167. FLIP_DISABLEDMASK(allButHeld);
  168. if( TEST_DISABLEDMASK_ANY(self->getDisabledFlags(), allButHeld) )
  169. {
  170. removeAllInfluence();
  171. return UPDATE_SLEEP_NONE;
  172. }
  173. }
  174. if( self->getContainedBy() && self->getContainedBy()->getContainedBy() )
  175. {
  176. // If our container is contained, we turn the heck off. Seems like a weird specific check, but all of
  177. // attacking is guarded by the same check in isPassengersAllowedToFire. We similarly work in a container,
  178. // but not in a double container.
  179. removeAllInfluence();
  180. return UPDATE_SLEEP_NONE;
  181. }
  182. // if it's not time to scan, nothing to do
  183. UnsignedInt currentFrame = TheGameLogic->getFrame();
  184. if( currentFrame - m_lastScanFrame >= modData->m_scanDelayInFrames )
  185. {
  186. // do a scan
  187. doScan();
  188. m_lastScanFrame = currentFrame;
  189. } // end if
  190. // go through any objects in our area of influence and do the effect logic on them
  191. Object *obj;
  192. ObjectTracker *curr = NULL, *prev = NULL, *next = NULL;
  193. for( curr = m_insideList; curr; curr = next )
  194. {
  195. // get the next link
  196. next = curr->next;
  197. // find this object
  198. obj = TheGameLogic->findObjectByID( curr->objectID );
  199. if ((obj) &&
  200. (obj->isKindOf(KINDOF_SCORE) || obj->isKindOf(KINDOF_SCORE_CREATE) || obj->isKindOf(KINDOF_SCORE_DESTROY) || obj->isKindOf(KINDOF_MP_COUNT_FOR_VICTORY)))
  201. {
  202. // give any bonus to this object
  203. effectLogic( obj, TRUE, getPropagandaTowerBehaviorModuleData() );
  204. // record this element as the previous one found in the list
  205. prev = curr;
  206. } // end if
  207. else
  208. {
  209. //
  210. // actual object wasn't found, remove this entry from our inside list so we don't
  211. // have to search through it again
  212. //
  213. if( prev )
  214. prev->next = curr->next;
  215. else
  216. m_insideList = curr->next;
  217. curr->deleteInstance();
  218. } // end else
  219. } // end for, curr
  220. return UPDATE_SLEEP_NONE;
  221. } // end update
  222. // ------------------------------------------------------------------------------------------------
  223. /** The death callback */
  224. // ------------------------------------------------------------------------------------------------
  225. void PropagandaTowerBehavior::onDie( const DamageInfo *damageInfo )
  226. {
  227. // remove any benefits from anybody in our area of influence
  228. removeAllInfluence();
  229. } // end onDie
  230. ///////////////////////////////////////////////////////////////////////////////////////////////////
  231. ///////////////////////////////////////////////////////////////////////////////////////////////////
  232. ///////////////////////////////////////////////////////////////////////////////////////////////////
  233. // ------------------------------------------------------------------------------------------------
  234. /** Grant or remove effect to this object */
  235. // ------------------------------------------------------------------------------------------------
  236. void PropagandaTowerBehavior::effectLogic( Object *obj, Bool giving,
  237. const PropagandaTowerBehaviorModuleData *modData )
  238. {
  239. Bool effectUpgraded = getObject()->getControllingPlayer()->hasUpgradeComplete( m_upgradeRequired );
  240. // if giving the effect
  241. if( giving )
  242. {
  243. if ( obj->hasAnyDamageWeapon() == TRUE )
  244. {
  245. if( obj->testWeaponBonusCondition( WEAPONBONUSCONDITION_ENTHUSIASTIC ) == FALSE )
  246. obj->setWeaponBonusCondition( WEAPONBONUSCONDITION_ENTHUSIASTIC );
  247. if (effectUpgraded)
  248. {
  249. if (obj->testWeaponBonusCondition( WEAPONBONUSCONDITION_SUBLIMINAL ) == FALSE)
  250. obj->setWeaponBonusCondition( WEAPONBONUSCONDITION_SUBLIMINAL );
  251. }
  252. } // hasdamageweapon
  253. // grant health to this object as well
  254. BodyModuleInterface *body = obj->getBodyModule();
  255. if( body )
  256. {
  257. Real healthPercent;
  258. if(effectUpgraded)
  259. healthPercent = modData->m_upgradedAutoHealPercentPerSecond;
  260. else
  261. healthPercent = modData->m_autoHealPercentPerSecond;
  262. Real amount = healthPercent / LOGICFRAMES_PER_SECOND * body->getMaxHealth();
  263. // Dustin wants the healing effect not to stack from multiple propaganda towers...
  264. // To accomplish this, I'll give every object a single healing-sender (ID)
  265. // Any given healing recipient (object) can only receive healing from one particular healing sender
  266. // and cannot change healing senders until the previous one expires (its scandelay)
  267. // obj->attemptHealing(amount, getObject()); // the regular way to give healing...
  268. obj->attemptHealingFromSoleBenefactor( amount, getObject(), modData->m_scanDelayInFrames );//the non-stacking way
  269. } // end if
  270. } // end if
  271. else
  272. {
  273. // taking effect away
  274. obj->clearWeaponBonusCondition( WEAPONBONUSCONDITION_ENTHUSIASTIC );
  275. obj->clearWeaponBonusCondition( WEAPONBONUSCONDITION_SUBLIMINAL );
  276. } // end else
  277. } // end effectLogic
  278. // ------------------------------------------------------------------------------------------------
  279. /** Remove all influence from objects we've given bonuses to */
  280. // ------------------------------------------------------------------------------------------------
  281. void PropagandaTowerBehavior::removeAllInfluence( void )
  282. {
  283. ObjectTracker *o;
  284. // go through all objects we've given bonuses to and remove them
  285. Object *obj;
  286. for( o = m_insideList; o; o = o->next )
  287. {
  288. obj = TheGameLogic->findObjectByID( o->objectID );
  289. if( obj )
  290. effectLogic( obj, FALSE, getPropagandaTowerBehaviorModuleData() );
  291. } // end for
  292. // delete the list of objects under our influence
  293. while( m_insideList )
  294. {
  295. o = m_insideList->next;
  296. m_insideList->deleteInstance();
  297. m_insideList = o;
  298. } // end while
  299. } // end removeAllInfluence
  300. // ------------------------------------------------------------------------------------------------
  301. /** Do a scan */
  302. // ------------------------------------------------------------------------------------------------
  303. void PropagandaTowerBehavior::doScan( void )
  304. {
  305. const PropagandaTowerBehaviorModuleData *modData = getPropagandaTowerBehaviorModuleData();
  306. Object *us = getObject();
  307. ObjectTracker *newInsideList = NULL;
  308. // The act of scanning is when we play our effect
  309. Bool upgradePresent = FALSE;
  310. if( m_upgradeRequired )
  311. {
  312. // see if we have the upgrade
  313. switch( m_upgradeRequired->getUpgradeType() )
  314. {
  315. // ------------------------------------------------------------------------------------------
  316. case UPGRADE_TYPE_PLAYER:
  317. {
  318. Player *player = us->getControllingPlayer();
  319. upgradePresent = player->hasUpgradeComplete( m_upgradeRequired );
  320. break;
  321. } // end player upgrade
  322. // ------------------------------------------------------------------------------------------
  323. case UPGRADE_TYPE_OBJECT:
  324. {
  325. upgradePresent = us->hasUpgrade( m_upgradeRequired );
  326. break;
  327. } // end object upgrade
  328. // ------------------------------------------------------------------------------------------
  329. default:
  330. {
  331. DEBUG_CRASH(( "PropagandaTowerBehavior::doScan - Unknown upgrade type '%d'\n",
  332. m_upgradeRequired->getUpgradeType() ));
  333. break;
  334. } // end default
  335. } // end switch
  336. } // end if
  337. Bool doFX = TRUE;
  338. // if it is us, or if it is he and we do see him
  339. Object *overlord = us->getContainedBy();
  340. if ( overlord )
  341. {
  342. if ( us->getControllingPlayer() != ThePlayerList->getLocalPlayer() )// daling with someone else's tower
  343. {
  344. if ( overlord->testStatus( OBJECT_STATUS_STEALTHED ) && !overlord->testStatus( OBJECT_STATUS_DETECTED ) )
  345. doFX = FALSE;// so they don't give up their position
  346. }
  347. // Sorry, this is a lot of hard coded mishmash, but it must be done... ship it!
  348. // Propaganda towers (proper) never get contained, so they don't care about this code
  349. // The PropTowers that ride on the backs of overlord tanks want to suppress their fx if the overlord is stealthed to the local player
  350. // The PropTowers that ride on the bellies of Helixes also suppress their fx when hiding stealthed (never happens?)
  351. // The PropTowers must do nothing, scanning-or-FX-wise when they are inside something... there are two cases
  352. // 1) When the prop tower is on an Overlord that is in a helicopter (likely a Helix II)
  353. // 2) When the prop tower is the EmperorTank, which is in a helicopter (likely a Helix II).
  354. if ( us->isKindOf( KINDOF_VEHICLE ) && !us->isKindOf( KINDOF_PORTABLE_STRUCTURE ) )//craptacular!
  355. // oh my dear Lord... I am not a propaganda tower, I am an emperorTank! that means the overlord is a helix or something!
  356. return; // proptowers that are riding IN things cannot do their scan!
  357. //okay this is wacky, but this proptower may be on an overlord thank that is riding in a helix... oy!
  358. Object *helix = overlord->getContainedBy();
  359. if ( helix )
  360. return; // proptowers that are riding ON things that are in-turn riding IN things cannot do their scan!
  361. }
  362. if ( us->getControllingPlayer() != ThePlayerList->getLocalPlayer() )// daling with someone else's tower
  363. {
  364. if ( us->testStatus( OBJECT_STATUS_STEALTHED ) && !us->testStatus( OBJECT_STATUS_DETECTED ) )
  365. {
  366. doFX = FALSE;// Certainly don't play if we ourselves are stelthed.
  367. }
  368. }
  369. if ( doFX )
  370. {
  371. // play the right pulse
  372. if( upgradePresent == TRUE )
  373. FXList::doFXObj( modData->m_upgradedPulseFX, us );
  374. else
  375. FXList::doFXObj( modData->m_pulseFX, us );
  376. }
  377. // setup scan filters
  378. PartitionFilterRelationship relationship( us, PartitionFilterRelationship::ALLOW_ALLIES );
  379. PartitionFilterAlive filterAlive;
  380. PartitionFilterSameMapStatus filterMapStatus(us);
  381. PartitionFilterAcceptByKindOf filterOutBuildings(KINDOFMASK_NONE, MAKE_KINDOF_MASK(KINDOF_STRUCTURE));
  382. PartitionFilter *filters[] = { &relationship,
  383. &filterAlive,
  384. &filterMapStatus,
  385. &filterOutBuildings,
  386. NULL
  387. };
  388. // scan objects in our region
  389. ObjectIterator *iter = ThePartitionManager->iterateObjectsInRange( us->getPosition(),
  390. modData->m_scanRadius,
  391. FROM_CENTER_2D,
  392. filters );
  393. MemoryPoolObjectHolder hold( iter );
  394. Object *obj;
  395. ObjectTracker *newEntry;
  396. for( obj = iter->first(); obj; obj = iter->next() )
  397. {
  398. // ignore ourselves, unless Design wants us to affect ourselves
  399. if( obj == us && !modData->m_affectsSelf)
  400. continue;
  401. // record this object as being in the new "in list"
  402. newEntry = newInstance(ObjectTracker);
  403. newEntry->objectID = obj->getID();
  404. newEntry->next = newInsideList;
  405. newInsideList = newEntry;
  406. } // end for obj
  407. //
  408. // now that we have a list of objects that are in our area of influence, look through
  409. // the objects that were last recorded as in our area of influence and remove any
  410. // bonus we've given them (if they are within the area of effect of another tower it's
  411. // OK, they'll get the bonus back again when that tower does a scan which won't be too long
  412. //
  413. for( ObjectTracker *curr = m_insideList; curr; curr = curr->next )
  414. {
  415. // find this entry in the new list
  416. ObjectTracker *o = NULL;
  417. for( o = newInsideList; o; o = o->next )
  418. if( o->objectID == curr->objectID )
  419. break;
  420. // if entry wasn't there, remove the bonus from this object
  421. if( o == NULL )
  422. {
  423. obj = TheGameLogic->findObjectByID( curr->objectID );
  424. if( obj )
  425. effectLogic( obj, FALSE, modData );
  426. } // end if
  427. } // end for
  428. // delete the inside list we have recoreded
  429. ObjectTracker *next;
  430. while( m_insideList )
  431. {
  432. next = m_insideList->next;
  433. m_insideList->deleteInstance();
  434. m_insideList = next;
  435. } // end while
  436. // set the new inside list to the one we're recording
  437. m_insideList = newInsideList;
  438. } // end doScan
  439. // ------------------------------------------------------------------------------------------------
  440. /** CRC */
  441. // ------------------------------------------------------------------------------------------------
  442. void PropagandaTowerBehavior::crc( Xfer *xfer )
  443. {
  444. // extend base class
  445. UpdateModule::crc( xfer );
  446. } // end crc
  447. // ------------------------------------------------------------------------------------------------
  448. /** Xfer method
  449. * Version Info:
  450. * 1: Initial version */
  451. // ------------------------------------------------------------------------------------------------
  452. void PropagandaTowerBehavior::xfer( Xfer *xfer )
  453. {
  454. // version
  455. XferVersion currentVersion = 1;
  456. XferVersion version = currentVersion;
  457. xfer->xferVersion( &version, currentVersion );
  458. // extend base class
  459. UpdateModule::xfer( xfer );
  460. // last scan frame
  461. xfer->xferUnsignedInt( &m_lastScanFrame );
  462. // inside list tracking
  463. ObjectTracker *trackerEntry;
  464. UnsignedShort insideCount = 0;
  465. for( trackerEntry = m_insideList; trackerEntry; trackerEntry = trackerEntry->next )
  466. insideCount++;
  467. xfer->xferUnsignedShort( &insideCount );
  468. if( xfer->getXferMode() == XFER_SAVE )
  469. {
  470. // write all entries
  471. for( trackerEntry = m_insideList; trackerEntry; trackerEntry = trackerEntry->next )
  472. {
  473. // object id
  474. xfer->xferObjectID( &trackerEntry->objectID );
  475. } // end for
  476. } // end if, save
  477. else
  478. {
  479. // sanity
  480. if( m_insideList != NULL )
  481. {
  482. DEBUG_CRASH(( "PropagandaTowerBehavior::xfer - m_insideList should be empty but is not\n" ));
  483. throw SC_INVALID_DATA;
  484. } // end if
  485. // read all entries
  486. for( UnsignedShort i = 0; i < insideCount; ++i )
  487. {
  488. // allocate new tracker entry and tie to list
  489. trackerEntry = newInstance(ObjectTracker);
  490. trackerEntry->next = m_insideList;
  491. m_insideList = trackerEntry;
  492. // read object id
  493. xfer->xferObjectID( &trackerEntry->objectID );
  494. } // end for i
  495. } // end else, load
  496. } // end xfer
  497. // ------------------------------------------------------------------------------------------------
  498. /** Load post process */
  499. // ------------------------------------------------------------------------------------------------
  500. void PropagandaTowerBehavior::loadPostProcess( void )
  501. {
  502. // extend base class
  503. UpdateModule::loadPostProcess();
  504. } // end loadPostProcess