BridgeBehavior.cpp 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483
  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: BridgeBehavior.cpp ///////////////////////////////////////////////////////////////////////
  24. // Author: Colin Day, July 2002
  25. // Desc: Behavior module for bridges
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/Radar.h"
  30. #include "Common/ThingFactory.h"
  31. #include "Common/ThingTemplate.h"
  32. #include "Common/Xfer.h"
  33. #include "GameClient/InGameUI.h"
  34. #include "GameClient/FXList.h"
  35. #include "GameClient/Line2D.h"
  36. #include "GameClient/TerrainRoads.h"
  37. #include "GameLogic/AI.h"
  38. #include "GameLogic/AIPathfind.h"
  39. #include "GameLogic/Object.h"
  40. #include "GameLogic/GameLogic.h"
  41. #include "GameLogic/ObjectCreationList.h"
  42. #include "GameLogic/Module/BodyModule.h"
  43. #include "GameLogic/Module/BridgeBehavior.h"
  44. #include "GameLogic/Module/BridgeScaffoldBehavior.h"
  45. #include "GameLogic/Module/PhysicsUpdate.h"
  46. #include "GameLogic/PartitionManager.h"
  47. #include "GameLogic/TerrainLogic.h"
  48. ///////////////////////////////////////////////////////////////////////////////////////////////////
  49. ///////////////////////////////////////////////////////////////////////////////////////////////////
  50. ///////////////////////////////////////////////////////////////////////////////////////////////////
  51. // ------------------------------------------------------------------------------------------------
  52. // ------------------------------------------------------------------------------------------------
  53. BridgeBehaviorModuleData::BridgeBehaviorModuleData( void )
  54. {
  55. m_lateralScaffoldSpeed = 1.0f;
  56. m_verticalScaffoldSpeed = 1.0f;
  57. } // end BridgeBehaviorModuleData
  58. // ------------------------------------------------------------------------------------------------
  59. // ------------------------------------------------------------------------------------------------
  60. BridgeBehaviorModuleData::~BridgeBehaviorModuleData( void )
  61. {
  62. // clear the fx list
  63. m_fx.clear();
  64. // clear the ocl list
  65. m_ocl.clear();
  66. } // end ~BridgeBehaviorModuleData
  67. // ------------------------------------------------------------------------------------------------
  68. // ------------------------------------------------------------------------------------------------
  69. /*static*/ void BridgeBehaviorModuleData::buildFieldParse( MultiIniFieldParse &p )
  70. {
  71. BehaviorModuleData::buildFieldParse( p );
  72. static const FieldParse dataFieldParse[] =
  73. {
  74. { "LateralScaffoldSpeed", INI::parseVelocityReal, NULL, offsetof( BridgeBehaviorModuleData, m_lateralScaffoldSpeed ) },
  75. { "VerticalScaffoldSpeed", INI::parseVelocityReal, NULL, offsetof( BridgeBehaviorModuleData, m_verticalScaffoldSpeed ) },
  76. { "BridgeDieFX", parseFX, NULL, offsetof( BridgeBehaviorModuleData, m_fx ) },
  77. { "BridgeDieOCL", parseOCL, NULL, offsetof( BridgeBehaviorModuleData, m_ocl ) },
  78. { 0, 0, 0, 0 }
  79. };
  80. p.add( dataFieldParse );
  81. } // end buildFieldParse
  82. // ------------------------------------------------------------------------------------------------
  83. /** Parse time and location info in the form of:
  84. * Delay:#### <Bone:BoneName> */
  85. // ------------------------------------------------------------------------------------------------
  86. static void parseTimeAndLocationInfo( INI *ini, void *instance,
  87. TimeAndLocationInfo *timeAndLocationInfo )
  88. {
  89. // delay label
  90. const char *token = ini->getNextToken( ini->getSepsColon() );
  91. if( stricmp( token, "Delay" ) != 0 )
  92. {
  93. DEBUG_CRASH(( "Expected 'Delay' token, found '%s'\n", token ));
  94. throw INI_INVALID_DATA;
  95. } // end if
  96. // delay value
  97. ini->parseDurationUnsignedInt( ini, instance, &timeAndLocationInfo->delay, NULL );
  98. // get optional bone label
  99. token = ini->getNextTokenOrNull( ini->getSepsColon() );
  100. if( token )
  101. {
  102. // token must be a label for bone location
  103. if( stricmp( token, "Bone" ) != 0 )
  104. {
  105. DEBUG_CRASH(( "Expected 'Bone' token, found '%s'\n", token ));
  106. throw INI_INVALID_DATA;
  107. } // end if
  108. // read bone name and store
  109. timeAndLocationInfo->boneName = ini->getNextAsciiString();
  110. } // end if
  111. } // end parseTimeAndLocationInfo
  112. //-------------------------------------------------------------------------------------------------
  113. // ------------------------------------------------------------------------------------------------
  114. /*static*/ void BridgeBehaviorModuleData::parseFX( INI *ini,
  115. void *instance,
  116. void *store,
  117. const void *userData )
  118. {
  119. const char *token;
  120. // create item we will read into and push on list
  121. BridgeFXInfo item;
  122. item.fx = NULL;
  123. // get list to store at
  124. BridgeFXList *bridgeFXList = (BridgeFXList *)store;
  125. // fx list label
  126. token = ini->getNextToken( ini->getSepsColon() );
  127. if( stricmp( token, "FX" ) != 0 )
  128. {
  129. DEBUG_CRASH(( "Expected 'FX' token, found '%s'\n", token ));
  130. throw INI_INVALID_DATA;
  131. } // end if
  132. // fx list name and store as pointer
  133. FXList *fx;
  134. ini->parseFXList( ini, instance, &fx, NULL );
  135. // store fx list to item
  136. item.fx = fx;
  137. // parse the timing and location info
  138. parseTimeAndLocationInfo( ini, instance, &item.timeAndLocationInfo );
  139. // put on list
  140. bridgeFXList->push_back( item );
  141. } // end parseFX
  142. // ------------------------------------------------------------------------------------------------
  143. // ------------------------------------------------------------------------------------------------
  144. /*static*/ void BridgeBehaviorModuleData::parseOCL( INI *ini,
  145. void *instance,
  146. void *store,
  147. const void *userData )
  148. {
  149. const char *token;
  150. // create item we will read into and push on list
  151. BridgeOCLInfo item;
  152. item.ocl = NULL;
  153. // get list to store at
  154. BridgeOCLList *bridgeOCLList = (BridgeOCLList *)store;
  155. // fx list label
  156. token = ini->getNextToken( ini->getSepsColon() );
  157. if( stricmp( token, "OCL" ) != 0 )
  158. {
  159. DEBUG_CRASH(( "Expected 'OCL' token, found '%s'\n", token ));
  160. throw INI_INVALID_DATA;
  161. } // end if
  162. // fx list name and store as pointer
  163. ObjectCreationList *ocl;
  164. ini->parseObjectCreationList( ini, instance, &ocl, NULL );
  165. // store ocl list to item
  166. item.ocl = ocl;
  167. // parse the timing and location info
  168. parseTimeAndLocationInfo( ini, instance, &item.timeAndLocationInfo );
  169. // put on list
  170. bridgeOCLList->push_back( item );
  171. } // end parseOCL
  172. ///////////////////////////////////////////////////////////////////////////////////////////////////
  173. ///////////////////////////////////////////////////////////////////////////////////////////////////
  174. ///////////////////////////////////////////////////////////////////////////////////////////////////
  175. // ------------------------------------------------------------------------------------------------
  176. // ------------------------------------------------------------------------------------------------
  177. BridgeBehavior::BridgeBehavior( Thing *thing, const ModuleData *moduleData )
  178. : UpdateModule( thing, moduleData )
  179. {
  180. Int i;
  181. m_scaffoldObjectIDList.clear();
  182. m_scaffoldPresent = FALSE;
  183. for( i = 0; i < BRIDGE_MAX_TOWERS; ++i )
  184. m_towerID[ i ] = INVALID_ID;
  185. m_fxResolved = FALSE;
  186. for( Int bodyState = BODY_PRISTINE; bodyState < BODYDAMAGETYPE_COUNT; ++bodyState )
  187. {
  188. // initialize the fx and ocl lists
  189. for( i = 0; i < MAX_BRIDGE_BODY_FX; ++i )
  190. {
  191. m_damageToOCL[ bodyState ][ i ] = NULL;
  192. m_damageToFX[ bodyState ][ i ] = NULL;
  193. m_repairToOCL[ bodyState ][ i ] = NULL;
  194. m_repairToFX[ bodyState ][ i ] = NULL;
  195. } // end for i
  196. // these don't need initialization, they have constructors
  197. // m_damageToSound[ bodyState ] = ???
  198. // m_repairToSound[ bodyState ] = ???
  199. } // end for, bodyState
  200. m_deathFrame = 0;
  201. } // end BridgeBehavior
  202. // ------------------------------------------------------------------------------------------------
  203. // ------------------------------------------------------------------------------------------------
  204. BridgeBehavior::~BridgeBehavior( void )
  205. {
  206. //
  207. // destroy our four towers if they are still present in the world (they wouldn't be if we
  208. // are resetting the engine, and those towers were earlier in the destruction list than
  209. // we were)
  210. //
  211. for( Int i = 0; i < BRIDGE_MAX_TOWERS; ++i )
  212. {
  213. Object *tower;
  214. // get the tower and destroy
  215. tower = TheGameLogic->findObjectByID( getTowerID( (BridgeTowerType)i ) );
  216. if( tower )
  217. TheGameLogic->destroyObject( tower );
  218. } // end for i
  219. } // end ~BridgeBehavior
  220. // ------------------------------------------------------------------------------------------------
  221. /** Get bridge behavior interface */
  222. // ------------------------------------------------------------------------------------------------
  223. /*static */BridgeBehaviorInterface *BridgeBehavior::getBridgeBehaviorInterfaceFromObject( Object *obj )
  224. {
  225. // sanity
  226. if( obj == NULL )
  227. return NULL;
  228. BehaviorModule **bmi;
  229. BridgeBehaviorInterface *bbi = NULL;
  230. for( bmi = obj->getBehaviorModules(); *bmi; ++bmi )
  231. {
  232. bbi = (*bmi)->getBridgeBehaviorInterface();
  233. if( bbi )
  234. return bbi;
  235. } // end for, bmi
  236. // interface not found
  237. return NULL;
  238. } // end getBridgeBehaviorInterfaceFromObject
  239. // ------------------------------------------------------------------------------------------------
  240. // ------------------------------------------------------------------------------------------------
  241. void BridgeBehavior::onDelete( void )
  242. {
  243. // clear the list of scaffold objects
  244. m_scaffoldObjectIDList.clear();
  245. } // end onDelete
  246. // ------------------------------------------------------------------------------------------------
  247. // ------------------------------------------------------------------------------------------------
  248. void BridgeBehavior::resolveFX( void )
  249. {
  250. Object *us = getObject();
  251. Bridge *bridge = TheTerrainLogic->findBridgeAt( us->getPosition() );
  252. // sanity
  253. if( bridge == NULL )
  254. return;
  255. // get the bridge template name
  256. AsciiString bridgeTemplateName = bridge->getBridgeTemplateName();
  257. // find the bridge template
  258. TerrainRoadType *bridgeTemplate = TheTerrainRoads->findBridge( bridgeTemplateName );
  259. // sanity
  260. if( bridgeTemplate == NULL )
  261. return;
  262. AsciiString name;
  263. for( Int bodyState = BODY_PRISTINE; bodyState < BODYDAMAGETYPE_COUNT; ++bodyState )
  264. {
  265. // initialize the fx and ocl lists
  266. for( Int i = 0; i < MAX_BRIDGE_BODY_FX; ++i )
  267. {
  268. name = bridgeTemplate->getDamageToOCLString( (BodyDamageType)bodyState, i );
  269. m_damageToOCL[ bodyState ][ i ] = TheObjectCreationListStore->findObjectCreationList( name.str() );
  270. if( name.isEmpty() == FALSE && m_damageToOCL[ bodyState ][ i ] == NULL )
  271. DEBUG_CRASH(( "OCL list '%s' not found\n", name.str() ));
  272. name = bridgeTemplate->getDamageToFXString( (BodyDamageType)bodyState, i );
  273. m_damageToFX[ bodyState ][ i ] = TheFXListStore->findFXList( name.str() );
  274. if( name.isEmpty() == FALSE && m_damageToFX[ bodyState ][ i ] == NULL )
  275. DEBUG_CRASH(( "FX list '%s' not found\n", name.str() ));
  276. name = bridgeTemplate->getRepairedToOCLString( (BodyDamageType)bodyState, i );
  277. m_repairToOCL[ bodyState ][ i ] = TheObjectCreationListStore->findObjectCreationList( name.str() );
  278. if( name.isEmpty() == FALSE && m_repairToOCL[ bodyState ][ i ] == NULL )
  279. DEBUG_CRASH(( "OCL list '%s' not found\n", name.str() ));
  280. name = bridgeTemplate->getRepairedToFXString( (BodyDamageType)bodyState, i );
  281. m_repairToFX[ bodyState ][ i ] = TheFXListStore->findFXList( name.str() );;
  282. if( name.isEmpty() == FALSE && m_repairToFX[ bodyState ][ i ] == NULL )
  283. DEBUG_CRASH(( "FX list '%s' not found\n", name.str() ));
  284. } // end for i
  285. // audio sounds
  286. name = bridgeTemplate->getDamageToSoundString( (BodyDamageType)bodyState );
  287. m_damageToSound[ bodyState ].setEventName( name );
  288. m_damageToSound[ bodyState ].setObjectID( us->getID() );
  289. name = bridgeTemplate->getRepairedToSoundString( (BodyDamageType)bodyState );
  290. m_repairToSound[ bodyState ].setEventName( name );
  291. m_repairToSound[ bodyState ].setObjectID( us->getID() );
  292. } // end for, bodyState
  293. // fx are now "resolved"
  294. m_fxResolved = TRUE;
  295. } // end resolveFX
  296. // ------------------------------------------------------------------------------------------------
  297. // ------------------------------------------------------------------------------------------------
  298. void BridgeBehavior::setTower( BridgeTowerType towerType, Object *tower )
  299. {
  300. // sanity
  301. if( towerType < 0 || towerType >= BRIDGE_MAX_TOWERS )
  302. {
  303. DEBUG_CRASH(( "BridgeBehavior::setTower - Invalid tower type index '%d'\n", towerType ));
  304. return;
  305. } // end if
  306. // store it
  307. if( tower )
  308. m_towerID[ towerType ] = tower->getID();
  309. else
  310. m_towerID[ towerType ] = INVALID_ID;
  311. } // end setTower
  312. // ------------------------------------------------------------------------------------------------
  313. // ------------------------------------------------------------------------------------------------
  314. ObjectID BridgeBehavior::getTowerID( BridgeTowerType towerType )
  315. {
  316. // sanity
  317. if( towerType < 0 || towerType >= BRIDGE_MAX_TOWERS )
  318. {
  319. DEBUG_CRASH(( "BridgeBehavior::setTower - Invalid tower type index '%d'\n", towerType ));
  320. return INVALID_ID;
  321. } // end if
  322. // return the stored ID
  323. return m_towerID[ towerType ];
  324. } // end getTowerID
  325. // ------------------------------------------------------------------------------------------------
  326. // ------------------------------------------------------------------------------------------------
  327. void BridgeBehavior::onDamage( DamageInfo *damageInfo )
  328. {
  329. //
  330. // get our body info so we now how much damage percent is being done to us ... we need this
  331. // so that we can propagate the same damage percentage amont the towers and the bridge
  332. //
  333. BodyModuleInterface *body = getObject()->getBodyModule();
  334. Real damagePercentage = damageInfo->in.m_amount / body->getMaxHealth();
  335. //
  336. // if the damage didn't come from a bridge tower, then we must propagate this damage
  337. // to all our towers
  338. //
  339. Object *source = TheGameLogic->findObjectByID( damageInfo->in.m_sourceID );
  340. if( source == NULL || source->isKindOf( KINDOF_BRIDGE_TOWER ) == FALSE )
  341. {
  342. Object *tower;
  343. for( Int i = 0; i < BRIDGE_MAX_TOWERS; i++ )
  344. {
  345. tower = TheGameLogic->findObjectByID( getTowerID( (BridgeTowerType)i ) );
  346. if( tower )
  347. {
  348. BodyModuleInterface *towerBody = tower->getBodyModule();
  349. DamageInfo towerDamage;
  350. towerDamage.in.m_amount = damagePercentage * towerBody->getMaxHealth();
  351. towerDamage.in.m_sourceID = getObject()->getID(); // we're now the source
  352. towerDamage.in.m_damageType = damageInfo->in.m_damageType;
  353. towerDamage.in.m_deathType = damageInfo->in.m_deathType;
  354. tower->attemptDamage( &towerDamage );
  355. } // end if
  356. } // end for i
  357. } // end if
  358. } // end onDamage
  359. // ------------------------------------------------------------------------------------------------
  360. // ------------------------------------------------------------------------------------------------
  361. void BridgeBehavior::onHealing( DamageInfo *damageInfo )
  362. {
  363. //
  364. // get our body info so we now how much healing percent is being done to us ... we need this
  365. // so that we can propagate the same healing percentage amont the towers and the bridge
  366. //
  367. BodyModuleInterface *body = getObject()->getBodyModule();
  368. Real healingPercentage = damageInfo->in.m_amount / body->getMaxHealth();
  369. //
  370. // if the healing didn't come from a bridge tower, then we must propagate this healing
  371. // to all our towers
  372. //
  373. Object *source = TheGameLogic->findObjectByID( damageInfo->in.m_sourceID );
  374. if( source == NULL || source->isKindOf( KINDOF_BRIDGE_TOWER ) == FALSE )
  375. {
  376. Object *tower;
  377. for( Int i = 0; i < BRIDGE_MAX_TOWERS; i++ )
  378. {
  379. tower = TheGameLogic->findObjectByID( getTowerID( (BridgeTowerType)i ) );
  380. if( tower )
  381. {
  382. BodyModuleInterface *towerBody = tower->getBodyModule();
  383. tower->attemptHealing(healingPercentage * towerBody->getMaxHealth(), getObject());
  384. } // end if
  385. } // end for i
  386. } // end if
  387. } // end onHealing
  388. // ------------------------------------------------------------------------------------------------
  389. /** Pick a random surface spot on the bridge surface */
  390. // ------------------------------------------------------------------------------------------------
  391. void BridgeBehavior::getRandomSurfacePosition( TerrainRoadType *bridgeTemplate,
  392. const BridgeInfo *bridgeInfo,
  393. Coord3D *pos )
  394. {
  395. // sanity
  396. if( bridgeInfo == NULL || pos == NULL )
  397. return;
  398. //
  399. // pick the spot by finding vectors along the edge of the bridge region, scaling
  400. // them and then adding them together
  401. //
  402. Real scale;
  403. Coord3D v1;
  404. v1.x = bridgeInfo->toLeft.x - bridgeInfo->fromLeft.x;
  405. v1.y = bridgeInfo->toLeft.y - bridgeInfo->fromLeft.y;
  406. v1.z = bridgeInfo->toLeft.z - bridgeInfo->fromLeft.z;
  407. scale = GameLogicRandomValueReal( 0.0f, 1.0f );
  408. v1.x *= scale;
  409. v1.y *= scale;
  410. v1.z *= scale;
  411. Coord3D v2;
  412. v2.x = bridgeInfo->fromRight.x - bridgeInfo->fromLeft.x;
  413. v2.y = bridgeInfo->fromRight.y - bridgeInfo->fromLeft.y;
  414. v2.z = bridgeInfo->fromRight.z - bridgeInfo->fromLeft.z;
  415. scale = GameLogicRandomValueReal( 0.0f, 1.0f );
  416. v2.x *= scale;
  417. v2.y *= scale;
  418. v2.z *= scale;
  419. // set the position
  420. pos->x = v1.x + v2.x + bridgeInfo->fromLeft.x;
  421. pos->y = v1.y + v2.y + bridgeInfo->fromLeft.y;
  422. pos->z = v1.z + v2.z + bridgeInfo->fromLeft.z;
  423. //
  424. // we now have a position picked, the last thing to do is add in an additional
  425. // Z component so that effects can be created in a "cube" area on and above the bridge
  426. //
  427. pos->z += GameLogicRandomValueReal( 0.0f, bridgeTemplate->getTransitionEffectsHeight() );
  428. } // end getRandomSurfacePosition
  429. // ------------------------------------------------------------------------------------------------
  430. // ------------------------------------------------------------------------------------------------
  431. void BridgeBehavior::doAreaEffects( TerrainRoadType *bridgeTemplate,
  432. Bridge *bridge,
  433. const ObjectCreationList *ocl,
  434. const FXList *fx )
  435. {
  436. // sanity
  437. if( bridge == NULL )
  438. return;
  439. // if no effects, don't bother
  440. if( ocl == NULL && fx == NULL )
  441. return;
  442. // get bridge info
  443. const BridgeInfo *bridgeInfo = bridge->peekBridgeInfo();
  444. // play effects in the bridge area
  445. const Int maxEffects = bridgeTemplate->getNumFXPerType();
  446. Coord3D pos;
  447. for( Int i = 0; i < maxEffects; ++i )
  448. {
  449. // pick spot in the bridge area and do FX
  450. if( fx )
  451. {
  452. getRandomSurfacePosition( bridgeTemplate, bridgeInfo, &pos );
  453. FXList::doFXPos( fx, &pos );
  454. } // end if
  455. // pick spot in the bridge area and do OCL
  456. if( ocl )
  457. {
  458. getRandomSurfacePosition( bridgeTemplate, bridgeInfo, &pos );
  459. ObjectCreationList::create( ocl, getObject(), &pos, NULL );
  460. } // end if
  461. } // end for i
  462. } // end doAreaEffects
  463. // ------------------------------------------------------------------------------------------------
  464. // ------------------------------------------------------------------------------------------------
  465. void BridgeBehavior::onBodyDamageStateChange( const DamageInfo* damageInfo,
  466. BodyDamageType oldState,
  467. BodyDamageType newState )
  468. {
  469. //
  470. // check for coming back from the dead, if our new state is not the rubble state, we can't
  471. // possibly be dead
  472. //
  473. if( newState != BODY_RUBBLE )
  474. m_deathFrame = 0;
  475. // first resolve any fx stuff if we need to
  476. if( m_fxResolved == FALSE )
  477. resolveFX();
  478. // sanity
  479. if( m_fxResolved == FALSE )
  480. return;
  481. // sanity
  482. DEBUG_ASSERTCRASH( oldState != newState, ("BridgeBehavior::onBodyDamageStateChange - oldState and newState should be different if this is getting called\n") );
  483. Object *us = getObject();
  484. Bridge *bridge = TheTerrainLogic->findBridgeAt( us->getPosition() );
  485. // sanity
  486. if( bridge == NULL )
  487. {
  488. DEBUG_CRASH(( "BridgeBehavior - Unable to find bridge\n" ));
  489. return;
  490. } // end if
  491. // get the bridge template name
  492. AsciiString bridgeTemplateName = bridge->getBridgeTemplateName();
  493. // find the bridge template
  494. TerrainRoadType *bridgeTemplate = TheTerrainRoads->findBridge( bridgeTemplateName );
  495. // sanity
  496. DEBUG_ASSERTCRASH( bridgeTemplate, ("BridgeBehavior: Unable to find bridge template '%s' in bridge object '%s'\n",
  497. bridgeTemplateName,
  498. us->getTemplate()->getName().str()) );
  499. //
  500. // given the old state and the new state, did we get worse (damaged) or did
  501. // we get better (repaired)?
  502. //
  503. Bool gotRepaired = IS_CONDITION_WORSE( oldState, newState );
  504. // get the effect data
  505. AsciiString soundString;
  506. AsciiString oclString[ MAX_BRIDGE_BODY_FX ];
  507. AsciiString fxString[ MAX_BRIDGE_BODY_FX ];
  508. if( gotRepaired )
  509. {
  510. // play the sound
  511. TheAudio->addAudioEvent( &m_repairToSound[ newState ] );
  512. for( Int i = 0; i < MAX_BRIDGE_BODY_FX; i++ )
  513. doAreaEffects( bridgeTemplate, bridge, m_repairToOCL[ newState ][ i ], m_repairToFX[ newState ][ i ] );
  514. } // end if
  515. else
  516. {
  517. // play the sound
  518. TheAudio->addAudioEvent( &m_damageToSound[ newState ] );
  519. for( Int i = 0; i < MAX_BRIDGE_BODY_FX; i++ )
  520. doAreaEffects( bridgeTemplate, bridge, m_damageToOCL[ newState ][ i ], m_damageToFX[ newState ][ i ] );
  521. } // end else
  522. // update bridge damage states
  523. ///@todo this should be re-written, there no need for this looping bridge examination
  524. TheTerrainLogic->updateBridgeDamageStates();
  525. //
  526. // for the local player, if this bridge has switched from rubble, to usable, or from
  527. // usable to rubble, we should reflect the change on the radar. note that we
  528. // request that the radar queue a refresh sometime in the future because it keeps
  529. // track of how often we makes requests to do a refresh and doesn't do them too
  530. // often because it's expensive to refresh the terrain
  531. //
  532. if( oldState == BODY_RUBBLE || newState == BODY_RUBBLE )
  533. TheRadar->queueTerrainRefresh();
  534. } // end onBodyDamageStateChange
  535. // ------------------------------------------------------------------------------------------------
  536. // ------------------------------------------------------------------------------------------------
  537. UpdateSleepTime BridgeBehavior::update( void )
  538. {
  539. // if we're dead, we need to possibly throw off some effects
  540. if( m_deathFrame != 0 )
  541. {
  542. AsciiString boneName;
  543. // get object
  544. Object *us = getObject();
  545. // get module data
  546. const BridgeBehaviorModuleData *modData = getBridgeBehaviorModuleData();
  547. // get bridge information
  548. Bridge *bridge = TheTerrainLogic->findBridgeAt( us->getPosition() );
  549. const BridgeInfo *bridgeInfo = NULL;
  550. TerrainRoadType *bridgeTemplate = NULL;
  551. if ( bridge )
  552. {
  553. DEBUG_ASSERTCRASH( bridge, ("BridgeBehavior::update - Unable to find bridge\n") );
  554. // get bridge info
  555. bridgeInfo = bridge->peekBridgeInfo();
  556. // get the bridge template info
  557. AsciiString bridgeTemplateName = bridge->getBridgeTemplateName();
  558. bridgeTemplate = TheTerrainRoads->findBridge( bridgeTemplateName );
  559. DEBUG_ASSERTCRASH( bridgeTemplate, ("BridgeBeahvior::getRandomSurfacePosition - Encountered a bridge with no template!\n") );
  560. }
  561. // how much time has passed between now and our destruction frame
  562. UnsignedInt deathTime = TheGameLogic->getFrame() - m_deathFrame;
  563. // see if there are any fx visuals we need to execute
  564. BridgeFXList::const_iterator fxIt;
  565. for( fxIt = modData->m_fx.begin(); fxIt != modData->m_fx.end(); ++fxIt )
  566. {
  567. //
  568. // we'll launch an fx list if our death time is equal to exactly the delay
  569. // we're waiting for to launch the list
  570. //
  571. if( deathTime == (*fxIt).timeAndLocationInfo.delay )
  572. {
  573. Coord3D pos;
  574. //
  575. // if a bone name is present, we'll use the bone position, otherwise we'll pick a
  576. // spot somewhere on the bridge surface
  577. //
  578. boneName = (*fxIt).timeAndLocationInfo.boneName;
  579. if( boneName.isEmpty() == FALSE )
  580. us->getSingleLogicalBonePosition( boneName.str(), &pos, NULL );
  581. else if ( bridge && bridgeTemplate && bridgeInfo)//we have valid Terrain data for the bridge
  582. getRandomSurfacePosition( bridgeTemplate, bridgeInfo, &pos );
  583. else
  584. pos.set( getObject()->getPosition() );
  585. // launch the fx list
  586. FXList::doFXPos( (*fxIt).fx, &pos );
  587. } // end if
  588. } // end for, fxIt
  589. // see if there are any ocl visuals we need to execute
  590. BridgeOCLList::const_iterator oclIt;
  591. for( oclIt = modData->m_ocl.begin(); oclIt != modData->m_ocl.end(); ++oclIt )
  592. {
  593. //
  594. // we'll launch an ocl list if our death time is equal to exactly the delay
  595. // we're waiting for to launch the list
  596. //
  597. if( deathTime == (*oclIt).timeAndLocationInfo.delay )
  598. {
  599. Coord3D pos;
  600. //
  601. // if a bone name is present, we'll use the bone position, otherwise we'll pick a
  602. // spot somewhere on the bridge surface
  603. //
  604. boneName = (*oclIt).timeAndLocationInfo.boneName;
  605. if( boneName.isEmpty() == FALSE )
  606. {
  607. //
  608. // special case for creating an OCL for using the bridge object parent center location
  609. // why do we have this ... well, apparently the OCL ignores the obj parameter
  610. // passed in if you give it a position parameter, and we need it to pay attention
  611. // to that object parameteter so the OCL stuff can inherit the LIKE_EXISTING
  612. // properties from its parent
  613. //
  614. if( boneName.compare( "ParentObject" ) == 0 )
  615. {
  616. // launch the effects just using the parent object for location info
  617. ObjectCreationList::create( (*oclIt).ocl, us, NULL );
  618. } // endif
  619. else
  620. {
  621. // get bone position
  622. us->getSingleLogicalBonePosition( boneName.str(), &pos, NULL );
  623. // launch the fx list
  624. ObjectCreationList::create( (*oclIt).ocl, us, &pos, NULL );
  625. } // end else
  626. } // end if, bone name not empty
  627. else
  628. {
  629. // get random place on bridge
  630. if ( bridge && bridgeTemplate && bridgeInfo )//we have valid Terrain data for the bridge
  631. getRandomSurfacePosition( bridgeTemplate, bridgeInfo, &pos );
  632. else
  633. pos.set( getObject()->getPosition() );
  634. // launch the fx list
  635. ObjectCreationList::create( (*oclIt).ocl, us, &pos, NULL );
  636. } // end else
  637. } // end if
  638. } // end for, oclIt
  639. } // end if
  640. return UPDATE_SLEEP_NONE;
  641. } // end update
  642. // ------------------------------------------------------------------------------------------------
  643. // ------------------------------------------------------------------------------------------------
  644. void BridgeBehavior::onDie( const DamageInfo *damageInfo )
  645. {
  646. // kill the towers associated with us
  647. Object *tower;
  648. for( Int i = 0; i < BRIDGE_MAX_TOWERS; ++i )
  649. {
  650. tower = TheGameLogic->findObjectByID( getTowerID( (BridgeTowerType)i ) );
  651. if( tower )
  652. tower->kill();
  653. } // end for, i
  654. // we need to handle anything that was on top of us now that we've been destroyed
  655. handleObjectsOnBridgeOnDie();
  656. // we have now died, record the death frame
  657. m_deathFrame = TheGameLogic->getFrame();
  658. } // end onDie
  659. // ------------------------------------------------------------------------------------------------
  660. // ------------------------------------------------------------------------------------------------
  661. void BridgeBehavior::handleObjectsOnBridgeOnDie( void )
  662. {
  663. const Object *bridge = getObject();
  664. const Coord3D *bridgePos = bridge->getPosition();
  665. Bridge *terrainBridge = TheTerrainLogic->findBridgeAt( getObject()->getPosition() );
  666. if( terrainBridge )
  667. {
  668. PathfindLayerEnum bridgeLayer = terrainBridge->getLayer();
  669. BridgeInfo bridgeInfo;
  670. // get the bridge info
  671. terrainBridge->getBridgeInfo( &bridgeInfo );
  672. // setup a polygon area using the bridge extents
  673. Coord3D bridgePolygon[ 4 ];
  674. bridgePolygon[ 0 ] = bridgeInfo.fromLeft;
  675. bridgePolygon[ 1 ] = bridgeInfo.fromRight;
  676. bridgePolygon[ 2 ] = bridgeInfo.toRight;
  677. bridgePolygon[ 3 ] = bridgeInfo.toLeft;
  678. //
  679. // find the lowest Z point of the bridge area ... we will use this to figure out of
  680. // objects in the bridge area are "on top" of the bridge
  681. //
  682. Real lowBridgeZ = bridgePolygon[ 0 ].z;
  683. for( Int i = 0; i < 4; ++i )
  684. if( bridgePolygon[ i ].z < lowBridgeZ )
  685. lowBridgeZ = bridgePolygon[ i ].z;
  686. //
  687. // given the polygon area, how big is the radius that we need to scan in the world
  688. // to cover from the center of the bridge (the bridge object position) to the edge
  689. // of the bridge
  690. //
  691. Coord2D v;
  692. v.x = bridgeInfo.toLeft.x - bridgePos->x;
  693. v.y = bridgeInfo.toLeft.y - bridgePos->y;
  694. Real radius = v.length();
  695. // scan the objects in the radius
  696. ObjectIterator *iter = ThePartitionManager->iterateObjectsInRange( bridgePos,
  697. radius,
  698. FROM_CENTER_2D );
  699. MemoryPoolObjectHolder hold( iter );
  700. Object *other;
  701. for( other = iter->first(); other; other = iter->next() )
  702. {
  703. // ingnore some kind of objects
  704. if( other->isKindOf( KINDOF_BRIDGE ) || other->isKindOf( KINDOF_BRIDGE_TOWER ) )
  705. continue;
  706. // ignore airborne objects
  707. if( other->isAboveTerrain() )
  708. continue;
  709. // ignore objects that were not actually on the bridge
  710. if( other->getPosition()->z < lowBridgeZ )
  711. continue;
  712. // ignore objects that are not inside the bridge polygon
  713. if( PointInsideArea2D( other->getPosition(), bridgePolygon, 4 ) == FALSE )
  714. continue;
  715. // if object not on same layer as bridge do nothing
  716. if( bridgeLayer != other->getLayer() )
  717. continue;
  718. if (other->getLayer() == bridgeLayer)
  719. other->setLayer(LAYER_GROUND);
  720. // if they have physics, let 'em fall, otherwise just kill 'em
  721. PhysicsBehavior* physics = other->getPhysics();
  722. if (physics)
  723. physics->setAllowToFall(true);
  724. else
  725. other->kill();
  726. } // end for, other
  727. } // end if, terrainBridge
  728. } // end handleObjectsOnBridgeDie
  729. // ------------------------------------------------------------------------------------------------
  730. /** Set all the position, angle, and speed data we need to for a single scaffold object */
  731. // ------------------------------------------------------------------------------------------------
  732. void BridgeBehavior::setScaffoldData( Object *obj,
  733. Real *angle,
  734. Real *sunkenHeight,
  735. const Coord3D *riseToPos,
  736. const Coord3D *buildPos,
  737. const Coord3D *bridgeCenter )
  738. {
  739. // sanity
  740. if( obj == NULL || angle == NULL || riseToPos == NULL || buildPos == NULL )
  741. return;
  742. const BridgeBehaviorModuleData *modData = getBridgeBehaviorModuleData();
  743. // get the scaffold behavior interface
  744. BridgeScaffoldBehaviorInterface *scaffoldBehavior;
  745. scaffoldBehavior = BridgeScaffoldBehavior::getBridgeScaffoldBehaviorInterfaceFromObject( obj );
  746. DEBUG_ASSERTCRASH( scaffoldBehavior, ("Unable to find bridge scaffold behavior interface\n") );
  747. // compute the sunken position that the object will initially start at
  748. Real fudge = 8.0f;
  749. Coord3D sunkenPos = *riseToPos;
  750. sunkenPos.z = sunkenPos.z - *sunkenHeight - fudge;
  751. // set object initial position
  752. obj->setPosition( &sunkenPos );
  753. // set all the destination points for all scaffold motion
  754. scaffoldBehavior->setPositions( &sunkenPos, riseToPos, buildPos );
  755. // set the scaffold object in motion rising up out of the ground
  756. scaffoldBehavior->setMotion( STM_RISE );
  757. // set object angle
  758. obj->setOrientation( *angle );
  759. //
  760. // set the speed of the scaffold "animation" which is based on how big of a distance
  761. // all the scaffold objects have to traverse in order to meet up and be complete in
  762. // the center of the bridge in an interesting way
  763. //
  764. Real lateralSpeed = modData->m_lateralScaffoldSpeed;
  765. Coord3D buildUpPosToBridgeCenter, riseToPosToBridgeCenter;
  766. buildUpPosToBridgeCenter.x = buildPos->x - riseToPos->x;
  767. buildUpPosToBridgeCenter.y = buildPos->y - riseToPos->y;
  768. buildUpPosToBridgeCenter.z = buildPos->z - riseToPos->z;
  769. riseToPosToBridgeCenter.x = bridgeCenter->x - riseToPos->x;
  770. riseToPosToBridgeCenter.y = bridgeCenter->y - riseToPos->y;
  771. riseToPosToBridgeCenter.z = bridgeCenter->z - riseToPos->z;
  772. Real distBuildUpPosToBridgeCenter = buildUpPosToBridgeCenter.length();
  773. Real distRiseToPosToBridgeCenter = riseToPosToBridgeCenter.length();
  774. scaffoldBehavior->setLateralSpeed( lateralSpeed * (distBuildUpPosToBridgeCenter / distRiseToPosToBridgeCenter) );
  775. // rising speed is always the same for all objects
  776. Real verticalSpeed = modData->m_verticalScaffoldSpeed;
  777. scaffoldBehavior->setVerticalSpeed( verticalSpeed );
  778. } // end setScaffoldData
  779. // ------------------------------------------------------------------------------------------------
  780. /** Start the bridge repair scaffolding. If we already have scaffolding this call
  781. * is ignored */
  782. // ------------------------------------------------------------------------------------------------
  783. void BridgeBehavior::createScaffolding( void )
  784. {
  785. // if we have scaffolding up already do nothing
  786. if( m_scaffoldPresent == TRUE )
  787. return;
  788. // get the bridge world object
  789. Object *us = getObject();
  790. const Coord3D *center = us->getPosition();
  791. // get our bridge object
  792. Bridge *bridge = TheTerrainLogic->findBridgeAt( us->getPosition() );
  793. // get the bridge template
  794. AsciiString bridgeTemplateName = bridge->getBridgeTemplateName();
  795. TerrainRoadType *bridgeTemplate = TheTerrainRoads->findBridge( bridgeTemplateName );
  796. DEBUG_ASSERTCRASH( bridgeTemplate, ("Unable to find bridge template to create scaffolding\n") );
  797. // get the thing template for the scaffold object we're going to use
  798. AsciiString scaffoldObjectName = bridgeTemplate->getScaffoldObjectName();
  799. const ThingTemplate *scaffoldTemplate = TheThingFactory->findTemplate( scaffoldObjectName );
  800. if( scaffoldTemplate == NULL )
  801. {
  802. DEBUG_CRASH(( "Unable to find bridge scaffold template\n" ));
  803. return;
  804. } // end if
  805. // get thing template for scaffold support object
  806. AsciiString scaffoldSupportObjectName = bridgeTemplate->getScaffoldSupportObjectName();
  807. const ThingTemplate *scaffoldSupportTemplate = TheThingFactory->findTemplate( scaffoldSupportObjectName );
  808. if( scaffoldSupportTemplate == NULL )
  809. {
  810. DEBUG_CRASH(( "Unable to find bridge support scaffold template\n" ));
  811. return;
  812. } // end if
  813. // how much space is going to be between each of the scaffold objects at their final positions
  814. Real spacing = scaffoldTemplate->getTemplateGeometryInfo().getMajorRadius() * 2.0f;
  815. // how tall are the scaffold objects
  816. Real scaffoldHeight = scaffoldTemplate->getTemplateGeometryInfo().getMaxHeightAbovePosition() +
  817. scaffoldTemplate->getTemplateGeometryInfo().getMaxHeightBelowPosition();
  818. Real scaffoldSupportHeight = scaffoldSupportTemplate->getTemplateGeometryInfo().getMaxHeightAbovePosition() +
  819. scaffoldSupportTemplate->getTemplateGeometryInfo().getMaxHeightBelowPosition();
  820. // get the bridge info
  821. BridgeInfo bridgeInfo;
  822. bridge->getBridgeInfo( &bridgeInfo );
  823. //
  824. // given the area of the bridge, figure out what the start and end points are to create
  825. // all the scaffold objects at (just in the 2D bridge plane, not thinking about
  826. // rising the objects up through the ground yet)
  827. //
  828. Coord3D leftStart;
  829. leftStart.x = ((bridgeInfo.fromLeft.x - bridgeInfo.fromRight.x) / 2.0f) + bridgeInfo.fromRight.x;
  830. leftStart.y = ((bridgeInfo.fromLeft.y - bridgeInfo.fromRight.y) / 2.0f) + bridgeInfo.fromRight.y;
  831. leftStart.z = ((bridgeInfo.fromLeft.z - bridgeInfo.fromRight.z) / 2.0f) + bridgeInfo.fromRight.z;
  832. Coord3D rightStart;
  833. rightStart.x = ((bridgeInfo.toLeft.x - bridgeInfo.toRight.x) / 2.0f) + bridgeInfo.toRight.x;
  834. rightStart.y = ((bridgeInfo.toLeft.y - bridgeInfo.toRight.y) / 2.0f) + bridgeInfo.toRight.y;
  835. rightStart.z = ((bridgeInfo.toLeft.z - bridgeInfo.toRight.z) / 2.0f) + bridgeInfo.toRight.z;
  836. //
  837. // now that we have the left and right start points, we will compute two angles to
  838. // use for all the objects that we will create ... objects on the left side of the
  839. // bridge will be given a 'leftAngle' pointing from 'leftStart' to 'rightStart' and
  840. // the opposite will be given to objects on the right side of the bridge
  841. //
  842. Coord2D angleV;
  843. angleV.x = rightStart.x - leftStart.x;
  844. angleV.y = rightStart.y - leftStart.y;
  845. Real leftAngle = angleV.toAngle();
  846. Real rightAngle = leftAngle + TWO_PI;
  847. // compute vector from left to right across bridge and the reverse
  848. Coord3D leftVector;
  849. leftVector.x = rightStart.x - leftStart.x;
  850. leftVector.y = rightStart.y - leftStart.y;
  851. leftVector.z = rightStart.z - leftStart.z;
  852. Coord3D rightVector;
  853. rightVector.x = leftStart.x - rightStart.x;
  854. rightVector.y = leftStart.y - rightStart.y;
  855. rightVector.z = leftStart.z - rightStart.z;
  856. //
  857. // how many of these scaffold objects will take to tile from each of the endpoints
  858. // to the center area of the bridge
  859. //
  860. Real tileDistance = leftVector.length();
  861. Int numObjects = REAL_TO_INT_CEIL( tileDistance / spacing ) + 1;
  862. //
  863. // given the number of objects that we need to tile across the whole bridge, we will
  864. // go through the creation loop ceil( numObjects / 2.0f ) times, and each
  865. // time through the loop we'll create an object to move from each side of the
  866. // bridge, except the last object if the number of objects is odd is dead in the
  867. // center
  868. //
  869. Int numIterations = REAL_TO_INT_CEIL( INT_TO_REAL( numObjects ) / 2.0f );
  870. //
  871. // normalize left and right vectors as it is a vector that goes from our left start
  872. // position to the destination right start position ... we will multiply this vector by a
  873. // spacing amount and add to the left start position to find a destination position
  874. // for a particular scaffold object along the bridge surface
  875. //
  876. leftVector.normalize();
  877. rightVector.normalize();
  878. // create the scaffold objects for now
  879. Int scaffoldObjectsCreated = 0;
  880. Coord3D destinationPos, *riseToPos;
  881. Real *angle;
  882. Object *obj;
  883. for( Int i = 0; i < numIterations; ++i )
  884. {
  885. // sanity
  886. DEBUG_ASSERTCRASH( scaffoldObjectsCreated < numObjects,
  887. ("Creating too many scaffold objects\n") );
  888. // create object
  889. obj = TheThingFactory->newObject( scaffoldTemplate, us->getTeam() );
  890. // this object is from the "left" side of the bridge
  891. riseToPos = &leftStart;
  892. angle = &leftAngle;
  893. //
  894. // compute position for object moving from the left side, we're adding 0.1 here
  895. // so that all scaffold objects *have* to move some distance ... that way we
  896. // can just assign the speeds so they line up perfectly and not have to worry
  897. // about any object reaching a destination before any other object
  898. //
  899. destinationPos.x = leftVector.x * (spacing * i) + riseToPos->x + 0.1f;
  900. destinationPos.y = leftVector.y * (spacing * i) + riseToPos->y;
  901. destinationPos.z = leftVector.z * (spacing * i) + riseToPos->z;
  902. //
  903. // now that they key positions are calculated, set the rest of the position data
  904. // and movement speeds for the object
  905. //
  906. setScaffoldData( obj, angle, &scaffoldHeight, riseToPos, &destinationPos, center );
  907. // keeping track of objects created
  908. scaffoldObjectsCreated++;
  909. m_scaffoldObjectIDList.push_back( obj->getID() );
  910. //
  911. // create support object layers under the scaffold object, this object mirrors the scaffold
  912. // object except is on a lower layer
  913. //
  914. Real offset = riseToPos->z;
  915. Coord3D supportRiseToPos = *riseToPos;
  916. Coord3D supportDestinationPos = destinationPos;
  917. Coord3D supportBridgeCenter = *center;
  918. while( offset >= 0.0f )
  919. {
  920. supportRiseToPos.z -= scaffoldSupportHeight;
  921. supportDestinationPos.z -= scaffoldSupportHeight;
  922. supportBridgeCenter.z -= scaffoldSupportHeight;
  923. obj = TheThingFactory->newObject( scaffoldSupportTemplate, us->getTeam() );
  924. setScaffoldData( obj,
  925. angle,
  926. &scaffoldSupportHeight,
  927. &supportRiseToPos,
  928. &supportDestinationPos,
  929. &supportBridgeCenter );
  930. m_scaffoldObjectIDList.push_back( obj->getID() );
  931. // off to the next layer
  932. offset -= scaffoldSupportHeight;
  933. } // end while
  934. //
  935. // now create the object from the "right" side of the bridge ... but note that
  936. // we don't do this on the last iteration through this loop when we have an odd
  937. // number of objects we're tiling because all the space is already perfectly used up)
  938. //
  939. if( scaffoldObjectsCreated < numObjects )
  940. {
  941. // sanity
  942. DEBUG_ASSERTCRASH( scaffoldObjectsCreated < numObjects,
  943. ("Creating too many scaffold objects\n") );
  944. // create new object
  945. obj = TheThingFactory->newObject( scaffoldTemplate, us->getTeam() );
  946. // this object is on the "right" side of the bridge
  947. riseToPos = &rightStart;
  948. angle = &rightAngle;
  949. //
  950. // compute position for object moving from the left side, we're adding 0.1 here
  951. // so that all scaffold objects *have* to move some distance ... that way we
  952. // can just assign the speeds so they line up perfectly and not have to worry
  953. // about any object reaching a destination before any other object
  954. //
  955. destinationPos.x = rightVector.x * (spacing * i) + riseToPos->x + 0.1f;
  956. destinationPos.y = rightVector.y * (spacing * i) + riseToPos->y;
  957. destinationPos.z = rightVector.z * (spacing * i) + riseToPos->z;
  958. // set the rest scaffold data again
  959. setScaffoldData( obj, angle, &scaffoldHeight, riseToPos, &destinationPos, center );
  960. // keeping track of objects created
  961. scaffoldObjectsCreated++;
  962. m_scaffoldObjectIDList.push_back( obj->getID() );
  963. //
  964. // create support object layers under the scaffold object, this object mirrors the scaffold
  965. // object except is on a lower layer
  966. //
  967. Real offset = riseToPos->z;
  968. Coord3D supportRiseToPos = *riseToPos;
  969. Coord3D supportDestinationPos = destinationPos;
  970. Coord3D supportBridgeCenter = *center;
  971. while( offset >= 0.0f )
  972. {
  973. supportRiseToPos.z -= scaffoldSupportHeight;
  974. supportDestinationPos.z -= scaffoldSupportHeight;
  975. supportBridgeCenter.z -= scaffoldSupportHeight;
  976. obj = TheThingFactory->newObject( scaffoldSupportTemplate, us->getTeam() );
  977. setScaffoldData( obj,
  978. angle,
  979. &scaffoldSupportHeight,
  980. &supportRiseToPos,
  981. &supportDestinationPos,
  982. &supportBridgeCenter );
  983. m_scaffoldObjectIDList.push_back( obj->getID() );
  984. // off to the next layer
  985. offset -= scaffoldSupportHeight;
  986. } // end while
  987. } // end if
  988. } // end for i
  989. // scaffolding is now present
  990. m_scaffoldPresent = TRUE;
  991. // when scaffolding is present, a bridge cannot be used
  992. TheAI->pathfinder()->changeBridgeState( bridge->getLayer(), FALSE );
  993. } // end createScaffolding
  994. // ------------------------------------------------------------------------------------------------
  995. /** Remove the bridge scaffolding. If we don't have any then this call is ignored */
  996. // ------------------------------------------------------------------------------------------------
  997. void BridgeBehavior::removeScaffolding( void )
  998. {
  999. // if we have no scaffolding, do nothing
  1000. if( m_scaffoldPresent == FALSE )
  1001. return;
  1002. // go through each object and tell them to reverse course
  1003. Object *obj;
  1004. ObjectIDListIterator it;
  1005. BridgeScaffoldBehaviorInterface *scaffoldBehavior;
  1006. for( it = m_scaffoldObjectIDList.begin(); it != m_scaffoldObjectIDList.end(); ++it )
  1007. {
  1008. // get the object
  1009. obj = TheGameLogic->findObjectByID( (*it) );
  1010. if( obj == NULL )
  1011. continue;
  1012. // get the scaffold behavior
  1013. scaffoldBehavior = BridgeScaffoldBehavior::getBridgeScaffoldBehaviorInterfaceFromObject( obj );
  1014. DEBUG_ASSERTCRASH( scaffoldBehavior, ("Unable to find bridge scaffold behavior interface\n") );
  1015. // reverse the motion
  1016. scaffoldBehavior->reverseMotion();
  1017. } // end for, it
  1018. // clear our scaffold object list
  1019. m_scaffoldObjectIDList.clear();
  1020. // scaffolding is no longer present
  1021. m_scaffoldPresent = FALSE;
  1022. // when scaffolding is gone, a bridge can be used again if we're not in a rubble state
  1023. Object *us = getObject();
  1024. BodyModuleInterface *body = us->getBodyModule();
  1025. if( body->getDamageState() != BODY_RUBBLE )
  1026. {
  1027. Bridge *bridge = TheTerrainLogic->findBridgeAt( us->getPosition() );
  1028. if( bridge )
  1029. TheAI->pathfinder()->changeBridgeState( bridge->getLayer(), TRUE );
  1030. } // end if
  1031. } // end removeScaffolding
  1032. // ------------------------------------------------------------------------------------------------
  1033. /** Is any of the scaffolding in motion */
  1034. // ------------------------------------------------------------------------------------------------
  1035. Bool BridgeBehavior::isScaffoldInMotion( void )
  1036. {
  1037. Object *obj;
  1038. // go through the scaffold objects, if any of them are in motion the scaffold is in motion
  1039. ObjectIDListIterator it;
  1040. for( it = m_scaffoldObjectIDList.begin(); it != m_scaffoldObjectIDList.end(); ++it )
  1041. {
  1042. // get object
  1043. obj = TheGameLogic->findObjectByID( (*it) );
  1044. if( obj == NULL )
  1045. continue;
  1046. // get scaffold interface
  1047. BridgeScaffoldBehaviorInterface *bsbi = BridgeScaffoldBehavior::getBridgeScaffoldBehaviorInterfaceFromObject( obj );
  1048. if( bsbi == NULL )
  1049. continue;
  1050. // check in motion
  1051. if( bsbi->getCurrentMotion() != STM_STILL )
  1052. return TRUE;
  1053. } // end for
  1054. // not in motion
  1055. return FALSE;
  1056. } // end isScaffoldInMotion
  1057. // ------------------------------------------------------------------------------------------------
  1058. /** CRC */
  1059. // ------------------------------------------------------------------------------------------------
  1060. void BridgeBehavior::crc( Xfer *xfer )
  1061. {
  1062. // extend base class
  1063. UpdateModule::crc( xfer );
  1064. } // end crc
  1065. // ------------------------------------------------------------------------------------------------
  1066. /** Xfer method
  1067. * Version Info:
  1068. * 1: Initial version */
  1069. // ------------------------------------------------------------------------------------------------
  1070. void BridgeBehavior::xfer( Xfer *xfer )
  1071. {
  1072. Object *us = getObject();
  1073. // version
  1074. XferVersion currentVersion = 1;
  1075. XferVersion version = currentVersion;
  1076. xfer->xferVersion( &version, currentVersion );
  1077. // extend base class
  1078. UpdateModule::xfer( xfer );
  1079. // set us as the bridge object in the bridge info
  1080. if( xfer->getXferMode() == XFER_LOAD )
  1081. {
  1082. Bridge *bridge = TheTerrainLogic->findBridgeAt( us->getPosition() );
  1083. // sanity
  1084. DEBUG_ASSERTCRASH( bridge, ("BridgeBehavior::xfer - Unable to find bridge\n" ));
  1085. // set new object ID in bridge info to us
  1086. bridge->setBridgeObjectID( us->getID() );
  1087. } // end if
  1088. // xfer the tower object ids
  1089. for( Int i = 0; i < BRIDGE_MAX_TOWERS; ++i )
  1090. xfer->xferObjectID( &m_towerID[ i ] );
  1091. // set the tower object ids in the bridge info
  1092. if( xfer->getXferMode() == XFER_LOAD )
  1093. {
  1094. Object *us = getObject();
  1095. Bridge *bridge = TheTerrainLogic->findBridgeAt( us->getPosition() );
  1096. // sanity
  1097. DEBUG_ASSERTCRASH( bridge, ("BridgeBehavior::xfer - Unable to find bridge\n" ));
  1098. // set new object ID in bridge info to us
  1099. for( Int i = 0; i < BRIDGE_MAX_TOWERS; ++i )
  1100. bridge->setTowerObjectID( m_towerID[ i ], (BridgeTowerType)i );
  1101. } // end if
  1102. // scaffold present flag
  1103. xfer->xferBool( &m_scaffoldPresent );
  1104. // scaffold object id list
  1105. UnsignedShort scaffoldObjectCount = 0;
  1106. scaffoldObjectCount = m_scaffoldObjectIDList.size();
  1107. xfer->xferUnsignedShort( &scaffoldObjectCount );
  1108. ObjectID scaffoldObjectID;
  1109. if( xfer->getXferMode() == XFER_SAVE )
  1110. {
  1111. // write out all object IDs
  1112. ObjectIDListIterator it;
  1113. for( it = m_scaffoldObjectIDList.begin(); it != m_scaffoldObjectIDList.end(); ++it )
  1114. {
  1115. scaffoldObjectID = *it;
  1116. xfer->xferObjectID( &scaffoldObjectID );
  1117. } // end for
  1118. } // end if, save
  1119. else
  1120. {
  1121. // read all object IDs
  1122. DEBUG_ASSERTCRASH( m_scaffoldObjectIDList.size() == 0,
  1123. ("BridgeBehavior::xfer - scaffold object list should be empty\n") );
  1124. for( Int i = 0; i < scaffoldObjectCount; ++i )
  1125. {
  1126. // read id
  1127. xfer->xferObjectID( &scaffoldObjectID );
  1128. // put on list
  1129. m_scaffoldObjectIDList.push_back( scaffoldObjectID );
  1130. } // end for i
  1131. } // end load
  1132. // death frame
  1133. xfer->xferUnsignedInt( &m_deathFrame );
  1134. } // end xfer
  1135. // ------------------------------------------------------------------------------------------------
  1136. /** Load post process */
  1137. // ------------------------------------------------------------------------------------------------
  1138. void BridgeBehavior::loadPostProcess( void )
  1139. {
  1140. // extend base class
  1141. UpdateModule::loadPostProcess();
  1142. } // end loadPostProcess