NeutronMissileUpdate.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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: NeutronMissileUpdate.cpp
  24. // Author: Michael S. Booth, December 2001
  25. // Desc: Implementation of missile behavior
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "Common/GameState.h"
  28. #include "Common/Thing.h"
  29. #include "Common/ThingTemplate.h"
  30. #include "Common/RandomValue.h"
  31. #include "Common/Xfer.h"
  32. #include "GameLogic/ExperienceTracker.h"
  33. #include "GameLogic/GameLogic.h"
  34. #include "GameLogic/TerrainLogic.h"
  35. #include "GameLogic/Object.h"
  36. #include "GameLogic/PartitionManager.h"
  37. #include "GameLogic/Module/NeutronMissileUpdate.h"
  38. #include "GameLogic/Module/AIUpdate.h"
  39. #include "GameLogic/Module/PhysicsUpdate.h"
  40. #include "GameClient/Drawable.h"
  41. #include "GameClient/FXList.h"
  42. #include "GameClient/InGameUI.h"
  43. #include "GameClient/ParticleSys.h"
  44. static const Real STRAIGHT_DOWN_SLOW_FACTOR = 0.5f;
  45. //-----------------------------------------------------------------------------
  46. //-----------------------------------------------------------------------------
  47. //-----------------------------------------------------------------------------
  48. //-----------------------------------------------------------------------------
  49. NeutronMissileUpdateModuleData::NeutronMissileUpdateModuleData()
  50. {
  51. m_initialDist = 0.0f;
  52. m_maxTurnRate = 999.0f;
  53. m_forwardDamping = 0;
  54. m_relativeSpeed = 1.0f;
  55. m_targetFromDirectlyAbove = 0.0f;
  56. m_ignitionFX = NULL;
  57. m_launchFX = NULL;
  58. m_specialAccelFactor = 1.0f;
  59. m_specialSpeedTime = 0;
  60. m_specialSpeedHeight = 0.0f;
  61. m_specialJitterDistance = 0.0f;
  62. m_deliveryDecalRadius = 0;
  63. }
  64. //-----------------------------------------------------------------------------
  65. void NeutronMissileUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
  66. {
  67. UpdateModuleData::buildFieldParse(p);
  68. static const FieldParse dataFieldParse[] =
  69. {
  70. { "DistanceToTravelBeforeTurning", INI::parseReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_initialDist ) },
  71. { "MaxTurnRate", INI::parseAngularVelocityReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_maxTurnRate ) },
  72. { "ForwardDamping", INI::parseReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_forwardDamping ) },
  73. { "RelativeSpeed", INI::parseReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_relativeSpeed ) },
  74. { "TargetFromDirectlyAbove", INI::parseReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_targetFromDirectlyAbove ) },
  75. { "LaunchFX", INI::parseFXList, NULL, offsetof( NeutronMissileUpdateModuleData, m_launchFX ) },
  76. { "SpecialSpeedTime", INI::parseDurationUnsignedInt, NULL, offsetof( NeutronMissileUpdateModuleData, m_specialSpeedTime ) },
  77. { "SpecialSpeedHeight", INI::parseReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_specialSpeedHeight ) },
  78. { "SpecialAccelFactor", INI::parseReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_specialAccelFactor ) },
  79. { "SpecialJitterDistance", INI::parseReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_specialJitterDistance ) },
  80. { "IgnitionFX", INI::parseFXList, NULL, offsetof( NeutronMissileUpdateModuleData, m_ignitionFX ) },
  81. { "DeliveryDecal", RadiusDecalTemplate::parseRadiusDecalTemplate, NULL, offsetof( NeutronMissileUpdateModuleData, m_deliveryDecalTemplate ) },
  82. { "DeliveryDecalRadius", INI::parseReal, NULL, offsetof( NeutronMissileUpdateModuleData, m_deliveryDecalRadius ) },
  83. { 0, 0, 0, 0 }
  84. };
  85. p.add(dataFieldParse);
  86. }
  87. //-------------------------------------------------------------------------------------------------
  88. //-------------------------------------------------------------------------------------------------
  89. //-------------------------------------------------------------------------------------------------
  90. //-------------------------------------------------------------------------------------------------
  91. NeutronMissileUpdate::NeutronMissileUpdate( Thing *thing, const ModuleData* moduleData ) : UpdateModule( thing, moduleData )
  92. {
  93. const NeutronMissileUpdateModuleData* d = getNeutronMissileUpdateModuleData();
  94. m_noTurnDistLeft = d->m_initialDist;
  95. m_reachedIntermediatePos = true;
  96. m_targetPos.zero();
  97. m_intermedPos.zero();
  98. m_accel.zero();
  99. m_vel.zero();
  100. m_state = PRELAUNCH;
  101. m_stateTimestamp = TheGameLogic->getFrame();
  102. m_isArmed = false;
  103. m_isLaunched = false;
  104. m_launcherID = INVALID_ID;
  105. m_attach_wslot = PRIMARY_WEAPON;
  106. m_attach_specificBarrelToUse = 0;
  107. m_heightAtLaunch = 0;
  108. m_frameAtLaunch = 0;
  109. m_exhaustSysTmpl = NULL;
  110. }
  111. //-------------------------------------------------------------------------------------------------
  112. NeutronMissileUpdate::~NeutronMissileUpdate( void )
  113. {
  114. m_deliveryDecal.clear();
  115. }
  116. //-------------------------------------------------------------------------------------------------
  117. void NeutronMissileUpdate::onDelete( void )
  118. {
  119. }
  120. //-------------------------------------------------------------------------------------------------
  121. // Prepares the missile for launch via proper weapon-system channels.
  122. //-------------------------------------------------------------------------------------------------
  123. void NeutronMissileUpdate::projectileLaunchAtObjectOrPosition(const Object *victim, const Coord3D* victimPos, const Object *launcher, WeaponSlotType wslot, Int specificBarrelToUse, const WeaponTemplate* detWeap, const ParticleSystemTemplate* exhaustSysOverride)
  124. {
  125. DEBUG_ASSERTCRASH(specificBarrelToUse>=0, ("specificBarrelToUse must now be explicit"));
  126. m_launcherID = launcher ? launcher->getID() : INVALID_ID;
  127. m_attach_wslot = wslot;
  128. m_attach_specificBarrelToUse = specificBarrelToUse;
  129. m_vel.zero();
  130. if (launcher)
  131. {
  132. const PhysicsBehavior *phys = launcher->getPhysics();
  133. if (phys)
  134. m_vel = *phys->getVelocity();
  135. }
  136. projectileFireAtObjectOrPosition( victim, victimPos, detWeap, exhaustSysOverride );
  137. }
  138. //-------------------------------------------------------------------------------------------------
  139. // The actual firing of the missile once setup.
  140. //-------------------------------------------------------------------------------------------------
  141. void NeutronMissileUpdate::projectileFireAtObjectOrPosition( const Object *victim, const Coord3D *victimPos, const WeaponTemplate *detWeap, const ParticleSystemTemplate* exhaustSysOverride )
  142. {
  143. m_exhaustSysTmpl = exhaustSysOverride;
  144. m_state = LAUNCH;
  145. m_stateTimestamp = TheGameLogic->getFrame();
  146. if( victim )
  147. {
  148. // CalcTarget will add half the target's height. But in this case, we are aiming at the ground
  149. // and need to stay aiming at the ground.
  150. m_targetPos = *victim->getPosition();
  151. m_intermedPos = m_targetPos;
  152. m_intermedPos.z += getNeutronMissileUpdateModuleData()->m_targetFromDirectlyAbove;
  153. }
  154. else
  155. {
  156. // Otherwise, we are just a Coord shot.
  157. m_targetPos = *victimPos;
  158. m_intermedPos = m_targetPos;
  159. m_intermedPos.z += getNeutronMissileUpdateModuleData()->m_targetFromDirectlyAbove;
  160. }
  161. m_deliveryDecal.clear();
  162. getNeutronMissileUpdateModuleData()->m_deliveryDecalTemplate.createRadiusDecal(m_targetPos,
  163. getNeutronMissileUpdateModuleData()->m_deliveryDecalRadius, getObject()->getControllingPlayer(), m_deliveryDecal);
  164. }
  165. //-------------------------------------------------------------------------------------------------
  166. /**
  167. * Implement LAUNCH state
  168. */
  169. void NeutronMissileUpdate::doLaunch( void )
  170. {
  171. if (!m_isLaunched)
  172. {
  173. Object *launcher = TheGameLogic->findObjectByID( m_launcherID );
  174. // if our launch vehicle is gone, destroy ourselves
  175. if (launcher == NULL)
  176. {
  177. m_launcherID = INVALID_ID;
  178. TheGameLogic->destroyObject( getObject() );
  179. return;
  180. }
  181. Matrix3D attachTransform;
  182. if (!launcher->getDrawable() ||
  183. !launcher->getDrawable()->getProjectileLaunchOffset(m_attach_wslot, m_attach_specificBarrelToUse, &attachTransform, TURRET_INVALID, NULL))
  184. {
  185. DEBUG_CRASH(("ProjectileLaunchPos %d %d not found!\n",m_attach_wslot, m_attach_specificBarrelToUse));
  186. attachTransform.Make_Identity();
  187. }
  188. Matrix3D worldTransform;
  189. launcher->convertBonePosToWorldPos(NULL, &attachTransform, NULL, &worldTransform);
  190. Vector3 tmp = worldTransform.Get_Translation();
  191. Coord3D worldPos;
  192. worldPos.x = tmp.X;
  193. worldPos.y = tmp.Y;
  194. worldPos.z = tmp.Z;
  195. //
  196. // the missile on the raising up launch platform is actually 45 degrees from the missile
  197. // that is flying around the world ... we want to rotate it "on end and in place" so
  198. // that we don't see any decals on the side of the missile 'pop' to the new angle
  199. /// @todo, this should not be a hard coded value ... I love demos!!!
  200. //
  201. worldTransform.Rotate_X( (PI / 2.0f) );
  202. getObject()->getDrawable()->setDrawableHidden(false);
  203. getObject()->setTransformMatrix(&worldTransform);
  204. getObject()->setPosition(&worldPos);
  205. getObject()->getExperienceTracker()->setExperienceSink( m_launcherID );
  206. m_isLaunched = true;
  207. if (getNeutronMissileUpdateModuleData()->m_targetFromDirectlyAbove)
  208. m_reachedIntermediatePos = false;
  209. FXList::doFXObj(getNeutronMissileUpdateModuleData()->m_launchFX, getObject());
  210. m_heightAtLaunch = getObject()->getPosition()->z;
  211. m_frameAtLaunch = TheGameLogic->getFrame();
  212. }
  213. // fall
  214. Coord3D pos = *getObject()->getPosition();
  215. pos.x += m_vel.x;
  216. pos.y += m_vel.y;
  217. pos.z += m_vel.z;
  218. getObject()->setPosition( &pos );
  219. FXList::doFXObj(getNeutronMissileUpdateModuleData()->m_ignitionFX, getObject());
  220. if (m_exhaustSysTmpl != NULL)
  221. TheParticleSystemManager->createAttachedParticleSystemID(m_exhaustSysTmpl, getObject());
  222. m_state = ATTACK;
  223. m_stateTimestamp = TheGameLogic->getFrame();
  224. // arm the missile's "warhead"
  225. m_isArmed = true;
  226. }
  227. //-----------------------------------------------------------------------------
  228. // return the angle (in 3-space) we actually turned.
  229. static Real calcTransform(const Object* obj, const Coord3D *pos, Real maxTurnRate, Matrix3D* newTransform )
  230. {
  231. // convert to Vector3, to use all its handy stuff
  232. Vector3 objPos(obj->getPosition()->x, obj->getPosition()->y, obj->getPosition()->z);
  233. Vector3 otherPos(pos->x, pos->y, pos->z);
  234. Vector3 objDir = obj->getTransformMatrix()->Rotate_Vector(Vector3(1.0f, 0.0f, 0.0f));
  235. Vector3 otherDir = otherPos - objPos;
  236. otherDir.Normalize();
  237. // dot of two unit vectors is cos of angle between them
  238. Real c = Vector3::Dot_Product(objDir, otherDir);
  239. // bound it in case of numerical error
  240. if (c < -1.0)
  241. c = -1.0;
  242. else if (c > 1.0)
  243. c = 1.0;
  244. Real angle = (Real)ACos( c );
  245. Vector3 newDir;
  246. if (fabs(angle) < maxTurnRate)
  247. {
  248. // close enough -- point exactly in the right dir
  249. newDir = otherDir;
  250. }
  251. else
  252. {
  253. // nah, turn as much as we can... this is icky, 'cuz
  254. // we need to rotate around the axis perpendicular to these two vecs
  255. angle = maxTurnRate;
  256. // cross of two vectors is the perpendicular axis
  257. #ifdef ALLOW_TEMPORARIES
  258. Vector3 objCrossOther = Vector3::Cross_Product(objDir, otherDir);
  259. objCrossOther.Normalize();
  260. #else
  261. Vector3 objCrossOther;
  262. Vector3::Normalized_Cross_Product(objDir, otherDir, &objCrossOther);
  263. #endif
  264. Matrix3D rotMtx(objCrossOther, angle);
  265. newDir = rotMtx.Rotate_Vector(objDir);
  266. }
  267. newTransform->buildTransformMatrix( objPos, newDir );
  268. return angle;
  269. }
  270. //-------------------------------------------------------------------------------------------------
  271. /**
  272. * Implement ATTACK state
  273. */
  274. void NeutronMissileUpdate::doAttack( void )
  275. {
  276. Matrix3D mx;
  277. Real speed = getNeutronMissileUpdateModuleData()->m_relativeSpeed;
  278. if (getNeutronMissileUpdateModuleData()->m_targetFromDirectlyAbove && m_reachedIntermediatePos)
  279. speed *= STRAIGHT_DOWN_SLOW_FACTOR;
  280. // if we're still in the no-turning-time, OR if we're out of fuel
  281. if (m_noTurnDistLeft > 0.0f)
  282. {
  283. mx = *getObject()->getTransformMatrix();
  284. }
  285. else
  286. {
  287. {
  288. //
  289. // Orient toward destination
  290. //
  291. Real relAngle = calcTransform(getObject(), m_reachedIntermediatePos ? &m_targetPos : &m_intermedPos, getNeutronMissileUpdateModuleData()->m_maxTurnRate, &mx);
  292. //
  293. // Modulate speed according to turning. The more we have to turn, the slower we go
  294. //
  295. Real angleCoeff = (Real)fabs( relAngle ) / (PI / 2.0f);
  296. if (angleCoeff > 1.0f)
  297. angleCoeff = 1.0;
  298. }
  299. }
  300. // get true forward direction of missile
  301. Vector3 trueDir = mx.Get_X_Vector();
  302. trueDir.Normalize();
  303. //
  304. // Move forward along forward direction
  305. //
  306. Real damping = getNeutronMissileUpdateModuleData()->m_forwardDamping;
  307. m_accel.x = speed * trueDir.X - damping * m_vel.x;
  308. m_accel.y = speed * trueDir.Y - damping * m_vel.y;
  309. m_accel.z = speed * trueDir.Z - damping * m_vel.z;
  310. m_vel.x += m_accel.x;
  311. m_vel.y += m_accel.y;
  312. m_vel.z += m_accel.z;
  313. Coord3D pos = *getObject()->getPosition();
  314. const NeutronMissileUpdateModuleData* d = getNeutronMissileUpdateModuleData();
  315. UnsignedInt now = TheGameLogic->getFrame();
  316. if (d->m_specialSpeedTime > 0 && now <= m_frameAtLaunch + d->m_specialSpeedTime)
  317. {
  318. getObject()->getDrawable()->setInstanceMatrix(NULL);
  319. UnsignedInt elapsed = now - m_frameAtLaunch;
  320. if (elapsed < d->m_specialSpeedTime)
  321. {
  322. Real timeFrac = (Real)elapsed / (Real)d->m_specialSpeedTime;
  323. Real accelFactor = d->m_specialAccelFactor;
  324. if (accelFactor < 0.01f) accelFactor = 0.01f;
  325. Coord3D newPos = pos;
  326. newPos.z = m_heightAtLaunch + (sqr(accelFactor * timeFrac) / accelFactor) * d->m_specialSpeedHeight;
  327. m_vel.x = newPos.x - pos.x;
  328. m_vel.y = newPos.y - pos.y;
  329. m_vel.z = newPos.z - pos.z;
  330. if (d->m_specialJitterDistance > 0.0f)
  331. {
  332. Real amplitude = (1.0f - timeFrac) * d->m_specialJitterDistance;
  333. Vector3 vectmp;
  334. vectmp.X = 0;
  335. // MDC: moving to GameLogicRandomValue. This does not need to be synced, but having it so makes searches *so* much nicer.
  336. vectmp.Y = GameLogicRandomValueReal(-1.0, 1.0) * amplitude;
  337. vectmp.Z = GameLogicRandomValueReal(-1.0, 1.0) * amplitude;
  338. vectmp = mx.Rotate_Vector(vectmp);
  339. Matrix3D mtxtmp(1);
  340. mtxtmp.Translate(vectmp);
  341. getObject()->getDrawable()->setInstanceMatrix( &mtxtmp );
  342. }
  343. }
  344. }
  345. pos.x += m_vel.x;
  346. pos.y += m_vel.y;
  347. pos.z += m_vel.z;
  348. //DEBUG_LOG(("vel %f accel %f z %f\n",m_vel.length(),m_accel.length(), pos.z));
  349. //Real vm = sqrt(m_vel.x*m_vel.x+m_vel.y*m_vel.y+m_vel.z*m_vel.z);
  350. //DEBUG_LOG(("vel is %f %f %f (%f)\n",m_vel.x,m_vel.y,m_vel.z,vm));
  351. getObject()->setTransformMatrix( &mx );
  352. getObject()->setPosition( &pos );
  353. }
  354. //-------------------------------------------------------------------------------------------------
  355. //-------------------------------------------------------------------------------------------------
  356. Bool NeutronMissileUpdate::projectileHandleCollision( Object *other )
  357. {
  358. Object* obj = getObject();
  359. // check if our warhead is "armed" - if not, we are inert
  360. if (projectileIsArmed() == false)
  361. return true;
  362. // Don't hit your own launcher, ever.
  363. if (other != NULL && projectileGetLauncherID() == other->getID())
  364. return true;
  365. // collided with something... blow'd up!
  366. detonate();
  367. // mark ourself as "no collisions" (since we might still exist in slow death mode)
  368. obj->setStatus(OBJECT_STATUS_NO_COLLISIONS);
  369. return true;
  370. }
  371. //-------------------------------------------------------------------------------------------------
  372. void NeutronMissileUpdate::onDie( const DamageInfo *damageInfo )
  373. {
  374. m_deliveryDecal.clear();
  375. }
  376. //-------------------------------------------------------------------------------------------------
  377. void NeutronMissileUpdate::detonate()
  378. {
  379. m_deliveryDecal.clear();
  380. Object* obj = getObject();
  381. // kill it (vs destroying it) so that its Die modules are called
  382. obj->kill();
  383. m_state = DEAD;
  384. if (obj->getDrawable())
  385. obj->getDrawable()->setDrawableHidden(true);
  386. }
  387. //-------------------------------------------------------------------------------------------------
  388. /**
  389. * Simulate one frame of a missile's behavior
  390. */
  391. UpdateSleepTime NeutronMissileUpdate::update( void )
  392. {
  393. m_deliveryDecal.update();
  394. if (!m_reachedIntermediatePos)
  395. {
  396. Real distSqr = ThePartitionManager->getDistanceSquared(getObject(), &m_intermedPos, FROM_CENTER_3D);
  397. Real boundSqr = sqr(getObject()->getGeometryInfo().getBoundingSphereRadius());
  398. if (distSqr <= boundSqr)
  399. {
  400. m_reachedIntermediatePos = true;
  401. getObject()->setPosition(&m_intermedPos);
  402. Real vel = m_vel.length();
  403. m_vel.x = 0;
  404. m_vel.y = 0;
  405. m_vel.z = -vel * STRAIGHT_DOWN_SLOW_FACTOR;
  406. }
  407. }
  408. Coord3D oldPos = *getObject()->getPosition();
  409. Bool oldPosValid = (m_state == ATTACK); // not valid till *after* we've launched
  410. switch( m_state )
  411. {
  412. case PRELAUNCH:
  413. // nothing... just ignore it.
  414. break;
  415. case LAUNCH:
  416. doLaunch();
  417. break;
  418. case ATTACK:
  419. doAttack();
  420. break;
  421. case DEAD:
  422. // do nothing
  423. break;
  424. }
  425. if (m_noTurnDistLeft > 0.0f && oldPosValid)
  426. {
  427. Coord3D newPos = *getObject()->getPosition();
  428. Real distThisTurn = sqrt(sqr(newPos.x-oldPos.x) + sqr(newPos.y-oldPos.y) + sqr(newPos.z-oldPos.z));
  429. //DEBUG_LOG(("noTurnDist goes from %f to %f\n",m_noTurnDistLeft,m_noTurnDistLeft-distThisTurn));
  430. m_noTurnDistLeft -= distThisTurn;
  431. }
  432. if (m_state != PRELAUNCH && m_state != DEAD && !getObject()->isAboveTerrain())
  433. {
  434. // the normal always points straight down, though we could
  435. // get the alignWithTerrain() normal if it proves interesting
  436. Coord3D normal;
  437. normal.x = normal.y = 0.0f;
  438. normal.z = -1.0f;
  439. getObject()->onCollide(NULL, getObject()->getPosition(), &normal);
  440. }
  441. return UPDATE_SLEEP_NONE;
  442. }
  443. // ------------------------------------------------------------------------------------------------
  444. /** CRC */
  445. // ------------------------------------------------------------------------------------------------
  446. void NeutronMissileUpdate::crc( Xfer *xfer )
  447. {
  448. // extend base class
  449. UpdateModule::crc( xfer );
  450. } // end crc
  451. // ------------------------------------------------------------------------------------------------
  452. /** Xfer method
  453. * Version Info:
  454. * 1: Initial version */
  455. // ------------------------------------------------------------------------------------------------
  456. void NeutronMissileUpdate::xfer( Xfer *xfer )
  457. {
  458. // version
  459. XferVersion currentVersion = 1;
  460. XferVersion version = currentVersion;
  461. xfer->xferVersion( &version, currentVersion );
  462. // extend base class
  463. UpdateModule::xfer( xfer );
  464. // state
  465. xfer->xferUser( &m_state, sizeof( MissileStateType ) );
  466. // target pos
  467. xfer->xferCoord3D( &m_targetPos );
  468. // intermed pos
  469. xfer->xferCoord3D( &m_intermedPos );
  470. // launcher ID
  471. xfer->xferObjectID( &m_launcherID );
  472. // attach weapon slot
  473. xfer->xferUser( &m_attach_wslot, sizeof( WeaponSlotType ) );
  474. // attach specific barrel
  475. xfer->xferInt( &m_attach_specificBarrelToUse );
  476. // accel
  477. xfer->xferCoord3D( &m_accel );
  478. // vel
  479. xfer->xferCoord3D( &m_vel );
  480. // state timestamp
  481. xfer->xferUnsignedInt( &m_stateTimestamp );
  482. // is launched
  483. xfer->xferBool( &m_isLaunched );
  484. // is armed
  485. xfer->xferBool( &m_isArmed );
  486. // no turn dist left
  487. xfer->xferReal( &m_noTurnDistLeft );
  488. // raeched intermediate pos
  489. xfer->xferBool( &m_reachedIntermediatePos );
  490. // farme at launch
  491. xfer->xferUnsignedInt( &m_frameAtLaunch );
  492. // height at launch
  493. xfer->xferReal( &m_heightAtLaunch );
  494. // decal, if any
  495. m_deliveryDecal.xferRadiusDecal(xfer);
  496. // particle system template
  497. AsciiString name = m_exhaustSysTmpl ? m_exhaustSysTmpl->getName() : AsciiString::TheEmptyString;
  498. xfer->xferAsciiString( &name );
  499. if( xfer->getXferMode() == XFER_LOAD )
  500. {
  501. // make system template NULL to be safe
  502. m_exhaustSysTmpl = NULL;
  503. if( name.isEmpty() == FALSE )
  504. {
  505. m_exhaustSysTmpl = TheParticleSystemManager->findTemplate( name );
  506. if( m_exhaustSysTmpl == NULL )
  507. {
  508. DEBUG_CRASH(( "NeutronMissileUpdate::xfer - Unable to find particle system '%s'\n", name.str() ));
  509. throw SC_INVALID_DATA;
  510. } // end if
  511. } // end if
  512. } // end if
  513. } // end xfer
  514. // ------------------------------------------------------------------------------------------------
  515. /** Load post process */
  516. // ------------------------------------------------------------------------------------------------
  517. void NeutronMissileUpdate::loadPostProcess( void )
  518. {
  519. // extend base class
  520. UpdateModule::loadPostProcess();
  521. } // end loadPostProcess