Item.cpp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355
  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. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. /*
  24. ===============================================================================
  25. idItem
  26. ===============================================================================
  27. */
  28. const idEventDef EV_DropToFloor( "<dropToFloor>" );
  29. const idEventDef EV_RespawnItem( "respawn" );
  30. const idEventDef EV_RespawnFx( "<respawnFx>" );
  31. const idEventDef EV_GetPlayerPos( "<getplayerpos>" );
  32. const idEventDef EV_HideObjective( "<hideobjective>", "e" );
  33. const idEventDef EV_CamShot( "<camshot>" );
  34. CLASS_DECLARATION( idEntity, idItem )
  35. EVENT( EV_DropToFloor, idItem::Event_DropToFloor )
  36. EVENT( EV_Touch, idItem::Event_Touch )
  37. EVENT( EV_Activate, idItem::Event_Trigger )
  38. EVENT( EV_RespawnItem, idItem::Event_Respawn )
  39. EVENT( EV_RespawnFx, idItem::Event_RespawnFx )
  40. END_CLASS
  41. /*
  42. ================
  43. idItem::idItem
  44. ================
  45. */
  46. idItem::idItem() {
  47. spin = false;
  48. inView = false;
  49. inViewTime = 0;
  50. lastCycle = 0;
  51. lastRenderViewTime = -1;
  52. itemShellHandle = -1;
  53. shellMaterial = NULL;
  54. orgOrigin.Zero();
  55. canPickUp = true;
  56. fl.networkSync = true;
  57. }
  58. /*
  59. ================
  60. idItem::~idItem
  61. ================
  62. */
  63. idItem::~idItem() {
  64. // remove the highlight shell
  65. if ( itemShellHandle != -1 ) {
  66. gameRenderWorld->FreeEntityDef( itemShellHandle );
  67. }
  68. }
  69. /*
  70. ================
  71. idItem::Save
  72. ================
  73. */
  74. void idItem::Save( idSaveGame *savefile ) const {
  75. savefile->WriteVec3( orgOrigin );
  76. savefile->WriteBool( spin );
  77. savefile->WriteBool( pulse );
  78. savefile->WriteBool( canPickUp );
  79. savefile->WriteMaterial( shellMaterial );
  80. savefile->WriteBool( inView );
  81. savefile->WriteInt( inViewTime );
  82. savefile->WriteInt( lastCycle );
  83. savefile->WriteInt( lastRenderViewTime );
  84. }
  85. /*
  86. ================
  87. idItem::Restore
  88. ================
  89. */
  90. void idItem::Restore( idRestoreGame *savefile ) {
  91. savefile->ReadVec3( orgOrigin );
  92. savefile->ReadBool( spin );
  93. savefile->ReadBool( pulse );
  94. savefile->ReadBool( canPickUp );
  95. savefile->ReadMaterial( shellMaterial );
  96. savefile->ReadBool( inView );
  97. savefile->ReadInt( inViewTime );
  98. savefile->ReadInt( lastCycle );
  99. savefile->ReadInt( lastRenderViewTime );
  100. itemShellHandle = -1;
  101. }
  102. /*
  103. ================
  104. idItem::UpdateRenderEntity
  105. ================
  106. */
  107. bool idItem::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const {
  108. if ( lastRenderViewTime == renderView->time ) {
  109. return false;
  110. }
  111. lastRenderViewTime = renderView->time;
  112. // check for glow highlighting if near the center of the view
  113. idVec3 dir = renderEntity->origin - renderView->vieworg;
  114. dir.Normalize();
  115. float d = dir * renderView->viewaxis[0];
  116. // two second pulse cycle
  117. float cycle = ( renderView->time - inViewTime ) / 2000.0f;
  118. if ( d > 0.94f ) {
  119. if ( !inView ) {
  120. inView = true;
  121. if ( cycle > lastCycle ) {
  122. // restart at the beginning
  123. inViewTime = renderView->time;
  124. cycle = 0.0f;
  125. }
  126. }
  127. } else {
  128. if ( inView ) {
  129. inView = false;
  130. lastCycle = ceil( cycle );
  131. }
  132. }
  133. // fade down after the last pulse finishes
  134. if ( !inView && cycle > lastCycle ) {
  135. renderEntity->shaderParms[4] = 0.0f;
  136. } else {
  137. // pulse up in 1/4 second
  138. cycle -= (int)cycle;
  139. if ( cycle < 0.1f ) {
  140. renderEntity->shaderParms[4] = cycle * 10.0f;
  141. } else if ( cycle < 0.2f ) {
  142. renderEntity->shaderParms[4] = 1.0f;
  143. } else if ( cycle < 0.3f ) {
  144. renderEntity->shaderParms[4] = 1.0f - ( cycle - 0.2f ) * 10.0f;
  145. } else {
  146. // stay off between pulses
  147. renderEntity->shaderParms[4] = 0.0f;
  148. }
  149. }
  150. // update every single time this is in view
  151. return true;
  152. }
  153. /*
  154. ================
  155. idItem::ModelCallback
  156. ================
  157. */
  158. bool idItem::ModelCallback( renderEntity_t *renderEntity, const renderView_t *renderView ) {
  159. const idItem *ent;
  160. // this may be triggered by a model trace or other non-view related source
  161. if ( !renderView ) {
  162. return false;
  163. }
  164. ent = static_cast<idItem *>(gameLocal.entities[ renderEntity->entityNum ]);
  165. if ( !ent ) {
  166. gameLocal.Error( "idItem::ModelCallback: callback with NULL game entity" );
  167. }
  168. return ent->UpdateRenderEntity( renderEntity, renderView );
  169. }
  170. /*
  171. ================
  172. idItem::Think
  173. ================
  174. */
  175. void idItem::Think( void ) {
  176. if ( thinkFlags & TH_THINK ) {
  177. if ( spin ) {
  178. idAngles ang;
  179. idVec3 org;
  180. ang.pitch = ang.roll = 0.0f;
  181. ang.yaw = ( gameLocal.time & 4095 ) * 360.0f / -4096.0f;
  182. SetAngles( ang );
  183. float scale = 0.005f + entityNumber * 0.00001f;
  184. org = orgOrigin;
  185. org.z += 4.0f + cos( ( gameLocal.time + 2000 ) * scale ) * 4.0f;
  186. SetOrigin( org );
  187. }
  188. }
  189. Present();
  190. }
  191. /*
  192. ================
  193. idItem::Present
  194. ================
  195. */
  196. void idItem::Present( void ) {
  197. idEntity::Present();
  198. if ( !fl.hidden && pulse ) {
  199. // also add a highlight shell model
  200. renderEntity_t shell;
  201. shell = renderEntity;
  202. // we will mess with shader parms when the item is in view
  203. // to give the "item pulse" effect
  204. shell.callback = idItem::ModelCallback;
  205. shell.entityNum = entityNumber;
  206. shell.customShader = shellMaterial;
  207. if ( itemShellHandle == -1 ) {
  208. itemShellHandle = gameRenderWorld->AddEntityDef( &shell );
  209. } else {
  210. gameRenderWorld->UpdateEntityDef( itemShellHandle, &shell );
  211. }
  212. }
  213. }
  214. /*
  215. ================
  216. idItem::Spawn
  217. ================
  218. */
  219. void idItem::Spawn( void ) {
  220. idStr giveTo;
  221. idEntity * ent;
  222. float tsize;
  223. if ( spawnArgs.GetBool( "dropToFloor" ) ) {
  224. PostEventMS( &EV_DropToFloor, 0 );
  225. }
  226. if ( spawnArgs.GetFloat( "triggersize", "0", tsize ) ) {
  227. GetPhysics()->GetClipModel()->LoadModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) );
  228. GetPhysics()->GetClipModel()->Link( gameLocal.clip );
  229. }
  230. if ( spawnArgs.GetBool( "start_off" ) ) {
  231. GetPhysics()->SetContents( 0 );
  232. Hide();
  233. } else {
  234. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  235. }
  236. giveTo = spawnArgs.GetString( "owner" );
  237. if ( giveTo.Length() ) {
  238. ent = gameLocal.FindEntity( giveTo );
  239. if ( !ent ) {
  240. gameLocal.Error( "Item couldn't find owner '%s'", giveTo.c_str() );
  241. }
  242. PostEventMS( &EV_Touch, 0, ent, NULL );
  243. }
  244. if ( spawnArgs.GetBool( "spin" ) || gameLocal.isMultiplayer ) {
  245. spin = true;
  246. BecomeActive( TH_THINK );
  247. }
  248. //pulse = !spawnArgs.GetBool( "nopulse" );
  249. //temp hack for tim
  250. pulse = false;
  251. orgOrigin = GetPhysics()->GetOrigin();
  252. canPickUp = !( spawnArgs.GetBool( "triggerFirst" ) || spawnArgs.GetBool( "no_touch" ) );
  253. inViewTime = -1000;
  254. lastCycle = -1;
  255. itemShellHandle = -1;
  256. shellMaterial = declManager->FindMaterial( "itemHighlightShell" );
  257. }
  258. /*
  259. ================
  260. idItem::GetAttributes
  261. ================
  262. */
  263. void idItem::GetAttributes( idDict &attributes ) {
  264. int i;
  265. const idKeyValue *arg;
  266. for( i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
  267. arg = spawnArgs.GetKeyVal( i );
  268. if ( arg->GetKey().Left( 4 ) == "inv_" ) {
  269. attributes.Set( arg->GetKey().Right( arg->GetKey().Length() - 4 ), arg->GetValue() );
  270. }
  271. }
  272. }
  273. /*
  274. ================
  275. idItem::GiveToPlayer
  276. ================
  277. */
  278. bool idItem::GiveToPlayer( idPlayer *player ) {
  279. if ( player == NULL ) {
  280. return false;
  281. }
  282. if ( spawnArgs.GetBool( "inv_carry" ) ) {
  283. return player->GiveInventoryItem( &spawnArgs );
  284. }
  285. return player->GiveItem( this );
  286. }
  287. /*
  288. ================
  289. idItem::Pickup
  290. ================
  291. */
  292. bool idItem::Pickup( idPlayer *player ) {
  293. if ( !GiveToPlayer( player ) ) {
  294. return false;
  295. }
  296. if ( gameLocal.isServer ) {
  297. ServerSendEvent( EVENT_PICKUP, NULL, false, -1 );
  298. }
  299. // play pickup sound
  300. StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL );
  301. // trigger our targets
  302. ActivateTargets( player );
  303. // clear our contents so the object isn't picked up twice
  304. GetPhysics()->SetContents( 0 );
  305. // hide the model
  306. Hide();
  307. // add the highlight shell
  308. if ( itemShellHandle != -1 ) {
  309. gameRenderWorld->FreeEntityDef( itemShellHandle );
  310. itemShellHandle = -1;
  311. }
  312. float respawn = spawnArgs.GetFloat( "respawn" );
  313. bool dropped = spawnArgs.GetBool( "dropped" );
  314. bool no_respawn = spawnArgs.GetBool( "no_respawn" );
  315. if ( gameLocal.isMultiplayer && respawn == 0.0f ) {
  316. respawn = 20.0f;
  317. }
  318. if ( respawn && !dropped && !no_respawn ) {
  319. const char *sfx = spawnArgs.GetString( "fxRespawn" );
  320. if ( sfx && *sfx ) {
  321. PostEventSec( &EV_RespawnFx, respawn - 0.5f );
  322. }
  323. PostEventSec( &EV_RespawnItem, respawn );
  324. } else if ( !spawnArgs.GetBool( "inv_objective" ) && !no_respawn ) {
  325. // give some time for the pickup sound to play
  326. // FIXME: Play on the owner
  327. if ( !spawnArgs.GetBool( "inv_carry" ) ) {
  328. PostEventMS( &EV_Remove, 5000 );
  329. }
  330. }
  331. BecomeInactive( TH_THINK );
  332. return true;
  333. }
  334. /*
  335. ================
  336. idItem::ClientPredictionThink
  337. ================
  338. */
  339. void idItem::ClientPredictionThink( void ) {
  340. // only think forward because the state is not synced through snapshots
  341. if ( !gameLocal.isNewFrame ) {
  342. return;
  343. }
  344. Think();
  345. }
  346. /*
  347. ================
  348. idItem::WriteFromSnapshot
  349. ================
  350. */
  351. void idItem::WriteToSnapshot( idBitMsgDelta &msg ) const {
  352. msg.WriteBits( IsHidden(), 1 );
  353. }
  354. /*
  355. ================
  356. idItem::ReadFromSnapshot
  357. ================
  358. */
  359. void idItem::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  360. if ( msg.ReadBits( 1 ) ) {
  361. Hide();
  362. } else {
  363. Show();
  364. }
  365. }
  366. /*
  367. ================
  368. idItem::ClientReceiveEvent
  369. ================
  370. */
  371. bool idItem::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  372. switch( event ) {
  373. case EVENT_PICKUP: {
  374. // play pickup sound
  375. StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL );
  376. // hide the model
  377. Hide();
  378. // remove the highlight shell
  379. if ( itemShellHandle != -1 ) {
  380. gameRenderWorld->FreeEntityDef( itemShellHandle );
  381. itemShellHandle = -1;
  382. }
  383. return true;
  384. }
  385. case EVENT_RESPAWN: {
  386. Event_Respawn();
  387. return true;
  388. }
  389. case EVENT_RESPAWNFX: {
  390. Event_RespawnFx();
  391. return true;
  392. }
  393. default: {
  394. return idEntity::ClientReceiveEvent( event, time, msg );
  395. }
  396. }
  397. return false;
  398. }
  399. /*
  400. ================
  401. idItem::Event_DropToFloor
  402. ================
  403. */
  404. void idItem::Event_DropToFloor( void ) {
  405. trace_t trace;
  406. // don't drop the floor if bound to another entity
  407. if ( GetBindMaster() != NULL && GetBindMaster() != this ) {
  408. return;
  409. }
  410. gameLocal.clip.TraceBounds( trace, renderEntity.origin, renderEntity.origin - idVec3( 0, 0, 64 ), renderEntity.bounds, MASK_SOLID | CONTENTS_CORPSE, this );
  411. SetOrigin( trace.endpos );
  412. }
  413. /*
  414. ================
  415. idItem::Event_Touch
  416. ================
  417. */
  418. void idItem::Event_Touch( idEntity *other, trace_t *trace ) {
  419. if ( !other->IsType( idPlayer::Type ) ) {
  420. return;
  421. }
  422. if ( !canPickUp ) {
  423. return;
  424. }
  425. Pickup( static_cast<idPlayer *>(other) );
  426. }
  427. /*
  428. ================
  429. idItem::Event_Trigger
  430. ================
  431. */
  432. void idItem::Event_Trigger( idEntity *activator ) {
  433. if ( !canPickUp && spawnArgs.GetBool( "triggerFirst" ) ) {
  434. canPickUp = true;
  435. return;
  436. }
  437. if ( activator && activator->IsType( idPlayer::Type ) ) {
  438. Pickup( static_cast<idPlayer *>( activator ) );
  439. }
  440. }
  441. /*
  442. ================
  443. idItem::Event_Respawn
  444. ================
  445. */
  446. void idItem::Event_Respawn( void ) {
  447. if ( gameLocal.isServer ) {
  448. ServerSendEvent( EVENT_RESPAWN, NULL, false, -1 );
  449. }
  450. BecomeActive( TH_THINK );
  451. Show();
  452. inViewTime = -1000;
  453. lastCycle = -1;
  454. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  455. SetOrigin( orgOrigin );
  456. StartSound( "snd_respawn", SND_CHANNEL_ITEM, 0, false, NULL );
  457. CancelEvents( &EV_RespawnItem ); // don't double respawn
  458. }
  459. /*
  460. ================
  461. idItem::Event_RespawnFx
  462. ================
  463. */
  464. void idItem::Event_RespawnFx( void ) {
  465. if ( gameLocal.isServer ) {
  466. ServerSendEvent( EVENT_RESPAWNFX, NULL, false, -1 );
  467. }
  468. const char *sfx = spawnArgs.GetString( "fxRespawn" );
  469. if ( sfx && *sfx ) {
  470. idEntityFx::StartFx( sfx, NULL, NULL, this, true );
  471. }
  472. }
  473. /*
  474. ===============================================================================
  475. idItemPowerup
  476. ===============================================================================
  477. */
  478. /*
  479. ===============
  480. idItemPowerup
  481. ===============
  482. */
  483. CLASS_DECLARATION( idItem, idItemPowerup )
  484. END_CLASS
  485. /*
  486. ================
  487. idItemPowerup::idItemPowerup
  488. ================
  489. */
  490. idItemPowerup::idItemPowerup() {
  491. time = 0;
  492. type = 0;
  493. }
  494. /*
  495. ================
  496. idItemPowerup::Save
  497. ================
  498. */
  499. void idItemPowerup::Save( idSaveGame *savefile ) const {
  500. savefile->WriteInt( time );
  501. savefile->WriteInt( type );
  502. }
  503. /*
  504. ================
  505. idItemPowerup::Restore
  506. ================
  507. */
  508. void idItemPowerup::Restore( idRestoreGame *savefile ) {
  509. savefile->ReadInt( time );
  510. savefile->ReadInt( type );
  511. }
  512. /*
  513. ================
  514. idItemPowerup::Spawn
  515. ================
  516. */
  517. void idItemPowerup::Spawn( void ) {
  518. time = spawnArgs.GetInt( "time", "30" );
  519. type = spawnArgs.GetInt( "type", "0" );
  520. }
  521. /*
  522. ================
  523. idItemPowerup::GiveToPlayer
  524. ================
  525. */
  526. bool idItemPowerup::GiveToPlayer( idPlayer *player ) {
  527. if ( player->spectating ) {
  528. return false;
  529. }
  530. player->GivePowerUp( type, time * 1000 );
  531. return true;
  532. }
  533. /*
  534. ===============================================================================
  535. idObjective
  536. ===============================================================================
  537. */
  538. CLASS_DECLARATION( idItem, idObjective )
  539. EVENT( EV_Activate, idObjective::Event_Trigger )
  540. EVENT( EV_HideObjective, idObjective::Event_HideObjective )
  541. EVENT( EV_GetPlayerPos, idObjective::Event_GetPlayerPos )
  542. EVENT( EV_CamShot, idObjective::Event_CamShot )
  543. END_CLASS
  544. /*
  545. ================
  546. idObjective::idObjective
  547. ================
  548. */
  549. idObjective::idObjective() {
  550. playerPos.Zero();
  551. }
  552. /*
  553. ================
  554. idObjective::Save
  555. ================
  556. */
  557. void idObjective::Save( idSaveGame *savefile ) const {
  558. savefile->WriteVec3( playerPos );
  559. }
  560. /*
  561. ================
  562. idObjective::Restore
  563. ================
  564. */
  565. void idObjective::Restore( idRestoreGame *savefile ) {
  566. savefile->ReadVec3( playerPos );
  567. PostEventMS( &EV_CamShot, 250 );
  568. }
  569. /*
  570. ================
  571. idObjective::Spawn
  572. ================
  573. */
  574. void idObjective::Spawn( void ) {
  575. Hide();
  576. PostEventMS( &EV_CamShot, 250 );
  577. }
  578. /*
  579. ================
  580. idObjective::Event_Screenshot
  581. ================
  582. */
  583. void idObjective::Event_CamShot( ) {
  584. const char *camName;
  585. idStr shotName = gameLocal.GetMapName();
  586. shotName.StripFileExtension();
  587. shotName += "/";
  588. shotName += spawnArgs.GetString( "screenshot" );
  589. shotName.SetFileExtension( ".tga" );
  590. if ( spawnArgs.GetString( "camShot", "", &camName ) ) {
  591. idEntity *ent = gameLocal.FindEntity( camName );
  592. if ( ent && ent->cameraTarget ) {
  593. const renderView_t *view = ent->cameraTarget->GetRenderView();
  594. renderView_t fullView = *view;
  595. fullView.width = SCREEN_WIDTH;
  596. fullView.height = SCREEN_HEIGHT;
  597. // draw a view to a texture
  598. renderSystem->CropRenderSize( 256, 256, true );
  599. gameRenderWorld->RenderScene( &fullView );
  600. renderSystem->CaptureRenderToFile( shotName );
  601. renderSystem->UnCrop();
  602. }
  603. }
  604. }
  605. /*
  606. ================
  607. idObjective::Event_Trigger
  608. ================
  609. */
  610. void idObjective::Event_Trigger( idEntity *activator ) {
  611. idPlayer *player = gameLocal.GetLocalPlayer();
  612. if ( player ) {
  613. //Pickup( player );
  614. if ( spawnArgs.GetString( "inv_objective", NULL ) ) {
  615. if ( player && player->hud ) {
  616. idStr shotName = gameLocal.GetMapName();
  617. shotName.StripFileExtension();
  618. shotName += "/";
  619. shotName += spawnArgs.GetString( "screenshot" );
  620. shotName.SetFileExtension( ".tga" );
  621. player->hud->SetStateString( "screenshot", shotName );
  622. player->hud->SetStateString( "objective", "1" );
  623. player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) );
  624. player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) );
  625. player->GiveObjective( spawnArgs.GetString( "objectivetitle" ), spawnArgs.GetString( "objectivetext" ), shotName );
  626. // a tad slow but keeps from having to update all objectives in all maps with a name ptr
  627. for( int i = 0; i < gameLocal.num_entities; i++ ) {
  628. if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idObjectiveComplete::Type ) ) {
  629. if ( idStr::Icmp( spawnArgs.GetString( "objectivetitle" ), gameLocal.entities[ i ]->spawnArgs.GetString( "objectivetitle" ) ) == 0 ){
  630. gameLocal.entities[ i ]->spawnArgs.SetBool( "objEnabled", true );
  631. break;
  632. }
  633. }
  634. }
  635. PostEventMS( &EV_GetPlayerPos, 2000 );
  636. }
  637. }
  638. }
  639. }
  640. /*
  641. ================
  642. idObjective::Event_GetPlayerPos
  643. ================
  644. */
  645. void idObjective::Event_GetPlayerPos() {
  646. idPlayer *player = gameLocal.GetLocalPlayer();
  647. if ( player ) {
  648. playerPos = player->GetPhysics()->GetOrigin();
  649. PostEventMS( &EV_HideObjective, 100, player );
  650. }
  651. }
  652. /*
  653. ================
  654. idObjective::Event_HideObjective
  655. ================
  656. */
  657. void idObjective::Event_HideObjective(idEntity *e) {
  658. idPlayer *player = gameLocal.GetLocalPlayer();
  659. if ( player ) {
  660. idVec3 v = player->GetPhysics()->GetOrigin() - playerPos;
  661. if ( v.Length() > 64.0f ) {
  662. player->HideObjective();
  663. PostEventMS( &EV_Remove, 0 );
  664. } else {
  665. PostEventMS( &EV_HideObjective, 100, player );
  666. }
  667. }
  668. }
  669. /*
  670. ===============================================================================
  671. idVideoCDItem
  672. ===============================================================================
  673. */
  674. CLASS_DECLARATION( idItem, idVideoCDItem )
  675. END_CLASS
  676. /*
  677. ================
  678. idVideoCDItem::Spawn
  679. ================
  680. */
  681. void idVideoCDItem::Spawn( void ) {
  682. }
  683. /*
  684. ================
  685. idVideoCDItem::GiveToPlayer
  686. ================
  687. */
  688. bool idVideoCDItem::GiveToPlayer( idPlayer *player ) {
  689. idStr str = spawnArgs.GetString( "video" );
  690. if ( player && str.Length() ) {
  691. player->GiveVideo( str, &spawnArgs );
  692. }
  693. return true;
  694. }
  695. /*
  696. ===============================================================================
  697. idPDAItem
  698. ===============================================================================
  699. */
  700. CLASS_DECLARATION( idItem, idPDAItem )
  701. END_CLASS
  702. /*
  703. ================
  704. idPDAItem::GiveToPlayer
  705. ================
  706. */
  707. bool idPDAItem::GiveToPlayer(idPlayer *player) {
  708. const char *str = spawnArgs.GetString( "pda_name" );
  709. if ( player ) {
  710. player->GivePDA( str, &spawnArgs );
  711. }
  712. return true;
  713. }
  714. /*
  715. ===============================================================================
  716. idMoveableItem
  717. ===============================================================================
  718. */
  719. CLASS_DECLARATION( idItem, idMoveableItem )
  720. EVENT( EV_DropToFloor, idMoveableItem::Event_DropToFloor )
  721. EVENT( EV_Gib, idMoveableItem::Event_Gib )
  722. END_CLASS
  723. /*
  724. ================
  725. idMoveableItem::idMoveableItem
  726. ================
  727. */
  728. idMoveableItem::idMoveableItem() {
  729. trigger = NULL;
  730. smoke = NULL;
  731. smokeTime = 0;
  732. }
  733. /*
  734. ================
  735. idMoveableItem::~idMoveableItem
  736. ================
  737. */
  738. idMoveableItem::~idMoveableItem() {
  739. if ( trigger ) {
  740. delete trigger;
  741. }
  742. }
  743. /*
  744. ================
  745. idMoveableItem::Save
  746. ================
  747. */
  748. void idMoveableItem::Save( idSaveGame *savefile ) const {
  749. savefile->WriteStaticObject( physicsObj );
  750. savefile->WriteClipModel( trigger );
  751. savefile->WriteParticle( smoke );
  752. savefile->WriteInt( smokeTime );
  753. }
  754. /*
  755. ================
  756. idMoveableItem::Restore
  757. ================
  758. */
  759. void idMoveableItem::Restore( idRestoreGame *savefile ) {
  760. savefile->ReadStaticObject( physicsObj );
  761. RestorePhysics( &physicsObj );
  762. savefile->ReadClipModel( trigger );
  763. savefile->ReadParticle( smoke );
  764. savefile->ReadInt( smokeTime );
  765. }
  766. /*
  767. ================
  768. idMoveableItem::Spawn
  769. ================
  770. */
  771. void idMoveableItem::Spawn( void ) {
  772. idTraceModel trm;
  773. float density, friction, bouncyness, tsize;
  774. idStr clipModelName;
  775. idBounds bounds;
  776. // create a trigger for item pickup
  777. spawnArgs.GetFloat( "triggersize", "16.0", tsize );
  778. trigger = new idClipModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) );
  779. trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
  780. trigger->SetContents( CONTENTS_TRIGGER );
  781. // check if a clip model is set
  782. spawnArgs.GetString( "clipmodel", "", clipModelName );
  783. if ( !clipModelName[0] ) {
  784. clipModelName = spawnArgs.GetString( "model" ); // use the visual model
  785. }
  786. // load the trace model
  787. if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) {
  788. gameLocal.Error( "idMoveableItem '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() );
  789. return;
  790. }
  791. // if the model should be shrinked
  792. if ( spawnArgs.GetBool( "clipshrink" ) ) {
  793. trm.Shrink( CM_CLIP_EPSILON );
  794. }
  795. // get rigid body properties
  796. spawnArgs.GetFloat( "density", "0.5", density );
  797. density = idMath::ClampFloat( 0.001f, 1000.0f, density );
  798. spawnArgs.GetFloat( "friction", "0.05", friction );
  799. friction = idMath::ClampFloat( 0.0f, 1.0f, friction );
  800. spawnArgs.GetFloat( "bouncyness", "0.6", bouncyness );
  801. bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness );
  802. // setup the physics
  803. physicsObj.SetSelf( this );
  804. physicsObj.SetClipModel( new idClipModel( trm ), density );
  805. physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
  806. physicsObj.SetAxis( GetPhysics()->GetAxis() );
  807. physicsObj.SetBouncyness( bouncyness );
  808. physicsObj.SetFriction( 0.6f, 0.6f, friction );
  809. physicsObj.SetGravity( gameLocal.GetGravity() );
  810. physicsObj.SetContents( CONTENTS_RENDERMODEL );
  811. physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
  812. SetPhysics( &physicsObj );
  813. smoke = NULL;
  814. smokeTime = 0;
  815. const char *smokeName = spawnArgs.GetString( "smoke_trail" );
  816. if ( *smokeName != '\0' ) {
  817. smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  818. smokeTime = gameLocal.time;
  819. BecomeActive( TH_UPDATEPARTICLES );
  820. }
  821. }
  822. /*
  823. ================
  824. idMoveableItem::Think
  825. ================
  826. */
  827. void idMoveableItem::Think( void ) {
  828. RunPhysics();
  829. if ( thinkFlags & TH_PHYSICS ) {
  830. // update trigger position
  831. trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity );
  832. }
  833. if ( thinkFlags & TH_UPDATEPARTICLES ) {
  834. if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ) ) {
  835. smokeTime = 0;
  836. BecomeInactive( TH_UPDATEPARTICLES );
  837. }
  838. }
  839. Present();
  840. }
  841. /*
  842. ================
  843. idMoveableItem::Pickup
  844. ================
  845. */
  846. bool idMoveableItem::Pickup( idPlayer *player ) {
  847. bool ret = idItem::Pickup( player );
  848. if ( ret ) {
  849. trigger->SetContents( 0 );
  850. }
  851. return ret;
  852. }
  853. /*
  854. ================
  855. idMoveableItem::DropItem
  856. ================
  857. */
  858. idEntity *idMoveableItem::DropItem( const char *classname, const idVec3 &origin, const idMat3 &axis, const idVec3 &velocity, int activateDelay, int removeDelay ) {
  859. idDict args;
  860. idEntity *item;
  861. args.Set( "classname", classname );
  862. args.Set( "dropped", "1" );
  863. // we sometimes drop idMoveables here, so set 'nodrop' to 1 so that it doesn't get put on the floor
  864. args.Set( "nodrop", "1" );
  865. if ( activateDelay ) {
  866. args.SetBool( "triggerFirst", true );
  867. }
  868. gameLocal.SpawnEntityDef( args, &item );
  869. if ( item ) {
  870. // set item position
  871. item->GetPhysics()->SetOrigin( origin );
  872. item->GetPhysics()->SetAxis( axis );
  873. item->GetPhysics()->SetLinearVelocity( velocity );
  874. item->UpdateVisuals();
  875. if ( activateDelay ) {
  876. item->PostEventMS( &EV_Activate, activateDelay, item );
  877. }
  878. if ( !removeDelay ) {
  879. removeDelay = 5 * 60 * 1000;
  880. }
  881. // always remove a dropped item after 5 minutes in case it dropped to an unreachable location
  882. item->PostEventMS( &EV_Remove, removeDelay );
  883. }
  884. return item;
  885. }
  886. /*
  887. ================
  888. idMoveableItem::DropItems
  889. The entity should have the following key/value pairs set:
  890. "def_drop<type>Item" "item def"
  891. "drop<type>ItemJoint" "joint name"
  892. "drop<type>ItemRotation" "pitch yaw roll"
  893. "drop<type>ItemOffset" "x y z"
  894. "skin_drop<type>" "skin name"
  895. To drop multiple items the following key/value pairs can be used:
  896. "def_drop<type>Item<X>" "item def"
  897. "drop<type>Item<X>Joint" "joint name"
  898. "drop<type>Item<X>Rotation" "pitch yaw roll"
  899. "drop<type>Item<X>Offset" "x y z"
  900. where <X> is an aribtrary string.
  901. ================
  902. */
  903. void idMoveableItem::DropItems( idAnimatedEntity *ent, const char *type, idList<idEntity *> *list ) {
  904. const idKeyValue *kv;
  905. const char *skinName, *c, *jointName;
  906. idStr key, key2;
  907. idVec3 origin;
  908. idMat3 axis;
  909. idAngles angles;
  910. const idDeclSkin *skin;
  911. jointHandle_t joint;
  912. idEntity *item;
  913. // drop all items
  914. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), NULL );
  915. while ( kv ) {
  916. c = kv->GetKey().c_str() + kv->GetKey().Length();
  917. if ( idStr::Icmp( c - 5, "Joint" ) != 0 && idStr::Icmp( c - 8, "Rotation" ) != 0 ) {
  918. key = kv->GetKey().c_str() + 4;
  919. key2 = key;
  920. key += "Joint";
  921. key2 += "Offset";
  922. jointName = ent->spawnArgs.GetString( key );
  923. joint = ent->GetAnimator()->GetJointHandle( jointName );
  924. if ( !ent->GetJointWorldTransform( joint, gameLocal.time, origin, axis ) ) {
  925. gameLocal.Warning( "%s refers to invalid joint '%s' on entity '%s'\n", key.c_str(), jointName, ent->name.c_str() );
  926. origin = ent->GetPhysics()->GetOrigin();
  927. axis = ent->GetPhysics()->GetAxis();
  928. }
  929. if ( g_dropItemRotation.GetString()[0] ) {
  930. angles.Zero();
  931. sscanf( g_dropItemRotation.GetString(), "%f %f %f", &angles.pitch, &angles.yaw, &angles.roll );
  932. } else {
  933. key = kv->GetKey().c_str() + 4;
  934. key += "Rotation";
  935. ent->spawnArgs.GetAngles( key, "0 0 0", angles );
  936. }
  937. axis = angles.ToMat3() * axis;
  938. origin += ent->spawnArgs.GetVector( key2, "0 0 0" );
  939. item = DropItem( kv->GetValue(), origin, axis, vec3_origin, 0, 0 );
  940. if ( list && item ) {
  941. list->Append( item );
  942. }
  943. }
  944. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), kv );
  945. }
  946. // change the skin to hide all items
  947. skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) );
  948. if ( skinName[0] ) {
  949. skin = declManager->FindSkin( skinName );
  950. ent->SetSkin( skin );
  951. }
  952. }
  953. /*
  954. ======================
  955. idMoveableItem::WriteToSnapshot
  956. ======================
  957. */
  958. void idMoveableItem::WriteToSnapshot( idBitMsgDelta &msg ) const {
  959. physicsObj.WriteToSnapshot( msg );
  960. }
  961. /*
  962. ======================
  963. idMoveableItem::ReadFromSnapshot
  964. ======================
  965. */
  966. void idMoveableItem::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  967. physicsObj.ReadFromSnapshot( msg );
  968. if ( msg.HasChanged() ) {
  969. UpdateVisuals();
  970. }
  971. }
  972. /*
  973. ============
  974. idMoveableItem::Gib
  975. ============
  976. */
  977. void idMoveableItem::Gib( const idVec3 &dir, const char *damageDefName ) {
  978. // spawn smoke puff
  979. const char *smokeName = spawnArgs.GetString( "smoke_gib" );
  980. if ( *smokeName != '\0' ) {
  981. const idDeclParticle *smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  982. gameLocal.smokeParticles->EmitSmoke( smoke, gameLocal.time, gameLocal.random.CRandomFloat(), renderEntity.origin, renderEntity.axis );
  983. }
  984. // remove the entity
  985. PostEventMS( &EV_Remove, 0 );
  986. }
  987. /*
  988. ================
  989. idMoveableItem::Event_DropToFloor
  990. ================
  991. */
  992. void idMoveableItem::Event_DropToFloor( void ) {
  993. // the physics will drop the moveable to the floor
  994. }
  995. /*
  996. ============
  997. idMoveableItem::Event_Gib
  998. ============
  999. */
  1000. void idMoveableItem::Event_Gib( const char *damageDefName ) {
  1001. Gib( idVec3( 0, 0, 1 ), damageDefName );
  1002. }
  1003. /*
  1004. ===============================================================================
  1005. idMoveablePDAItem
  1006. ===============================================================================
  1007. */
  1008. CLASS_DECLARATION( idMoveableItem, idMoveablePDAItem )
  1009. END_CLASS
  1010. /*
  1011. ================
  1012. idMoveablePDAItem::GiveToPlayer
  1013. ================
  1014. */
  1015. bool idMoveablePDAItem::GiveToPlayer(idPlayer *player) {
  1016. const char *str = spawnArgs.GetString( "pda_name" );
  1017. if ( player ) {
  1018. player->GivePDA( str, &spawnArgs );
  1019. }
  1020. return true;
  1021. }
  1022. /*
  1023. ===============================================================================
  1024. idItemRemover
  1025. ===============================================================================
  1026. */
  1027. CLASS_DECLARATION( idEntity, idItemRemover )
  1028. EVENT( EV_Activate, idItemRemover::Event_Trigger )
  1029. END_CLASS
  1030. /*
  1031. ================
  1032. idItemRemover::Spawn
  1033. ================
  1034. */
  1035. void idItemRemover::Spawn( void ) {
  1036. }
  1037. /*
  1038. ================
  1039. idItemRemover::RemoveItem
  1040. ================
  1041. */
  1042. void idItemRemover::RemoveItem( idPlayer *player ) {
  1043. const char *remove;
  1044. remove = spawnArgs.GetString( "remove" );
  1045. player->RemoveInventoryItem( remove );
  1046. }
  1047. /*
  1048. ================
  1049. idItemRemover::Event_Trigger
  1050. ================
  1051. */
  1052. void idItemRemover::Event_Trigger( idEntity *activator ) {
  1053. if ( activator->IsType( idPlayer::Type ) ) {
  1054. RemoveItem( static_cast<idPlayer *>(activator) );
  1055. }
  1056. }
  1057. /*
  1058. ===============================================================================
  1059. idObjectiveComplete
  1060. ===============================================================================
  1061. */
  1062. CLASS_DECLARATION( idItemRemover, idObjectiveComplete )
  1063. EVENT( EV_Activate, idObjectiveComplete::Event_Trigger )
  1064. EVENT( EV_HideObjective, idObjectiveComplete::Event_HideObjective )
  1065. EVENT( EV_GetPlayerPos, idObjectiveComplete::Event_GetPlayerPos )
  1066. END_CLASS
  1067. /*
  1068. ================
  1069. idObjectiveComplete::idObjectiveComplete
  1070. ================
  1071. */
  1072. idObjectiveComplete::idObjectiveComplete() {
  1073. playerPos.Zero();
  1074. }
  1075. /*
  1076. ================
  1077. idObjectiveComplete::Save
  1078. ================
  1079. */
  1080. void idObjectiveComplete::Save( idSaveGame *savefile ) const {
  1081. savefile->WriteVec3( playerPos );
  1082. }
  1083. /*
  1084. ================
  1085. idObjectiveComplete::Restore
  1086. ================
  1087. */
  1088. void idObjectiveComplete::Restore( idRestoreGame *savefile ) {
  1089. savefile->ReadVec3( playerPos );
  1090. }
  1091. /*
  1092. ================
  1093. idObjectiveComplete::Spawn
  1094. ================
  1095. */
  1096. void idObjectiveComplete::Spawn( void ) {
  1097. spawnArgs.SetBool( "objEnabled", false );
  1098. Hide();
  1099. }
  1100. /*
  1101. ================
  1102. idObjectiveComplete::Event_Trigger
  1103. ================
  1104. */
  1105. void idObjectiveComplete::Event_Trigger( idEntity *activator ) {
  1106. if ( !spawnArgs.GetBool( "objEnabled" ) ) {
  1107. return;
  1108. }
  1109. idPlayer *player = gameLocal.GetLocalPlayer();
  1110. if ( player ) {
  1111. RemoveItem( player );
  1112. if ( spawnArgs.GetString( "inv_objective", NULL ) ) {
  1113. if ( player->hud ) {
  1114. player->hud->SetStateString( "objective", "2" );
  1115. player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) );
  1116. player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) );
  1117. player->CompleteObjective( spawnArgs.GetString( "objectivetitle" ) );
  1118. PostEventMS( &EV_GetPlayerPos, 2000 );
  1119. }
  1120. }
  1121. }
  1122. }
  1123. /*
  1124. ================
  1125. idObjectiveComplete::Event_GetPlayerPos
  1126. ================
  1127. */
  1128. void idObjectiveComplete::Event_GetPlayerPos() {
  1129. idPlayer *player = gameLocal.GetLocalPlayer();
  1130. if ( player ) {
  1131. playerPos = player->GetPhysics()->GetOrigin();
  1132. PostEventMS( &EV_HideObjective, 100, player );
  1133. }
  1134. }
  1135. /*
  1136. ================
  1137. idObjectiveComplete::Event_HideObjective
  1138. ================
  1139. */
  1140. void idObjectiveComplete::Event_HideObjective( idEntity *e ) {
  1141. idPlayer *player = gameLocal.GetLocalPlayer();
  1142. if ( player ) {
  1143. idVec3 v = player->GetPhysics()->GetOrigin();
  1144. v -= playerPos;
  1145. if ( v.Length() > 64.0f ) {
  1146. player->hud->HandleNamedEvent( "closeObjective" );
  1147. PostEventMS( &EV_Remove, 0 );
  1148. } else {
  1149. PostEventMS( &EV_HideObjective, 100, player );
  1150. }
  1151. }
  1152. }