PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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