proximityMine.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "core/stream/bitStream.h"
  24. #include "console/console.h"
  25. #include "console/consoleTypes.h"
  26. #include "console/engineAPI.h"
  27. #include "sim/netConnection.h"
  28. #include "math/mMath.h"
  29. #include "math/mathIO.h"
  30. #include "math/mathUtils.h"
  31. #include "gfx/gfxTransformSaver.h"
  32. #include "gfx/gfxDrawUtil.h"
  33. #include "sfx/sfxTrack.h"
  34. #include "sfx/sfxTypes.h"
  35. #include "sfx/sfxSystem.h"
  36. #include "ts/tsShapeInstance.h"
  37. #include "T3D/fx/explosion.h"
  38. #include "T3D/proximityMine.h"
  39. #include "T3D/physics/physicsBody.h"
  40. const U32 sTriggerCollisionMask = ( VehicleObjectType | PlayerObjectType );
  41. static S32 gAutoDeleteTicks = 16; // Provides about half a second for all clients to be updated
  42. // before a mine is deleted on the server.
  43. //----------------------------------------------------------------------------
  44. IMPLEMENT_CO_DATABLOCK_V1( ProximityMineData );
  45. ConsoleDocClass( ProximityMineData,
  46. "@brief Stores common properties for a ProximityMine.\n\n"
  47. "@see ProximityMine\n"
  48. "@ingroup gameObjects\n"
  49. );
  50. IMPLEMENT_CALLBACK( ProximityMineData, onTriggered, void, ( ProximityMine* obj, SceneObject *target ),( obj, target ),
  51. "Callback invoked when an object triggers the ProximityMine.\n\n"
  52. "@param obj The ProximityMine object\n"
  53. "@param target The object that triggered the mine\n"
  54. "@note This callback is only invoked on the server.\n"
  55. "@see ProximityMine\n"
  56. );
  57. IMPLEMENT_CALLBACK( ProximityMineData, onExplode, void, ( ProximityMine* obj, Point3F pos ),( obj, pos ),
  58. "Callback invoked when a ProximityMine is about to explode.\n\n"
  59. "@param obj The ProximityMine object\n"
  60. "@param pos The position of the mine explosion\n"
  61. "@note This callback is only invoked on the server.\n"
  62. "@see ProximityMine\n"
  63. );
  64. ProximityMineData::ProximityMineData()
  65. : armingDelay( 0 ),
  66. armingSequence( -1 ),
  67. triggerRadius( 5.0f ),
  68. triggerSpeed( 1.0f ),
  69. autoTriggerDelay( 0 ),
  70. triggerOnOwner( false ),
  71. triggerDelay( 0 ),
  72. triggerSequence( -1 ),
  73. explosionOffset( 0.05f )
  74. {
  75. INIT_ASSET(ArmSound);
  76. INIT_ASSET(TriggerSound);
  77. }
  78. void ProximityMineData::initPersistFields()
  79. {
  80. docsURL;
  81. Parent::initPersistFields();
  82. addGroup("Sounds");
  83. INITPERSISTFIELD_SOUNDASSET(ArmSound, ProximityMineData, "Arming sound for this proximity mine.");
  84. INITPERSISTFIELD_SOUNDASSET(TriggerSound, ProximityMineData, "Arming sound for this proximity mine.");
  85. endGroup("Sounds");
  86. addGroup( "Arming" );
  87. addFieldV( "armingDelay", TypeRangedF32, Offset(armingDelay, ProximityMineData), &CommonValidators::PositiveFloat,
  88. "Delay (in seconds) from when the mine is placed to when it becomes active." );
  89. endGroup( "Arming" );
  90. addGroup( "Triggering" );
  91. addFieldV( "autoTriggerDelay", TypeRangedF32, Offset(autoTriggerDelay, ProximityMineData), &CommonValidators::PositiveFloat,
  92. "@brief Delay (in seconds) from arming until the mine automatically "
  93. "triggers and explodes, even if no object has entered the trigger area.\n\n"
  94. "Set to 0 to disable." );
  95. addField( "triggerOnOwner", TypeBool, Offset(triggerOnOwner, ProximityMineData),
  96. "@brief Controls whether the mine can be triggered by the object that owns it.\n\n"
  97. "For example, a player could deploy mines that are only dangerous to other "
  98. "players and not himself." );
  99. addFieldV( "triggerRadius", TypeRangedF32, Offset(triggerRadius, ProximityMineData), &CommonValidators::PositiveFloat,
  100. "Distance at which an activated mine will detect other objects and explode." );
  101. addFieldV( "triggerSpeed", TypeRangedF32, Offset(triggerSpeed, ProximityMineData), &CommonValidators::PositiveFloat,
  102. "Speed above which moving objects within the trigger radius will trigger the mine" );
  103. addFieldV( "triggerDelay", TypeRangedF32, Offset(triggerDelay, ProximityMineData), &CommonValidators::PositiveFloat,
  104. "Delay (in seconds) from when the mine is triggered until it explodes." );
  105. endGroup( "Triggering" );
  106. addGroup( "Explosion" );
  107. addFieldV( "explosionOffset", TypeRangedF32, Offset(explosionOffset, ProximityMineData), &CommonValidators::F32Range,
  108. "@brief Offset from the mine's origin where the explosion emanates from."
  109. "Sometimes a thrown mine may be slightly sunk into the ground. This can be just "
  110. "enough to cause the explosion to occur under the ground, especially on flat "
  111. "ground, which can end up blocking the explosion. This offset along the mine's "
  112. "'up' normal allows you to raise the explosion origin to a better height.");
  113. endGroup( "Explosion" );
  114. }
  115. bool ProximityMineData::preload( bool server, String& errorStr )
  116. {
  117. if ( Parent::preload( server, errorStr ) == false )
  118. return false;
  119. if ( !server )
  120. {
  121. if(!isArmSoundValid() )
  122. {
  123. //return false; -TODO: trigger asset download
  124. }
  125. if(!isTriggerSoundValid() )
  126. {
  127. //return false; -TODO: trigger asset download
  128. }
  129. }
  130. if ( getShape() )
  131. {
  132. // Lookup animation sequences
  133. armingSequence = getShape()->findSequence( "armed" );
  134. triggerSequence = getShape()->findSequence( "triggered" );
  135. }
  136. return true;
  137. }
  138. void ProximityMineData::packData( BitStream* stream )
  139. {
  140. Parent::packData( stream );
  141. stream->write( armingDelay );
  142. PACKDATA_ASSET(ArmSound);
  143. stream->write( autoTriggerDelay );
  144. stream->writeFlag( triggerOnOwner );
  145. stream->write( triggerRadius );
  146. stream->write( triggerSpeed );
  147. stream->write( triggerDelay );
  148. PACKDATA_ASSET(TriggerSound);
  149. }
  150. void ProximityMineData::unpackData( BitStream* stream )
  151. {
  152. Parent::unpackData(stream);
  153. stream->read( &armingDelay );
  154. UNPACKDATA_ASSET(ArmSound);
  155. stream->read( &autoTriggerDelay );
  156. triggerOnOwner = stream->readFlag();
  157. stream->read( &triggerRadius );
  158. stream->read( &triggerSpeed );
  159. stream->read( &triggerDelay );
  160. UNPACKDATA_ASSET(TriggerSound);
  161. }
  162. //----------------------------------------------------------------------------
  163. IMPLEMENT_CO_NETOBJECT_V1( ProximityMine );
  164. ConsoleDocClass( ProximityMine,
  165. "@brief A simple proximity mine.\n\n"
  166. "Proximity mines can be deployed using the world editor or thrown by an "
  167. "in-game object. Once armed, any Player or Vehicle object that moves within "
  168. "the mine's trigger area will cause it to explode.\n\n"
  169. "Internally, the ProximityMine object transitions through the following states:\n"
  170. "<ol>\n"
  171. " <li><b>Thrown</b>: Mine has been thrown, but has not yet attached to a surface</li>\n"
  172. " <li><b>Deployed</b>: Mine has attached to a surface but is not yet armed. Start "
  173. "playing the #armingSound and <i>armed</i> sequence.</li>\n"
  174. " <li><b>Armed</b>: Mine is armed and will trigger if a Vehicle or Player object moves "
  175. "within the trigger area.</li>\n"
  176. " <li><b>Triggered</b>: Mine has been triggered and will explode soon. Invoke the "
  177. "onTriggered callback, and start playing the #triggerSound and <i>triggered</i> "
  178. "sequence.</li>\n"
  179. " <li><b>Exploded</b>: Mine has exploded and will be deleted on the server shortly. "
  180. "Invoke the onExplode callback on the server and generate the explosion effects "
  181. "on the client.</li>\n"
  182. "</ol>\n\n"
  183. "@note Proximity mines with the #static field set to true will start in the "
  184. "<b>Armed</b> state. Use this for mines placed with the World Editor.\n\n"
  185. "The shape used for the mine may optionally define the following sequences:\n"
  186. "<dl>\n"
  187. " <dt>armed</dt><dd>Sequence to play when the mine is deployed, but before "
  188. "it becomes active and triggerable (#armingDelay should be set appropriately).</dd>\n"
  189. " <dt>triggered</dt><dd>Sequence to play when the mine is triggered, just "
  190. "before it explodes (#triggerDelay should be set appropriately).<dd>\n"
  191. "</dl>\n\n"
  192. "@tsexample\n"
  193. "datablock ProximityMineData( SimpleMine )\n"
  194. "{\n"
  195. " // ShapeBaseData fields\n"
  196. " category = \"Weapon\";\n"
  197. " shapeFile = \"art/shapes/weapons/misc/proximityMine.dts\";\n\n"
  198. " // ItemData fields\n"
  199. " sticky = true;\n\n"
  200. " // ProximityMineData fields\n"
  201. " armingDelay = 0.5;\n"
  202. " armingSound = MineArmedSound;\n\n"
  203. " autoTriggerDelay = 0;\n"
  204. " triggerOnOwner = true;\n"
  205. " triggerRadius = 5.0;\n"
  206. " triggerSpeed = 1.0;\n"
  207. " triggerDelay = 0.5;\n"
  208. " triggerSound = MineTriggeredSound;\n"
  209. " explosion = RocketLauncherExplosion;\n\n"
  210. " // dynamic fields\n"
  211. " pickUpName = \"Proximity Mines\";\n"
  212. " maxInventory = 20;\n\n"
  213. " damageType = \"MineDamage\"; // type of damage applied to objects in radius\n"
  214. " radiusDamage = 30; // amount of damage to apply to objects in radius\n"
  215. " damageRadius = 8; // search radius to damage objects when exploding\n"
  216. " areaImpulse = 2000; // magnitude of impulse to apply to objects in radius\n"
  217. "};\n\n"
  218. "function ProximityMineData::onTriggered( %this, %obj, %target )\n"
  219. "{\n"
  220. " echo( %this.name SPC \"triggered by \" @ %target.getClassName() );\n"
  221. "}\n\n"
  222. "function ProximityMineData::onExplode( %this, %obj, %position )\n"
  223. "{\n"
  224. " // Damage objects within the mine's damage radius\n"
  225. " if ( %this.damageRadius > 0 )\n"
  226. " radiusDamage( %obj.sourceObject, %position, %this.damageRadius, %this.radiusDamage, %this.damageType, %this.areaImpulse );\n"
  227. "}\n\n"
  228. "function ProximityMineData::damage( %this, %obj, %position, %source, %amount, %damageType )\n"
  229. "{\n"
  230. " // Explode if any damage is applied to the mine\n"
  231. " %obj.schedule(50 + getRandom(50), explode);\n"
  232. "}\n\n"
  233. "%obj = new ProximityMine()\n"
  234. "{\n"
  235. " dataBlock = SimpleMine;\n"
  236. "};\n"
  237. "@endtsexample\n\n"
  238. "@see ProximityMineData\n"
  239. "@ingroup gameObjects\n"
  240. );
  241. ProximityMine::ProximityMine()
  242. {
  243. mTypeMask |= StaticShapeObjectType;
  244. mDataBlock = 0;
  245. mStickyCollisionPos.zero();
  246. mOwner = NULL;
  247. mState = Thrown;
  248. mStateTimeout = 0;
  249. mAnimThread = NULL;
  250. // For the Item class
  251. mSubclassItemHandlesScene = true;
  252. }
  253. ProximityMine::~ProximityMine()
  254. {
  255. }
  256. //----------------------------------------------------------------------------
  257. void ProximityMine::consoleInit()
  258. {
  259. Parent::consoleInit();
  260. Con::addVariable("$ProxMine::autoDeleteTicks", TypeS32, &gAutoDeleteTicks,
  261. "@brief Number of ticks until an exploded mine is deleted on the server.\n\n"
  262. "After a mine has exploded it remains in the server's scene graph for a time "
  263. "to allow its exploded state to be passed along to each client. This variable "
  264. "controls how long a mine remains before it is deleted. Any client that has not "
  265. "received the exploded state by then (perhaps due to lag) will not see any "
  266. "explosion produced by the mine.\n\n"
  267. "@ingroup GameObjects");
  268. }
  269. //----------------------------------------------------------------------------
  270. bool ProximityMine::onAdd()
  271. {
  272. if ( !Parent::onAdd() || !mDataBlock )
  273. return false;
  274. addToScene();
  275. if (isServerObject())
  276. scriptOnAdd();
  277. if ( mStatic )
  278. {
  279. // static mines are armed immediately
  280. mState = Deployed;
  281. mStateTimeout = 0;
  282. }
  283. return true;
  284. }
  285. bool ProximityMine::onNewDataBlock( GameBaseData* dptr, bool reload )
  286. {
  287. mDataBlock = dynamic_cast<ProximityMineData*>( dptr );
  288. if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
  289. return false;
  290. scriptOnNewDataBlock(reload);
  291. return true;
  292. }
  293. void ProximityMine::onRemove()
  294. {
  295. scriptOnRemove();
  296. removeFromScene();
  297. Parent::onRemove();
  298. }
  299. //----------------------------------------------------------------------------
  300. void ProximityMine::setTransform( const MatrixF& mat )
  301. {
  302. ShapeBase::setTransform( mat ); // Skip Item::setTransform as it restricts rotation to the Z axis
  303. if ( !mStatic )
  304. {
  305. mAtRest = false;
  306. mAtRestCounter = 0;
  307. }
  308. if ( mPhysicsRep )
  309. mPhysicsRep->setTransform( getTransform() );
  310. setMaskBits( Item::RotationMask | Item::PositionMask | Item::NoWarpMask );
  311. }
  312. void ProximityMine::setDeployedPos( const Point3F& pos, const Point3F& normal )
  313. {
  314. // Align to deployed surface normal
  315. MatrixF mat( true );
  316. MathUtils::getMatrixFromUpVector( normal, &mat );
  317. mat.setPosition( pos + normal * mObjBox.minExtents.z );
  318. mDelta.pos = pos;
  319. mDelta.posVec.set(0, 0, 0);
  320. ShapeBase::setTransform( mat );
  321. if ( mPhysicsRep )
  322. mPhysicsRep->setTransform( getTransform() );
  323. setMaskBits( DeployedMask );
  324. }
  325. void ProximityMine::processTick( const Move* move )
  326. {
  327. Parent::processTick( move );
  328. // Process state machine
  329. mStateTimeout -= TickSec;
  330. State lastState = NumStates;;
  331. while ( mState != lastState )
  332. {
  333. lastState = mState;
  334. switch ( mState )
  335. {
  336. case Thrown:
  337. if ( mAtRest )
  338. {
  339. mState = Deployed;
  340. mStateTimeout = mDataBlock->armingDelay;
  341. // Get deployed position if mine was not stuck to another surface
  342. if ( mStickyCollisionPos.isZero() )
  343. {
  344. mObjToWorld.getColumn( 2, &mStickyCollisionNormal );
  345. mObjToWorld.getColumn( 3, &mStickyCollisionPos );
  346. }
  347. setDeployedPos( mStickyCollisionPos, mStickyCollisionNormal );
  348. if ( mDataBlock->armingSequence != -1 )
  349. {
  350. mAnimThread = mShapeInstance->addThread();
  351. mShapeInstance->setSequence( mAnimThread, mDataBlock->armingSequence, 0.0f );
  352. }
  353. if ( mDataBlock->getArmSoundProfile() )
  354. SFX->playOnce( mDataBlock->getArmSoundProfile(), &getRenderTransform() );
  355. }
  356. break;
  357. case Deployed:
  358. // Timeout into Armed state
  359. if ( mStateTimeout <= 0 )
  360. {
  361. mState = Armed;
  362. mStateTimeout = mDataBlock->autoTriggerDelay ? mDataBlock->autoTriggerDelay : F32_MAX;
  363. }
  364. break;
  365. case Armed:
  366. {
  367. // Check for objects within the trigger area
  368. Box3F triggerBox( mDataBlock->triggerRadius * 2 );
  369. triggerBox.setCenter( getTransform().getPosition() );
  370. SimpleQueryList sql;
  371. getContainer()->findObjects( triggerBox, sTriggerCollisionMask,
  372. SimpleQueryList::insertionCallback, &sql );
  373. for ( S32 i = 0; i < sql.mList.size(); i++ )
  374. {
  375. // Detect movement in the trigger area
  376. if ( ( sql.mList[i] == mOwner && !mDataBlock->triggerOnOwner ) ||
  377. sql.mList[i]->getVelocity().len() < mDataBlock->triggerSpeed )
  378. continue;
  379. // Mine has been triggered
  380. mShapeInstance->destroyThread( mAnimThread );
  381. mAnimThread = NULL;
  382. mState = Triggered;
  383. mStateTimeout = mDataBlock->triggerDelay;
  384. if ( mDataBlock->triggerSequence != -1 )
  385. {
  386. mAnimThread = mShapeInstance->addThread();
  387. mShapeInstance->setSequence( mAnimThread, mDataBlock->triggerSequence, 0.0f );
  388. }
  389. if ( mDataBlock->getTriggerSoundProfile() )
  390. SFX->playOnce( mDataBlock->getTriggerSoundProfile(), &getRenderTransform() );
  391. if ( isServerObject() )
  392. mDataBlock->onTriggered_callback( this, sql.mList[0] );
  393. }
  394. break;
  395. }
  396. case Triggered:
  397. // Timeout into exploded state
  398. if ( mStateTimeout <= 0 )
  399. {
  400. explode();
  401. }
  402. break;
  403. case Exploded:
  404. // Mine's delete themselves on the server after exploding
  405. if ( isServerObject() && ( mStateTimeout <= 0 ) )
  406. {
  407. deleteObject();
  408. return;
  409. }
  410. break;
  411. default:
  412. // just break out, unknown state, covers warnings for not fulfilling all possiblities in enum.
  413. break;
  414. }
  415. }
  416. }
  417. //----------------------------------------------------------------------------
  418. void ProximityMine::explode()
  419. {
  420. // Make sure we don't explode twice
  421. if ( mState == Exploded )
  422. {
  423. return;
  424. }
  425. mState = Exploded;
  426. mStateTimeout = TickSec * gAutoDeleteTicks; // auto-delete on server N ticks after exploding
  427. // Move the explosion point slightly off the surface to avoid problems with radius damage
  428. Point3F normal = getTransform().getUpVector();
  429. Point3F explodePos = getTransform().getPosition() + normal * mDataBlock->explosionOffset;
  430. if ( isServerObject() )
  431. {
  432. // Do what the server needs to do, damage the surrounding objects, etc.
  433. mDataBlock->onExplode_callback( this, explodePos );
  434. setMaskBits( ExplosionMask );
  435. // Wait till the timeout to self delete. This gives the server object time
  436. // to get ghosted to the client
  437. }
  438. else
  439. {
  440. // Client just plays the explosion effect at the right place
  441. if ( mDataBlock->explosion )
  442. {
  443. Explosion *pExplosion = new Explosion;
  444. pExplosion->onNewDataBlock( mDataBlock->explosion, false );
  445. MatrixF xform( true );
  446. xform.setPosition( explodePos );
  447. pExplosion->setTransform( xform );
  448. pExplosion->setInitialState( explodePos, normal );
  449. pExplosion->setCollideType( sTriggerCollisionMask );
  450. if ( pExplosion->registerObject() == false )
  451. {
  452. Con::errorf( ConsoleLogEntry::General, "ProximityMine(%s)::explode: couldn't register explosion",
  453. mDataBlock->getName() );
  454. delete pExplosion;
  455. }
  456. }
  457. }
  458. }
  459. void ProximityMine::advanceTime( F32 dt )
  460. {
  461. Parent::advanceTime( dt );
  462. if ( mAnimThread )
  463. mShapeInstance->advancePos( dt, mAnimThread );
  464. }
  465. //----------------------------------------------------------------------------
  466. U32 ProximityMine::packUpdate( NetConnection* connection, U32 mask, BitStream* stream )
  467. {
  468. // Handle rotation ourselves (so it is not locked to the Z axis like for Items)
  469. U32 retMask = Parent::packUpdate( connection, mask & (~Item::RotationMask), stream );
  470. if ( stream->writeFlag( mask & Item::RotationMask ) )
  471. {
  472. QuatF rot( mObjToWorld );
  473. mathWrite( *stream, rot );
  474. }
  475. if ( stream->writeFlag( !mStatic && ( mask & DeployedMask ) && ( mState > Thrown ) ) )
  476. {
  477. mathWrite( *stream, mStickyCollisionPos );
  478. mathWrite( *stream, mStickyCollisionNormal );
  479. }
  480. stream->writeFlag( ( mask & ExplosionMask ) && ( mState == Exploded ) );
  481. return retMask;
  482. }
  483. void ProximityMine::unpackUpdate( NetConnection* connection, BitStream* stream )
  484. {
  485. Parent::unpackUpdate( connection, stream );
  486. // Item::RotationMask
  487. if ( stream->readFlag() )
  488. {
  489. QuatF rot;
  490. mathRead( *stream, &rot );
  491. Point3F pos = mObjToWorld.getPosition();
  492. rot.setMatrix( &mObjToWorld );
  493. mObjToWorld.setPosition( pos );
  494. }
  495. // !mStatic && ( mask & DeployedMask ) && ( mState > Thrown )
  496. if ( stream->readFlag() )
  497. {
  498. mathRead( *stream, &mStickyCollisionPos );
  499. mathRead( *stream, &mStickyCollisionNormal );
  500. mAtRest = true;
  501. setDeployedPos( mStickyCollisionPos, mStickyCollisionNormal );
  502. }
  503. // ( mask & ExplosionMask ) && ( mState == Exploded )
  504. if ( stream->readFlag() )
  505. {
  506. // start the explosion visuals on the client
  507. explode();
  508. }
  509. if ( mStatic && mState <= Deployed )
  510. {
  511. // static mines are armed immediately
  512. mState = Deployed;
  513. mStateTimeout = 0;
  514. }
  515. }
  516. //----------------------------------------------------------------------------
  517. void ProximityMine::prepRenderImage( SceneRenderState* state )
  518. {
  519. // Don't render the mine if exploded
  520. if ( mState == Exploded )
  521. return;
  522. // Use ShapeBase to render the 3D shape
  523. Parent::prepRenderImage( state );
  524. // Add a custom render instance to draw the trigger area
  525. if ( !state->isShadowPass() )
  526. {
  527. ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  528. ri->renderDelegate.bind( this, &ProximityMine::renderObject );
  529. ri->type = RenderPassManager::RIT_ObjectTranslucent;
  530. ri->translucentSort = true;
  531. ri->defaultKey = 1;
  532. state->getRenderPass()->addInst( ri );
  533. }
  534. }
  535. void ProximityMine::renderObject( ObjectRenderInst* ri,
  536. SceneRenderState* state,
  537. BaseMatInstance* overrideMat )
  538. {
  539. if ( overrideMat )
  540. return;
  541. /*
  542. // Render the trigger area
  543. if ( mState == Armed || mState == Triggered )
  544. {
  545. const LinearColorF drawColor(1, 0, 0, 0.05f);
  546. if ( drawColor.alpha > 0 )
  547. {
  548. GFXStateBlockDesc desc;
  549. desc.setZReadWrite( true, false );
  550. desc.setBlend( true );
  551. GFXTransformSaver saver;
  552. MatrixF mat = getRenderTransform();
  553. mat.scale( getScale() );
  554. GFX->getDrawUtil()->drawSphere( desc, mDataBlock->triggerRadius, mat.getPosition(),
  555. drawColor, true, false, &mat );
  556. }
  557. }
  558. */
  559. }
  560. //----------------------------------------------------------------------------
  561. DefineEngineMethod( ProximityMine, explode, void, (),,
  562. "@brief Manually cause the mine to explode.\n\n")
  563. {
  564. object->explode();
  565. }