PageRenderTime 33ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/dhewm3-master/neo/game/Misc.cpp

https://bitbucket.org/peanut64/dhewm3-dhewm
C++ | 3158 lines | 1676 code | 426 blank | 1056 comment | 281 complexity | 3d4b7eae002a9604eabfe4b76f25c512 MD5 | raw file
Possible License(s): GPL-3.0, Unlicense, CC0-1.0, GPL-2.0

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

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

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