PageRenderTime 65ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/neo/d3xp/Misc.cpp

https://github.com/bubble8773/RBDOOM-3-BFG
C++ | 4441 lines | 2575 code | 563 blank | 1303 comment | 329 complexity | 76c63072bb648eeccd8e9a5e771113ec MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code 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. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. /*
  21. Various utility objects and functions.
  22. */
  23. #include "precompiled.h"
  24. #pragma hdrstop
  25. #include "Game_local.h"
  26. /*
  27. ===============================================================================
  28. idSpawnableEntity
  29. A simple, spawnable entity with a model and no functionable ability of it's own.
  30. For example, it can be used as a placeholder during development, for marking
  31. locations on maps for script, or for simple placed models without any behavior
  32. that can be bound to other entities. Should not be subclassed.
  33. ===============================================================================
  34. */
  35. CLASS_DECLARATION( idEntity, idSpawnableEntity )
  36. END_CLASS
  37. /*
  38. ======================
  39. idSpawnableEntity::Spawn
  40. ======================
  41. */
  42. void idSpawnableEntity::Spawn()
  43. {
  44. // this just holds dict information
  45. }
  46. /*
  47. ===============================================================================
  48. idPlayerStart
  49. ===============================================================================
  50. */
  51. const idEventDef EV_TeleportStage( "<TeleportStage>", "e" );
  52. CLASS_DECLARATION( idEntity, idPlayerStart )
  53. EVENT( EV_Activate, idPlayerStart::Event_TeleportPlayer )
  54. EVENT( EV_TeleportStage, idPlayerStart::Event_TeleportStage )
  55. END_CLASS
  56. /*
  57. ===============
  58. idPlayerStart::idPlayerStart
  59. ================
  60. */
  61. idPlayerStart::idPlayerStart()
  62. {
  63. teleportStage = 0;
  64. }
  65. /*
  66. ===============
  67. idPlayerStart::Spawn
  68. ================
  69. */
  70. void idPlayerStart::Spawn()
  71. {
  72. teleportStage = 0;
  73. }
  74. /*
  75. ================
  76. idPlayerStart::Save
  77. ================
  78. */
  79. void idPlayerStart::Save( idSaveGame* savefile ) const
  80. {
  81. savefile->WriteInt( teleportStage );
  82. }
  83. /*
  84. ================
  85. idPlayerStart::Restore
  86. ================
  87. */
  88. void idPlayerStart::Restore( idRestoreGame* savefile )
  89. {
  90. savefile->ReadInt( teleportStage );
  91. }
  92. /*
  93. ================
  94. idPlayerStart::ClientReceiveEvent
  95. ================
  96. */
  97. bool idPlayerStart::ClientReceiveEvent( int event, int time, const idBitMsg& msg )
  98. {
  99. int entityNumber;
  100. switch( event )
  101. {
  102. case EVENT_TELEPORTPLAYER:
  103. {
  104. entityNumber = msg.ReadBits( GENTITYNUM_BITS );
  105. idPlayer* player = static_cast<idPlayer*>( gameLocal.entities[entityNumber] );
  106. if( player != NULL && player->IsType( idPlayer::Type ) )
  107. {
  108. Event_TeleportPlayer( player );
  109. }
  110. return true;
  111. }
  112. default:
  113. {
  114. return idEntity::ClientReceiveEvent( event, time, msg );
  115. }
  116. }
  117. }
  118. /*
  119. ===============
  120. idPlayerStart::Event_TeleportStage
  121. FIXME: add functionality to fx system ( could be done with player scripting too )
  122. ================
  123. */
  124. void idPlayerStart::Event_TeleportStage( idEntity* _player )
  125. {
  126. idPlayer* player;
  127. if( !_player->IsType( idPlayer::Type ) )
  128. {
  129. common->Warning( "idPlayerStart::Event_TeleportStage: entity is not an idPlayer\n" );
  130. return;
  131. }
  132. player = static_cast<idPlayer*>( _player );
  133. float teleportDelay = spawnArgs.GetFloat( "teleportDelay" );
  134. switch( teleportStage )
  135. {
  136. case 0:
  137. player->playerView.Flash( colorWhite, 125 );
  138. player->SetInfluenceLevel( INFLUENCE_LEVEL3 );
  139. player->SetInfluenceView( spawnArgs.GetString( "mtr_teleportFx" ), NULL, 0.0f, NULL );
  140. gameSoundWorld->FadeSoundClasses( 0, -20.0f, teleportDelay );
  141. player->StartSound( "snd_teleport_start", SND_CHANNEL_BODY2, 0, false, NULL );
  142. teleportStage++;
  143. PostEventSec( &EV_TeleportStage, teleportDelay, player );
  144. break;
  145. case 1:
  146. gameSoundWorld->FadeSoundClasses( 0, 0.0f, 0.25f );
  147. teleportStage++;
  148. PostEventSec( &EV_TeleportStage, 0.25f, player );
  149. break;
  150. case 2:
  151. player->SetInfluenceView( NULL, NULL, 0.0f, NULL );
  152. TeleportPlayer( player );
  153. player->StopSound( SND_CHANNEL_BODY2, false );
  154. player->SetInfluenceLevel( INFLUENCE_NONE );
  155. teleportStage = 0;
  156. break;
  157. default:
  158. break;
  159. }
  160. }
  161. /*
  162. ===============
  163. idPlayerStart::TeleportPlayer
  164. ================
  165. */
  166. void idPlayerStart::TeleportPlayer( idPlayer* player )
  167. {
  168. float pushVel = spawnArgs.GetFloat( "push", "300" );
  169. float f = spawnArgs.GetFloat( "visualEffect", "0" );
  170. const char* viewName = spawnArgs.GetString( "visualView", "" );
  171. idEntity* ent = viewName ? gameLocal.FindEntity( viewName ) : NULL;
  172. SetTimeState ts( player->timeGroup );
  173. if( f && ent != NULL )
  174. {
  175. // place in private camera view for some time
  176. // the entity needs to teleport to where the camera view is to have the PVS right
  177. player->Teleport( ent->GetPhysics()->GetOrigin(), ang_zero, this );
  178. player->StartSound( "snd_teleport_enter", SND_CHANNEL_ANY, 0, false, NULL );
  179. player->SetPrivateCameraView( static_cast<idCamera*>( ent ) );
  180. // the player entity knows where to spawn from the previous Teleport call
  181. if( !common->IsClient() )
  182. {
  183. player->PostEventSec( &EV_Player_ExitTeleporter, f );
  184. }
  185. }
  186. else
  187. {
  188. // direct to exit, Teleport will take care of the killbox
  189. player->Teleport( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis().ToAngles(), NULL );
  190. // multiplayer hijacked this entity, so only push the player in multiplayer
  191. if( common->IsMultiplayer() )
  192. {
  193. player->GetPhysics()->SetLinearVelocity( GetPhysics()->GetAxis()[0] * pushVel );
  194. }
  195. }
  196. }
  197. /*
  198. ===============
  199. idPlayerStart::Event_TeleportPlayer
  200. ================
  201. */
  202. void idPlayerStart::Event_TeleportPlayer( idEntity* activator )
  203. {
  204. idPlayer* player;
  205. if( activator->IsType( idPlayer::Type ) )
  206. {
  207. player = static_cast<idPlayer*>( activator );
  208. }
  209. else
  210. {
  211. player = gameLocal.GetLocalPlayer();
  212. }
  213. if( player )
  214. {
  215. if( spawnArgs.GetBool( "visualFx" ) )
  216. {
  217. teleportStage = 0;
  218. Event_TeleportStage( player );
  219. }
  220. else
  221. {
  222. if( common->IsServer() )
  223. {
  224. idBitMsg msg;
  225. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  226. msg.InitWrite( msgBuf, sizeof( msgBuf ) );
  227. msg.BeginWriting();
  228. msg.WriteBits( player->entityNumber, GENTITYNUM_BITS );
  229. ServerSendEvent( EVENT_TELEPORTPLAYER, &msg, false );
  230. }
  231. TeleportPlayer( player );
  232. }
  233. }
  234. }
  235. /*
  236. ===============================================================================
  237. idActivator
  238. ===============================================================================
  239. */
  240. CLASS_DECLARATION( idEntity, idActivator )
  241. EVENT( EV_Activate, idActivator::Event_Activate )
  242. END_CLASS
  243. /*
  244. ===============
  245. idActivator::Save
  246. ================
  247. */
  248. void idActivator::Save( idSaveGame* savefile ) const
  249. {
  250. savefile->WriteBool( stay_on );
  251. }
  252. /*
  253. ===============
  254. idActivator::Restore
  255. ================
  256. */
  257. void idActivator::Restore( idRestoreGame* savefile )
  258. {
  259. savefile->ReadBool( stay_on );
  260. if( stay_on )
  261. {
  262. BecomeActive( TH_THINK );
  263. }
  264. }
  265. /*
  266. ===============
  267. idActivator::Spawn
  268. ================
  269. */
  270. void idActivator::Spawn()
  271. {
  272. bool start_off;
  273. spawnArgs.GetBool( "stay_on", "0", stay_on );
  274. spawnArgs.GetBool( "start_off", "0", start_off );
  275. GetPhysics()->SetClipBox( idBounds( vec3_origin ).Expand( 4 ), 1.0f );
  276. GetPhysics()->SetContents( 0 );
  277. if( !start_off )
  278. {
  279. BecomeActive( TH_THINK );
  280. }
  281. }
  282. /*
  283. ===============
  284. idActivator::Think
  285. ================
  286. */
  287. void idActivator::Think()
  288. {
  289. RunPhysics();
  290. if( thinkFlags & TH_THINK )
  291. {
  292. if( TouchTriggers() )
  293. {
  294. if( !stay_on )
  295. {
  296. BecomeInactive( TH_THINK );
  297. }
  298. }
  299. }
  300. Present();
  301. }
  302. /*
  303. ===============
  304. idActivator::Activate
  305. ================
  306. */
  307. void idActivator::Event_Activate( idEntity* activator )
  308. {
  309. if( thinkFlags & TH_THINK )
  310. {
  311. BecomeInactive( TH_THINK );
  312. }
  313. else
  314. {
  315. BecomeActive( TH_THINK );
  316. }
  317. }
  318. /*
  319. ===============================================================================
  320. idPathCorner
  321. ===============================================================================
  322. */
  323. CLASS_DECLARATION( idEntity, idPathCorner )
  324. EVENT( AI_RandomPath, idPathCorner::Event_RandomPath )
  325. END_CLASS
  326. /*
  327. =====================
  328. idPathCorner::Spawn
  329. =====================
  330. */
  331. void idPathCorner::Spawn()
  332. {
  333. }
  334. /*
  335. =====================
  336. idPathCorner::DrawDebugInfo
  337. =====================
  338. */
  339. void idPathCorner::DrawDebugInfo()
  340. {
  341. idEntity* ent;
  342. idBounds bnds( idVec3( -4.0, -4.0f, -8.0f ), idVec3( 4.0, 4.0f, 64.0f ) );
  343. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() )
  344. {
  345. if( !ent->IsType( idPathCorner::Type ) )
  346. {
  347. continue;
  348. }
  349. idVec3 org = ent->GetPhysics()->GetOrigin();
  350. gameRenderWorld->DebugBounds( colorRed, bnds, org, 0 );
  351. }
  352. }
  353. /*
  354. ============
  355. idPathCorner::RandomPath
  356. ============
  357. */
  358. idPathCorner* idPathCorner::RandomPath( const idEntity* source, const idEntity* ignore )
  359. {
  360. int i;
  361. int num;
  362. int which;
  363. idEntity* ent;
  364. idPathCorner* path[ MAX_GENTITIES ];
  365. num = 0;
  366. for( i = 0; i < source->targets.Num(); i++ )
  367. {
  368. ent = source->targets[ i ].GetEntity();
  369. if( ent != NULL && ( ent != ignore ) && ent->IsType( idPathCorner::Type ) )
  370. {
  371. path[ num++ ] = static_cast<idPathCorner*>( ent );
  372. if( num >= MAX_GENTITIES )
  373. {
  374. break;
  375. }
  376. }
  377. }
  378. if( !num )
  379. {
  380. return NULL;
  381. }
  382. which = gameLocal.random.RandomInt( num );
  383. return path[ which ];
  384. }
  385. /*
  386. =====================
  387. idPathCorner::Event_RandomPath
  388. =====================
  389. */
  390. void idPathCorner::Event_RandomPath()
  391. {
  392. idPathCorner* path;
  393. path = RandomPath( this, NULL );
  394. idThread::ReturnEntity( path );
  395. }
  396. /*
  397. ===============================================================================
  398. idDamagable
  399. ===============================================================================
  400. */
  401. const idEventDef EV_RestoreDamagable( "<RestoreDamagable>" );
  402. CLASS_DECLARATION( idEntity, idDamagable )
  403. EVENT( EV_Activate, idDamagable::Event_BecomeBroken )
  404. EVENT( EV_RestoreDamagable, idDamagable::Event_RestoreDamagable )
  405. END_CLASS
  406. /*
  407. ================
  408. idDamagable::idDamagable
  409. ================
  410. */
  411. idDamagable::idDamagable()
  412. {
  413. count = 0;
  414. nextTriggerTime = 0;
  415. }
  416. /*
  417. ================
  418. idDamagable::Save
  419. ================
  420. */
  421. void idDamagable::Save( idSaveGame* savefile ) const
  422. {
  423. savefile->WriteInt( count );
  424. savefile->WriteInt( nextTriggerTime );
  425. }
  426. /*
  427. ================
  428. idDamagable::Restore
  429. ================
  430. */
  431. void idDamagable::Restore( idRestoreGame* savefile )
  432. {
  433. savefile->ReadInt( count );
  434. savefile->ReadInt( nextTriggerTime );
  435. }
  436. /*
  437. ================
  438. idDamagable::Spawn
  439. ================
  440. */
  441. void idDamagable::Spawn()
  442. {
  443. idStr broken;
  444. health = spawnArgs.GetInt( "health", "5" );
  445. spawnArgs.GetInt( "count", "1", count );
  446. nextTriggerTime = 0;
  447. // make sure the model gets cached
  448. spawnArgs.GetString( "broken", "", broken );
  449. if( broken.Length() && !renderModelManager->CheckModel( broken ) )
  450. {
  451. gameLocal.Error( "idDamagable '%s' at (%s): cannot load broken model '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), broken.c_str() );
  452. }
  453. fl.takedamage = true;
  454. GetPhysics()->SetContents( CONTENTS_SOLID );
  455. }
  456. /*
  457. ================
  458. idDamagable::BecomeBroken
  459. ================
  460. */
  461. void idDamagable::BecomeBroken( idEntity* activator )
  462. {
  463. float forceState;
  464. int numStates;
  465. int cycle;
  466. float wait;
  467. if( gameLocal.time < nextTriggerTime )
  468. {
  469. return;
  470. }
  471. spawnArgs.GetFloat( "wait", "0.1", wait );
  472. nextTriggerTime = gameLocal.time + SEC2MS( wait );
  473. if( count > 0 )
  474. {
  475. count--;
  476. if( !count )
  477. {
  478. fl.takedamage = false;
  479. }
  480. else
  481. {
  482. health = spawnArgs.GetInt( "health", "5" );
  483. }
  484. }
  485. idStr broken;
  486. spawnArgs.GetString( "broken", "", broken );
  487. if( broken.Length() )
  488. {
  489. SetModel( broken );
  490. }
  491. // offset the start time of the shader to sync it to the gameLocal time
  492. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  493. spawnArgs.GetInt( "numstates", "1", numStates );
  494. spawnArgs.GetInt( "cycle", "0", cycle );
  495. spawnArgs.GetFloat( "forcestate", "0", forceState );
  496. // set the state parm
  497. if( cycle )
  498. {
  499. renderEntity.shaderParms[ SHADERPARM_MODE ]++;
  500. if( renderEntity.shaderParms[ SHADERPARM_MODE ] > numStates )
  501. {
  502. renderEntity.shaderParms[ SHADERPARM_MODE ] = 0;
  503. }
  504. }
  505. else if( forceState )
  506. {
  507. renderEntity.shaderParms[ SHADERPARM_MODE ] = forceState;
  508. }
  509. else
  510. {
  511. renderEntity.shaderParms[ SHADERPARM_MODE ] = gameLocal.random.RandomInt( numStates ) + 1;
  512. }
  513. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  514. ActivateTargets( activator );
  515. if( spawnArgs.GetBool( "hideWhenBroken" ) )
  516. {
  517. Hide();
  518. PostEventMS( &EV_RestoreDamagable, nextTriggerTime - gameLocal.time );
  519. BecomeActive( TH_THINK );
  520. }
  521. }
  522. /*
  523. ================
  524. idDamagable::Killed
  525. ================
  526. */
  527. void idDamagable::Killed( idEntity* inflictor, idEntity* attacker, int damage, const idVec3& dir, int location )
  528. {
  529. if( gameLocal.time < nextTriggerTime )
  530. {
  531. health += damage;
  532. return;
  533. }
  534. BecomeBroken( attacker );
  535. }
  536. /*
  537. ================
  538. idDamagable::Hide
  539. ================
  540. */
  541. void idDamagable::Hide()
  542. {
  543. idEntity::Hide();
  544. GetPhysics()->SetContents( 0 );
  545. }
  546. /*
  547. ================
  548. idDamagable::Show
  549. ================
  550. */
  551. void idDamagable::Show()
  552. {
  553. idEntity::Show();
  554. GetPhysics()->SetContents( CONTENTS_SOLID );
  555. }
  556. /*
  557. ================
  558. idDamagable::Event_BecomeBroken
  559. ================
  560. */
  561. void idDamagable::Event_BecomeBroken( idEntity* activator )
  562. {
  563. BecomeBroken( activator );
  564. }
  565. /*
  566. ================
  567. idDamagable::Event_RestoreDamagable
  568. ================
  569. */
  570. void idDamagable::Event_RestoreDamagable()
  571. {
  572. health = spawnArgs.GetInt( "health", "5" );
  573. Show();
  574. }
  575. /*
  576. ===============================================================================
  577. idExplodable
  578. ===============================================================================
  579. */
  580. CLASS_DECLARATION( idEntity, idExplodable )
  581. EVENT( EV_Activate, idExplodable::Event_Explode )
  582. END_CLASS
  583. /*
  584. ================
  585. idExplodable::Spawn
  586. ================
  587. */
  588. void idExplodable::Spawn()
  589. {
  590. Hide();
  591. }
  592. /*
  593. ================
  594. idExplodable::Event_Explode
  595. ================
  596. */
  597. void idExplodable::Event_Explode( idEntity* activator )
  598. {
  599. const char* temp;
  600. if( spawnArgs.GetString( "def_damage", "damage_explosion", &temp ) )
  601. {
  602. gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), activator, activator, this, this, temp );
  603. }
  604. StartSound( "snd_explode", SND_CHANNEL_ANY, 0, false, NULL );
  605. // Show() calls UpdateVisuals, so we don't need to call it ourselves after setting the shaderParms
  606. renderEntity.shaderParms[SHADERPARM_RED] = 1.0f;
  607. renderEntity.shaderParms[SHADERPARM_GREEN] = 1.0f;
  608. renderEntity.shaderParms[SHADERPARM_BLUE] = 1.0f;
  609. renderEntity.shaderParms[SHADERPARM_ALPHA] = 1.0f;
  610. renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
  611. renderEntity.shaderParms[SHADERPARM_DIVERSITY] = 0.0f;
  612. Show();
  613. PostEventMS( &EV_Remove, 2000 );
  614. ActivateTargets( activator );
  615. }
  616. /*
  617. ===============================================================================
  618. idSpring
  619. ===============================================================================
  620. */
  621. CLASS_DECLARATION( idEntity, idSpring )
  622. EVENT( EV_PostSpawn, idSpring::Event_LinkSpring )
  623. END_CLASS
  624. /*
  625. ================
  626. idSpring::Think
  627. ================
  628. */
  629. void idSpring::Think()
  630. {
  631. idVec3 start, end, origin;
  632. idMat3 axis;
  633. // run physics
  634. RunPhysics();
  635. if( thinkFlags & TH_THINK )
  636. {
  637. // evaluate force
  638. spring.Evaluate( gameLocal.time );
  639. start = p1;
  640. if( ent1->GetPhysics() )
  641. {
  642. axis = ent1->GetPhysics()->GetAxis();
  643. origin = ent1->GetPhysics()->GetOrigin();
  644. start = origin + start * axis;
  645. }
  646. end = p2;
  647. if( ent2->GetPhysics() )
  648. {
  649. axis = ent2->GetPhysics()->GetAxis();
  650. origin = ent2->GetPhysics()->GetOrigin();
  651. end = origin + p2 * axis;
  652. }
  653. gameRenderWorld->DebugLine( idVec4( 1, 1, 0, 1 ), start, end, 0, true );
  654. }
  655. Present();
  656. }
  657. /*
  658. ================
  659. idSpring::Event_LinkSpring
  660. ================
  661. */
  662. void idSpring::Event_LinkSpring()
  663. {
  664. idStr name1, name2;
  665. spawnArgs.GetString( "ent1", "", name1 );
  666. spawnArgs.GetString( "ent2", "", name2 );
  667. if( name1.Length() )
  668. {
  669. ent1 = gameLocal.FindEntity( name1 );
  670. if( ent1 == NULL )
  671. {
  672. gameLocal.Error( "idSpring '%s' at (%s): cannot find first entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), name1.c_str() );
  673. return;
  674. }
  675. }
  676. else
  677. {
  678. ent1 = gameLocal.entities[ENTITYNUM_WORLD];
  679. }
  680. if( name2.Length() )
  681. {
  682. ent2 = gameLocal.FindEntity( name2 );
  683. if( ent2 == NULL )
  684. {
  685. gameLocal.Error( "idSpring '%s' at (%s): cannot find second entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), name2.c_str() );
  686. return;
  687. }
  688. }
  689. else
  690. {
  691. ent2 = gameLocal.entities[ENTITYNUM_WORLD];
  692. }
  693. spring.SetPosition( ent1->GetPhysics(), id1, p1, ent2->GetPhysics(), id2, p2 );
  694. BecomeActive( TH_THINK );
  695. }
  696. /*
  697. ================
  698. idSpring::Spawn
  699. ================
  700. */
  701. void idSpring::Spawn()
  702. {
  703. float Kstretch, damping, restLength;
  704. spawnArgs.GetInt( "id1", "0", id1 );
  705. spawnArgs.GetInt( "id2", "0", id2 );
  706. spawnArgs.GetVector( "point1", "0 0 0", p1 );
  707. spawnArgs.GetVector( "point2", "0 0 0", p2 );
  708. spawnArgs.GetFloat( "constant", "100.0f", Kstretch );
  709. spawnArgs.GetFloat( "damping", "10.0f", damping );
  710. spawnArgs.GetFloat( "restlength", "0.0f", restLength );
  711. spring.InitSpring( Kstretch, 0.0f, damping, restLength );
  712. ent1 = ent2 = NULL;
  713. PostEventMS( &EV_PostSpawn, 0 );
  714. }
  715. /*
  716. ===============================================================================
  717. idForceField
  718. ===============================================================================
  719. */
  720. const idEventDef EV_Toggle( "Toggle", NULL );
  721. CLASS_DECLARATION( idEntity, idForceField )
  722. EVENT( EV_Activate, idForceField::Event_Activate )
  723. EVENT( EV_Toggle, idForceField::Event_Toggle )
  724. EVENT( EV_FindTargets, idForceField::Event_FindTargets )
  725. END_CLASS
  726. /*
  727. ===============
  728. idForceField::Toggle
  729. ================
  730. */
  731. void idForceField::Toggle()
  732. {
  733. if( thinkFlags & TH_THINK )
  734. {
  735. BecomeInactive( TH_THINK );
  736. }
  737. else
  738. {
  739. BecomeActive( TH_THINK );
  740. }
  741. }
  742. /*
  743. ================
  744. idForceField::Think
  745. ================
  746. */
  747. void idForceField::ClientThink( const int curTime, const float fraction, const bool predict )
  748. {
  749. // evaluate force
  750. forceField.Evaluate( gameLocal.time );
  751. Present();
  752. }
  753. /*
  754. ================
  755. idForceField::Think
  756. ================
  757. */
  758. void idForceField::Think()
  759. {
  760. if( thinkFlags & TH_THINK )
  761. {
  762. // evaluate force
  763. forceField.Evaluate( gameLocal.time );
  764. }
  765. Present();
  766. }
  767. /*
  768. ================
  769. idForceField::Save
  770. ================
  771. */
  772. void idForceField::Save( idSaveGame* savefile ) const
  773. {
  774. savefile->WriteStaticObject( forceField );
  775. }
  776. /*
  777. ================
  778. idForceField::Restore
  779. ================
  780. */
  781. void idForceField::Restore( idRestoreGame* savefile )
  782. {
  783. savefile->ReadStaticObject( forceField );
  784. }
  785. /*
  786. ================
  787. idForceField::Spawn
  788. ================
  789. */
  790. void idForceField::Spawn()
  791. {
  792. idVec3 uniform;
  793. float explosion, implosion, randomTorque;
  794. if( spawnArgs.GetVector( "uniform", "0 0 0", uniform ) )
  795. {
  796. forceField.Uniform( uniform );
  797. }
  798. else if( spawnArgs.GetFloat( "explosion", "0", explosion ) )
  799. {
  800. forceField.Explosion( explosion );
  801. }
  802. else if( spawnArgs.GetFloat( "implosion", "0", implosion ) )
  803. {
  804. forceField.Implosion( implosion );
  805. }
  806. if( spawnArgs.GetFloat( "randomTorque", "0", randomTorque ) )
  807. {
  808. forceField.RandomTorque( randomTorque );
  809. }
  810. if( spawnArgs.GetBool( "applyForce", "0" ) )
  811. {
  812. forceField.SetApplyType( FORCEFIELD_APPLY_FORCE );
  813. }
  814. else if( spawnArgs.GetBool( "applyImpulse", "0" ) )
  815. {
  816. forceField.SetApplyType( FORCEFIELD_APPLY_IMPULSE );
  817. }
  818. else
  819. {
  820. forceField.SetApplyType( FORCEFIELD_APPLY_VELOCITY );
  821. }
  822. forceField.SetPlayerOnly( spawnArgs.GetBool( "playerOnly", "0" ) );
  823. forceField.SetMonsterOnly( spawnArgs.GetBool( "monsterOnly", "0" ) );
  824. // set the collision model on the force field
  825. forceField.SetClipModel( new( TAG_PHYSICS_CLIP_ENTITY ) idClipModel( GetPhysics()->GetClipModel() ) );
  826. // remove the collision model from the physics object
  827. GetPhysics()->SetClipModel( NULL, 1.0f );
  828. if( spawnArgs.GetBool( "start_on" ) )
  829. {
  830. BecomeActive( TH_THINK );
  831. }
  832. }
  833. /*
  834. ===============
  835. idForceField::Event_Toggle
  836. ================
  837. */
  838. void idForceField::Event_Toggle()
  839. {
  840. Toggle();
  841. }
  842. /*
  843. ================
  844. idForceField::Event_Activate
  845. ================
  846. */
  847. void idForceField::Event_Activate( idEntity* activator )
  848. {
  849. float wait;
  850. Toggle();
  851. if( spawnArgs.GetFloat( "wait", "0.01", wait ) )
  852. {
  853. PostEventSec( &EV_Toggle, wait );
  854. }
  855. }
  856. /*
  857. ================
  858. idForceField::Event_FindTargets
  859. ================
  860. */
  861. void idForceField::Event_FindTargets()
  862. {
  863. FindTargets();
  864. RemoveNullTargets();
  865. if( targets.Num() )
  866. {
  867. forceField.Uniform( targets[0].GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() );
  868. }
  869. }
  870. /*
  871. ===============================================================================
  872. idAnimated
  873. ===============================================================================
  874. */
  875. const idEventDef EV_Animated_Start( "<start>" );
  876. const idEventDef EV_LaunchMissiles( "launchMissiles", "ssssdf" );
  877. const idEventDef EV_LaunchMissilesUpdate( "<launchMissiles>", "dddd" );
  878. const idEventDef EV_AnimDone( "<AnimDone>", "d" );
  879. const idEventDef EV_StartRagdoll( "startRagdoll" );
  880. const idEventDef EV_SetAnimation( "setAnimation", "s" );
  881. const idEventDef EV_GetAnimationLength( "getAnimationLength", NULL, 'f' );
  882. CLASS_DECLARATION( idAFEntity_Gibbable, idAnimated )
  883. EVENT( EV_Activate, idAnimated::Event_Activate )
  884. EVENT( EV_Animated_Start, idAnimated::Event_Start )
  885. EVENT( EV_StartRagdoll, idAnimated::Event_StartRagdoll )
  886. EVENT( EV_AnimDone, idAnimated::Event_AnimDone )
  887. EVENT( EV_Footstep, idAnimated::Event_Footstep )
  888. EVENT( EV_FootstepLeft, idAnimated::Event_Footstep )
  889. EVENT( EV_FootstepRight, idAnimated::Event_Footstep )
  890. EVENT( EV_LaunchMissiles, idAnimated::Event_LaunchMissiles )
  891. EVENT( EV_LaunchMissilesUpdate, idAnimated::Event_LaunchMissilesUpdate )
  892. EVENT( EV_SetAnimation, idAnimated::Event_SetAnimation )
  893. EVENT( EV_GetAnimationLength, idAnimated::Event_GetAnimationLength )
  894. END_CLASS
  895. /*
  896. ===============
  897. idAnimated::idAnimated
  898. ================
  899. */
  900. idAnimated::idAnimated()
  901. {
  902. anim = 0;
  903. blendFrames = 0;
  904. soundJoint = INVALID_JOINT;
  905. activated = false;
  906. combatModel = NULL;
  907. activator = NULL;
  908. current_anim_index = 0;
  909. num_anims = 0;
  910. achievement = -1;
  911. }
  912. /*
  913. ===============
  914. idAnimated::idAnimated
  915. ================
  916. */
  917. idAnimated::~idAnimated()
  918. {
  919. delete combatModel;
  920. combatModel = NULL;
  921. }
  922. /*
  923. ===============
  924. idAnimated::Save
  925. ================
  926. */
  927. void idAnimated::Save( idSaveGame* savefile ) const
  928. {
  929. savefile->WriteInt( current_anim_index );
  930. savefile->WriteInt( num_anims );
  931. savefile->WriteInt( anim );
  932. savefile->WriteInt( blendFrames );
  933. savefile->WriteJoint( soundJoint );
  934. activator.Save( savefile );
  935. savefile->WriteBool( activated );
  936. }
  937. /*
  938. ===============
  939. idAnimated::Restore
  940. ================
  941. */
  942. void idAnimated::Restore( idRestoreGame* savefile )
  943. {
  944. savefile->ReadInt( current_anim_index );
  945. savefile->ReadInt( num_anims );
  946. savefile->ReadInt( anim );
  947. savefile->ReadInt( blendFrames );
  948. savefile->ReadJoint( soundJoint );
  949. activator.Restore( savefile );
  950. savefile->ReadBool( activated );
  951. }
  952. /*
  953. ===============
  954. idAnimated::Spawn
  955. ================
  956. */
  957. void idAnimated::Spawn()
  958. {
  959. idStr animname;
  960. int anim2;
  961. float wait;
  962. const char* joint;
  963. joint = spawnArgs.GetString( "sound_bone", "origin" );
  964. soundJoint = animator.GetJointHandle( joint );
  965. if( soundJoint == INVALID_JOINT )
  966. {
  967. gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), joint );
  968. }
  969. LoadAF();
  970. // allow bullets to collide with a combat model
  971. if( spawnArgs.GetBool( "combatModel", "0" ) )
  972. {
  973. combatModel = new( TAG_PHYSICS_CLIP_ENTITY ) idClipModel( modelDefHandle );
  974. }
  975. // allow the entity to take damage
  976. if( spawnArgs.GetBool( "takeDamage", "0" ) )
  977. {
  978. fl.takedamage = true;
  979. }
  980. current_anim_index = 0;
  981. spawnArgs.GetInt( "num_anims", "0", num_anims );
  982. blendFrames = spawnArgs.GetInt( "blend_in" );
  983. animname = spawnArgs.GetString( num_anims ? "anim1" : "anim" );
  984. if( !animname.Length() )
  985. {
  986. anim = 0;
  987. }
  988. else
  989. {
  990. anim = animator.GetAnim( animname );
  991. if( !anim )
  992. {
  993. gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), animname.c_str() );
  994. }
  995. }
  996. if( spawnArgs.GetBool( "hide" ) )
  997. {
  998. Hide();
  999. if( !num_anims )
  1000. {
  1001. blendFrames = 0;
  1002. }
  1003. }
  1004. else if( spawnArgs.GetString( "start_anim", "", animname ) )
  1005. {
  1006. anim2 = animator.GetAnim( animname );
  1007. if( !anim2 )
  1008. {
  1009. gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), animname.c_str() );
  1010. }
  1011. animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, 0 );
  1012. }
  1013. else if( anim )
  1014. {
  1015. // init joints to the first frame of the animation
  1016. animator.SetFrame( ANIMCHANNEL_ALL, anim, 1, gameLocal.time, 0 );
  1017. if( !num_anims )
  1018. {
  1019. blendFrames = 0;
  1020. }
  1021. }
  1022. spawnArgs.GetFloat( "wait", "-1", wait );
  1023. if( wait >= 0 )
  1024. {
  1025. PostEventSec( &EV_Activate, wait, this );
  1026. }
  1027. }
  1028. /*
  1029. ===============
  1030. idAnimated::LoadAF
  1031. ===============
  1032. */
  1033. bool idAnimated::LoadAF()
  1034. {
  1035. idStr fileName;
  1036. if( !spawnArgs.GetString( "ragdoll", "*unknown*", fileName ) )
  1037. {
  1038. return false;
  1039. }
  1040. af.SetAnimator( GetAnimator() );
  1041. return af.Load( this, fileName );
  1042. }
  1043. /*
  1044. ===============
  1045. idAnimated::GetPhysicsToSoundTransform
  1046. ===============
  1047. */
  1048. bool idAnimated::GetPhysicsToSoundTransform( idVec3& origin, idMat3& axis )
  1049. {
  1050. animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis );
  1051. axis = renderEntity.axis;
  1052. return true;
  1053. }
  1054. /*
  1055. ================
  1056. idAnimated::StartRagdoll
  1057. ================
  1058. */
  1059. bool idAnimated::StartRagdoll()
  1060. {
  1061. // if no AF loaded
  1062. if( !af.IsLoaded() )
  1063. {
  1064. return false;
  1065. }
  1066. // if the AF is already active
  1067. if( af.IsActive() )
  1068. {
  1069. return true;
  1070. }
  1071. // disable any collision model used
  1072. GetPhysics()->DisableClip();
  1073. // start using the AF
  1074. af.StartFromCurrentPose( spawnArgs.GetInt( "velocityTime", "0" ) );
  1075. return true;
  1076. }
  1077. /*
  1078. =====================
  1079. idAnimated::PlayNextAnim
  1080. =====================
  1081. */
  1082. void idAnimated::PlayNextAnim()
  1083. {
  1084. const char* animname;
  1085. int len;
  1086. int cycle;
  1087. if( current_anim_index >= num_anims )
  1088. {
  1089. Hide();
  1090. if( spawnArgs.GetBool( "remove" ) )
  1091. {
  1092. PostEventMS( &EV_Remove, 0 );
  1093. }
  1094. else
  1095. {
  1096. current_anim_index = 0;
  1097. }
  1098. return;
  1099. }
  1100. Show();
  1101. current_anim_index++;
  1102. spawnArgs.GetString( va( "anim%d", current_anim_index ), NULL, &animname );
  1103. if( !animname )
  1104. {
  1105. anim = 0;
  1106. animator.Clear( ANIMCHANNEL_ALL, gameLocal.time, FRAME2MS( blendFrames ) );
  1107. return;
  1108. }
  1109. anim = animator.GetAnim( animname );
  1110. if( !anim )
  1111. {
  1112. gameLocal.Warning( "missing anim '%s' on %s", animname, name.c_str() );
  1113. return;
  1114. }
  1115. if( g_debugCinematic.GetBool() )
  1116. {
  1117. gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animname );
  1118. }
  1119. spawnArgs.GetInt( "cycle", "1", cycle );
  1120. if( ( current_anim_index == num_anims ) && spawnArgs.GetBool( "loop_last_anim" ) )
  1121. {
  1122. cycle = -1;
  1123. }
  1124. animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  1125. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
  1126. len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength();
  1127. if( len >= 0 )
  1128. {
  1129. PostEventMS( &EV_AnimDone, len, current_anim_index );
  1130. }
  1131. // offset the start time of the shader to sync it to the game time
  1132. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  1133. animator.ForceUpdate();
  1134. UpdateAnimation();
  1135. UpdateVisuals();
  1136. Present();
  1137. }
  1138. /*
  1139. ===============
  1140. idAnimated::Event_StartRagdoll
  1141. ================
  1142. */
  1143. void idAnimated::Event_StartRagdoll()
  1144. {
  1145. StartRagdoll();
  1146. }
  1147. /*
  1148. ===============
  1149. idAnimated::Event_AnimDone
  1150. ================
  1151. */
  1152. void idAnimated::Event_AnimDone( int animindex )
  1153. {
  1154. if( g_debugCinematic.GetBool() )
  1155. {
  1156. const idAnim* animPtr = animator.GetAnim( anim );
  1157. gameLocal.Printf( "%d: '%s' end anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" );
  1158. }
  1159. if( ( animindex >= num_anims ) && spawnArgs.GetBool( "remove" ) )
  1160. {
  1161. Hide();
  1162. PostEventMS( &EV_Remove, 0 );
  1163. }
  1164. else if( spawnArgs.GetBool( "auto_advance" ) )
  1165. {
  1166. PlayNextAnim();
  1167. }
  1168. else
  1169. {
  1170. activated = false;
  1171. }
  1172. ActivateTargets( activator.GetEntity() );
  1173. }
  1174. /*
  1175. ===============
  1176. idAnimated::Event_Activate
  1177. ================
  1178. */
  1179. void idAnimated::Event_Activate( idEntity* _activator )
  1180. {
  1181. if( num_anims )
  1182. {
  1183. PlayNextAnim();
  1184. activator = _activator;
  1185. return;
  1186. }
  1187. if( activated )
  1188. {
  1189. // already activated
  1190. return;
  1191. }
  1192. // achievement associated with this entity (given on activation)
  1193. achievement = spawnArgs.GetInt( "achievement", "-1" );
  1194. if( achievement != -1 )
  1195. {
  1196. idPlayer* player = gameLocal.GetLocalPlayer();
  1197. if( player != NULL )
  1198. {
  1199. bool shouldCountAction = true;
  1200. // only count unlocking lockers if we're in the base game
  1201. if( achievement == ACHIEVEMENT_OPEN_ALL_LOCKERS && player->GetExpansionType() != GAME_BASE )
  1202. {
  1203. shouldCountAction = false;
  1204. }
  1205. if( shouldCountAction )
  1206. {
  1207. player->GetAchievementManager().EventCompletesAchievement( ( achievement_t )achievement );
  1208. }
  1209. }
  1210. }
  1211. activated = true;
  1212. activator = _activator;
  1213. ProcessEvent( &EV_Animated_Start );
  1214. }
  1215. /*
  1216. ===============
  1217. idAnimated::Event_Start
  1218. ================
  1219. */
  1220. void idAnimated::Event_Start()
  1221. {
  1222. int cycle;
  1223. int len;
  1224. Show();
  1225. if( num_anims )
  1226. {
  1227. PlayNextAnim();
  1228. return;
  1229. }
  1230. if( anim )
  1231. {
  1232. if( g_debugCinematic.GetBool() )
  1233. {
  1234. const idAnim* animPtr = animator.GetAnim( anim );
  1235. gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" );
  1236. }
  1237. spawnArgs.GetInt( "cycle", "1", cycle );
  1238. animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  1239. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
  1240. len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength();
  1241. if( len >= 0 )
  1242. {
  1243. PostEventMS( &EV_AnimDone, len, 1 );
  1244. }
  1245. }
  1246. // offset the start time of the shader to sync it to the game time
  1247. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  1248. animator.ForceUpdate();
  1249. UpdateAnimation();
  1250. UpdateVisuals();
  1251. Present();
  1252. }
  1253. /*
  1254. ===============
  1255. idAnimated::Event_Footstep
  1256. ===============
  1257. */
  1258. void idAnimated::Event_Footstep()
  1259. {
  1260. StartSound( "snd_footstep", SND_CHANNEL_BODY, 0, false, NULL );
  1261. }
  1262. /*
  1263. =====================
  1264. idAnimated::Event_LaunchMissilesUpdate
  1265. =====================
  1266. */
  1267. void idAnimated::Event_LaunchMissilesUpdate( int launchjoint, int targetjoint, int numshots, int framedelay )
  1268. {
  1269. idVec3 launchPos;
  1270. idVec3 targetPos;
  1271. idMat3 axis;
  1272. idVec3 dir;
  1273. idEntity* ent;
  1274. idProjectile* projectile;
  1275. const idDict* projectileDef;
  1276. const char* projectilename;
  1277. projectilename = spawnArgs.GetString( "projectilename" );
  1278. projectileDef = gameLocal.FindEntityDefDict( projectilename, false );
  1279. if( !projectileDef )
  1280. {
  1281. gameLocal.Warning( "idAnimated '%s' at (%s): 'launchMissiles' called with unknown projectile '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), projectilename );
  1282. return;
  1283. }
  1284. StartSound( "snd_missile", SND_CHANNEL_WEAPON, 0, false, NULL );
  1285. animator.GetJointTransform( ( jointHandle_t )launchjoint, gameLocal.time, launchPos, axis );
  1286. launchPos = renderEntity.origin + launchPos * renderEntity.axis;
  1287. animator.GetJointTransform( ( jointHandle_t )targetjoint, gameLocal.time, targetPos, axis );
  1288. targetPos = renderEntity.origin + targetPos * renderEntity.axis;
  1289. dir = targetPos - launchPos;
  1290. dir.Normalize();
  1291. gameLocal.SpawnEntityDef( *projectileDef, &ent, false );
  1292. if( ent == NULL || !ent->IsType( idProjectile::Type ) )
  1293. {
  1294. gameLocal.Error( "idAnimated '%s' at (%s): in 'launchMissiles' call '%s' is not an idProjectile", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), projectilename );
  1295. return;
  1296. }
  1297. projectile = ( idProjectile* )ent;
  1298. projectile->Create( this, launchPos, dir );
  1299. projectile->Launch( launchPos, dir, vec3_origin );
  1300. if( numshots > 0 )
  1301. {
  1302. PostEventMS( &EV_LaunchMissilesUpdate, FRAME2MS( framedelay ), launchjoint, targetjoint, numshots - 1, framedelay );
  1303. }
  1304. }
  1305. /*
  1306. =====================
  1307. idAnimated::Event_LaunchMissiles
  1308. =====================
  1309. */
  1310. void idAnimated::Event_LaunchMissiles( const char* projectilename, const char* sound, const char* launchjoint, const char* targetjoint, int numshots, int framedelay )
  1311. {
  1312. const idDict* projectileDef;
  1313. jointHandle_t launch;
  1314. jointHandle_t target;
  1315. projectileDef = gameLocal.FindEntityDefDict( projectilename, false );
  1316. if( !projectileDef )
  1317. {
  1318. gameLocal.Warning( "idAnimated '%s' at (%s): unknown projectile '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), projectilename );
  1319. return;
  1320. }
  1321. launch = animator.GetJointHandle( launchjoint );
  1322. if( launch == INVALID_JOINT )
  1323. {
  1324. gameLocal.Warning( "idAnimated '%s' at (%s): unknown launch joint '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), launchjoint );
  1325. gameLocal.Error( "Unknown joint '%s'", launchjoint );
  1326. }
  1327. target = animator.GetJointHandle( targetjoint );
  1328. if( target == INVALID_JOINT )
  1329. {
  1330. gameLocal.Warning( "idAnimated '%s' at (%s): unknown target joint '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), targetjoint );
  1331. }
  1332. spawnArgs.Set( "projectilename", projectilename );
  1333. spawnArgs.Set( "missilesound", sound );
  1334. CancelEvents( &EV_LaunchMissilesUpdate );
  1335. ProcessEvent( &EV_LaunchMissilesUpdate, launch, target, numshots - 1, framedelay );
  1336. }
  1337. /*
  1338. =====================
  1339. idAnimated::Event_SetAnimation
  1340. =====================
  1341. */
  1342. void idAnimated::Event_SetAnimation( const char* animName )
  1343. {
  1344. //BSM Nerve: Need to add some error checking so we don't change the animation
  1345. //in the middle of the existing animation
  1346. anim = animator.GetAnim( animName );
  1347. if( !anim )
  1348. {
  1349. gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), animName );
  1350. }
  1351. }
  1352. /*
  1353. =====================
  1354. idAnimated::Event_GetAnimationLength
  1355. =====================
  1356. */
  1357. void idAnimated::Event_GetAnimationLength()
  1358. {
  1359. float length = 0;
  1360. if( anim )
  1361. {
  1362. length = ( float )( animator.AnimLength( anim ) ) / 1000.f;
  1363. }
  1364. idThread::ReturnFloat( length );
  1365. }
  1366. /*
  1367. ===============================================================================
  1368. idStaticEntity
  1369. Some static entities may be optimized into inline geometry by dmap
  1370. ===============================================================================
  1371. */
  1372. CLASS_DECLARATION( idEntity, idStaticEntity )
  1373. EVENT( EV_Activate, idStaticEntity::Event_Activate )
  1374. END_CLASS
  1375. /*
  1376. ===============
  1377. idStaticEntity::idStaticEntity
  1378. ===============
  1379. */
  1380. idStaticEntity::idStaticEntity()
  1381. {
  1382. spawnTime = 0;
  1383. active = false;
  1384. fadeFrom.Set( 1, 1, 1, 1 );
  1385. fadeTo.Set( 1, 1, 1, 1 );
  1386. fadeStart = 0;
  1387. fadeEnd = 0;
  1388. runGui = false;
  1389. }
  1390. /*
  1391. ===============
  1392. idStaticEntity::Save
  1393. ===============
  1394. */
  1395. void idStaticEntity::Save( idSaveGame* savefile ) const
  1396. {
  1397. savefile->WriteInt( spawnTime );
  1398. savefile->WriteBool( active );
  1399. savefile->WriteVec4( fadeFrom );
  1400. savefile->WriteVec4( fadeTo );
  1401. savefile->WriteInt( fadeStart );
  1402. savefile->WriteInt( fadeEnd );
  1403. savefile->WriteBool( runGui );
  1404. }
  1405. /*
  1406. ===============
  1407. idStaticEntity::Restore
  1408. ===============
  1409. */
  1410. void idStaticEntity::Restore( idRestoreGame* savefile )
  1411. {
  1412. savefile->ReadInt( spawnTime );
  1413. savefile->ReadBool( active );
  1414. savefile->ReadVec4( fadeFrom );
  1415. savefile->ReadVec4( fadeTo );
  1416. savefile->ReadInt( fadeStart );
  1417. savefile->ReadInt( fadeEnd );
  1418. savefile->ReadBool( runGui );
  1419. }
  1420. /*
  1421. ===============
  1422. idStaticEntity::Spawn
  1423. ===============
  1424. */
  1425. void idStaticEntity::Spawn()
  1426. {
  1427. bool solid;
  1428. bool hidden;
  1429. // an inline static model will not do anything at all
  1430. if( spawnArgs.GetBool( "inline" ) || gameLocal.world->spawnArgs.GetBool( "inlineAllStatics" ) )
  1431. {
  1432. Hide();
  1433. return;
  1434. }
  1435. solid = spawnArgs.GetBool( "solid" );
  1436. hidden = spawnArgs.GetBool( "hide" );
  1437. if( solid && !hidden )
  1438. {
  1439. GetPhysics()->SetContents( CONTENTS_SOLID );
  1440. }
  1441. else
  1442. {
  1443. GetPhysics()->SetContents( 0 );
  1444. }
  1445. spawnTime = gameLocal.time;
  1446. active = false;
  1447. idStr model = spawnArgs.GetString( "model" );
  1448. if( model.Find( ".prt" ) >= 0 )
  1449. {
  1450. // we want the parametric particles out of sync with each other
  1451. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = gameLocal.random.RandomInt( 32767 );
  1452. }
  1453. fadeFrom.Set( 1, 1, 1, 1 );
  1454. fadeTo.Set( 1, 1, 1, 1 );
  1455. fadeStart = 0;
  1456. fadeEnd = 0;
  1457. // NOTE: this should be used very rarely because it is expensive
  1458. runGui = spawnArgs.GetBool( "runGui" );
  1459. if( runGui )
  1460. {
  1461. BecomeActive( TH_THINK );
  1462. }
  1463. }
  1464. /*
  1465. ================
  1466. idStaticEntity::ShowEditingDialog
  1467. ================
  1468. */
  1469. void idStaticEntity::ShowEditingDialog()
  1470. {
  1471. }
  1472. /*
  1473. ================
  1474. idStaticEntity::Think
  1475. ================
  1476. */
  1477. void idStaticEntity::Think()
  1478. {
  1479. idEntity::Think();
  1480. if( thinkFlags & TH_THINK )
  1481. {
  1482. if( runGui && renderEntity.gui[0] )
  1483. {
  1484. idPlayer* player = gameLocal.GetLocalPlayer();
  1485. if( player )
  1486. {
  1487. if( !player->objectiveSystemOpen )
  1488. {
  1489. renderEntity.gui[0]->StateChanged( gameLocal.time, true );
  1490. if( renderEntity.gui[1] )
  1491. {
  1492. renderEntity.gui[1]->StateChanged( gameLocal.time, true );
  1493. }
  1494. if( renderEntity.gui[2] )
  1495. {
  1496. renderEntity.gui[2]->StateChanged( gameLocal.time, true );
  1497. }
  1498. }
  1499. }
  1500. }
  1501. if( fadeEnd > 0 )
  1502. {
  1503. idVec4 color;
  1504. if( gameLocal.time < fadeEnd )
  1505. {
  1506. color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) );
  1507. }
  1508. else
  1509. {
  1510. color = fadeTo;
  1511. fadeEnd = 0;
  1512. BecomeInactive( TH_THINK );
  1513. }
  1514. SetColor( color );
  1515. }
  1516. }
  1517. }
  1518. /*
  1519. ================
  1520. idStaticEntity::Fade
  1521. ================
  1522. */
  1523. void idStaticEntity::Fade( const idVec4& to, float fadeTime )
  1524. {
  1525. GetColor( fadeFrom );
  1526. fadeTo = to;
  1527. fadeStart = gameLocal.time;
  1528. fadeEnd = gameLocal.time + SEC2MS( fadeTime );
  1529. BecomeActive( TH_THINK );
  1530. }
  1531. /*
  1532. ================
  1533. idStaticEntity::Hide
  1534. ================
  1535. */
  1536. void idStaticEntity::Hide()
  1537. {
  1538. idEntity::Hide();
  1539. GetPhysics()->SetContents( 0 );
  1540. }
  1541. /*
  1542. ================
  1543. idStaticEntity::Show
  1544. ================
  1545. */
  1546. void idStaticEntity::Show()
  1547. {
  1548. idEntity::Show();
  1549. if( spawnArgs.GetBool( "solid" ) )
  1550. {
  1551. GetPhysics()->SetContents( CONTENTS_SOLID );
  1552. }
  1553. }
  1554. /*
  1555. ================
  1556. idStaticEntity::Event_Activate
  1557. ================
  1558. */
  1559. void idStaticEntity::Event_Activate( idEntity* activator )
  1560. {
  1561. idStr activateGui;
  1562. spawnTime = gameLocal.time;
  1563. active = !active;
  1564. const idKeyValue* kv = spawnArgs.FindKey( "hide" );
  1565. if( kv )
  1566. {
  1567. if( IsHidden() )
  1568. {
  1569. Show();
  1570. }
  1571. else
  1572. {
  1573. Hide();
  1574. }
  1575. }
  1576. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( spawnTime );
  1577. renderEntity.shaderParms[5] = active;
  1578. // this change should be a good thing, it will automatically turn on
  1579. // lights etc.. when triggered so that does not have to be specifically done
  1580. // with trigger parms.. it MIGHT break things so need to keep an eye on it
  1581. renderEntity.shaderParms[ SHADERPARM_MODE ] = ( renderEntity.shaderParms[ SHADERPARM_MODE ] ) ? 0.0f : 1.0f;
  1582. BecomeActive( TH_UPDATEVISUALS );
  1583. }
  1584. /*
  1585. ================
  1586. idStaticEntity::WriteToSnapshot
  1587. ================
  1588. */
  1589. void idStaticEntity::WriteToSnapshot( idBitMsg& msg ) const
  1590. {
  1591. GetPhysics()->WriteToSnapshot( msg );
  1592. WriteBindToSnapshot( msg );
  1593. WriteColorToSnapshot( msg );
  1594. WriteGUIToSnapshot( msg );
  1595. msg.WriteBits( IsHidden() ? 1 : 0, 1 );
  1596. }
  1597. /*
  1598. ================
  1599. idStaticEntity::ReadFromSnapshot
  1600. ================
  1601. */
  1602. void idStaticEntity::ReadFromSnapshot( const idBitMsg& msg )
  1603. {
  1604. bool hidden;
  1605. GetPhysics()->ReadFromSnapshot( msg );
  1606. ReadBindFromSnapshot( msg );
  1607. ReadColorFromSnapshot( msg );
  1608. ReadGUIFromSnapshot( msg );
  1609. hidden = msg.ReadBits( 1 ) == 1;
  1610. if( hidden != IsHidden() )
  1611. {
  1612. if( hidden )
  1613. {
  1614. Hide();
  1615. }
  1616. else
  1617. {
  1618. Show();
  1619. }
  1620. }
  1621. if( msg.HasChanged() )
  1622. {
  1623. UpdateVisuals();
  1624. }
  1625. }
  1626. /*
  1627. ===============================================================================
  1628. idFuncEmitter
  1629. ===============================================================================
  1630. */
  1631. CLASS_DECLARATION( idStaticEntity, idFuncEmitter )
  1632. EVENT( EV_Activate, idFuncEmitter::Event_Activate )
  1633. END_CLASS
  1634. /*
  1635. ===============
  1636. idFuncEmitter::idFuncEmitter
  1637. ===============
  1638. */
  1639. idFuncEmitter::idFuncEmitter()
  1640. {
  1641. hidden = false;
  1642. }
  1643. /*
  1644. ===============
  1645. idFuncEmitter::Spawn
  1646. ===============
  1647. */
  1648. void idFuncEmitter::Spawn()
  1649. {
  1650. if( spawnArgs.GetBool( "start_off" ) )
  1651. {
  1652. hidden = true;
  1653. renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( 1 );
  1654. UpdateVisuals();
  1655. }
  1656. else
  1657. {
  1658. hidden = false;
  1659. }
  1660. }
  1661. /*
  1662. ===============
  1663. idFuncEmitter::Save
  1664. ===============
  1665. */
  1666. void idFuncEmitter::Save( idSaveGame* savefile ) const
  1667. {
  1668. savefile->WriteBool( hidden );
  1669. }
  1670. /*
  1671. ===============
  1672. idFuncEmitter::Restore
  1673. ===============
  1674. */
  1675. void idFuncEmitter::Restore( idRestoreGame* savefile )
  1676. {
  1677. savefile->ReadBool( hidden );
  1678. }
  1679. /*
  1680. ================
  1681. idFuncEmitter::Event_Activate
  1682. ================
  1683. */
  1684. void idFuncEmitter::Event_Activate( idEntity* activator )
  1685. {
  1686. if( hidden || spawnArgs.GetBool( "cycleTrigger" ) )
  1687. {
  1688. renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = 0;
  1689. renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
  1690. hidden = false;
  1691. }
  1692. else
  1693. {
  1694. renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( gameLocal.time );
  1695. hidden = true;
  1696. }
  1697. UpdateVisuals();
  1698. }
  1699. /*
  1700. ================
  1701. idFuncEmitter::WriteToSnapshot
  1702. ================
  1703. */
  1704. void idFuncEmitter::WriteToSnapshot( idBitMsg& msg ) const
  1705. {
  1706. msg.WriteBits( hidden ? 1 : 0, 1 );
  1707. msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] );
  1708. msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] );
  1709. }
  1710. /*
  1711. ================
  1712. idFuncEmitter::ReadFromSnapshot
  1713. ================
  1714. */
  1715. void idFuncEmitter::ReadFromSnapshot( const idBitMsg& msg )
  1716. {
  1717. hidden = msg.ReadBits( 1 ) != 0;
  1718. renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] = msg.ReadFloat();
  1719. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = msg.ReadFloat();
  1720. if( msg.HasChanged() )
  1721. {
  1722. UpdateVisuals();
  1723. }
  1724. }
  1725. /*
  1726. ===============================================================================
  1727. idFuncShootProjectile
  1728. ===============================================================================
  1729. */
  1730. CLASS_DECLARATION( idStaticEntity, idFuncShootProjectile )
  1731. EVENT( EV_Activate, idFuncShootProjectile::Event_Activate )
  1732. END_CLASS
  1733. /*
  1734. ===============
  1735. idFuncShootProjectile::idFuncShootProjectile
  1736. ===============
  1737. */
  1738. idFuncShootProjectile::idFuncShootProjectile()
  1739. {
  1740. mRespawnDelay = 1000;
  1741. mRespawnTime = 0;
  1742. mShootSpeed = 1000;
  1743. mShootDir = idVec3( 0.0f, 0.0f, 1.0f );
  1744. }
  1745. /*
  1746. ===============
  1747. idFuncShootProjectile::Spawn
  1748. ===============
  1749. */
  1750. void idFuncShootProjectile::Spawn()
  1751. {
  1752. }
  1753. /*
  1754. ===============
  1755. idFuncShootProjectile::Think
  1756. ===============
  1757. */
  1758. void idFuncShootProjectile::Think()
  1759. {
  1760. if( thinkFlags & TH_THINK )
  1761. {
  1762. // time to spawn a new projectile?
  1763. if( mRespawnTime > 0 && mRespawnTime <= gameLocal.GetTime() )
  1764. {
  1765. const idDict* dict = gameLocal.FindEntityDefDict( mEntityDefName );
  1766. idEntity* ent = NULL;
  1767. gameLocal.SpawnEntityDef( *dict, &ent );
  1768. if( ent != NULL )
  1769. {
  1770. idProjectile* proj = static_cast<idProjectile*>( ent );
  1771. idVec3 pushVel = mShootDir * mShootSpeed;
  1772. proj->Create( this, GetPhysics()->GetOrigin(), mShootDir );
  1773. proj->Launch( GetPhysics()->GetOrigin(), mShootDir, pushVel );
  1774. if( mShootSpeed == 0.0f )
  1775. {
  1776. proj->GetPhysics()->SetLinearVelocity( vec3_zero );
  1777. }
  1778. else
  1779. {
  1780. proj->GetPhysics()->SetLinearVelocity( pushVel );
  1781. }
  1782. mLastProjectile = proj;
  1783. }
  1784. if( mShootSpeed == 0.0f )
  1785. {
  1786. mRespawnTime = 0; // stationary, respawn when triggered
  1787. }
  1788. else
  1789. {
  1790. mRespawnTime = gameLocal.GetTime() + mRespawnDelay; // moving, respawn after delay
  1791. }
  1792. }
  1793. }
  1794. }
  1795. /*
  1796. ===============
  1797. idFuncShootProjectile::Save
  1798. ===============
  1799. */
  1800. void idFuncShootProjectile::Save( idSaveGame* savefile ) const
  1801. {
  1802. savefile->WriteInt( mRespawnDelay );
  1803. savefile->WriteInt( mRespawnTime );
  1804. savefile->WriteFloat( mShootSpeed );
  1805. savefile->WriteVec3( mShootDir );
  1806. savefile->WriteString( mEntityDefName );
  1807. }
  1808. /*
  1809. ===============
  1810. idFuncShootProjectile::Restore
  1811. ===============
  1812. */
  1813. void idFuncShootProjectile::Restore( idRestoreGame* savefile )
  1814. {
  1815. savefile->ReadInt( mRespawnDelay );
  1816. savefile->ReadInt( mRespawnTime );
  1817. savefile->ReadFloat( mShootSpeed );
  1818. savefile->ReadVec3( mShootDir );
  1819. savefile->ReadString( mEntityDefName );
  1820. }
  1821. /*
  1822. ================
  1823. idFuncShootProjectile::Event_Activate
  1824. ================
  1825. */
  1826. void idFuncShootProjectile::Event_Activate( idEntity* activator )
  1827. {
  1828. if( ( thinkFlags & TH_THINK ) != 0 )
  1829. {
  1830. if( mShootSpeed == 0.0f && mRespawnTime == 0 )
  1831. {
  1832. mRespawnTime = gameLocal.GetTime();
  1833. return;
  1834. }
  1835. }
  1836. mRespawnDelay = spawnArgs.GetInt( "spawn_delay_ms" );
  1837. mShootSpeed = spawnArgs.GetFloat( "speed" );
  1838. mEntityDefName = spawnArgs.GetString( "def_projectile" );
  1839. if( targets.Num() > 0 && targets[0].IsValid() )
  1840. {
  1841. mShootDir = targets[0]->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  1842. mShootDir.Normalize();
  1843. }
  1844. else
  1845. {
  1846. // stationary projectile, doesn't move and only respawns when triggered
  1847. mShootSpeed = 0.0f;
  1848. mRespawnTime = 0;
  1849. }
  1850. if( ( thinkFlags & TH_THINK ) != 0 )
  1851. {
  1852. // currently active, deactivate
  1853. BecomeInactive( TH_THINK );
  1854. }
  1855. else
  1856. {
  1857. // currently inactive, activate
  1858. BecomeActive( TH_THINK );
  1859. mRespawnTime = gameLocal.GetTime();
  1860. }
  1861. }
  1862. /*
  1863. ================
  1864. idFuncShootProjectile::WriteToSnapshot
  1865. ================
  1866. */
  1867. void idFuncShootProjectile::WriteToSnapshot( idBitMsg& msg ) const
  1868. {
  1869. // msg.WriteBits( hidden ? 1 : 0, 1 );
  1870. // msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] );
  1871. // msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] );
  1872. }
  1873. /*
  1874. ================
  1875. idFuncShootProjectile::ReadFromSnapshot
  1876. ================
  1877. */
  1878. void idFuncShootProjectile::ReadFromSnapshot( const idBitMsg& msg )
  1879. {
  1880. // hidden = msg.ReadBits( 1 ) != 0;
  1881. // renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] = msg.ReadFloat();
  1882. // renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = msg.ReadFloat();
  1883. // if ( msg.HasChanged() ) {
  1884. // UpdateVisuals();
  1885. // }
  1886. }
  1887. /*
  1888. ===============================================================================
  1889. idFuncSplat
  1890. ===============================================================================
  1891. */
  1892. const idEventDef EV_Splat( "<Splat>" );
  1893. CLASS_DECLARATION( idFuncEmitter, idFuncSplat )
  1894. EVENT( EV_Activate, idFuncSplat::Event_Activate )
  1895. EVENT( EV_Splat, idFuncSplat::Event_Splat )
  1896. END_CLASS
  1897. /*
  1898. ===============
  1899. idFuncSplat::idFuncSplat
  1900. ===============
  1901. */
  1902. idFuncSplat::idFuncSplat()
  1903. {
  1904. }
  1905. /*
  1906. ===============
  1907. idFuncSplat::Spawn
  1908. ===============
  1909. */
  1910. void idFuncSplat::Spawn()
  1911. {
  1912. }
  1913. /*
  1914. ================
  1915. idFuncSplat::Event_Splat
  1916. ================
  1917. */
  1918. void idFuncSplat::Event_Splat()
  1919. {
  1920. const char* splat = NULL;
  1921. int count = spawnArgs.GetInt( "splatCount", "1" );
  1922. for( int i = 0; i < count; i++ )
  1923. {
  1924. splat = spawnArgs.RandomPrefix( "mtr_splat", gameLocal.random );
  1925. if( splat != NULL && *splat != '\0' )
  1926. {
  1927. float size = spawnArgs.GetFloat( "splatSize", "128" );
  1928. float dist = spawnArgs.GetFloat( "splatDistance", "128" );
  1929. float angle = spawnArgs.GetFloat( "splatAngle", "0" );
  1930. gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[2], dist, true, size, splat, angle );
  1931. }
  1932. }
  1933. StartSound( "snd_splat", SND_CHANNEL_ANY, 0, false, NULL );
  1934. }
  1935. /*
  1936. ================
  1937. idFuncSplat::Event_Activate
  1938. ================
  1939. */
  1940. void idFuncSplat::Event_Activate( idEntity* activator )
  1941. {
  1942. idFuncEmitter::Event_Activate( activator );
  1943. PostEventSec( &EV_Splat, spawnArgs.GetFloat( "splatDelay", "0.25" ) );
  1944. StartSound( "snd_spurt", SND_CHANNEL_ANY, 0, false, NULL );
  1945. }
  1946. /*
  1947. ===============================================================================
  1948. idFuncSmoke
  1949. ===============================================================================
  1950. */
  1951. CLASS_DECLARATION( idEntity, idFuncSmoke )
  1952. EVENT( EV_Activate, idFuncSmoke::Event_Activate )
  1953. END_CLASS
  1954. /*
  1955. ===============
  1956. idFuncSmoke::idFuncSmoke
  1957. ===============
  1958. */
  1959. idFuncSmoke::idFuncSmoke()
  1960. {
  1961. smokeTime = 0;
  1962. smoke = NULL;
  1963. restart = false;
  1964. }
  1965. /*
  1966. ===============
  1967. idFuncSmoke::Save
  1968. ===============
  1969. */
  1970. void idFuncSmoke::Save( idSaveGame* savefile ) const
  1971. {
  1972. savefile->WriteInt( smokeTime );
  1973. savefile->WriteParticle( smoke );
  1974. savefile->WriteBool( restart );
  1975. }
  1976. /*
  1977. ===============
  1978. idFuncSmoke::Restore
  1979. ===============
  1980. */
  1981. void idFuncSmoke::Restore( idRestoreGame* savefile )
  1982. {
  1983. savefile->ReadInt( smokeTime );
  1984. savefile->ReadParticle( smoke );
  1985. savefile->ReadBool( restart );
  1986. }
  1987. /*
  1988. ===============
  1989. idFuncSmoke::Spawn
  1990. ===============
  1991. */
  1992. void idFuncSmoke::Spawn()
  1993. {
  1994. const char* smokeName = spawnArgs.GetString( "smoke" );
  1995. if( *smokeName != '\0' )
  1996. {
  1997. smoke = static_cast<const idDeclParticle*>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1998. }
  1999. else
  2000. {
  2001. smoke = NULL;
  2002. }
  2003. if( spawnAr

Large files files are truncated, but you can click here to view the full file