PageRenderTime 69ms CodeModel.GetById 23ms 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
  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( spawnArgs.GetBool( "start_off" ) )
  2004. {
  2005. smokeTime = 0;
  2006. restart = false;
  2007. }
  2008. else if( smoke )
  2009. {
  2010. smokeTime = gameLocal.time;
  2011. BecomeActive( TH_UPDATEPARTICLES );
  2012. restart = true;
  2013. }
  2014. GetPhysics()->SetContents( 0 );
  2015. }
  2016. /*
  2017. ================
  2018. idFuncSmoke::Event_Activate
  2019. ================
  2020. */
  2021. void idFuncSmoke::Event_Activate( idEntity* activator )
  2022. {
  2023. if( thinkFlags & TH_UPDATEPARTICLES )
  2024. {
  2025. restart = false;
  2026. return;
  2027. }
  2028. else
  2029. {
  2030. BecomeActive( TH_UPDATEPARTICLES );
  2031. restart = true;
  2032. smokeTime = gameLocal.time;
  2033. }
  2034. }
  2035. /*
  2036. ===============
  2037. idFuncSmoke::Think
  2038. ================
  2039. */
  2040. void idFuncSmoke::Think()
  2041. {
  2042. // if we are completely closed off from the player, don't do anything at all
  2043. if( CheckDormant() || smoke == NULL || smokeTime == -1 )
  2044. {
  2045. return;
  2046. }
  2047. if( ( thinkFlags & TH_UPDATEPARTICLES ) && !IsHidden() )
  2048. {
  2049. if( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) )
  2050. {
  2051. if( restart )
  2052. {
  2053. smokeTime = gameLocal.time;
  2054. }
  2055. else
  2056. {
  2057. smokeTime = 0;
  2058. BecomeInactive( TH_UPDATEPARTICLES );
  2059. }
  2060. }
  2061. }
  2062. }
  2063. /*
  2064. ===============================================================================
  2065. idTextEntity
  2066. ===============================================================================
  2067. */
  2068. CLASS_DECLARATION( idEntity, idTextEntity )
  2069. END_CLASS
  2070. /*
  2071. ================
  2072. idTextEntity::Spawn
  2073. ================
  2074. */
  2075. void idTextEntity::Spawn()
  2076. {
  2077. // these are cached as the are used each frame
  2078. text = spawnArgs.GetString( "text" );
  2079. playerOriented = spawnArgs.GetBool( "playerOriented" );
  2080. bool force = spawnArgs.GetBool( "force" );
  2081. if( developer.GetBool() || force )
  2082. {
  2083. BecomeActive( TH_THINK );
  2084. }
  2085. }
  2086. /*
  2087. ================
  2088. idTextEntity::Save
  2089. ================
  2090. */
  2091. void idTextEntity::Save( idSaveGame* savefile ) const
  2092. {
  2093. savefile->WriteString( text );
  2094. savefile->WriteBool( playerOriented );
  2095. }
  2096. /*
  2097. ================
  2098. idTextEntity::Restore
  2099. ================
  2100. */
  2101. void idTextEntity::Restore( idRestoreGame* savefile )
  2102. {
  2103. savefile->ReadString( text );
  2104. savefile->ReadBool( playerOriented );
  2105. }
  2106. /*
  2107. ================
  2108. idTextEntity::Think
  2109. ================
  2110. */
  2111. void idTextEntity::Think()
  2112. {
  2113. if( thinkFlags & TH_THINK )
  2114. {
  2115. gameRenderWorld->DrawText( text, GetPhysics()->GetOrigin(), 0.25, colorWhite, playerOriented ? gameLocal.GetLocalPlayer()->viewAngles.ToMat3() : GetPhysics()->GetAxis().Transpose(), 1 );
  2116. for( int i = 0; i < targets.Num(); i++ )
  2117. {
  2118. if( targets[i].GetEntity() )
  2119. {
  2120. gameRenderWorld->DebugArrow( colorBlue, GetPhysics()->GetOrigin(), targets[i].GetEntity()->GetPhysics()->GetOrigin(), 1 );
  2121. }
  2122. }
  2123. }
  2124. else
  2125. {
  2126. BecomeInactive( TH_ALL );
  2127. }
  2128. }
  2129. /*
  2130. ===============================================================================
  2131. idVacuumSeperatorEntity
  2132. Can be triggered to let vacuum through a portal (blown out window)
  2133. ===============================================================================
  2134. */
  2135. CLASS_DECLARATION( idEntity, idVacuumSeparatorEntity )
  2136. EVENT( EV_Activate, idVacuumSeparatorEntity::Event_Activate )
  2137. END_CLASS
  2138. /*
  2139. ================
  2140. idVacuumSeparatorEntity::idVacuumSeparatorEntity
  2141. ================
  2142. */
  2143. idVacuumSeparatorEntity::idVacuumSeparatorEntity()
  2144. {
  2145. portal = 0;
  2146. }
  2147. /*
  2148. ================
  2149. idVacuumSeparatorEntity::Save
  2150. ================
  2151. */
  2152. void idVacuumSeparatorEntity::Save( idSaveGame* savefile ) const
  2153. {
  2154. savefile->WriteInt( ( int )portal );
  2155. savefile->WriteInt( gameRenderWorld->GetPortalState( portal ) );
  2156. }
  2157. /*
  2158. ================
  2159. idVacuumSeparatorEntity::Restore
  2160. ================
  2161. */
  2162. void idVacuumSeparatorEntity::Restore( idRestoreGame* savefile )
  2163. {
  2164. int state;
  2165. savefile->ReadInt( ( int& )portal );
  2166. savefile->ReadInt( state );
  2167. gameLocal.SetPortalState( portal, state );
  2168. }
  2169. /*
  2170. ================
  2171. idVacuumSeparatorEntity::Spawn
  2172. ================
  2173. */
  2174. void idVacuumSeparatorEntity::Spawn()
  2175. {
  2176. idBounds b;
  2177. b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 );
  2178. portal = gameRenderWorld->FindPortal( b );
  2179. if( !portal )
  2180. {
  2181. gameLocal.Warning( "VacuumSeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) );
  2182. return;
  2183. }
  2184. gameLocal.SetPortalState( portal, PS_BLOCK_AIR | PS_BLOCK_LOCATION );
  2185. }
  2186. /*
  2187. ================
  2188. idVacuumSeparatorEntity::Event_Activate
  2189. ================
  2190. */
  2191. void idVacuumSeparatorEntity::Event_Activate( idEntity* activator )
  2192. {
  2193. if( !portal )
  2194. {
  2195. return;
  2196. }
  2197. gameLocal.SetPortalState( portal, PS_BLOCK_NONE );
  2198. }
  2199. /*
  2200. ===============================================================================
  2201. idLocationSeparatorEntity
  2202. ===============================================================================
  2203. */
  2204. CLASS_DECLARATION( idEntity, idLocationSeparatorEntity )
  2205. END_CLASS
  2206. /*
  2207. ================
  2208. idLocationSeparatorEntity::Spawn
  2209. ================
  2210. */
  2211. void idLocationSeparatorEntity::Spawn()
  2212. {
  2213. idBounds b;
  2214. b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 );
  2215. qhandle_t portal = gameRenderWorld->FindPortal( b );
  2216. if( !portal )
  2217. {
  2218. gameLocal.Warning( "LocationSeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) );
  2219. }
  2220. gameLocal.SetPortalState( portal, PS_BLOCK_LOCATION );
  2221. }
  2222. /*
  2223. ===============================================================================
  2224. idVacuumEntity
  2225. Levels should only have a single vacuum entity.
  2226. ===============================================================================
  2227. */
  2228. CLASS_DECLARATION( idEntity, idVacuumEntity )
  2229. END_CLASS
  2230. /*
  2231. ================
  2232. idVacuumEntity::Spawn
  2233. ================
  2234. */
  2235. void idVacuumEntity::Spawn()
  2236. {
  2237. if( gameLocal.vacuumAreaNum != -1 )
  2238. {
  2239. gameLocal.Warning( "idVacuumEntity::Spawn: multiple idVacuumEntity in level" );
  2240. return;
  2241. }
  2242. idVec3 org = spawnArgs.GetVector( "origin" );
  2243. gameLocal.vacuumAreaNum = gameRenderWorld->PointInArea( org );
  2244. }
  2245. /*
  2246. ===============================================================================
  2247. idLocationEntity
  2248. ===============================================================================
  2249. */
  2250. CLASS_DECLARATION( idEntity, idLocationEntity )
  2251. END_CLASS
  2252. /*
  2253. ======================
  2254. idLocationEntity::Spawn
  2255. ======================
  2256. */
  2257. void idLocationEntity::Spawn()
  2258. {
  2259. idStr realName;
  2260. // this just holds dict information
  2261. // if "location" not already set, use the entity name.
  2262. if( !spawnArgs.GetString( "location", "", realName ) )
  2263. {
  2264. spawnArgs.Set( "location", name );
  2265. }
  2266. }
  2267. /*
  2268. ======================
  2269. idLocationEntity::GetLocation
  2270. ======================
  2271. */
  2272. const char* idLocationEntity::GetLocation() const
  2273. {
  2274. return spawnArgs.GetString( "location" );
  2275. }
  2276. /*
  2277. ===============================================================================
  2278. idBeam
  2279. ===============================================================================
  2280. */
  2281. CLASS_DECLARATION( idEntity, idBeam )
  2282. EVENT( EV_PostSpawn, idBeam::Event_MatchTarget )
  2283. EVENT( EV_Activate, idBeam::Event_Activate )
  2284. END_CLASS
  2285. /*
  2286. ===============
  2287. idBeam::idBeam
  2288. ===============
  2289. */
  2290. idBeam::idBeam()
  2291. {
  2292. target = NULL;
  2293. master = NULL;
  2294. }
  2295. /*
  2296. ===============
  2297. idBeam::Save
  2298. ===============
  2299. */
  2300. void idBeam::Save( idSaveGame* savefile ) const
  2301. {
  2302. target.Save( savefile );
  2303. master.Save( savefile );
  2304. }
  2305. /*
  2306. ===============
  2307. idBeam::Restore
  2308. ===============
  2309. */
  2310. void idBeam::Restore( idRestoreGame* savefile )
  2311. {
  2312. target.Restore( savefile );
  2313. master.Restore( savefile );
  2314. }
  2315. /*
  2316. ===============
  2317. idBeam::Spawn
  2318. ===============
  2319. */
  2320. void idBeam::Spawn()
  2321. {
  2322. float width;
  2323. if( spawnArgs.GetFloat( "width", "0", width ) )
  2324. {
  2325. renderEntity.shaderParms[ SHADERPARM_BEAM_WIDTH ] = width;
  2326. }
  2327. SetModel( "_BEAM" );
  2328. Hide();
  2329. PostEventMS( &EV_PostSpawn, 0 );
  2330. }
  2331. /*
  2332. ================
  2333. idBeam::Think
  2334. ================
  2335. */
  2336. void idBeam::Think()
  2337. {
  2338. idBeam* masterEnt;
  2339. if( !IsHidden() && !target.GetEntity() )
  2340. {
  2341. // hide if our target is removed
  2342. Hide();
  2343. }
  2344. RunPhysics();
  2345. masterEnt = master.GetEntity();
  2346. if( masterEnt )
  2347. {
  2348. const idVec3& origin = GetPhysics()->GetOrigin();
  2349. masterEnt->SetBeamTarget( origin );
  2350. }
  2351. Present();
  2352. }
  2353. /*
  2354. ================
  2355. idBeam::SetMaster
  2356. ================
  2357. */
  2358. void idBeam::SetMaster( idBeam* masterbeam )
  2359. {
  2360. master = masterbeam;
  2361. }
  2362. /*
  2363. ================
  2364. idBeam::SetBeamTarget
  2365. ================
  2366. */
  2367. void idBeam::SetBeamTarget( const idVec3& origin )
  2368. {
  2369. if( ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] != origin.x ) || ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] != origin.y ) || ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] != origin.z ) )
  2370. {
  2371. renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] = origin.x;
  2372. renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] = origin.y;
  2373. renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] = origin.z;
  2374. UpdateVisuals();
  2375. }
  2376. }
  2377. /*
  2378. ================
  2379. idBeam::Show
  2380. ================
  2381. */
  2382. void idBeam::Show()
  2383. {
  2384. idBeam* targetEnt;
  2385. idEntity::Show();
  2386. targetEnt = target.GetEntity();
  2387. if( targetEnt )
  2388. {
  2389. const idVec3& origin = targetEnt->GetPhysics()->GetOrigin();
  2390. SetBeamTarget( origin );
  2391. }
  2392. }
  2393. /*
  2394. ================
  2395. idBeam::Event_MatchTarget
  2396. ================
  2397. */
  2398. void idBeam::Event_MatchTarget()
  2399. {
  2400. int i;
  2401. idEntity* targetEnt;
  2402. idBeam* targetBeam;
  2403. if( !targets.Num() )
  2404. {
  2405. return;
  2406. }
  2407. targetBeam = NULL;
  2408. for( i = 0; i < targets.Num(); i++ )
  2409. {
  2410. targetEnt = targets[ i ].GetEntity();
  2411. if( targetEnt != NULL && targetEnt->IsType( idBeam::Type ) )
  2412. {
  2413. targetBeam = static_cast<idBeam*>( targetEnt );
  2414. break;
  2415. }
  2416. }
  2417. if( targetBeam == NULL )
  2418. {
  2419. gameLocal.Error( "Could not find valid beam target for '%s'", name.c_str() );
  2420. return;
  2421. }
  2422. target = targetBeam;
  2423. targetBeam->SetMaster( this );
  2424. if( !spawnArgs.GetBool( "start_off" ) )
  2425. {
  2426. Show();
  2427. }
  2428. }
  2429. /*
  2430. ================
  2431. idBeam::Event_Activate
  2432. ================
  2433. */
  2434. void idBeam::Event_Activate( idEntity* activator )
  2435. {
  2436. if( IsHidden() )
  2437. {
  2438. Show();
  2439. }
  2440. else
  2441. {
  2442. Hide();
  2443. }
  2444. }
  2445. /*
  2446. ================
  2447. idBeam::WriteToSnapshot
  2448. ================
  2449. */
  2450. void idBeam::WriteToSnapshot( idBitMsg& msg ) const
  2451. {
  2452. GetPhysics()->WriteToSnapshot( msg );
  2453. WriteBindToSnapshot( msg );
  2454. WriteColorToSnapshot( msg );
  2455. msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_X] );
  2456. msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_Y] );
  2457. msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_Z] );
  2458. }
  2459. /*
  2460. ================
  2461. idBeam::ReadFromSnapshot
  2462. ================
  2463. */
  2464. void idBeam::ReadFromSnapshot( const idBitMsg& msg )
  2465. {
  2466. GetPhysics()->ReadFromSnapshot( msg );
  2467. ReadBindFromSnapshot( msg );
  2468. ReadColorFromSnapshot( msg );
  2469. renderEntity.shaderParms[SHADERPARM_BEAM_END_X] = msg.ReadFloat();
  2470. renderEntity.shaderParms[SHADERPARM_BEAM_END_Y] = msg.ReadFloat();
  2471. renderEntity.shaderParms[SHADERPARM_BEAM_END_Z] = msg.ReadFloat();
  2472. if( msg.HasChanged() )
  2473. {
  2474. UpdateVisuals();
  2475. }
  2476. }
  2477. /*
  2478. ===============================================================================
  2479. idLiquid
  2480. ===============================================================================
  2481. */
  2482. CLASS_DECLARATION( idEntity, idLiquid )
  2483. EVENT( EV_Touch, idLiquid::Event_Touch )
  2484. END_CLASS
  2485. /*
  2486. ================
  2487. idLiquid::Save
  2488. ================
  2489. */
  2490. void idLiquid::Save( idSaveGame* savefile ) const
  2491. {
  2492. // Nothing to save
  2493. }
  2494. /*
  2495. ================
  2496. idLiquid::Restore
  2497. ================
  2498. */
  2499. void idLiquid::Restore( idRestoreGame* savefile )
  2500. {
  2501. //FIXME: NO!
  2502. Spawn();
  2503. }
  2504. /*
  2505. ================
  2506. idLiquid::Spawn
  2507. ================
  2508. */
  2509. void idLiquid::Spawn()
  2510. {
  2511. /*
  2512. model = dynamic_cast<idRenderModelLiquid *>( renderEntity.hModel );
  2513. if ( !model ) {
  2514. gameLocal.Error( "Entity '%s' must have liquid model", name.c_str() );
  2515. }
  2516. model->Reset();
  2517. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  2518. */
  2519. }
  2520. /*
  2521. ================
  2522. idLiquid::Event_Touch
  2523. ================
  2524. */
  2525. void idLiquid::Event_Touch( idEntity* other, trace_t* trace )
  2526. {
  2527. // FIXME: for QuakeCon
  2528. /*
  2529. if ( common->IsClient() ) {
  2530. return;
  2531. }
  2532. idVec3 pos;
  2533. pos = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  2534. model->IntersectBounds( other->GetPhysics()->GetBounds().Translate( pos ), -10.0f );
  2535. */
  2536. }
  2537. /*
  2538. ===============================================================================
  2539. idShaking
  2540. ===============================================================================
  2541. */
  2542. CLASS_DECLARATION( idEntity, idShaking )
  2543. EVENT( EV_Activate, idShaking::Event_Activate )
  2544. END_CLASS
  2545. /*
  2546. ===============
  2547. idShaking::idShaking
  2548. ===============
  2549. */
  2550. idShaking::idShaking()
  2551. {
  2552. active = false;
  2553. }
  2554. /*
  2555. ===============
  2556. idShaking::Save
  2557. ===============
  2558. */
  2559. void idShaking::Save( idSaveGame* savefile ) const
  2560. {
  2561. savefile->WriteBool( active );
  2562. savefile->WriteStaticObject( physicsObj );
  2563. }
  2564. /*
  2565. ===============
  2566. idShaking::Restore
  2567. ===============
  2568. */
  2569. void idShaking::Restore( idRestoreGame* savefile )
  2570. {
  2571. savefile->ReadBool( active );
  2572. savefile->ReadStaticObject( physicsObj );
  2573. RestorePhysics( &physicsObj );
  2574. }
  2575. /*
  2576. ===============
  2577. idShaking::Spawn
  2578. ===============
  2579. */
  2580. void idShaking::Spawn()
  2581. {
  2582. physicsObj.SetSelf( this );
  2583. physicsObj.SetClipModel( new( TAG_PHYSICS_CLIP_ENTITY ) idClipModel( GetPhysics()->GetClipModel() ), 1.0f );
  2584. physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
  2585. physicsObj.SetAxis( GetPhysics()->GetAxis() );
  2586. physicsObj.SetClipMask( MASK_SOLID );
  2587. SetPhysics( &physicsObj );
  2588. active = false;
  2589. if( !spawnArgs.GetBool( "start_off" ) )
  2590. {
  2591. BeginShaking();
  2592. }
  2593. }
  2594. /*
  2595. ================
  2596. idShaking::BeginShaking
  2597. ================
  2598. */
  2599. void idShaking::BeginShaking()
  2600. {
  2601. int phase;
  2602. idAngles shake;
  2603. int period;
  2604. active = true;
  2605. phase = gameLocal.random.RandomInt( 1000 );
  2606. shake = spawnArgs.GetAngles( "shake", "0.5 0.5 0.5" );
  2607. period = spawnArgs.GetFloat( "period", "0.05" ) * 1000;
  2608. physicsObj.SetAngularExtrapolation( extrapolation_t( EXTRAPOLATION_DECELSINE | EXTRAPOLATION_NOSTOP ), phase, period * 0.25f, GetPhysics()->GetAxis().ToAngles(), shake, ang_zero );
  2609. }
  2610. /*
  2611. ================
  2612. idShaking::Event_Activate
  2613. ================
  2614. */
  2615. void idShaking::Event_Activate( idEntity* activator )
  2616. {
  2617. if( !active )
  2618. {
  2619. BeginShaking();
  2620. }
  2621. else
  2622. {
  2623. active = false;
  2624. physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, physicsObj.GetAxis().ToAngles(), ang_zero, ang_zero );
  2625. }
  2626. }
  2627. /*
  2628. ===============================================================================
  2629. idEarthQuake
  2630. ===============================================================================
  2631. */
  2632. CLASS_DECLARATION( idEntity, idEarthQuake )
  2633. EVENT( EV_Activate, idEarthQuake::Event_Activate )
  2634. END_CLASS
  2635. /*
  2636. ===============
  2637. idEarthQuake::idEarthQuake
  2638. ===============
  2639. */
  2640. idEarthQuake::idEarthQuake()
  2641. {
  2642. wait = 0.0f;
  2643. random = 0.0f;
  2644. nextTriggerTime = 0;
  2645. shakeStopTime = 0;
  2646. triggered = false;
  2647. playerOriented = false;
  2648. disabled = false;
  2649. shakeTime = 0.0f;
  2650. }
  2651. /*
  2652. ===============
  2653. idEarthQuake::Save
  2654. ===============
  2655. */
  2656. void idEarthQuake::Save( idSaveGame* savefile ) const
  2657. {
  2658. savefile->WriteInt( nextTriggerTime );
  2659. savefile->WriteInt( shakeStopTime );
  2660. savefile->WriteFloat( wait );
  2661. savefile->WriteFloat( random );
  2662. savefile->WriteBool( triggered );
  2663. savefile->WriteBool( playerOriented );
  2664. savefile->WriteBool( disabled );
  2665. savefile->WriteFloat( shakeTime );
  2666. }
  2667. /*
  2668. ===============
  2669. idEarthQuake::Restore
  2670. ===============
  2671. */
  2672. void idEarthQuake::Restore( idRestoreGame* savefile )
  2673. {
  2674. savefile->ReadInt( nextTriggerTime );
  2675. savefile->ReadInt( shakeStopTime );
  2676. savefile->ReadFloat( wait );
  2677. savefile->ReadFloat( random );
  2678. savefile->ReadBool( triggered );
  2679. savefile->ReadBool( playerOriented );
  2680. savefile->ReadBool( disabled );
  2681. savefile->ReadFloat( shakeTime );
  2682. if( shakeStopTime > gameLocal.time )
  2683. {
  2684. BecomeActive( TH_THINK );
  2685. }
  2686. }
  2687. /*
  2688. ===============
  2689. idEarthQuake::Spawn
  2690. ===============
  2691. */
  2692. void idEarthQuake::Spawn()
  2693. {
  2694. nextTriggerTime = 0;
  2695. shakeStopTime = 0;
  2696. wait = spawnArgs.GetFloat( "wait", "15" );
  2697. random = spawnArgs.GetFloat( "random", "5" );
  2698. triggered = spawnArgs.GetBool( "triggered" );
  2699. playerOriented = spawnArgs.GetBool( "playerOriented" );
  2700. disabled = false;
  2701. shakeTime = spawnArgs.GetFloat( "shakeTime", "0" );
  2702. if( !triggered )
  2703. {
  2704. PostEventSec( &EV_Activate, spawnArgs.GetFloat( "wait" ), this );
  2705. }
  2706. BecomeInactive( TH_THINK );
  2707. }
  2708. /*
  2709. ================
  2710. idEarthQuake::Event_Activate
  2711. ================
  2712. */
  2713. void idEarthQuake::Event_Activate( idEntity* activator )
  2714. {
  2715. if( nextTriggerTime > gameLocal.time )
  2716. {
  2717. return;
  2718. }
  2719. if( disabled && activator == this )
  2720. {
  2721. return;
  2722. }
  2723. idPlayer* player = gameLocal.GetLocalPlayer();
  2724. if( player == NULL )
  2725. {
  2726. return;
  2727. }
  2728. nextTriggerTime = 0;
  2729. if( !triggered && activator != this )
  2730. {
  2731. // if we are not triggered ( i.e. random ), disable or enable
  2732. disabled ^= 1;
  2733. if( disabled )
  2734. {
  2735. return;
  2736. }
  2737. else
  2738. {
  2739. PostEventSec( &EV_Activate, wait + random * gameLocal.random.CRandomFloat(), this );
  2740. }
  2741. }
  2742. ActivateTargets( activator );
  2743. const idSoundShader* shader = declManager->FindSound( spawnArgs.GetString( "snd_quake" ) );
  2744. if( playerOriented )
  2745. {
  2746. player->StartSoundShader( shader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
  2747. }
  2748. else
  2749. {
  2750. StartSoundShader( shader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
  2751. }
  2752. if( shakeTime > 0.0f )
  2753. {
  2754. shakeStopTime = gameLocal.time + SEC2MS( shakeTime );
  2755. BecomeActive( TH_THINK );
  2756. }
  2757. if( wait > 0.0f )
  2758. {
  2759. if( !triggered )
  2760. {
  2761. PostEventSec( &EV_Activate, wait + random * gameLocal.random.CRandomFloat(), this );
  2762. }
  2763. else
  2764. {
  2765. nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() );
  2766. }
  2767. }
  2768. else if( shakeTime == 0.0f )
  2769. {
  2770. PostEventMS( &EV_Remove, 0 );
  2771. }
  2772. }
  2773. /*
  2774. ===============
  2775. idEarthQuake::Think
  2776. ================
  2777. */
  2778. void idEarthQuake::Think()
  2779. {
  2780. if( thinkFlags & TH_THINK )
  2781. {
  2782. if( gameLocal.time > shakeStopTime )
  2783. {
  2784. BecomeInactive( TH_THINK );
  2785. if( wait <= 0.0f )
  2786. {
  2787. PostEventMS( &EV_Remove, 0 );
  2788. }
  2789. return;
  2790. }
  2791. float shakeVolume = gameSoundWorld->CurrentShakeAmplitude();
  2792. gameLocal.RadiusPush( GetPhysics()->GetOrigin(), 256, 1500 * shakeVolume, this, this, 1.0f, true );
  2793. }
  2794. BecomeInactive( TH_UPDATEVISUALS );
  2795. }
  2796. /*
  2797. ===============================================================================
  2798. idFuncPortal
  2799. ===============================================================================
  2800. */
  2801. CLASS_DECLARATION( idEntity, idFuncPortal )
  2802. EVENT( EV_Activate, idFuncPortal::Event_Activate )
  2803. END_CLASS
  2804. /*
  2805. ===============
  2806. idFuncPortal::idFuncPortal
  2807. ===============
  2808. */
  2809. idFuncPortal::idFuncPortal()
  2810. {
  2811. portal = 0;
  2812. state = false;
  2813. }
  2814. /*
  2815. ===============
  2816. idFuncPortal::Save
  2817. ===============
  2818. */
  2819. void idFuncPortal::Save( idSaveGame* savefile ) const
  2820. {
  2821. savefile->WriteInt( ( int )portal );
  2822. savefile->WriteBool( state );
  2823. }
  2824. /*
  2825. ===============
  2826. idFuncPortal::Restore
  2827. ===============
  2828. */
  2829. void idFuncPortal::Restore( idRestoreGame* savefile )
  2830. {
  2831. savefile->ReadInt( ( int& )portal );
  2832. savefile->ReadBool( state );
  2833. gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  2834. }
  2835. /*
  2836. ===============
  2837. idFuncPortal::Spawn
  2838. ===============
  2839. */
  2840. void idFuncPortal::Spawn()
  2841. {
  2842. portal = gameRenderWorld->FindPortal( GetPhysics()->GetAbsBounds().Expand( 32.0f ) );
  2843. if( portal > 0 )
  2844. {
  2845. state = spawnArgs.GetBool( "start_on" );
  2846. gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  2847. }
  2848. }
  2849. /*
  2850. ================
  2851. idFuncPortal::Event_Activate
  2852. ================
  2853. */
  2854. void idFuncPortal::Event_Activate( idEntity* activator )
  2855. {
  2856. if( portal > 0 )
  2857. {
  2858. state = !state;
  2859. gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  2860. }
  2861. }
  2862. /*
  2863. ===============================================================================
  2864. idFuncAASPortal
  2865. ===============================================================================
  2866. */
  2867. CLASS_DECLARATION( idEntity, idFuncAASPortal )
  2868. EVENT( EV_Activate, idFuncAASPortal::Event_Activate )
  2869. END_CLASS
  2870. /*
  2871. ===============
  2872. idFuncAASPortal::idFuncAASPortal
  2873. ===============
  2874. */
  2875. idFuncAASPortal::idFuncAASPortal()
  2876. {
  2877. state = false;
  2878. }
  2879. /*
  2880. ===============
  2881. idFuncAASPortal::Save
  2882. ===============
  2883. */
  2884. void idFuncAASPortal::Save( idSaveGame* savefile ) const
  2885. {
  2886. savefile->WriteBool( state );
  2887. }
  2888. /*
  2889. ===============
  2890. idFuncAASPortal::Restore
  2891. ===============
  2892. */
  2893. void idFuncAASPortal::Restore( idRestoreGame* savefile )
  2894. {
  2895. savefile->ReadBool( state );
  2896. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  2897. }
  2898. /*
  2899. ===============
  2900. idFuncAASPortal::Spawn
  2901. ===============
  2902. */
  2903. void idFuncAASPortal::Spawn()
  2904. {
  2905. state = spawnArgs.GetBool( "start_on" );
  2906. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  2907. }
  2908. /*
  2909. ================
  2910. idFuncAASPortal::Event_Activate
  2911. ================
  2912. */
  2913. void idFuncAASPortal::Event_Activate( idEntity* activator )
  2914. {
  2915. state ^= 1;
  2916. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  2917. }
  2918. /*
  2919. ===============================================================================
  2920. idFuncAASObstacle
  2921. ===============================================================================
  2922. */
  2923. CLASS_DECLARATION( idEntity, idFuncAASObstacle )
  2924. EVENT( EV_Activate, idFuncAASObstacle::Event_Activate )
  2925. END_CLASS
  2926. /*
  2927. ===============
  2928. idFuncAASObstacle::idFuncAASObstacle
  2929. ===============
  2930. */
  2931. idFuncAASObstacle::idFuncAASObstacle()
  2932. {
  2933. state = false;
  2934. }
  2935. /*
  2936. ===============
  2937. idFuncAASObstacle::Save
  2938. ===============
  2939. */
  2940. void idFuncAASObstacle::Save( idSaveGame* savefile ) const
  2941. {
  2942. savefile->WriteBool( state );
  2943. }
  2944. /*
  2945. ===============
  2946. idFuncAASObstacle::Restore
  2947. ===============
  2948. */
  2949. void idFuncAASObstacle::Restore( idRestoreGame* savefile )
  2950. {
  2951. savefile->ReadBool( state );
  2952. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  2953. }
  2954. /*
  2955. ===============
  2956. idFuncAASObstacle::Spawn
  2957. ===============
  2958. */
  2959. void idFuncAASObstacle::Spawn()
  2960. {
  2961. state = spawnArgs.GetBool( "start_on" );
  2962. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  2963. }
  2964. /*
  2965. ================
  2966. idFuncAASObstacle::Event_Activate
  2967. ================
  2968. */
  2969. void idFuncAASObstacle::Event_Activate( idEntity* activator )
  2970. {
  2971. state ^= 1;
  2972. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  2973. }
  2974. /*
  2975. ===============================================================================
  2976. idFuncRadioChatter
  2977. ===============================================================================
  2978. */
  2979. const idEventDef EV_ResetRadioHud( "<resetradiohud>", "e" );
  2980. CLASS_DECLARATION( idEntity, idFuncRadioChatter )
  2981. EVENT( EV_Activate, idFuncRadioChatter::Event_Activate )
  2982. EVENT( EV_ResetRadioHud, idFuncRadioChatter::Event_ResetRadioHud )
  2983. END_CLASS
  2984. /*
  2985. ===============
  2986. idFuncRadioChatter::idFuncRadioChatter
  2987. ===============
  2988. */
  2989. idFuncRadioChatter::idFuncRadioChatter()
  2990. {
  2991. time = 0.0;
  2992. }
  2993. /*
  2994. ===============
  2995. idFuncRadioChatter::Save
  2996. ===============
  2997. */
  2998. void idFuncRadioChatter::Save( idSaveGame* savefile ) const
  2999. {
  3000. savefile->WriteFloat( time );
  3001. }
  3002. /*
  3003. ===============
  3004. idFuncRadioChatter::Restore
  3005. ===============
  3006. */
  3007. void idFuncRadioChatter::Restore( idRestoreGame* savefile )
  3008. {
  3009. savefile->ReadFloat( time );
  3010. }
  3011. /*
  3012. ===============
  3013. idFuncRadioChatter::Spawn
  3014. ===============
  3015. */
  3016. void idFuncRadioChatter::Spawn()
  3017. {
  3018. time = spawnArgs.GetFloat( "time", "5.0" );
  3019. }
  3020. /*
  3021. ================
  3022. idFuncRadioChatter::Event_Activate
  3023. ================
  3024. */
  3025. void idFuncRadioChatter::Event_Activate( idEntity* activator )
  3026. {
  3027. idPlayer* player = gameLocal.GetLocalPlayer();
  3028. if( player != NULL && player->hudManager )
  3029. {
  3030. player->hudManager->SetRadioMessage( true );
  3031. }
  3032. const char* sound = spawnArgs.GetString( "snd_radiochatter", "" );
  3033. if( sound != NULL && *sound != '\0' )
  3034. {
  3035. const idSoundShader* shader = declManager->FindSound( sound );
  3036. int length = 0;
  3037. player->StartSoundShader( shader, SND_CHANNEL_RADIO, SSF_GLOBAL, false, &length );
  3038. time = MS2SEC( length + 150 );
  3039. }
  3040. // we still put the hud up because this is used with no sound on
  3041. // certain frame commands when the chatter is triggered
  3042. PostEventSec( &EV_ResetRadioHud, time, player );
  3043. }
  3044. /*
  3045. ================
  3046. idFuncRadioChatter::Event_ResetRadioHud
  3047. ================
  3048. */
  3049. void idFuncRadioChatter::Event_ResetRadioHud( idEntity* activator )
  3050. {
  3051. idPlayer* player = ( activator->IsType( idPlayer::Type ) ) ? static_cast<idPlayer*>( activator ) : gameLocal.GetLocalPlayer();
  3052. if( player != NULL && player->hudManager )
  3053. {
  3054. player->hudManager->SetRadioMessage( false );
  3055. }
  3056. ActivateTargets( activator );
  3057. }
  3058. /*
  3059. ===============================================================================
  3060. idPhantomObjects
  3061. ===============================================================================
  3062. */
  3063. CLASS_DECLARATION( idEntity, idPhantomObjects )
  3064. EVENT( EV_Activate, idPhantomObjects::Event_Activate )
  3065. END_CLASS
  3066. /*
  3067. ===============
  3068. idPhantomObjects::idPhantomObjects
  3069. ===============
  3070. */
  3071. idPhantomObjects::idPhantomObjects()
  3072. {
  3073. target = NULL;
  3074. end_time = 0;
  3075. throw_time = 0.0f;
  3076. shake_time = 0.0f;
  3077. shake_ang.Zero();
  3078. speed = 0.0f;
  3079. min_wait = 0;
  3080. max_wait = 0;
  3081. fl.neverDormant = false;
  3082. }
  3083. /*
  3084. ===============
  3085. idPhantomObjects::Save
  3086. ===============
  3087. */
  3088. void idPhantomObjects::Save( idSaveGame* savefile ) const
  3089. {
  3090. int i;
  3091. savefile->WriteInt( end_time );
  3092. savefile->WriteFloat( throw_time );
  3093. savefile->WriteFloat( shake_time );
  3094. savefile->WriteVec3( shake_ang );
  3095. savefile->WriteFloat( speed );
  3096. savefile->WriteInt( min_wait );
  3097. savefile->WriteInt( max_wait );
  3098. target.Save( savefile );
  3099. savefile->WriteInt( targetTime.Num() );
  3100. for( i = 0; i < targetTime.Num(); i++ )
  3101. {
  3102. savefile->WriteInt( targetTime[ i ] );
  3103. }
  3104. for( i = 0; i < lastTargetPos.Num(); i++ )
  3105. {
  3106. savefile->WriteVec3( lastTargetPos[ i ] );
  3107. }
  3108. }
  3109. /*
  3110. ===============
  3111. idPhantomObjects::Restore
  3112. ===============
  3113. */
  3114. void idPhantomObjects::Restore( idRestoreGame* savefile )
  3115. {
  3116. int num;
  3117. int i;
  3118. savefile->ReadInt( end_time );
  3119. savefile->ReadFloat( throw_time );
  3120. savefile->ReadFloat( shake_time );
  3121. savefile->ReadVec3( shake_ang );
  3122. savefile->ReadFloat( speed );
  3123. savefile->ReadInt( min_wait );
  3124. savefile->ReadInt( max_wait );
  3125. target.Restore( savefile );
  3126. savefile->ReadInt( num );
  3127. targetTime.SetGranularity( 1 );
  3128. targetTime.SetNum( num );
  3129. lastTargetPos.SetGranularity( 1 );
  3130. lastTargetPos.SetNum( num );
  3131. for( i = 0; i < num; i++ )
  3132. {
  3133. savefile->ReadInt( targetTime[ i ] );
  3134. }
  3135. for( i = 0; i < num; i++ )
  3136. {
  3137. savefile->ReadVec3( lastTargetPos[ i ] );
  3138. }
  3139. }
  3140. /*
  3141. ===============
  3142. idPhantomObjects::Spawn
  3143. ===============
  3144. */
  3145. void idPhantomObjects::Spawn()
  3146. {
  3147. throw_time = spawnArgs.GetFloat( "time", "5" );
  3148. speed = spawnArgs.GetFloat( "speed", "1200" );
  3149. shake_time = spawnArgs.GetFloat( "shake_time", "1" );
  3150. throw_time -= shake_time;
  3151. if( throw_time < 0.0f )
  3152. {
  3153. throw_time = 0.0f;
  3154. }
  3155. min_wait = SEC2MS( spawnArgs.GetFloat( "min_wait", "1" ) );
  3156. max_wait = SEC2MS( spawnArgs.GetFloat( "max_wait", "3" ) );
  3157. shake_ang = spawnArgs.GetVector( "shake_ang", "65 65 65" );
  3158. Hide();
  3159. GetPhysics()->SetContents( 0 );
  3160. }
  3161. /*
  3162. ================
  3163. idPhantomObjects::Event_Activate
  3164. ================
  3165. */
  3166. void idPhantomObjects::Event_Activate( idEntity* activator )
  3167. {
  3168. int i;
  3169. float time;
  3170. float frac;
  3171. float scale;
  3172. if( thinkFlags & TH_THINK )
  3173. {
  3174. BecomeInactive( TH_THINK );
  3175. return;
  3176. }
  3177. RemoveNullTargets();
  3178. if( !targets.Num() )
  3179. {
  3180. return;
  3181. }
  3182. if( !activator || !activator->IsType( idActor::Type ) )
  3183. {
  3184. target = gameLocal.GetLocalPlayer();
  3185. }
  3186. else
  3187. {
  3188. target = static_cast<idActor*>( activator );
  3189. }
  3190. end_time = gameLocal.time + SEC2MS( spawnArgs.GetFloat( "end_time", "0" ) );
  3191. targetTime.SetNum( targets.Num() );
  3192. lastTargetPos.SetNum( targets.Num() );
  3193. const idVec3& toPos = target.GetEntity()->GetEyePosition();
  3194. // calculate the relative times of all the objects
  3195. time = 0.0f;
  3196. for( i = 0; i < targetTime.Num(); i++ )
  3197. {
  3198. targetTime[ i ] = SEC2MS( time );
  3199. lastTargetPos[ i ] = toPos;
  3200. frac = 1.0f - ( float )i / ( float )targetTime.Num();
  3201. time += ( gameLocal.random.RandomFloat() + 1.0f ) * 0.5f * frac + 0.1f;
  3202. }
  3203. // scale up the times to fit within throw_time
  3204. scale = throw_time / time;
  3205. for( i = 0; i < targetTime.Num(); i++ )
  3206. {
  3207. targetTime[ i ] = gameLocal.time + SEC2MS( shake_time ) + targetTime[ i ] * scale;
  3208. }
  3209. BecomeActive( TH_THINK );
  3210. }
  3211. /*
  3212. ===============
  3213. idPhantomObjects::Think
  3214. ================
  3215. */
  3216. void idPhantomObjects::Think()
  3217. {
  3218. int i;
  3219. int num;
  3220. float time;
  3221. idVec3 vel;
  3222. idVec3 ang;
  3223. idEntity* ent;
  3224. idActor* targetEnt;
  3225. idPhysics* entPhys;
  3226. trace_t tr;
  3227. // if we are completely closed off from the player, don't do anything at all
  3228. if( CheckDormant() )
  3229. {
  3230. return;
  3231. }
  3232. if( !( thinkFlags & TH_THINK ) )
  3233. {
  3234. BecomeInactive( thinkFlags & ~TH_THINK );
  3235. return;
  3236. }
  3237. targetEnt = target.GetEntity();
  3238. if( targetEnt == NULL || ( targetEnt->health <= 0 ) || ( end_time && ( gameLocal.time > end_time ) ) || gameLocal.inCinematic )
  3239. {
  3240. BecomeInactive( TH_THINK );
  3241. return;
  3242. }
  3243. const idVec3& toPos = targetEnt->GetEyePosition();
  3244. num = 0;
  3245. for( i = 0; i < targets.Num(); i++ )
  3246. {
  3247. ent = targets[ i ].GetEntity();
  3248. if( !ent )
  3249. {
  3250. continue;
  3251. }
  3252. if( ent->fl.hidden )
  3253. {
  3254. // don't throw hidden objects
  3255. continue;
  3256. }
  3257. if( !targetTime[ i ] )
  3258. {
  3259. // already threw this object
  3260. continue;
  3261. }
  3262. num++;
  3263. time = MS2SEC( targetTime[ i ] - gameLocal.time );
  3264. if( time > shake_time )
  3265. {
  3266. continue;
  3267. }
  3268. entPhys = ent->GetPhysics();
  3269. const idVec3& entOrg = entPhys->GetOrigin();
  3270. gameLocal.clip.TracePoint( tr, entOrg, toPos, MASK_OPAQUE, ent );
  3271. if( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == targetEnt ) )
  3272. {
  3273. lastTargetPos[ i ] = toPos;
  3274. }
  3275. if( time < 0.0f )
  3276. {
  3277. idAI::PredictTrajectory( entPhys->GetOrigin(), lastTargetPos[ i ], speed, entPhys->GetGravity(),
  3278. entPhys->GetClipModel(), entPhys->GetClipMask(), 256.0f, ent, targetEnt, ai_debugTrajectory.GetBool() ? 1 : 0, vel );
  3279. vel *= speed;
  3280. entPhys->SetLinearVelocity( vel );
  3281. if( !end_time )
  3282. {
  3283. targetTime[ i ] = 0;
  3284. }
  3285. else
  3286. {
  3287. targetTime[ i ] = gameLocal.time + gameLocal.random.RandomInt( max_wait - min_wait ) + min_wait;
  3288. }
  3289. if( ent->IsType( idMoveable::Type ) )
  3290. {
  3291. idMoveable* ment = static_cast<idMoveable*>( ent );
  3292. ment->EnableDamage( true, 2.5f );
  3293. }
  3294. }
  3295. else
  3296. {
  3297. // this is not the right way to set the angular velocity, but the effect is nice, so I'm keeping it. :)
  3298. ang.Set( gameLocal.random.CRandomFloat() * shake_ang.x, gameLocal.random.CRandomFloat() * shake_ang.y, gameLocal.random.CRandomFloat() * shake_ang.z );
  3299. ang *= ( 1.0f - time / shake_time );
  3300. entPhys->SetAngularVelocity( ang );
  3301. }
  3302. }
  3303. if( !num )
  3304. {
  3305. BecomeInactive( TH_THINK );
  3306. }
  3307. }
  3308. /*
  3309. ===============================================================================
  3310. idShockwave
  3311. ===============================================================================
  3312. */
  3313. CLASS_DECLARATION( idEntity, idShockwave )
  3314. EVENT( EV_Activate, idShockwave::Event_Activate )
  3315. END_CLASS
  3316. /*
  3317. ===============
  3318. idShockwave::idShockwave
  3319. ===============
  3320. */
  3321. idShockwave::idShockwave()
  3322. {
  3323. isActive = false;
  3324. startTime = 0;
  3325. duration = 0;
  3326. startSize = 0.f;
  3327. endSize = 0.f;
  3328. currentSize = 0.f;
  3329. magnitude = 0.f;
  3330. height = 0.0f;
  3331. playerDamaged = false;
  3332. playerDamageSize = 0.0f;
  3333. }
  3334. /*
  3335. ===============
  3336. idShockwave::~idShockwave
  3337. ===============
  3338. */
  3339. idShockwave::~idShockwave()
  3340. {
  3341. }
  3342. /*
  3343. ===============
  3344. idShockwave::Save
  3345. ===============
  3346. */
  3347. void idShockwave::Save( idSaveGame* savefile ) const
  3348. {
  3349. savefile->WriteBool( isActive );
  3350. savefile->WriteInt( startTime );
  3351. savefile->WriteInt( duration );
  3352. savefile->WriteFloat( startSize );
  3353. savefile->WriteFloat( endSize );
  3354. savefile->WriteFloat( currentSize );
  3355. savefile->WriteFloat( magnitude );
  3356. savefile->WriteFloat( height );
  3357. savefile->WriteBool( playerDamaged );
  3358. savefile->WriteFloat( playerDamageSize );
  3359. }
  3360. /*
  3361. ===============
  3362. idShockwave::Restore
  3363. ===============
  3364. */
  3365. void idShockwave::Restore( idRestoreGame* savefile )
  3366. {
  3367. savefile->ReadBool( isActive );
  3368. savefile->ReadInt( startTime );
  3369. savefile->ReadInt( duration );
  3370. savefile->ReadFloat( startSize );
  3371. savefile->ReadFloat( endSize );
  3372. savefile->ReadFloat( currentSize );
  3373. savefile->ReadFloat( magnitude );
  3374. savefile->ReadFloat( height );
  3375. savefile->ReadBool( playerDamaged );
  3376. savefile->ReadFloat( playerDamageSize );
  3377. }
  3378. /*
  3379. ===============
  3380. idShockwave::Spawn
  3381. ===============
  3382. */
  3383. void idShockwave::Spawn()
  3384. {
  3385. spawnArgs.GetInt( "duration", "1000", duration );
  3386. spawnArgs.GetFloat( "startsize", "8", startSize );
  3387. spawnArgs.GetFloat( "endsize", "512", endSize );
  3388. spawnArgs.GetFloat( "magnitude", "100", magnitude );
  3389. spawnArgs.GetFloat( "height", "0", height );
  3390. spawnArgs.GetFloat( "player_damage_size", "20", playerDamageSize );
  3391. if( spawnArgs.GetBool( "start_on" ) )
  3392. {
  3393. ProcessEvent( &EV_Activate, this );
  3394. }
  3395. }
  3396. /*
  3397. ===============
  3398. idShockwave::Think
  3399. ===============
  3400. */
  3401. void idShockwave::Think()
  3402. {
  3403. int endTime;
  3404. if( !isActive )
  3405. {
  3406. BecomeInactive( TH_THINK );
  3407. return;
  3408. }
  3409. endTime = startTime + duration;
  3410. if( gameLocal.time < endTime )
  3411. {
  3412. float u;
  3413. float newSize;
  3414. // Expand shockwave
  3415. u = ( float )( gameLocal.time - startTime ) / ( float )duration;
  3416. newSize = startSize + u * ( endSize - startSize );
  3417. // Find all clipmodels between currentSize and newSize
  3418. idVec3 pos, end;
  3419. idClipModel* clipModelList[ MAX_GENTITIES ];
  3420. idClipModel* clip;
  3421. idEntity* ent;
  3422. int i, listedClipModels;
  3423. // Set bounds
  3424. pos = GetPhysics()->GetOrigin();
  3425. float zVal;
  3426. if( !height )
  3427. {
  3428. zVal = newSize;
  3429. }
  3430. else
  3431. {
  3432. zVal = height / 2.0f;
  3433. }
  3434. //Expand in a sphere
  3435. end = pos + idVec3( newSize, newSize, zVal );
  3436. idBounds bounds( end );
  3437. end = pos + idVec3( -newSize, -newSize, -zVal );
  3438. bounds.AddPoint( end );
  3439. if( g_debugShockwave.GetBool() )
  3440. {
  3441. gameRenderWorld->DebugBounds( colorRed, bounds, vec3_origin );
  3442. }
  3443. listedClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
  3444. for( i = 0; i < listedClipModels; i++ )
  3445. {
  3446. clip = clipModelList[ i ];
  3447. ent = clip->GetEntity();
  3448. if( ent->IsHidden() )
  3449. {
  3450. continue;
  3451. }
  3452. if( !ent->IsType( idMoveable::Type ) && !ent->IsType( idAFEntity_Base::Type ) && !ent->IsType( idPlayer::Type ) )
  3453. {
  3454. continue;
  3455. }
  3456. idVec3 point = ent->GetPhysics()->GetOrigin();
  3457. idVec3 force = point - pos;
  3458. float dist = force.Normalize();
  3459. if( ent->IsType( idPlayer::Type ) )
  3460. {
  3461. if( ent->GetPhysics()->GetAbsBounds().IntersectsBounds( bounds ) )
  3462. {
  3463. //For player damage we check the current radius and a specified player damage ring size
  3464. if( dist <= newSize && dist > newSize - playerDamageSize )
  3465. {
  3466. idStr damageDef = spawnArgs.GetString( "def_player_damage", "" );
  3467. if( damageDef.Length() > 0 && !playerDamaged )
  3468. {
  3469. playerDamaged = true; //Only damage once per shockwave
  3470. idPlayer* player = static_cast< idPlayer* >( ent );
  3471. idVec3 dir = ent->GetPhysics()->GetOrigin() - pos;
  3472. dir.NormalizeFast();
  3473. player->Damage( NULL, NULL, dir, damageDef, 1.0f, INVALID_JOINT );
  3474. }
  3475. }
  3476. }
  3477. }
  3478. else
  3479. {
  3480. // If the object is inside the current expansion...
  3481. if( dist <= newSize && dist > currentSize )
  3482. {
  3483. force.z += 4.f;
  3484. force.NormalizeFast();
  3485. if( ent->IsType( idAFEntity_Base::Type ) )
  3486. {
  3487. force = force * ( ent->GetPhysics()->GetMass() * magnitude * 0.01f );
  3488. }
  3489. else
  3490. {
  3491. force = force * ent->GetPhysics()->GetMass() * magnitude;
  3492. }
  3493. // Kick it up, move force point off object origin
  3494. float rad = ent->GetPhysics()->GetBounds().GetRadius();
  3495. point.x += gameLocal.random.CRandomFloat() * rad;
  3496. point.y += gameLocal.random.CRandomFloat() * rad;
  3497. int j;
  3498. for( j = 0; j < ent->GetPhysics()->GetNumClipModels(); j++ )
  3499. {
  3500. ent->GetPhysics()->AddForce( j, point, force );
  3501. }
  3502. }
  3503. }
  3504. }
  3505. // Update currentSize for next frame
  3506. currentSize = newSize;
  3507. }
  3508. else
  3509. {
  3510. // turn off
  3511. isActive = false;
  3512. }
  3513. }
  3514. /*
  3515. ===============
  3516. idShockwave::Event_Activate
  3517. ===============
  3518. */
  3519. void idShockwave::Event_Activate( idEntity* activator )
  3520. {
  3521. isActive = true;
  3522. startTime = gameLocal.time;
  3523. playerDamaged = false;
  3524. BecomeActive( TH_THINK );
  3525. }
  3526. /*
  3527. ===============================================================================
  3528. idFuncMountedObject
  3529. ===============================================================================
  3530. */
  3531. CLASS_DECLARATION( idEntity, idFuncMountedObject )
  3532. EVENT( EV_Touch, idFuncMountedObject::Event_Touch )
  3533. EVENT( EV_Activate, idFuncMountedObject::Event_Activate )
  3534. END_CLASS
  3535. /*
  3536. ===============
  3537. idFuncMountedObject::idFuncMountedObject
  3538. ===============
  3539. */
  3540. idFuncMountedObject::idFuncMountedObject()
  3541. {
  3542. isMounted = false;
  3543. scriptFunction = NULL;
  3544. mountedPlayer = NULL;
  3545. harc = 0;
  3546. varc = 0;
  3547. }
  3548. /*
  3549. ===============
  3550. idFuncMountedObject::idFuncMountedObject
  3551. ===============
  3552. */
  3553. idFuncMountedObject::~idFuncMountedObject()
  3554. {
  3555. }
  3556. /*
  3557. ===============
  3558. idFuncMountedObject::Spawn
  3559. ===============
  3560. */
  3561. void idFuncMountedObject::Spawn()
  3562. {
  3563. // Get viewOffset
  3564. spawnArgs.GetInt( "harc", "45", harc );
  3565. spawnArgs.GetInt( "varc", "30", varc );
  3566. // Get script function
  3567. idStr funcName = spawnArgs.GetString( "call", "" );
  3568. if( funcName.Length() )
  3569. {
  3570. scriptFunction = gameLocal.program.FindFunction( funcName );
  3571. if( scriptFunction == NULL )
  3572. {
  3573. gameLocal.Warning( "idFuncMountedObject '%s' at (%s) calls unknown function '%s'\n", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ), funcName.c_str() );
  3574. }
  3575. }
  3576. BecomeActive( TH_THINK );
  3577. }
  3578. /*
  3579. ================
  3580. idFuncMountedObject::Think
  3581. ================
  3582. */
  3583. void idFuncMountedObject::Think()
  3584. {
  3585. idEntity::Think();
  3586. }
  3587. /*
  3588. ================
  3589. idFuncMountedObject::GetViewInfo
  3590. ================
  3591. */
  3592. void idFuncMountedObject::GetAngleRestrictions( int& yaw_min, int& yaw_max, int& pitch )
  3593. {
  3594. idMat3 axis;
  3595. idAngles angs;
  3596. axis = GetPhysics()->GetAxis();
  3597. angs = axis.ToAngles();
  3598. yaw_min = angs.yaw - harc;
  3599. yaw_min = idMath::AngleNormalize180( yaw_min );
  3600. yaw_max = angs.yaw + harc;
  3601. yaw_max = idMath::AngleNormalize180( yaw_max );
  3602. pitch = varc;
  3603. }
  3604. /*
  3605. ================
  3606. idFuncMountedObject::Event_Touch
  3607. ================
  3608. */
  3609. void idFuncMountedObject::Event_Touch( idEntity* other, trace_t* trace )
  3610. {
  3611. if( common->IsClient() )
  3612. {
  3613. return;
  3614. }
  3615. ProcessEvent( &EV_Activate, other );
  3616. }
  3617. /*
  3618. ================
  3619. idFuncMountedObject::Event_Activate
  3620. ================
  3621. */
  3622. void idFuncMountedObject::Event_Activate( idEntity* activator )
  3623. {
  3624. if( !isMounted && activator->IsType( idPlayer::Type ) )
  3625. {
  3626. idPlayer* client = ( idPlayer* )activator;
  3627. mountedPlayer = client;
  3628. /*
  3629. // Place player at path_corner targeted by mounted object
  3630. int i;
  3631. idPathCorner *spot;
  3632. for ( i = 0; i < targets.Num(); i++ ) {
  3633. if ( targets[i]->IsType( idPathCorner::Type ) ) {
  3634. spot = (idPathCorner*)targets[i];
  3635. break;
  3636. }
  3637. }
  3638. mountedPlayer->GetPhysics()->SetOrigin( spot->GetPhysics()->GetOrigin() );
  3639. mountedPlayer->GetPhysics()->SetAxis( spot->GetPhysics()->GetAxis() );
  3640. */
  3641. mountedPlayer->Bind( this, true );
  3642. mountedPlayer->mountedObject = this;
  3643. // Call a script function
  3644. idThread* mountthread;
  3645. if( scriptFunction )
  3646. {
  3647. mountthread = new idThread( scriptFunction );
  3648. mountthread->DelayedStart( 0 );
  3649. }
  3650. isMounted = true;
  3651. }
  3652. }
  3653. /*
  3654. ===============================================================================
  3655. idFuncMountedWeapon
  3656. ===============================================================================
  3657. */
  3658. CLASS_DECLARATION( idFuncMountedObject, idFuncMountedWeapon )
  3659. EVENT( EV_PostSpawn, idFuncMountedWeapon::Event_PostSpawn )
  3660. END_CLASS
  3661. idFuncMountedWeapon::idFuncMountedWeapon()
  3662. {
  3663. turret = NULL;
  3664. weaponLastFireTime = 0;
  3665. weaponFireDelay = 0;
  3666. projectile = NULL;
  3667. }
  3668. idFuncMountedWeapon::~idFuncMountedWeapon()
  3669. {
  3670. }
  3671. void idFuncMountedWeapon::Spawn()
  3672. {
  3673. // Get projectile info
  3674. projectile = gameLocal.FindEntityDefDict( spawnArgs.GetString( "def_projectile" ), false );
  3675. if( !projectile )
  3676. {
  3677. gameLocal.Warning( "Invalid projectile on func_mountedweapon." );
  3678. }
  3679. float firerate;
  3680. spawnArgs.GetFloat( "firerate", "3", firerate );
  3681. weaponFireDelay = 1000.f / firerate;
  3682. // Get the firing sound
  3683. idStr fireSound;
  3684. spawnArgs.GetString( "snd_fire", "", fireSound );
  3685. soundFireWeapon = declManager->FindSound( fireSound );
  3686. PostEventMS( &EV_PostSpawn, 0 );
  3687. }
  3688. void idFuncMountedWeapon::Think()
  3689. {
  3690. if( isMounted && turret )
  3691. {
  3692. idVec3 vec = mountedPlayer->viewAngles.ToForward();
  3693. idAngles ang = mountedPlayer->GetLocalVector( vec ).ToAngles();
  3694. turret->GetPhysics()->SetAxis( ang.ToMat3() );
  3695. turret->UpdateVisuals();
  3696. // Check for firing
  3697. if( mountedPlayer->usercmd.buttons & BUTTON_ATTACK && ( gameLocal.time > weaponLastFireTime + weaponFireDelay ) )
  3698. {
  3699. // FIRE!
  3700. idEntity* ent;
  3701. idProjectile* proj;
  3702. idBounds projBounds;
  3703. idVec3 dir;
  3704. gameLocal.SpawnEntityDef( *projectile, &ent );
  3705. if( !ent || !ent->IsType( idProjectile::Type ) )
  3706. {
  3707. const char* projectileName = spawnArgs.GetString( "def_projectile" );
  3708. gameLocal.Error( "'%s' is not an idProjectile", projectileName );
  3709. }
  3710. mountedPlayer->GetViewPos( muzzleOrigin, muzzleAxis );
  3711. muzzleOrigin += ( muzzleAxis[0] * 128 );
  3712. muzzleOrigin -= ( muzzleAxis[2] * 20 );
  3713. dir = muzzleAxis[0];
  3714. proj = static_cast<idProjectile*>( ent );
  3715. proj->Create( this, muzzleOrigin, dir );
  3716. projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() );
  3717. proj->Launch( muzzleOrigin, dir, vec3_origin );
  3718. StartSoundShader( soundFireWeapon, SND_CHANNEL_WEAPON, SSF_GLOBAL, false, NULL );
  3719. weaponLastFireTime = gameLocal.time;
  3720. }
  3721. }
  3722. idFuncMountedObject::Think();
  3723. }
  3724. void idFuncMountedWeapon::Event_PostSpawn()
  3725. {
  3726. if( targets.Num() >= 1 )
  3727. {
  3728. for( int i = 0; i < targets.Num(); i++ )
  3729. {
  3730. if( targets[i].GetEntity()->IsType( idStaticEntity::Type ) )
  3731. {
  3732. turret = targets[i].GetEntity();
  3733. break;
  3734. }
  3735. }
  3736. }
  3737. else
  3738. {
  3739. gameLocal.Warning( "idFuncMountedWeapon::Spawn: Please target one model for a turret\n" );
  3740. }
  3741. }
  3742. /*
  3743. ===============================================================================
  3744. idPortalSky
  3745. ===============================================================================
  3746. */
  3747. CLASS_DECLARATION( idEntity, idPortalSky )
  3748. EVENT( EV_PostSpawn, idPortalSky::Event_PostSpawn )
  3749. EVENT( EV_Activate, idPortalSky::Event_Activate )
  3750. END_CLASS
  3751. /*
  3752. ===============
  3753. idPortalSky::idPortalSky
  3754. ===============
  3755. */
  3756. idPortalSky::idPortalSky()
  3757. {
  3758. }
  3759. /*
  3760. ===============
  3761. idPortalSky::~idPortalSky
  3762. ===============
  3763. */
  3764. idPortalSky::~idPortalSky()
  3765. {
  3766. }
  3767. /*
  3768. ===============
  3769. idPortalSky::Spawn
  3770. ===============
  3771. */
  3772. void idPortalSky::Spawn()
  3773. {
  3774. if( !spawnArgs.GetBool( "triggered" ) )
  3775. {
  3776. PostEventMS( &EV_PostSpawn, 1 );
  3777. }
  3778. }
  3779. /*
  3780. ================
  3781. idPortalSky::Event_PostSpawn
  3782. ================
  3783. */
  3784. void idPortalSky::Event_PostSpawn()
  3785. {
  3786. gameLocal.SetPortalSkyEnt( this );
  3787. }
  3788. /*
  3789. ================
  3790. idPortalSky::Event_Activate
  3791. ================
  3792. */
  3793. void idPortalSky::Event_Activate( idEntity* activator )
  3794. {
  3795. gameLocal.SetPortalSkyEnt( this );
  3796. }