DeliverPayloadAIUpdate.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  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. // DeliverPayloadAIUpdate.cpp ////////////
  24. // Author: Graham Smallwood, March 2002
  25. // Desc: State machine that controls the approach and deployment of airborne cargo
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #define DEFINE_WEAPONSLOTTYPE_NAMES
  28. #include "Common/Player.h"
  29. #include "Common/RandomValue.h"
  30. #include "Common/ThingFactory.h"
  31. #include "Common/ThingTemplate.h"
  32. #include "Common/Xfer.h"
  33. #include "GameClient/Drawable.h"
  34. #include "GameClient/FXList.h"
  35. #include "GameClient/InGameUI.h"
  36. #include "GameLogic/Locomotor.h"
  37. #include "GameLogic/Module/BodyModule.h"
  38. #include "GameLogic/Module/ContainModule.h"
  39. #include "GameLogic/Module/DeliverPayloadAIUpdate.h"
  40. #include "GameLogic/Module/GenerateMinefieldBehavior.h"
  41. #include "GameLogic/Module/PhysicsUpdate.h"
  42. #include "GameLogic/Module/ParachuteContain.h"
  43. #include "GameLogic/Object.h"
  44. #include "GameLogic/PartitionManager.h"
  45. #include "GameLogic/Weapon.h"
  46. #include "GameLogic/WeaponSet.h"
  47. #ifdef _INTERNAL
  48. // for occasional debugging...
  49. //#pragma optimize("", off)
  50. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  51. #endif
  52. //-------------------------------------------------------------------------------------------------
  53. const FieldParse* DeliverPayloadData::getFieldParse()
  54. {
  55. static const FieldParse dataFieldParse[] =
  56. {
  57. { "DeliveryDistance", INI::parseReal, NULL, offsetof( DeliverPayloadData, m_distToTarget) },
  58. { "PreOpenDistance", INI::parseReal, NULL, offsetof( DeliverPayloadData, m_preOpenDistance) },
  59. { "MaxAttempts", INI::parseInt, NULL, offsetof( DeliverPayloadData, m_maxAttempts) },
  60. //Drop information
  61. { "DropDelay", INI::parseDurationUnsignedInt,NULL, offsetof( DeliverPayloadData, m_dropDelay ) },
  62. { "DropOffset", INI::parseCoord3D, NULL, offsetof( DeliverPayloadData, m_dropOffset ) },
  63. { "DropVariance", INI::parseCoord3D, NULL, offsetof( DeliverPayloadData, m_dropVariance ) },
  64. { "InheritTransportVelocity", INI::parseBool, NULL, offsetof( DeliverPayloadData, m_inheritTransportVelocity ) },
  65. { "ExitPitchRate", INI::parseAngularVelocityReal,NULL, offsetof( DeliverPayloadData, m_exitPitchRate ) },
  66. { "ParachuteDirectly", INI::parseBool, NULL, offsetof( DeliverPayloadData, m_isParachuteDirectly) },
  67. //Visible payload information (payload assumed to be show visibly and it's created only when dropped)
  68. { "VisibleItemsDroppedPerInterval", INI::parseInt, NULL, offsetof( DeliverPayloadData, m_visibleItemsDroppedPerInterval ) },
  69. { "VisibleDropBoneBaseName", INI::parseAsciiString, NULL, offsetof( DeliverPayloadData, m_visibleDropBoneName ) },
  70. { "VisibleSubObjectBaseName", INI::parseAsciiString, NULL, offsetof( DeliverPayloadData, m_visibleSubObjectName ) },
  71. { "VisibleNumBones", INI::parseInt, NULL, offsetof( DeliverPayloadData, m_visibleNumBones ) },
  72. { "VisiblePayloadTemplateName", INI::parseAsciiString, NULL, offsetof( DeliverPayloadData, m_visiblePayloadTemplateName ) },
  73. { "VisiblePayloadWeaponTemplate", INI::parseWeaponTemplate, NULL, offsetof( DeliverPayloadData, m_visiblePayloadWeaponTemplate ) },
  74. { "SelfDestructObject", INI::parseBool, NULL, offsetof( DeliverPayloadData, m_selfDestructObject ) },
  75. //Weapon based payload
  76. { "FireWeapon", INI::parseBool, NULL, offsetof( DeliverPayloadData, m_fireWeapon ) },
  77. //Specify an additional weaponslot to be fired while strafing
  78. { "DiveStartDistance", INI::parseReal, NULL, offsetof( DeliverPayloadData, m_diveStartDistance ) },
  79. { "DiveEndDistance", INI::parseReal, NULL, offsetof( DeliverPayloadData, m_diveEndDistance ) },
  80. { "StrafingWeaponSlot", INI::parseLookupList, TheWeaponSlotTypeNamesLookupList, offsetof( DeliverPayloadData, m_strafingWeaponSlot ) },
  81. { "StrafeWeaponFX", INI::parseFXList, NULL, offsetof( DeliverPayloadData, m_strafeFX ) },
  82. { "StrafeLength", INI::parseReal, NULL, offsetof( DeliverPayloadData, m_strafeLength ) },
  83. { "DeliveryDecal", RadiusDecalTemplate::parseRadiusDecalTemplate, NULL, offsetof( DeliverPayloadData, m_deliveryDecalTemplate ) },
  84. { "DeliveryDecalRadius", INI::parseReal, NULL, offsetof(DeliverPayloadData, m_deliveryDecalRadius) },
  85. { 0, 0, 0, 0 }
  86. };
  87. return dataFieldParse;
  88. }
  89. //-------------------------------------------------------------------------------------------------
  90. //-------------------------------------------------------------------------------------------------
  91. //-------------------------------------------------------------------------------------------------
  92. //-------------------------------------------------------------------------------------------------
  93. AIStateMachine* DeliverPayloadAIUpdate::makeStateMachine()
  94. {
  95. return newInstance(AIStateMachine)( getObject(), "DeliverPayloadBasicAI");
  96. }
  97. //-------------------------------------------------------------------------------------------------
  98. DeliverPayloadAIUpdate::DeliverPayloadAIUpdate( Thing *thing, const ModuleData* moduleData ) : AIUpdateInterface( thing, moduleData )
  99. {
  100. m_deliverPayloadStateMachine = NULL;
  101. m_targetPos.zero();
  102. m_moveToPos.zero();
  103. m_visibleItemsDelivered = 0;
  104. m_deliveryDecal.clear();
  105. m_previousDistanceSqr = 0;
  106. m_freeToExit = FALSE;
  107. m_acceptingCommands = TRUE;
  108. // Added By Sadullah Nader
  109. // Initialization missing and needed
  110. m_diveState = DIVESTATE_PREDIVE;
  111. // End Add
  112. }
  113. //-------------------------------------------------------------------------------------------------
  114. DeliverPayloadAIUpdate::~DeliverPayloadAIUpdate( void )
  115. {
  116. m_deliveryDecal.clear();
  117. if (m_deliverPayloadStateMachine)
  118. m_deliverPayloadStateMachine->deleteInstance();
  119. }
  120. //-------------------------------------------------------------------------------------------------
  121. AIFreeToExitType DeliverPayloadAIUpdate::getAiFreeToExit(const Object* exiter) const
  122. {
  123. if( getObject()->isEffectivelyDead() )
  124. return NOT_FREE_TO_EXIT;
  125. return m_freeToExit ? FREE_TO_EXIT : NOT_FREE_TO_EXIT;
  126. }
  127. //-------------------------------------------------------------------------------------------------
  128. void DeliverPayloadAIUpdate::killDeliveryDecal()
  129. {
  130. m_deliveryDecal.clear();
  131. }
  132. //-------------------------------------------------------------------------------------------------
  133. Bool DeliverPayloadAIUpdate::isAllowedToRespondToAiCommands(const AICommandParms* parms) const
  134. {
  135. if (!m_acceptingCommands)
  136. {
  137. return false;
  138. }
  139. return AIUpdateInterface::isAllowedToRespondToAiCommands(parms);
  140. }
  141. //-------------------------------------------------------------------------------------------------
  142. UpdateSleepTime DeliverPayloadAIUpdate::update( void )
  143. {
  144. m_deliveryDecal.update();
  145. if(!(isAiInDeadState()) && m_deliverPayloadStateMachine)
  146. m_deliverPayloadStateMachine->updateStateMachine();
  147. //Handling diving logic (regardless of state)
  148. if( m_diveState != DIVESTATE_POSTDIVE )
  149. {
  150. if( m_diveState == DIVESTATE_PREDIVE )
  151. {
  152. //Check to see if we are close enough to start diving.
  153. Real startDiveDistanceSquared = sqr( getData()->m_diveStartDistance );
  154. Real currentDistanceSquared = ThePartitionManager->getDistanceSquared( getObject(), getTargetPos(), FROM_CENTER_2D );
  155. if( currentDistanceSquared <= startDiveDistanceSquared )
  156. {
  157. m_diveState = DIVESTATE_DIVING;
  158. getObject()->getAIUpdateInterface()->getCurLocomotor()->setUsePreciseZPos( true );
  159. AudioEventRTS soundDive = *(getObject()->getTemplate()->getPerUnitSound("StartDive"));
  160. if( soundDive.getEventName().isNotEmpty() )
  161. {
  162. soundDive.setPosition( getObject()->getPosition() );
  163. TheAudio->addAudioEvent( &soundDive );
  164. }
  165. }
  166. }
  167. else
  168. {
  169. //Check to see when we shall end diving
  170. Real endDiveDistanceSquared = sqr( getData()->m_diveEndDistance );
  171. Real currentDistanceSquared = ThePartitionManager->getDistanceSquared( getObject(), getTargetPos(), FROM_CENTER_3D );
  172. if( currentDistanceSquared <= endDiveDistanceSquared )
  173. {
  174. m_diveState = DIVESTATE_POSTDIVE;
  175. getObject()->getAIUpdateInterface()->getCurLocomotor()->setUsePreciseZPos( false );
  176. }
  177. if( m_data.m_strafingWeaponSlot != -1 )
  178. {
  179. //SHOOT!!
  180. const Coord3D *velocity = getObject()->getPhysics()->getVelocity();
  181. if( velocity->z < 5.0f )
  182. {
  183. //Calc strafe ratio
  184. Real startDiveDistance = getData()->m_diveStartDistance;
  185. Real endDiveDistance = sqrt( endDiveDistanceSquared );
  186. Real currentDistance = sqrt( currentDistanceSquared );
  187. Real diveRatio = (startDiveDistance - currentDistance) / (startDiveDistance - endDiveDistance);
  188. Coord3D velocity = *getObject()->getPhysics()->getVelocity();
  189. velocity.z = 0.0f;
  190. velocity.normalize();
  191. velocity.scale( diveRatio * 100.0f );
  192. Coord3D backwards = velocity;
  193. backwards.scale( 0.33f );
  194. Coord3D strafePoint = *getTargetPos();
  195. strafePoint.sub( &backwards );
  196. strafePoint.add( &velocity );
  197. strafePoint.z = TheTerrainLogic->getGroundHeight( strafePoint.x, strafePoint.y );
  198. // lock it just till the weapon is empty or the attack is "done"
  199. getObject()->setWeaponLock( m_data.m_strafingWeaponSlot, LOCKED_TEMPORARILY );
  200. getObject()->fireCurrentWeapon( &strafePoint );
  201. FXList::doFXPos( m_data.m_strafeFX, &strafePoint );
  202. }
  203. }
  204. }
  205. }
  206. AIUpdateInterface::update();
  207. return UPDATE_SLEEP_NONE; // ignore our parent, and never sleep
  208. }
  209. //-------------------------------------------------------------------------------------------------
  210. void DeliverPayloadAIUpdate::deliverPayload(
  211. const Coord3D *moveToPos,
  212. const Coord3D *targetPos,
  213. const DeliverPayloadData *data
  214. )
  215. {
  216. //****************************************************
  217. //THIS GETS CALLED VIA OBJECT CREATION LISTS ONLY!!!
  218. //****************************************************
  219. if (m_deliverPayloadStateMachine)
  220. m_deliverPayloadStateMachine->deleteInstance();
  221. m_deliverPayloadStateMachine = NULL;
  222. m_moveToPos = *moveToPos;
  223. m_targetPos = *targetPos;
  224. m_data = *data;
  225. m_deliveryDecal.clear();
  226. m_data.m_deliveryDecalTemplate.createRadiusDecal(*targetPos,
  227. m_data.m_deliveryDecalRadius, getObject()->getControllingPlayer(), m_deliveryDecal);
  228. if( m_data.m_diveStartDistance <= 0.0f )
  229. {
  230. //We can't dive, so setting it to post-dive will prevent
  231. //dive logic from being processed.
  232. m_diveState = DIVESTATE_POSTDIVE;
  233. }
  234. else
  235. {
  236. m_diveState = DIVESTATE_PREDIVE;
  237. }
  238. m_visibleItemsDelivered = 0;
  239. //If we have visible bones, then show each of those subobjects.
  240. Drawable *draw = getObject()->getDrawable();
  241. if( draw )
  242. {
  243. for( int i = 1; i <= m_data.m_visibleNumBones; i++ )
  244. {
  245. if( m_data.m_visibleSubObjectName.isNotEmpty() )
  246. {
  247. AsciiString name;
  248. name.format( "%s%02d", m_data.m_visibleSubObjectName.str(), i );
  249. draw->showSubObject( name, true );
  250. }
  251. }
  252. }
  253. // must make the state machine AFTER initing the other stuff, since it may inquire of its values...
  254. m_deliverPayloadStateMachine = newInstance(DeliverPayloadStateMachine)( getObject() );
  255. m_deliverPayloadStateMachine->initDefaultState();
  256. #ifdef _DEBUG
  257. m_deliverPayloadStateMachine->setName("DeliverPayloadSpecificAI");
  258. #endif
  259. }
  260. //-------------------------------------------------------------------------------------------------
  261. void DeliverPayloadAIUpdate::deliverPayloadViaModuleData( const Coord3D *moveToPos )
  262. {
  263. const DeliverPayloadAIUpdateModuleData *data = getDeliverPayloadAIUpdateModuleData();
  264. //****************************************************
  265. //THIS GETS CALLED FOR SCRIPTED REINFORCEMENTS ONLY!!!
  266. //These don't and can't use object creation lists.
  267. //****************************************************
  268. DeliverPayloadData dpData;
  269. dpData.m_dropOffset.set( &data->m_dropOffset );
  270. dpData.m_dropVariance.set( &data->m_dropVariance );
  271. dpData.m_distToTarget = data->m_maxDistanceToTarget;
  272. dpData.m_maxAttempts = data->m_maxNumberAttempts;
  273. dpData.m_dropDelay = data->m_dropDelay;
  274. dpData.m_deliveryDecalTemplate = data->m_deliveryDecalTemplate;
  275. dpData.m_deliveryDecalRadius = data->m_deliveryDecalRadius;
  276. deliverPayload( moveToPos, moveToPos, &dpData );
  277. }
  278. //-------------------------------------------------------------------------------------------------
  279. const ThingTemplate* DeliverPayloadAIUpdate::getPutInContainerTemplateViaModuleData() const
  280. {
  281. AsciiString name = getDeliverPayloadAIUpdateModuleData()->m_putInContainerName;
  282. return name.isEmpty() ? NULL : TheThingFactory->findTemplate( name );
  283. }
  284. //-------------------------------------------------------------------------------------------------
  285. Real DeliverPayloadAIUpdate::calcMinTurnRadius(Real* timeToTravelThatDist) const
  286. {
  287. const Locomotor* loco = getCurLocomotor();
  288. BodyDamageType bdt = getObject()->getBodyModule()->getDamageState();
  289. /// @todo srj -- this should probably use min-speed, not max-speed... fix after E3
  290. Real maxSpeed = loco->getMaxSpeedForCondition(bdt); // in dist/frame
  291. Real maxTurnRate = loco->getMaxTurnRate(bdt); // in rads/frame
  292. /*
  293. our minimum circumference will be like so:
  294. Real minTurnCircum = maxSpeed * (2*PI / maxTurnRate);
  295. so therefore our minimum turn radius is:
  296. Real minTurnRadius = minTurnCircum / 2*PI;
  297. so we just eliminate the middleman:
  298. */
  299. Real minTurnRadius = (maxTurnRate > 0.0f) ? (maxSpeed / maxTurnRate) : 999999.0f;
  300. if (timeToTravelThatDist)
  301. *timeToTravelThatDist = minTurnRadius / maxSpeed;
  302. return minTurnRadius;
  303. }
  304. //-------------------------------------------------------------------------------------------------
  305. Bool DeliverPayloadAIUpdate::isCloseEnoughToTarget()
  306. {
  307. // In addition to testing distance, it is also sensitive to being in/outward bound
  308. ////The new getPreOpenDistance() allows the deliver state to fire early, but only if inbound,
  309. ////so the doors can open and payload can get ready...
  310. Real allowedDistanceSqr = sqr( getAllowedDistanceToTarget() );
  311. Real currentDistanceSqr = ThePartitionManager->getDistanceSquared( getObject(), getTargetPos(), FROM_CENTER_2D );
  312. Bool inBound = m_previousDistanceSqr > currentDistanceSqr;
  313. m_previousDistanceSqr = currentDistanceSqr;// for the next test
  314. if ( inBound )
  315. allowedDistanceSqr = sqr(getAllowedDistanceToTarget() + getPreOpenDistance());
  316. //DEBUG_LOG(("Dist to target is %f (allowed %f)\n",sqrt(currentDistanceSqr),sqrt(allowedDistanceSqr)));
  317. if ( allowedDistanceSqr > currentDistanceSqr )
  318. return TRUE;
  319. return FALSE;
  320. }
  321. //-------------------------------------------------------------------------------------------------
  322. Bool DeliverPayloadAIUpdate::isOffMap() const
  323. {
  324. Region3D mapRegion;
  325. TheTerrainLogic->getExtentIncludingBorder( &mapRegion );
  326. if (!mapRegion.isInRegionNoZ( getObject()->getPosition() ))
  327. return true;
  328. return false;
  329. }
  330. // ------------------------------------------------------------------------------------------------
  331. /** CRC */
  332. // ------------------------------------------------------------------------------------------------
  333. void DeliverPayloadAIUpdate::crc( Xfer *xfer )
  334. {
  335. // extend base class
  336. AIUpdateInterface::crc(xfer);
  337. } // end crc
  338. // ------------------------------------------------------------------------------------------------
  339. /** Xfer method
  340. * Version Info:
  341. * 1: Initial version */
  342. // ------------------------------------------------------------------------------------------------
  343. void DeliverPayloadAIUpdate::xfer( Xfer *xfer )
  344. {
  345. // version
  346. const XferVersion currentVersion = 3;
  347. XferVersion version = currentVersion;
  348. xfer->xferVersion( &version, currentVersion );
  349. // extend base class
  350. AIUpdateInterface::xfer(xfer);
  351. xfer->xferCoord3D(&m_targetPos);
  352. xfer->xferCoord3D(&m_moveToPos);
  353. xfer->xferInt(&m_visibleItemsDelivered);
  354. xfer->xferUser(&m_diveState, sizeof(m_diveState));
  355. DeliverPayloadData data = m_data;
  356. xfer->xferAsciiString(&data.m_visibleDropBoneName);
  357. xfer->xferAsciiString(&data.m_visibleSubObjectName);
  358. xfer->xferAsciiString(&data.m_visiblePayloadTemplateName);
  359. xfer->xferReal(&data.m_distToTarget);
  360. xfer->xferInt(&data.m_maxAttempts);
  361. xfer->xferCoord3D(&data.m_dropOffset);
  362. xfer->xferCoord3D(&data.m_dropVariance);
  363. xfer->xferUnsignedInt(&data.m_dropDelay);
  364. xfer->xferBool(&data.m_fireWeapon);
  365. xfer->xferBool(&data.m_selfDestructObject);
  366. xfer->xferInt(&data.m_visibleNumBones);
  367. xfer->xferReal(&data.m_diveStartDistance);
  368. xfer->xferReal(&data.m_diveEndDistance);
  369. xfer->xferUser(&data.m_strafingWeaponSlot, sizeof(data.m_strafingWeaponSlot));
  370. xfer->xferInt(&data.m_visibleItemsDroppedPerInterval);
  371. xfer->xferBool(&data.m_inheritTransportVelocity);
  372. xfer->xferBool(&data.m_isParachuteDirectly);
  373. xfer->xferReal(&data.m_exitPitchRate);
  374. // const FXList *m_strafeFX;
  375. xfer->xferReal(&data.m_strafeLength);
  376. AsciiString weaponTemplateName;
  377. if (data.m_visiblePayloadWeaponTemplate)
  378. {
  379. weaponTemplateName = data.m_visiblePayloadWeaponTemplate->getName();
  380. }
  381. xfer->xferAsciiString(&weaponTemplateName);
  382. if( xfer->getXferMode() == XFER_LOAD && weaponTemplateName.isNotEmpty())
  383. {
  384. data.m_visiblePayloadWeaponTemplate = TheWeaponStore->findWeaponTemplate(weaponTemplateName);
  385. }
  386. data.m_deliveryDecalTemplate.xferRadiusDecalTemplate(xfer);
  387. xfer->xferReal(&data.m_deliveryDecalRadius);
  388. *((DeliverPayloadData*)&m_data) = data;
  389. Bool hasStateMachine = m_deliverPayloadStateMachine!=NULL;
  390. xfer->xferBool(&hasStateMachine);
  391. if (hasStateMachine && m_deliverPayloadStateMachine==NULL)
  392. {
  393. m_deliverPayloadStateMachine = newInstance(DeliverPayloadStateMachine)( getObject() );
  394. }
  395. if (m_deliverPayloadStateMachine && version >= 2)
  396. {
  397. xfer->xferSnapshot(m_deliverPayloadStateMachine);
  398. }
  399. m_deliveryDecal.xferRadiusDecal(xfer);
  400. if (version >= 2)
  401. {
  402. xfer->xferBool(&m_freeToExit);
  403. }
  404. if (version >= 3)
  405. {
  406. xfer->xferBool(&m_acceptingCommands);
  407. }
  408. } // end xfer
  409. // ------------------------------------------------------------------------------------------------
  410. /** Load post process */
  411. // ------------------------------------------------------------------------------------------------
  412. void DeliverPayloadAIUpdate::loadPostProcess( void )
  413. {
  414. // extend base class
  415. AIUpdateInterface::loadPostProcess();
  416. } // end loadPostProcess
  417. //-------------------------------------------------------------------------------------------------
  418. //-------------------------------------------------------------------------------------------------
  419. //-------------------------------------------------------------------------------------------------
  420. //-------------------------------------------------------------------------------------------------
  421. DeliverPayloadStateMachine::DeliverPayloadStateMachine( Object *owner ) : StateMachine( owner, "DeliverPayloadStateMachine" )
  422. {
  423. // DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  424. static const StateConditionInfo considerConditions[] =
  425. {
  426. StateConditionInfo(DeliverPayloadStateMachine::isOffMap, RECOVER_FROM_OFF_MAP, NULL),
  427. StateConditionInfo(NULL, NULL, NULL) // keep last
  428. };
  429. // order matters: first state is the default state.
  430. defineState( APPROACH, newInstance(ApproachState)( this ), DELIVERING, CONSIDER_NEW_APPROACH );
  431. defineState( DELIVERING, newInstance(DeliveringState)( this ), HEAD_OFF_MAP, CONSIDER_NEW_APPROACH );
  432. defineState( CONSIDER_NEW_APPROACH, newInstance(ConsiderNewApproachState)( this ), APPROACH, HEAD_OFF_MAP, considerConditions );
  433. defineState( RECOVER_FROM_OFF_MAP, newInstance(RecoverFromOffMapState)( this ), APPROACH, APPROACH );
  434. defineState( HEAD_OFF_MAP, newInstance(HeadOffMapState)( this ), CLEAN_UP, CLEAN_UP );
  435. defineState( CLEAN_UP, newInstance(CleanUpState)( this ), INVALID_STATE_ID, INVALID_STATE_ID );
  436. }
  437. //-------------------------------------------------------------------------------------------------
  438. DeliverPayloadStateMachine::~DeliverPayloadStateMachine()
  439. {
  440. }
  441. // ------------------------------------------------------------------------------------------------
  442. /** CRC */
  443. // ------------------------------------------------------------------------------------------------
  444. void DeliverPayloadStateMachine::crc( Xfer *xfer )
  445. {
  446. StateMachine::crc(xfer);
  447. } // end crc
  448. // ------------------------------------------------------------------------------------------------
  449. /** Xfer Method */
  450. // ------------------------------------------------------------------------------------------------
  451. void DeliverPayloadStateMachine::xfer( Xfer *xfer )
  452. {
  453. XferVersion cv = 1;
  454. XferVersion v = cv;
  455. xfer->xferVersion( &v, cv );
  456. StateMachine::xfer(xfer);
  457. } // end xfer
  458. // ------------------------------------------------------------------------------------------------
  459. /** Load post process */
  460. // ------------------------------------------------------------------------------------------------
  461. void DeliverPayloadStateMachine::loadPostProcess( void )
  462. {
  463. StateMachine::loadPostProcess();
  464. } // end loadPostProcess
  465. //-------------------------------------------------------------------------------------------------
  466. /*static*/ Bool DeliverPayloadStateMachine::isOffMap( State *thisState, void* userData )
  467. {
  468. Object *owner = thisState->getMachineOwner();
  469. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  470. if( !ai )
  471. {
  472. return TRUE;
  473. }
  474. return ai->isOffMap();
  475. }
  476. //-------------------------------------------------------------------------------------------------
  477. //-------------------------------------------------------------------------------------------------
  478. //-------------------------------------------------------------------------------------------------
  479. //-------------------------------------------------------------------------------------------------
  480. StateReturnType ApproachState::onEnter() // Give the move command
  481. {
  482. Object *owner = getMachineOwner();
  483. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  484. if( !ai )
  485. {
  486. return STATE_FAILURE;
  487. }
  488. if (ai->isAiInDeadState())
  489. {
  490. return STATE_FAILURE;
  491. }
  492. ai->aiMoveToPosition( ai->getMoveToPos(), CMD_FROM_AI );
  493. return STATE_CONTINUE;
  494. }
  495. //-------------------------------------------------------------------------------------------------
  496. StateReturnType ApproachState::update()
  497. {
  498. Object *owner = getMachineOwner();
  499. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  500. if( !ai )
  501. {
  502. return STATE_FAILURE;
  503. }
  504. if (ai->isAiInDeadState())
  505. {
  506. return STATE_FAILURE;
  507. }
  508. if (ai->isCloseEnoughToTarget())
  509. return STATE_SUCCESS;
  510. if (ai->getAIStateType() != AI_MOVE_TO)
  511. {
  512. DEBUG_CRASH(("hmm, bailed from moveto state early... should this be possible?"));
  513. ai->aiMoveToPosition( ai->getMoveToPos(), CMD_FROM_AI );
  514. }
  515. return STATE_CONTINUE;
  516. }
  517. //-------------------------------------------------------------------------------------------------
  518. //-------------------------------------------------------------------------------------------------
  519. //-------------------------------------------------------------------------------------------------
  520. // ------------------------------------------------------------------------------------------------
  521. /** CRC */
  522. // ------------------------------------------------------------------------------------------------
  523. void DeliveringState::crc( Xfer *xfer )
  524. {
  525. } // end crc
  526. // ------------------------------------------------------------------------------------------------
  527. /** Xfer Method */
  528. // ------------------------------------------------------------------------------------------------
  529. void DeliveringState::xfer( Xfer *xfer )
  530. {
  531. // version
  532. XferVersion currentVersion = 1;
  533. XferVersion version = currentVersion;
  534. xfer->xferVersion( &version, currentVersion );
  535. xfer->xferUnsignedInt(&m_dropDelayLeft);
  536. xfer->xferBool(&m_didOpen);
  537. } // end xfer
  538. // ------------------------------------------------------------------------------------------------
  539. /** Load post process */
  540. // ------------------------------------------------------------------------------------------------
  541. void DeliveringState::loadPostProcess( void )
  542. {
  543. } // end loadPostProcess
  544. //-------------------------------------------------------------------------------------------------
  545. StateReturnType DeliveringState::onEnter() // Open the pod bay doors, Hal
  546. {
  547. Object *owner = getMachineOwner();
  548. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  549. if( !ai )
  550. {
  551. return STATE_FAILURE;
  552. }
  553. /// @todo srj -- for now, this assumes at most one door
  554. owner->clearAndSetModelConditionState( MODELCONDITION_DOOR_1_CLOSING, MODELCONDITION_DOOR_1_OPENING );
  555. m_dropDelayLeft = ai->getDoorDelay();
  556. m_didOpen = false;
  557. return STATE_CONTINUE;
  558. }
  559. //-------------------------------------------------------------------------------------------------
  560. StateReturnType DeliveringState::update() // Kick a dude out every so often
  561. {
  562. if (m_dropDelayLeft > 0)
  563. {
  564. --m_dropDelayLeft;
  565. return STATE_CONTINUE;
  566. }
  567. Object *owner = getMachineOwner();
  568. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  569. if( !ai )
  570. {
  571. return STATE_FAILURE;
  572. }
  573. ai->friend_setFreeToExit(true);
  574. m_didOpen = true;
  575. m_dropDelayLeft = ai->getDropDelay();
  576. if (!ai->isCloseEnoughToTarget())
  577. return STATE_FAILURE;
  578. const ContainedItemsList* items = owner->getContain() ? owner->getContain()->getContainedItemsList() : NULL;
  579. if( (!items || !items->size()) && ai->getVisibleItemsDelivered() == ai->getData()->m_visibleNumBones )
  580. {
  581. //We are out of payload to drop AND our visible payload is empty. It's possible for deliverers to
  582. //have one or the other or even both.
  583. return STATE_SUCCESS;
  584. }
  585. //Handle contained payload delivery.
  586. if( items )
  587. {
  588. Object* item = items->front();
  589. if( ai->isFireWeapon() )
  590. {
  591. Coord3D pos = *ai->getTargetPos();
  592. pos.x += ai->getDropOffset().x;
  593. pos.y += ai->getDropOffset().y;
  594. pos.z += ai->getDropOffset().z;
  595. owner->fireCurrentWeapon( &pos );
  596. TheGameLogic->destroyObject( item );
  597. }
  598. else
  599. {
  600. AIUpdateInterface* itemAI = item->getAIUpdateInterface();
  601. if (itemAI)
  602. {
  603. itemAI->aiExit(NULL, CMD_FROM_AI);
  604. }
  605. Coord3D pos = *item->getPosition();
  606. if (ai->getDropVariance().x > 0)
  607. pos.x += GameLogicRandomValueReal(-ai->getDropVariance().x, ai->getDropVariance().x);
  608. if (ai->getDropVariance().y > 0)
  609. pos.y += GameLogicRandomValueReal(-ai->getDropVariance().y, ai->getDropVariance().y);
  610. if (ai->getDropVariance().z > 0)
  611. pos.z += GameLogicRandomValueReal(-ai->getDropVariance().z, ai->getDropVariance().z);
  612. pos.x += ai->getDropOffset().x;
  613. pos.y += ai->getDropOffset().y;
  614. pos.z += ai->getDropOffset().z;
  615. item->setPosition(&pos);
  616. ContainModuleInterface *contain = item->getContain();
  617. if( ai->getData()->m_isParachuteDirectly && contain )
  618. {
  619. contain->setOverrideDestination( ai->getTargetPos() );// go for the direct hit
  620. }
  621. else if (itemAI)
  622. {
  623. // This will most likely be ignored, as the item is still in the transport, and therefore Held.
  624. itemAI->aiMoveToPosition( ai->getMoveToPos(), CMD_FROM_AI );
  625. }
  626. /// @todo srj -- urg. icky.
  627. static NameKeyType key_GenerateMinefieldBehavior = NAMEKEY("GenerateMinefieldBehavior");
  628. GenerateMinefieldBehavior* mfb = (GenerateMinefieldBehavior *)item->findUpdateModule(key_GenerateMinefieldBehavior);
  629. if (mfb)
  630. {
  631. mfb->setMinefieldTarget(ai->getMoveToPos());
  632. }
  633. if( ai->getData()->m_inheritTransportVelocity )
  634. {
  635. Coord3D velocity = *owner->getPhysics()->getVelocity();
  636. item->getPhysics()->applyForce( &velocity );
  637. }
  638. }
  639. }
  640. //Handle visible payload delivery.
  641. if( ai->getVisibleItemsDelivered() < ai->getData()->m_visibleNumBones )
  642. {
  643. Int attemptDrops = ai->getData()->m_visibleItemsDroppedPerInterval;
  644. Drawable *draw = owner->getDrawable();
  645. Bool updateSubObjects = false;
  646. while( attemptDrops && ai->getVisibleItemsDelivered() < ai->getData()->m_visibleNumBones )
  647. {
  648. //Drop an item!
  649. if( draw )
  650. {
  651. //First hide the subobject as it becomes the delivered payload.
  652. if( ai->getData()->m_visibleSubObjectName.isNotEmpty() )
  653. {
  654. AsciiString name;
  655. name.format( "%s%02d", ai->getData()->m_visibleSubObjectName.str(), ai->getVisibleItemsDelivered() + 1 );
  656. draw->showSubObject( name, false );
  657. updateSubObjects = true;
  658. }
  659. //Second, create the subobject for real
  660. if( ai->getData()->m_visiblePayloadTemplateName.isNotEmpty() )
  661. {
  662. const ThingTemplate* thing = TheThingFactory->findTemplate( ai->getData()->m_visiblePayloadTemplateName.str() );
  663. Object *payload = TheThingFactory->newObject( thing, owner->getControllingPlayer()->getDefaultTeam() );
  664. if( payload )
  665. {
  666. payload->setProducer( owner );
  667. if( ai->getData()->m_visibleDropBoneName.isNotEmpty() )
  668. {
  669. Coord3D pos;
  670. AsciiString bone;
  671. bone.format( "%s%02d", ai->getData()->m_visibleDropBoneName.str(), ai->getVisibleItemsDelivered() + 1 );
  672. if( draw->getPristineBonePositions( ai->getData()->m_visibleDropBoneName.str(), ai->getVisibleItemsDelivered() + 1, &pos, NULL, 1 ) > 0 )
  673. {
  674. draw->convertBonePosToWorldPos( &pos, NULL, &pos, NULL );
  675. payload->setPosition( &pos );
  676. }
  677. else
  678. {
  679. payload->setPosition( owner->getPosition() );
  680. }
  681. }
  682. else
  683. {
  684. payload->setPosition( owner->getPosition() );
  685. }
  686. payload->setOrientation( owner->getOrientation() );
  687. //If we want the payload to inherit the transport's velocity, do so now.
  688. if( ai->getData()->m_inheritTransportVelocity )
  689. {
  690. Coord3D startingForce = *owner->getPhysics()->getVelocity();
  691. startingForce.scale( payload->getPhysics()->getMass() );
  692. payload->getPhysics()->applyMotiveForce( &startingForce );
  693. Coord3D backPosition = *owner->getPhysics()->getVelocity();
  694. backPosition.scale( -1.0f );
  695. backPosition.add( payload->getPosition() );
  696. payload->setPosition( &backPosition );
  697. }
  698. //Are we firing a missile?
  699. Bool projectileFired = false;
  700. for( BehaviorModule** u = payload->getBehaviorModules(); *u; ++u )
  701. {
  702. ProjectileUpdateInterface* pui = (*u)->getProjectileUpdateInterface();
  703. if( pui )
  704. {
  705. //Missile!
  706. const WeaponTemplate *weaponTemplate = ai->getData()->m_visiblePayloadWeaponTemplate;
  707. if( !weaponTemplate )
  708. {
  709. DEBUG_ASSERTCRASH( 0, ("%s tried to fire missile %s via DeliverPayload, and is missing required weapon template in ObjectCreationList.ini entry.",
  710. owner->getTemplate()->getName().str(), payload->getTemplate()->getName().str() ) );
  711. break;
  712. }
  713. VeterancyLevel v = owner->getVeterancyLevel();
  714. pui->projectileFireAtObjectOrPosition( NULL, ai->getTargetPos(), weaponTemplate, weaponTemplate->getProjectileExhaust(v) );
  715. projectileFired = true;
  716. //damageInfo.in.m_sourceID = pui->projectileGetLauncherID();
  717. break;
  718. }
  719. }
  720. //If not, are we dropping a bomb?
  721. if( !projectileFired )
  722. {
  723. //Bomb!
  724. if( ai->getData()->m_exitPitchRate != 0 )
  725. {
  726. //If the payload needs to pitch, do so now.
  727. Real pitchRate = payload->getPhysics()->getCenterOfMassOffset() * ai->getData()->m_exitPitchRate;
  728. payload->getPhysics()->setPitchRate( pitchRate );
  729. }
  730. //If payload can move independently, order the move. A lot of bombs don't have locomotors,
  731. //in which case the "start move sound" is played, but nothing else actually happens.
  732. if( payload->getAIUpdateInterface() )
  733. {
  734. payload->getAIUpdateInterface()->aiMoveToPosition( ai->getMoveToPos(), CMD_FROM_AI );
  735. }
  736. }
  737. }
  738. }
  739. }
  740. //Update the counters
  741. attemptDrops--;
  742. ai->setVisibleItemsDelivered( ai->getVisibleItemsDelivered() + 1 );
  743. }
  744. if( updateSubObjects )
  745. {
  746. draw->updateSubObjects();
  747. }
  748. }
  749. return STATE_CONTINUE;
  750. }
  751. //-------------------------------------------------------------------------------------------------
  752. void DeliveringState::onExit( StateExitType ) // Close the doors
  753. {
  754. Object *owner = getMachineOwner();
  755. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  756. if (ai)
  757. ai->friend_setFreeToExit(false);
  758. DEBUG_ASSERTCRASH(m_didOpen, ("Not enough time for the doors to open to drop anything!"));
  759. /// @todo srj -- for now, this assumes at most one door
  760. owner->clearAndSetModelConditionState( MODELCONDITION_DOOR_1_OPENING, MODELCONDITION_DOOR_1_CLOSING );
  761. }
  762. //-------------------------------------------------------------------------------------------------
  763. //-------------------------------------------------------------------------------------------------
  764. //-------------------------------------------------------------------------------------------------
  765. // ------------------------------------------------------------------------------------------------
  766. /** CRC */
  767. // ------------------------------------------------------------------------------------------------
  768. void ConsiderNewApproachState::crc( Xfer *xfer )
  769. {
  770. } // end crc
  771. // ------------------------------------------------------------------------------------------------
  772. /** Xfer Method */
  773. // ------------------------------------------------------------------------------------------------
  774. void ConsiderNewApproachState::xfer( Xfer *xfer )
  775. {
  776. // version
  777. XferVersion currentVersion = 1;
  778. XferVersion version = currentVersion;
  779. xfer->xferVersion( &version, currentVersion );
  780. xfer->xferInt(&m_numberEntriesToState);
  781. } // end xfer
  782. // ------------------------------------------------------------------------------------------------
  783. /** Load post process */
  784. // ------------------------------------------------------------------------------------------------
  785. void ConsiderNewApproachState::loadPostProcess( void )
  786. {
  787. } // end loadPostProcess
  788. //-------------------------------------------------------------------------------------------------
  789. StateReturnType ConsiderNewApproachState::onEnter() // Increment local counter o' futility
  790. {
  791. Object *owner = getMachineOwner();
  792. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  793. if( !ai )
  794. {
  795. return STATE_FAILURE;
  796. }
  797. ++m_numberEntriesToState;
  798. DEBUG_LOG(("Considering approach #%d...\n",m_numberEntriesToState));
  799. if( m_numberEntriesToState > ai->getMaxNumberAttempts() )
  800. {
  801. DEBUG_LOG(("Too many approaches! Time to give up.\n"));
  802. return STATE_FAILURE;
  803. }
  804. // ok, play some games here... the pathfinder is pretty dumb about things with big turning radii,
  805. // so we have to force the issue here... basically, estimate our necessary turning radius
  806. // based on loco values, move off far enough so we can turn, then head back. (if we just say
  807. // "head back directly", the code will just keep turning in circles, not realizing that our
  808. // turning radius is too large for that ever to work.)
  809. Real minTurnRadius = ai->calcMinTurnRadius(NULL);
  810. // how far is "far enough"? we must be at least 2*radius dist away from our target.
  811. // (we add a little fudge since we may not be able to travel our max speed while
  812. // turning.)
  813. const Real DIST_FUDGE = 2.2f;
  814. Real minReApproachDist = minTurnRadius * DIST_FUDGE;
  815. const Coord3D* dir = owner->getUnitDirectionVector2D();
  816. Coord3D reApproachPoint;
  817. reApproachPoint.x = owner->getPosition()->x + dir->x * minReApproachDist;
  818. reApproachPoint.y = owner->getPosition()->y + dir->y * minReApproachDist;
  819. reApproachPoint.z = 0.0f; // yeah, yeah, should be terrainpos, but doesn't really matter here...
  820. ai->aiMoveToPosition( &reApproachPoint, CMD_FROM_AI );
  821. // we allow these guys to go to invalid (ie, off-map) positions
  822. ai->getCurLocomotor()->setAllowInvalidPosition(true);
  823. return STATE_CONTINUE;
  824. }
  825. //-------------------------------------------------------------------------------------------------
  826. StateReturnType ConsiderNewApproachState::update() // Success if we should try again, failure if we should give up
  827. {
  828. Object *owner = getMachineOwner();
  829. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  830. if( !ai )
  831. {
  832. return STATE_FAILURE;
  833. }
  834. // stay in this state 'till we reach our goal.
  835. if (ai->getAIStateType() != AI_MOVE_TO)
  836. {
  837. return STATE_SUCCESS;
  838. }
  839. return STATE_CONTINUE;
  840. }
  841. //-------------------------------------------------------------------------------------------------
  842. void ConsiderNewApproachState::onExit( StateExitType status )
  843. {
  844. Object *owner = getMachineOwner();
  845. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  846. if( !ai )
  847. {
  848. return;
  849. }
  850. // go back to normal.
  851. ai->getCurLocomotor()->setAllowInvalidPosition(true);
  852. }
  853. //-------------------------------------------------------------------------------------------------
  854. //-------------------------------------------------------------------------------------------------
  855. //-------------------------------------------------------------------------------------------------
  856. // ------------------------------------------------------------------------------------------------
  857. /** CRC */
  858. // ------------------------------------------------------------------------------------------------
  859. void RecoverFromOffMapState::crc( Xfer *xfer )
  860. {
  861. } // end crc
  862. // ------------------------------------------------------------------------------------------------
  863. /** Xfer Method */
  864. // ------------------------------------------------------------------------------------------------
  865. void RecoverFromOffMapState::xfer( Xfer *xfer )
  866. {
  867. // version
  868. XferVersion currentVersion = 1;
  869. XferVersion version = currentVersion;
  870. xfer->xferVersion( &version, currentVersion );
  871. xfer->xferUnsignedInt(&m_reEntryFrame);
  872. } // end xfer
  873. // ------------------------------------------------------------------------------------------------
  874. /** Load post process */
  875. // ------------------------------------------------------------------------------------------------
  876. void RecoverFromOffMapState::loadPostProcess( void )
  877. {
  878. } // end loadPostProcess
  879. //-------------------------------------------------------------------------------------------------
  880. StateReturnType RecoverFromOffMapState::onEnter() // Increment local counter o' futility
  881. {
  882. Object *owner = getMachineOwner();
  883. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  884. if( !ai )
  885. {
  886. return STATE_FAILURE;
  887. }
  888. // have him hold in place, if possible.
  889. ai->aiMoveToPosition( owner->getPosition(), CMD_FROM_AI );
  890. // a little cheesy... make a delay based on turn-radius time to simulate offscreen
  891. // maneuvering.
  892. Real timeToTravelThatDist;
  893. /*Real minTurnRadius =*/ ai->calcMinTurnRadius(&timeToTravelThatDist);
  894. m_reEntryFrame = TheGameLogic->getFrame() + REAL_TO_INT_CEIL(timeToTravelThatDist);
  895. // kill its momentum
  896. PhysicsBehavior* physics = owner->getPhysics();
  897. physics->resetDynamicPhysics();
  898. ThePartitionManager->unRegisterObject( owner );
  899. if( owner->getDrawable() )
  900. owner->getDrawable()->setDrawableHidden( true );
  901. return STATE_CONTINUE;
  902. }
  903. //-------------------------------------------------------------------------------------------------
  904. StateReturnType RecoverFromOffMapState::update() // Success if we should try again, failure if we should give up
  905. {
  906. if (TheGameLogic->getFrame() < m_reEntryFrame)
  907. return STATE_CONTINUE;
  908. Object *owner = getMachineOwner();
  909. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  910. if( !ai )
  911. {
  912. return STATE_FAILURE;
  913. }
  914. ThePartitionManager->registerObject( owner );
  915. if( owner->getDrawable() )
  916. owner->getDrawable()->setDrawableHidden( false );
  917. Coord3D enterCoord = TheTerrainLogic->findClosestEdgePoint( owner->getPosition() );
  918. if (owner->isAboveTerrain())
  919. enterCoord.z = owner->getPosition()->z;
  920. owner->setPosition(&enterCoord);
  921. Real enterAngle = atan2(ai->getMoveToPos()->y - enterCoord.y, ai->getMoveToPos()->x - enterCoord.x);
  922. owner->setOrientation(enterAngle);
  923. PhysicsBehavior* physics = owner->getPhysics();
  924. physics->resetDynamicPhysics();
  925. return STATE_SUCCESS;
  926. }
  927. //-------------------------------------------------------------------------------------------------
  928. //-------------------------------------------------------------------------------------------------
  929. //-------------------------------------------------------------------------------------------------
  930. //-------------------------------------------------------------------------------------------------
  931. StateReturnType HeadOffMapState::onEnter() // Give move order out of town
  932. {
  933. Object *owner = getMachineOwner();
  934. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  935. if( !ai )
  936. {
  937. return STATE_FAILURE;
  938. }
  939. ai->killDeliveryDecal();
  940. if ( ai->getData()->m_selfDestructObject ) //Lorenzen... this makes delivery unit pop away like a bubble...
  941. {
  942. TheGameLogic->destroyObject( owner );
  943. return STATE_CONTINUE;
  944. }
  945. //Coord3D exitCoord = TheTerrainLogic->findClosestEdgePoint( owner->getPosition() );
  946. // just keep moving straight ahead till we exit the map.
  947. Coord3D exitCoord = *owner->getPosition();
  948. const Coord3D* dir = owner->getUnitDirectionVector2D();
  949. Region3D terrainExtent;
  950. TheTerrainLogic->getExtent( &terrainExtent );
  951. const Real FUDGE = 1.2f;
  952. Real HUGE_DIST = FUDGE * sqrt(sqr(terrainExtent.hi.x - terrainExtent.lo.x) + sqr(terrainExtent.hi.y - terrainExtent.lo.y));
  953. exitCoord.x += dir->x * HUGE_DIST;
  954. exitCoord.y += dir->y * HUGE_DIST;
  955. ai->getCurLocomotor()->setAllowInvalidPosition(true);
  956. ai->getCurLocomotor()->setUltraAccurate(true); // set ultra-accurate just so AI won't try to adjust our dest
  957. ai->aiMoveToPosition( &exitCoord, CMD_FROM_AI );
  958. // once we get into head-off-map state, we're done... don't respond to anything else.
  959. // this addresses the bug where a plane delivering team "foo" hasn't made it off the map
  960. // before all of team "foo" lands, whereupon team "foo" is given a script command to
  961. // (say) move to a given point... and since the cargo plane might be a member of "foo"
  962. // it would respond to said command, which sucks and is confusing. might be better
  963. // to have these guys generally ignore most commands, but this is pretty safe, in that
  964. // AFAIK nothing with deliverpayload should ever respond to anything, not even IDLE,
  965. // once they start heading off the map. (srj)
  966. ai->friend_setAcceptingCommands(false);
  967. return STATE_CONTINUE;
  968. }
  969. //-------------------------------------------------------------------------------------------------
  970. StateReturnType HeadOffMapState::update()
  971. {
  972. Object *owner = getMachineOwner();
  973. DeliverPayloadAIUpdate *ai = (DeliverPayloadAIUpdate*)owner->getAIUpdateInterface();
  974. if( !ai )
  975. {
  976. return STATE_FAILURE;
  977. }
  978. if (ai->isOffMap())
  979. return STATE_SUCCESS;
  980. return STATE_CONTINUE;
  981. }
  982. //-------------------------------------------------------------------------------------------------
  983. //-------------------------------------------------------------------------------------------------
  984. //-------------------------------------------------------------------------------------------------
  985. //-------------------------------------------------------------------------------------------------
  986. StateReturnType CleanUpState::onEnter() // Delete my successful butt
  987. {
  988. if( getMachineOwner()->getContain() )
  989. {
  990. DEBUG_ASSERTCRASH(getMachineOwner()->getContain()->getContainCount() == 0, ("did not drop all items!"));
  991. }
  992. Object *owner = getMachineOwner();
  993. TheGameLogic->destroyObject( owner );
  994. return STATE_CONTINUE;
  995. }