Item.cpp 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165
  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. #ifdef CTF
  245. // idItemTeam does not rotate and bob
  246. if ( spawnArgs.GetBool( "spin" ) || (gameLocal.isMultiplayer && !this->IsType( idItemTeam::Type ) ) ) {
  247. spin = true;
  248. BecomeActive( TH_THINK );
  249. }
  250. #else
  251. if ( spawnArgs.GetBool( "spin" ) || gameLocal.isMultiplayer ) {
  252. spin = true;
  253. BecomeActive( TH_THINK );
  254. }
  255. #endif
  256. //pulse = !spawnArgs.GetBool( "nopulse" );
  257. //temp hack for tim
  258. pulse = false;
  259. orgOrigin = GetPhysics()->GetOrigin();
  260. canPickUp = !( spawnArgs.GetBool( "triggerFirst" ) || spawnArgs.GetBool( "no_touch" ) );
  261. inViewTime = -1000;
  262. lastCycle = -1;
  263. itemShellHandle = -1;
  264. shellMaterial = declManager->FindMaterial( "itemHighlightShell" );
  265. }
  266. /*
  267. ================
  268. idItem::GetAttributes
  269. ================
  270. */
  271. void idItem::GetAttributes( idDict &attributes ) {
  272. int i;
  273. const idKeyValue *arg;
  274. for( i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
  275. arg = spawnArgs.GetKeyVal( i );
  276. if ( arg->GetKey().Left( 4 ) == "inv_" ) {
  277. attributes.Set( arg->GetKey().Right( arg->GetKey().Length() - 4 ), arg->GetValue() );
  278. }
  279. }
  280. }
  281. /*
  282. ================
  283. idItem::GiveToPlayer
  284. ================
  285. */
  286. bool idItem::GiveToPlayer( idPlayer *player ) {
  287. if ( player == NULL ) {
  288. return false;
  289. }
  290. if ( spawnArgs.GetBool( "inv_carry" ) ) {
  291. return player->GiveInventoryItem( &spawnArgs );
  292. }
  293. return player->GiveItem( this );
  294. }
  295. /*
  296. ================
  297. idItem::Pickup
  298. ================
  299. */
  300. bool idItem::Pickup( idPlayer *player ) {
  301. if ( !GiveToPlayer( player ) ) {
  302. return false;
  303. }
  304. if ( gameLocal.isServer ) {
  305. ServerSendEvent( EVENT_PICKUP, NULL, false, -1 );
  306. }
  307. // play pickup sound
  308. StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL );
  309. // trigger our targets
  310. ActivateTargets( player );
  311. // clear our contents so the object isn't picked up twice
  312. GetPhysics()->SetContents( 0 );
  313. // hide the model
  314. Hide();
  315. // add the highlight shell
  316. if ( itemShellHandle != -1 ) {
  317. gameRenderWorld->FreeEntityDef( itemShellHandle );
  318. itemShellHandle = -1;
  319. }
  320. float respawn = spawnArgs.GetFloat( "respawn" );
  321. bool dropped = spawnArgs.GetBool( "dropped" );
  322. bool no_respawn = spawnArgs.GetBool( "no_respawn" );
  323. if ( gameLocal.isMultiplayer && respawn == 0.0f ) {
  324. respawn = 20.0f;
  325. }
  326. if ( respawn && !dropped && !no_respawn ) {
  327. const char *sfx = spawnArgs.GetString( "fxRespawn" );
  328. if ( sfx && *sfx ) {
  329. PostEventSec( &EV_RespawnFx, respawn - 0.5f );
  330. }
  331. PostEventSec( &EV_RespawnItem, respawn );
  332. } else if ( !spawnArgs.GetBool( "inv_objective" ) && !no_respawn ) {
  333. // give some time for the pickup sound to play
  334. // FIXME: Play on the owner
  335. if ( !spawnArgs.GetBool( "inv_carry" ) ) {
  336. PostEventMS( &EV_Remove, 5000 );
  337. }
  338. }
  339. BecomeInactive( TH_THINK );
  340. return true;
  341. }
  342. /*
  343. ================
  344. idItem::ClientPredictionThink
  345. ================
  346. */
  347. void idItem::ClientPredictionThink( void ) {
  348. // only think forward because the state is not synced through snapshots
  349. if ( !gameLocal.isNewFrame ) {
  350. return;
  351. }
  352. Think();
  353. }
  354. /*
  355. ================
  356. idItem::WriteFromSnapshot
  357. ================
  358. */
  359. void idItem::WriteToSnapshot( idBitMsgDelta &msg ) const {
  360. msg.WriteBits( IsHidden(), 1 );
  361. }
  362. /*
  363. ================
  364. idItem::ReadFromSnapshot
  365. ================
  366. */
  367. void idItem::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  368. if ( msg.ReadBits( 1 ) ) {
  369. Hide();
  370. } else {
  371. Show();
  372. }
  373. }
  374. /*
  375. ================
  376. idItem::ClientReceiveEvent
  377. ================
  378. */
  379. bool idItem::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  380. switch( event ) {
  381. case EVENT_PICKUP: {
  382. // play pickup sound
  383. StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL );
  384. // hide the model
  385. Hide();
  386. // remove the highlight shell
  387. if ( itemShellHandle != -1 ) {
  388. gameRenderWorld->FreeEntityDef( itemShellHandle );
  389. itemShellHandle = -1;
  390. }
  391. return true;
  392. }
  393. case EVENT_RESPAWN: {
  394. Event_Respawn();
  395. return true;
  396. }
  397. case EVENT_RESPAWNFX: {
  398. Event_RespawnFx();
  399. return true;
  400. }
  401. default: {
  402. return idEntity::ClientReceiveEvent( event, time, msg );
  403. }
  404. }
  405. return false;
  406. }
  407. /*
  408. ================
  409. idItem::Event_DropToFloor
  410. ================
  411. */
  412. void idItem::Event_DropToFloor( void ) {
  413. trace_t trace;
  414. // don't drop the floor if bound to another entity
  415. if ( GetBindMaster() != NULL && GetBindMaster() != this ) {
  416. return;
  417. }
  418. gameLocal.clip.TraceBounds( trace, renderEntity.origin, renderEntity.origin - idVec3( 0, 0, 64 ), renderEntity.bounds, MASK_SOLID | CONTENTS_CORPSE, this );
  419. SetOrigin( trace.endpos );
  420. }
  421. /*
  422. ================
  423. idItem::Event_Touch
  424. ================
  425. */
  426. void idItem::Event_Touch( idEntity *other, trace_t *trace ) {
  427. if ( !other->IsType( idPlayer::Type ) ) {
  428. return;
  429. }
  430. if ( !canPickUp ) {
  431. return;
  432. }
  433. Pickup( static_cast<idPlayer *>(other) );
  434. }
  435. /*
  436. ================
  437. idItem::Event_Trigger
  438. ================
  439. */
  440. void idItem::Event_Trigger( idEntity *activator ) {
  441. if ( !canPickUp && spawnArgs.GetBool( "triggerFirst" ) ) {
  442. canPickUp = true;
  443. return;
  444. }
  445. if ( activator && activator->IsType( idPlayer::Type ) ) {
  446. Pickup( static_cast<idPlayer *>( activator ) );
  447. }
  448. }
  449. /*
  450. ================
  451. idItem::Event_Respawn
  452. ================
  453. */
  454. void idItem::Event_Respawn( void ) {
  455. if ( gameLocal.isServer ) {
  456. ServerSendEvent( EVENT_RESPAWN, NULL, false, -1 );
  457. }
  458. BecomeActive( TH_THINK );
  459. Show();
  460. inViewTime = -1000;
  461. lastCycle = -1;
  462. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  463. SetOrigin( orgOrigin );
  464. StartSound( "snd_respawn", SND_CHANNEL_ITEM, 0, false, NULL );
  465. CancelEvents( &EV_RespawnItem ); // don't double respawn
  466. }
  467. /*
  468. ================
  469. idItem::Event_RespawnFx
  470. ================
  471. */
  472. void idItem::Event_RespawnFx( void ) {
  473. if ( gameLocal.isServer ) {
  474. ServerSendEvent( EVENT_RESPAWNFX, NULL, false, -1 );
  475. }
  476. const char *sfx = spawnArgs.GetString( "fxRespawn" );
  477. if ( sfx && *sfx ) {
  478. idEntityFx::StartFx( sfx, NULL, NULL, this, true );
  479. }
  480. }
  481. /*
  482. ===============================================================================
  483. idItemPowerup
  484. ===============================================================================
  485. */
  486. /*
  487. ===============
  488. idItemPowerup
  489. ===============
  490. */
  491. CLASS_DECLARATION( idItem, idItemPowerup )
  492. END_CLASS
  493. /*
  494. ================
  495. idItemPowerup::idItemPowerup
  496. ================
  497. */
  498. idItemPowerup::idItemPowerup() {
  499. time = 0;
  500. type = 0;
  501. }
  502. /*
  503. ================
  504. idItemPowerup::Save
  505. ================
  506. */
  507. void idItemPowerup::Save( idSaveGame *savefile ) const {
  508. savefile->WriteInt( time );
  509. savefile->WriteInt( type );
  510. }
  511. /*
  512. ================
  513. idItemPowerup::Restore
  514. ================
  515. */
  516. void idItemPowerup::Restore( idRestoreGame *savefile ) {
  517. savefile->ReadInt( time );
  518. savefile->ReadInt( type );
  519. }
  520. /*
  521. ================
  522. idItemPowerup::Spawn
  523. ================
  524. */
  525. void idItemPowerup::Spawn( void ) {
  526. time = spawnArgs.GetInt( "time", "30" );
  527. type = spawnArgs.GetInt( "type", "0" );
  528. }
  529. /*
  530. ================
  531. idItemPowerup::GiveToPlayer
  532. ================
  533. */
  534. bool idItemPowerup::GiveToPlayer( idPlayer *player ) {
  535. if ( player->spectating ) {
  536. return false;
  537. }
  538. player->GivePowerUp( type, time * 1000 );
  539. return true;
  540. }
  541. #ifdef CTF
  542. /*
  543. ===============================================================================
  544. idItemTeam
  545. Used for flags in Capture the Flag
  546. ===============================================================================
  547. */
  548. // temporarely removed these events
  549. const idEventDef EV_FlagReturn( "flagreturn", "e" );
  550. const idEventDef EV_TakeFlag( "takeflag", "e" );
  551. const idEventDef EV_DropFlag( "dropflag", "d" );
  552. const idEventDef EV_FlagCapture( "flagcapture" );
  553. CLASS_DECLARATION( idItem, idItemTeam )
  554. EVENT( EV_FlagReturn, idItemTeam::Event_FlagReturn )
  555. EVENT( EV_TakeFlag, idItemTeam::Event_TakeFlag )
  556. EVENT( EV_DropFlag, idItemTeam::Event_DropFlag )
  557. EVENT( EV_FlagCapture, idItemTeam::Event_FlagCapture )
  558. END_CLASS
  559. /*
  560. ===============
  561. idItemTeam::idItemTeam
  562. ===============
  563. */
  564. idItemTeam::idItemTeam() {
  565. team = -1;
  566. carried = false;
  567. dropped = false;
  568. lastDrop = 0;
  569. itemGlowHandle = -1;
  570. skinDefault = NULL;
  571. skinCarried = NULL;
  572. scriptTaken = NULL;
  573. scriptDropped = NULL;
  574. scriptReturned = NULL;
  575. scriptCaptured = NULL;
  576. lastNuggetDrop = 0;
  577. nuggetName = 0;
  578. }
  579. /*
  580. ===============
  581. idItemTeam::~idItemTeam
  582. ===============
  583. */
  584. idItemTeam::~idItemTeam() {
  585. FreeLightDef();
  586. }
  587. /*
  588. ===============
  589. idItemTeam::Spawn
  590. ===============
  591. */
  592. void idItemTeam::Spawn( void ) {
  593. team = spawnArgs.GetInt( "team" );
  594. returnOrigin = GetPhysics()->GetOrigin() + idVec3( 0, 0, 20 );
  595. returnAxis = GetPhysics()->GetAxis();
  596. BecomeActive( TH_THINK );
  597. const char * skinName;
  598. skinName = spawnArgs.GetString( "skin", "" );
  599. if ( skinName[0] )
  600. skinDefault = declManager->FindSkin( skinName );
  601. skinName = spawnArgs.GetString( "skin_carried", "" );
  602. if ( skinName[0] )
  603. skinCarried = declManager->FindSkin( skinName );
  604. nuggetName = spawnArgs.GetString( "nugget_name", "" );
  605. if ( !nuggetName[0] ) {
  606. nuggetName = NULL;
  607. }
  608. scriptTaken = LoadScript( "script_taken" );
  609. scriptDropped = LoadScript( "script_dropped" );
  610. scriptReturned = LoadScript( "script_returned" );
  611. scriptCaptured = LoadScript( "script_captured" );
  612. /* Spawn attached dlight */
  613. /*
  614. idDict args;
  615. idVec3 lightOffset( 0.0f, 20.0f, 0.0f );
  616. // Set up the flag's dynamic light
  617. memset( &itemGlow, 0, sizeof( itemGlow ) );
  618. itemGlow.axis = mat3_identity;
  619. itemGlow.lightRadius.x = 128.0f;
  620. itemGlow.lightRadius.y = itemGlow.lightRadius.z = itemGlow.lightRadius.x;
  621. itemGlow.noShadows = true;
  622. itemGlow.pointLight = true;
  623. itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f;
  624. itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f;
  625. itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f;
  626. itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f;
  627. // Select a shader based on the team
  628. if ( team == 0 )
  629. itemGlow.shader = declManager->FindMaterial( "lights/redflag" );
  630. else
  631. itemGlow.shader = declManager->FindMaterial( "lights/blueflag" );
  632. */
  633. idMoveableItem::Spawn();
  634. physicsObj.SetContents( 0 );
  635. physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
  636. physicsObj.SetGravity( idVec3( 0, 0, spawnArgs.GetInt("gravity", "-30" ) ) );
  637. }
  638. /*
  639. ===============
  640. idItemTeam::LoadScript
  641. ===============
  642. */
  643. function_t * idItemTeam::LoadScript( char * script ) {
  644. function_t * function = NULL;
  645. idStr funcname = spawnArgs.GetString( script, "" );
  646. if ( funcname.Length() ) {
  647. function = gameLocal.program.FindFunction( funcname );
  648. if ( function == NULL ) {
  649. #ifdef _DEBUG
  650. gameLocal.Warning( "idItemTeam '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() );
  651. #endif
  652. }
  653. }
  654. return function;
  655. }
  656. /*
  657. ===============
  658. idItemTeam::Think
  659. ===============
  660. */
  661. void idItemTeam::Think( void ) {
  662. idMoveableItem::Think();
  663. TouchTriggers();
  664. // TODO : only update on updatevisuals
  665. /*idVec3 offset( 0.0f, 0.0f, 20.0f );
  666. itemGlow.origin = GetPhysics()->GetOrigin() + offset;
  667. if ( itemGlowHandle == -1 ) {
  668. itemGlowHandle = gameRenderWorld->AddLightDef( &itemGlow );
  669. } else {
  670. gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );
  671. }*/
  672. #if 1
  673. // should only the server do this?
  674. if ( gameLocal.isServer && nuggetName && carried && ( !lastNuggetDrop || (gameLocal.time - lastNuggetDrop) > spawnArgs.GetInt("nugget_frequency") ) ) {
  675. SpawnNugget( GetPhysics()->GetOrigin() );
  676. lastNuggetDrop = gameLocal.time;
  677. }
  678. #endif
  679. // return dropped flag after si_flagDropTimeLimit seconds
  680. if ( dropped && !carried && lastDrop != 0 && (gameLocal.time - lastDrop) > ( si_flagDropTimeLimit.GetInteger()*1000 ) ) {
  681. Return(); // return flag after 30 seconds on ground
  682. return;
  683. }
  684. }
  685. /*
  686. ===============
  687. idItemTeam::Pickup
  688. ===============
  689. */
  690. bool idItemTeam::Pickup( idPlayer *player ) {
  691. if ( !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */
  692. return false;
  693. if ( gameLocal.mpGame.GetGameState() == idMultiplayerGame::WARMUP ||
  694. gameLocal.mpGame.GetGameState() == idMultiplayerGame::COUNTDOWN )
  695. return false;
  696. // wait 2 seconds after drop before beeing picked up again
  697. if ( lastDrop != 0 && (gameLocal.time - lastDrop) < spawnArgs.GetInt("pickupDelay", "500") )
  698. return false;
  699. if ( carried == false && player->team != this->team ) {
  700. PostEventMS( &EV_TakeFlag, 0, player );
  701. return true;
  702. } else if ( carried == false && dropped == true && player->team == this->team ) {
  703. gameLocal.mpGame.PlayerScoreCTF( player->entityNumber, 5 );
  704. // return flag
  705. PostEventMS( &EV_FlagReturn, 0, player );
  706. return false;
  707. }
  708. return false;
  709. }
  710. /*
  711. ===============
  712. idItemTeam::ClientReceiveEvent
  713. ===============
  714. */
  715. bool idItemTeam::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  716. gameLocal.DPrintf("ClientRecieveEvent: %i\n", event );
  717. switch ( event ) {
  718. case EVENT_TAKEFLAG: {
  719. idPlayer * player = static_cast<idPlayer *>(gameLocal.entities[ msg.ReadBits( GENTITYNUM_BITS ) ]);
  720. if ( player == NULL ) {
  721. gameLocal.Warning( "NULL player takes flag?\n" );
  722. return false;
  723. }
  724. Event_TakeFlag( player );
  725. }
  726. return true;
  727. case EVENT_DROPFLAG : {
  728. bool death = bool( msg.ReadBits( 1 ) == 1 );
  729. Event_DropFlag( death );
  730. }
  731. return true;
  732. case EVENT_FLAGRETURN : {
  733. Hide();
  734. FreeModelDef();
  735. FreeLightDef();
  736. Event_FlagReturn();
  737. }
  738. return true;
  739. case EVENT_FLAGCAPTURE : {
  740. Hide();
  741. FreeModelDef();
  742. FreeLightDef();
  743. Event_FlagCapture();
  744. }
  745. return true;
  746. };
  747. return false;
  748. }
  749. /*
  750. ================
  751. idItemTeam::Drop
  752. ================
  753. */
  754. void idItemTeam::Drop( bool death )
  755. {
  756. // PostEventMS( &EV_DropFlag, 0, int(death == true) );
  757. // had to remove the delayed drop because of drop flag on disconnect
  758. Event_DropFlag( death );
  759. }
  760. /*
  761. ================
  762. idItemTeam::Return
  763. ================
  764. */
  765. void idItemTeam::Return( idPlayer * player )
  766. {
  767. if ( team != 0 && team != 1 )
  768. return;
  769. // PostEventMS( &EV_FlagReturn, 0 );
  770. Event_FlagReturn();
  771. }
  772. /*
  773. ================
  774. idItemTeam::Capture
  775. ================
  776. */
  777. void idItemTeam::Capture( void )
  778. {
  779. if ( team != 0 && team != 1 )
  780. return;
  781. PostEventMS( &EV_FlagCapture, 0 );
  782. }
  783. /*
  784. ================
  785. idItemTeam::PrivateReturn
  786. ================
  787. */
  788. void idItemTeam::PrivateReturn( void )
  789. {
  790. Unbind();
  791. if ( gameLocal.isServer && carried && !dropped ) {
  792. int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team );
  793. if ( playerIdx != -1 ) {
  794. idPlayer * player = static_cast<idPlayer*>( gameLocal.entities[ playerIdx ] );
  795. player->carryingFlag = false;
  796. } else {
  797. gameLocal.Warning( "BUG: carried flag has no carrier before return" );
  798. }
  799. }
  800. dropped = false;
  801. carried = false;
  802. SetOrigin( returnOrigin );
  803. SetAxis( returnAxis );
  804. trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity );
  805. SetSkin( skinDefault );
  806. // Turn off the light
  807. /*itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f;
  808. itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f;
  809. itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f;
  810. itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f;
  811. if ( itemGlowHandle != -1 )
  812. gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/
  813. GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) );
  814. GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) );
  815. }
  816. /*
  817. ================
  818. idItemTeam::Event_TakeFlag
  819. ================
  820. */
  821. void idItemTeam::Event_TakeFlag( idPlayer * player ) {
  822. gameLocal.DPrintf("Event_TakeFlag()!\n");
  823. if ( gameLocal.isServer ) {
  824. idBitMsg msg;
  825. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  826. // Send the event
  827. msg.Init( msgBuf, sizeof( msgBuf ) );
  828. msg.BeginWriting();
  829. msg.WriteBits( player->entityNumber, GENTITYNUM_BITS );
  830. ServerSendEvent( EVENT_TAKEFLAG, &msg, false, -1 );
  831. gameLocal.mpGame.PlayTeamSound( player->team, SND_FLAG_TAKEN_THEIRS );
  832. gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_TAKEN_YOURS );
  833. gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGTAKEN, team, player->entityNumber );
  834. // dont drop a nugget RIGHT away
  835. lastNuggetDrop = gameLocal.time - gameLocal.random.RandomInt( 1000 );
  836. }
  837. BindToJoint( player, g_flagAttachJoint.GetString(), true );
  838. idVec3 origin( g_flagAttachOffsetX.GetFloat(), g_flagAttachOffsetY.GetFloat(), g_flagAttachOffsetZ.GetFloat() );
  839. idAngles angle( g_flagAttachAngleX.GetFloat(), g_flagAttachAngleY.GetFloat(), g_flagAttachAngleZ.GetFloat() );
  840. SetAngles( angle );
  841. SetOrigin( origin );
  842. // Turn the light on
  843. /*itemGlow.shaderParms[ SHADERPARM_RED ] = 1.0f;
  844. itemGlow.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
  845. itemGlow.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
  846. itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 1.0f;
  847. if ( itemGlowHandle != -1 )
  848. gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/
  849. if ( scriptTaken ) {
  850. idThread *thread = new idThread();
  851. thread->CallFunction( scriptTaken, false );
  852. thread->DelayedStart( 0 );
  853. }
  854. dropped = false;
  855. carried = true;
  856. player->carryingFlag = true;
  857. SetSkin( skinCarried );
  858. UpdateVisuals();
  859. UpdateGuis();
  860. if ( gameLocal.isServer ) {
  861. if ( team == 0 )
  862. gameLocal.mpGame.player_red_flag = player->entityNumber;
  863. else
  864. gameLocal.mpGame.player_blue_flag = player->entityNumber;
  865. }
  866. }
  867. /*
  868. ================
  869. idItemTeam::Event_DropFlag
  870. ================
  871. */
  872. void idItemTeam::Event_DropFlag( bool death ) {
  873. gameLocal.DPrintf("Event_DropFlag()!\n");
  874. if ( gameLocal.isServer ) {
  875. idBitMsg msg;
  876. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  877. // Send the event
  878. msg.Init( msgBuf, sizeof( msgBuf ) );
  879. msg.BeginWriting();
  880. msg.WriteBits( death, 1 );
  881. ServerSendEvent( EVENT_DROPFLAG, &msg, false, -1 );
  882. if ( gameLocal.mpGame.IsFlagMsgOn() ) {
  883. gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_DROPPED_THEIRS );
  884. gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_DROPPED_YOURS );
  885. gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGDROP, team );
  886. }
  887. }
  888. lastDrop = gameLocal.time;
  889. BecomeActive( TH_THINK );
  890. Show();
  891. if ( death )
  892. GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) );
  893. else
  894. GetPhysics()->SetLinearVelocity( idVec3(0, 0, 20) );
  895. GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) );
  896. // GetPhysics()->SetLinearVelocity( ( GetPhysics()->GetLinearVelocity() * GetBindMaster()->GetPhysics()->GetAxis() ) + GetBindMaster()->GetPhysics()->GetLinearVelocity() );
  897. if ( GetBindMaster() ) {
  898. const idBounds bounds = GetPhysics()->GetBounds();
  899. idVec3 origin = GetBindMaster()->GetPhysics()->GetOrigin() + idVec3(0, 0, ( bounds[1].z-bounds[0].z )*0.6f );
  900. Unbind();
  901. SetOrigin( origin );
  902. }
  903. idAngles angle = GetPhysics()->GetAxis().ToAngles();
  904. angle.roll = 0;
  905. angle.pitch = 0;
  906. SetAxis( angle.ToMat3() );
  907. dropped = true;
  908. carried = false;
  909. if ( scriptDropped ) {
  910. idThread *thread = new idThread();
  911. thread->CallFunction( scriptDropped, false );
  912. thread->DelayedStart( 0 );
  913. }
  914. SetSkin( skinDefault );
  915. UpdateVisuals();
  916. UpdateGuis();
  917. if ( gameLocal.isServer ) {
  918. if ( team == 0 )
  919. gameLocal.mpGame.player_red_flag = -1;
  920. else
  921. gameLocal.mpGame.player_blue_flag = -1;
  922. }
  923. }
  924. /*
  925. ================
  926. idItemTeam::Event_FlagReturn
  927. ================
  928. */
  929. void idItemTeam::Event_FlagReturn( idPlayer * player ) {
  930. gameLocal.DPrintf("Event_FlagReturn()!\n");
  931. if ( gameLocal.isServer ) {
  932. ServerSendEvent( EVENT_FLAGRETURN, NULL, false, -1 );
  933. if ( gameLocal.mpGame.IsFlagMsgOn() ) {
  934. gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_RETURN );
  935. gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_RETURN );
  936. int entitynum = 255;
  937. if ( player ) {
  938. entitynum = player->entityNumber;
  939. }
  940. gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGRETURN, team, entitynum );
  941. }
  942. }
  943. BecomeActive( TH_THINK );
  944. Show();
  945. PrivateReturn();
  946. if ( scriptReturned ) {
  947. idThread *thread = new idThread();
  948. thread->CallFunction( scriptReturned, false );
  949. thread->DelayedStart( 0 );
  950. }
  951. UpdateVisuals();
  952. UpdateGuis();
  953. // Present();
  954. if ( gameLocal.isServer ) {
  955. if ( team == 0 )
  956. gameLocal.mpGame.player_red_flag = -1;
  957. else
  958. gameLocal.mpGame.player_blue_flag = -1;
  959. }
  960. }
  961. /*
  962. ================
  963. idItemTeam::Event_FlagCapture
  964. ================
  965. */
  966. void idItemTeam::Event_FlagCapture( void ) {
  967. gameLocal.DPrintf("Event_FlagCapture()!\n");
  968. if ( gameLocal.isServer ) {
  969. ServerSendEvent( EVENT_FLAGCAPTURE, NULL, false, -1 );
  970. gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_CAPTURED_THEIRS );
  971. gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_CAPTURED_YOURS );
  972. gameLocal.mpGame.TeamScoreCTF( 1-team, 1 );
  973. int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team );
  974. if ( playerIdx != -1 ) {
  975. gameLocal.mpGame.PlayerScoreCTF( playerIdx, 10 );
  976. } else {
  977. playerIdx = 255;
  978. }
  979. gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGCAPTURE, team, playerIdx );
  980. }
  981. BecomeActive( TH_THINK );
  982. Show();
  983. PrivateReturn();
  984. if ( scriptCaptured ) {
  985. idThread *thread = new idThread();
  986. thread->CallFunction( scriptCaptured, false );
  987. thread->DelayedStart( 0 );
  988. }
  989. UpdateVisuals();
  990. UpdateGuis();
  991. if ( gameLocal.isServer ) {
  992. if ( team == 0 )
  993. gameLocal.mpGame.player_red_flag = -1;
  994. else
  995. gameLocal.mpGame.player_blue_flag = -1;
  996. }
  997. }
  998. /*
  999. ================
  1000. idItemTeam::FreeLightDef
  1001. ================
  1002. */
  1003. void idItemTeam::FreeLightDef( void ) {
  1004. if ( itemGlowHandle != -1 ) {
  1005. gameRenderWorld->FreeLightDef( itemGlowHandle );
  1006. itemGlowHandle = -1;
  1007. }
  1008. }
  1009. /*
  1010. ================
  1011. idItemTeam::SpawnNugget
  1012. ================
  1013. */
  1014. void idItemTeam::SpawnNugget( idVec3 pos ) {
  1015. idAngles angle( gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_pitch", "30")), gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_yaw", "360" )), 0 );
  1016. float velocity = float(gameLocal.random.RandomInt( 40 )+15);
  1017. velocity *= spawnArgs.GetFloat("nugget_velocity", "1" );
  1018. idEntity * ent = idMoveableItem::DropItem( nuggetName, pos, GetPhysics()->GetAxis(), angle.ToMat3()*idVec3(velocity, velocity, velocity), 0, spawnArgs.GetInt("nugget_removedelay") );
  1019. idPhysics_RigidBody * physics = static_cast<idPhysics_RigidBody *>( ent->GetPhysics() );
  1020. if ( physics && physics->IsType( idPhysics_RigidBody::Type ) ) {
  1021. physics->DisableImpact();
  1022. }
  1023. }
  1024. /*
  1025. ================
  1026. idItemTeam::Event_FlagCapture
  1027. ================
  1028. */
  1029. void idItemTeam::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1030. msg.WriteBits( carried, 1 );
  1031. msg.WriteBits( dropped, 1 );
  1032. WriteBindToSnapshot( msg );
  1033. idMoveableItem::WriteToSnapshot( msg );
  1034. }
  1035. /*
  1036. ================
  1037. idItemTeam::ReadFromSnapshot
  1038. ================
  1039. */
  1040. void idItemTeam::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1041. carried = msg.ReadBits( 1 ) == 1;
  1042. dropped = msg.ReadBits( 1 ) == 1;
  1043. ReadBindFromSnapshot( msg );
  1044. if ( msg.HasChanged() )
  1045. {
  1046. UpdateGuis();
  1047. if ( carried == true )
  1048. SetSkin( skinCarried );
  1049. else
  1050. SetSkin( skinDefault );
  1051. }
  1052. idMoveableItem::ReadFromSnapshot( msg );
  1053. }
  1054. /*
  1055. ================
  1056. idItemTeam::UpdateGuis
  1057. Update all client's huds wrt the flag status.
  1058. ================
  1059. */
  1060. void idItemTeam::UpdateGuis( void ) {
  1061. idPlayer *player;
  1062. for ( int i = 0; i < gameLocal.numClients; i++ ) {
  1063. player = static_cast<idPlayer *>( gameLocal.entities[ i ] );
  1064. if ( player == NULL || player->hud == NULL )
  1065. continue;
  1066. player->hud->SetStateInt( "red_flagstatus", gameLocal.mpGame.GetFlagStatus( 0 ) );
  1067. player->hud->SetStateInt( "blue_flagstatus", gameLocal.mpGame.GetFlagStatus( 1 ) );
  1068. player->hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints( 0 ) );
  1069. player->hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints( 1 ) );
  1070. }
  1071. }
  1072. /*
  1073. ================
  1074. idItemTeam::Present
  1075. ================
  1076. */
  1077. void idItemTeam::Present( void ) {
  1078. // hide the flag for localplayer if in first person
  1079. if ( carried && GetBindMaster() ) {
  1080. idPlayer * player = static_cast<idPlayer *>( GetBindMaster() );
  1081. if ( player == gameLocal.GetLocalPlayer() && !pm_thirdPerson.GetBool() ) {
  1082. FreeModelDef();
  1083. BecomeActive( TH_UPDATEVISUALS );
  1084. return;
  1085. }
  1086. }
  1087. idEntity::Present();
  1088. }
  1089. #endif
  1090. /*
  1091. ===============================================================================
  1092. idObjective
  1093. ===============================================================================
  1094. */
  1095. CLASS_DECLARATION( idItem, idObjective )
  1096. EVENT( EV_Activate, idObjective::Event_Trigger )
  1097. EVENT( EV_HideObjective, idObjective::Event_HideObjective )
  1098. EVENT( EV_GetPlayerPos, idObjective::Event_GetPlayerPos )
  1099. EVENT( EV_CamShot, idObjective::Event_CamShot )
  1100. END_CLASS
  1101. /*
  1102. ================
  1103. idObjective::idObjective
  1104. ================
  1105. */
  1106. idObjective::idObjective() {
  1107. playerPos.Zero();
  1108. }
  1109. /*
  1110. ================
  1111. idObjective::Save
  1112. ================
  1113. */
  1114. void idObjective::Save( idSaveGame *savefile ) const {
  1115. savefile->WriteVec3( playerPos );
  1116. }
  1117. /*
  1118. ================
  1119. idObjective::Restore
  1120. ================
  1121. */
  1122. void idObjective::Restore( idRestoreGame *savefile ) {
  1123. savefile->ReadVec3( playerPos );
  1124. }
  1125. /*
  1126. ================
  1127. idObjective::Spawn
  1128. ================
  1129. */
  1130. void idObjective::Spawn( void ) {
  1131. Hide();
  1132. if ( cvarSystem->GetCVarBool( "com_makingBuild") ) {
  1133. PostEventMS( &EV_CamShot, 250 );
  1134. }
  1135. }
  1136. /*
  1137. ================
  1138. idObjective::Event_Screenshot
  1139. ================
  1140. */
  1141. void idObjective::Event_CamShot( ) {
  1142. const char *camName;
  1143. idStr shotName = gameLocal.GetMapName();
  1144. shotName.StripFileExtension();
  1145. shotName += "/";
  1146. shotName += spawnArgs.GetString( "screenshot" );
  1147. shotName.SetFileExtension( ".tga" );
  1148. if ( spawnArgs.GetString( "camShot", "", &camName ) ) {
  1149. idEntity *ent = gameLocal.FindEntity( camName );
  1150. if ( ent && ent->cameraTarget ) {
  1151. const renderView_t *view = ent->cameraTarget->GetRenderView();
  1152. renderView_t fullView = *view;
  1153. fullView.width = SCREEN_WIDTH;
  1154. fullView.height = SCREEN_HEIGHT;
  1155. #ifdef _D3XP
  1156. // HACK : always draw sky-portal view if there is one in the map, this isn't real-time
  1157. if ( gameLocal.portalSkyEnt.GetEntity() && g_enablePortalSky.GetBool() ) {
  1158. renderView_t portalView = fullView;
  1159. portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin();
  1160. // setup global fixup projection vars
  1161. if ( 1 ) {
  1162. int vidWidth, vidHeight;
  1163. idVec2 shiftScale;
  1164. renderSystem->GetGLSettings( vidWidth, vidHeight );
  1165. float pot;
  1166. int temp;
  1167. int w = vidWidth;
  1168. for (temp = 1 ; temp < w ; temp<<=1) {
  1169. }
  1170. pot = (float)temp;
  1171. shiftScale.x = (float)w / pot;
  1172. int h = vidHeight;
  1173. for (temp = 1 ; temp < h ; temp<<=1) {
  1174. }
  1175. pot = (float)temp;
  1176. shiftScale.y = (float)h / pot;
  1177. fullView.shaderParms[4] = shiftScale.x;
  1178. fullView.shaderParms[5] = shiftScale.y;
  1179. }
  1180. gameRenderWorld->RenderScene( &portalView );
  1181. renderSystem->CaptureRenderToImage( "_currentRender" );
  1182. }
  1183. #endif
  1184. // draw a view to a texture
  1185. renderSystem->CropRenderSize( 256, 256, true );
  1186. gameRenderWorld->RenderScene( &fullView );
  1187. renderSystem->CaptureRenderToFile( shotName );
  1188. renderSystem->UnCrop();
  1189. }
  1190. }
  1191. }
  1192. /*
  1193. ================
  1194. idObjective::Event_Trigger
  1195. ================
  1196. */
  1197. void idObjective::Event_Trigger( idEntity *activator ) {
  1198. idPlayer *player = gameLocal.GetLocalPlayer();
  1199. if ( player ) {
  1200. //Pickup( player );
  1201. if ( spawnArgs.GetString( "inv_objective", NULL ) ) {
  1202. if ( player && player->hud ) {
  1203. idStr shotName = gameLocal.GetMapName();
  1204. shotName.StripFileExtension();
  1205. shotName += "/";
  1206. shotName += spawnArgs.GetString( "screenshot" );
  1207. shotName.SetFileExtension( ".tga" );
  1208. player->hud->SetStateString( "screenshot", shotName );
  1209. player->hud->SetStateString( "objective", "1" );
  1210. player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) );
  1211. player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) );
  1212. player->GiveObjective( spawnArgs.GetString( "objectivetitle" ), spawnArgs.GetString( "objectivetext" ), shotName );
  1213. // a tad slow but keeps from having to update all objectives in all maps with a name ptr
  1214. for( int i = 0; i < gameLocal.num_entities; i++ ) {
  1215. if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idObjectiveComplete::Type ) ) {
  1216. if ( idStr::Icmp( spawnArgs.GetString( "objectivetitle" ), gameLocal.entities[ i ]->spawnArgs.GetString( "objectivetitle" ) ) == 0 ){
  1217. gameLocal.entities[ i ]->spawnArgs.SetBool( "objEnabled", true );
  1218. break;
  1219. }
  1220. }
  1221. }
  1222. PostEventMS( &EV_GetPlayerPos, 2000 );
  1223. }
  1224. }
  1225. }
  1226. }
  1227. /*
  1228. ================
  1229. idObjective::Event_GetPlayerPos
  1230. ================
  1231. */
  1232. void idObjective::Event_GetPlayerPos() {
  1233. idPlayer *player = gameLocal.GetLocalPlayer();
  1234. if ( player ) {
  1235. playerPos = player->GetPhysics()->GetOrigin();
  1236. PostEventMS( &EV_HideObjective, 100, player );
  1237. }
  1238. }
  1239. /*
  1240. ================
  1241. idObjective::Event_HideObjective
  1242. ================
  1243. */
  1244. void idObjective::Event_HideObjective(idEntity *e) {
  1245. idPlayer *player = gameLocal.GetLocalPlayer();
  1246. if ( player ) {
  1247. idVec3 v = player->GetPhysics()->GetOrigin() - playerPos;
  1248. if ( v.Length() > 64.0f ) {
  1249. player->HideObjective();
  1250. PostEventMS( &EV_Remove, 0 );
  1251. } else {
  1252. PostEventMS( &EV_HideObjective, 100, player );
  1253. }
  1254. }
  1255. }
  1256. /*
  1257. ===============================================================================
  1258. idVideoCDItem
  1259. ===============================================================================
  1260. */
  1261. CLASS_DECLARATION( idItem, idVideoCDItem )
  1262. END_CLASS
  1263. /*
  1264. ================
  1265. idVideoCDItem::Spawn
  1266. ================
  1267. */
  1268. void idVideoCDItem::Spawn( void ) {
  1269. }
  1270. /*
  1271. ================
  1272. idVideoCDItem::GiveToPlayer
  1273. ================
  1274. */
  1275. bool idVideoCDItem::GiveToPlayer( idPlayer *player ) {
  1276. idStr str = spawnArgs.GetString( "video" );
  1277. if ( player && str.Length() ) {
  1278. player->GiveVideo( str, &spawnArgs );
  1279. }
  1280. return true;
  1281. }
  1282. /*
  1283. ===============================================================================
  1284. idPDAItem
  1285. ===============================================================================
  1286. */
  1287. CLASS_DECLARATION( idItem, idPDAItem )
  1288. END_CLASS
  1289. /*
  1290. ================
  1291. idPDAItem::GiveToPlayer
  1292. ================
  1293. */
  1294. bool idPDAItem::GiveToPlayer(idPlayer *player) {
  1295. const char *str = spawnArgs.GetString( "pda_name" );
  1296. if ( player ) {
  1297. player->GivePDA( str, &spawnArgs );
  1298. }
  1299. return true;
  1300. }
  1301. /*
  1302. ===============================================================================
  1303. idMoveableItem
  1304. ===============================================================================
  1305. */
  1306. CLASS_DECLARATION( idItem, idMoveableItem )
  1307. EVENT( EV_DropToFloor, idMoveableItem::Event_DropToFloor )
  1308. EVENT( EV_Gib, idMoveableItem::Event_Gib )
  1309. END_CLASS
  1310. /*
  1311. ================
  1312. idMoveableItem::idMoveableItem
  1313. ================
  1314. */
  1315. idMoveableItem::idMoveableItem() {
  1316. trigger = NULL;
  1317. smoke = NULL;
  1318. smokeTime = 0;
  1319. #ifdef _D3XP
  1320. nextSoundTime = 0;
  1321. #endif
  1322. #ifdef CTF
  1323. repeatSmoke = false;
  1324. #endif
  1325. }
  1326. /*
  1327. ================
  1328. idMoveableItem::~idMoveableItem
  1329. ================
  1330. */
  1331. idMoveableItem::~idMoveableItem() {
  1332. if ( trigger ) {
  1333. delete trigger;
  1334. }
  1335. }
  1336. /*
  1337. ================
  1338. idMoveableItem::Save
  1339. ================
  1340. */
  1341. void idMoveableItem::Save( idSaveGame *savefile ) const {
  1342. savefile->WriteStaticObject( physicsObj );
  1343. savefile->WriteClipModel( trigger );
  1344. savefile->WriteParticle( smoke );
  1345. savefile->WriteInt( smokeTime );
  1346. #ifdef _D3XP
  1347. savefile->WriteInt( nextSoundTime );
  1348. #endif
  1349. }
  1350. /*
  1351. ================
  1352. idMoveableItem::Restore
  1353. ================
  1354. */
  1355. void idMoveableItem::Restore( idRestoreGame *savefile ) {
  1356. savefile->ReadStaticObject( physicsObj );
  1357. RestorePhysics( &physicsObj );
  1358. savefile->ReadClipModel( trigger );
  1359. savefile->ReadParticle( smoke );
  1360. savefile->ReadInt( smokeTime );
  1361. #ifdef _D3XP
  1362. savefile->ReadInt( nextSoundTime );
  1363. #endif
  1364. }
  1365. /*
  1366. ================
  1367. idMoveableItem::Spawn
  1368. ================
  1369. */
  1370. void idMoveableItem::Spawn( void ) {
  1371. idTraceModel trm;
  1372. float density, friction, bouncyness, tsize;
  1373. idStr clipModelName;
  1374. idBounds bounds;
  1375. #ifdef _D3XP
  1376. SetTimeState ts( timeGroup );
  1377. #endif
  1378. // create a trigger for item pickup
  1379. spawnArgs.GetFloat( "triggersize", "16.0", tsize );
  1380. trigger = new idClipModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) );
  1381. trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
  1382. trigger->SetContents( CONTENTS_TRIGGER );
  1383. // check if a clip model is set
  1384. spawnArgs.GetString( "clipmodel", "", clipModelName );
  1385. if ( !clipModelName[0] ) {
  1386. clipModelName = spawnArgs.GetString( "model" ); // use the visual model
  1387. }
  1388. // load the trace model
  1389. if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) {
  1390. gameLocal.Error( "idMoveableItem '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() );
  1391. return;
  1392. }
  1393. // if the model should be shrinked
  1394. if ( spawnArgs.GetBool( "clipshrink" ) ) {
  1395. trm.Shrink( CM_CLIP_EPSILON );
  1396. }
  1397. // get rigid body properties
  1398. spawnArgs.GetFloat( "density", "0.5", density );
  1399. density = idMath::ClampFloat( 0.001f, 1000.0f, density );
  1400. spawnArgs.GetFloat( "friction", "0.05", friction );
  1401. friction = idMath::ClampFloat( 0.0f, 1.0f, friction );
  1402. spawnArgs.GetFloat( "bouncyness", "0.6", bouncyness );
  1403. bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness );
  1404. // setup the physics
  1405. physicsObj.SetSelf( this );
  1406. physicsObj.SetClipModel( new idClipModel( trm ), density );
  1407. physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
  1408. physicsObj.SetAxis( GetPhysics()->GetAxis() );
  1409. physicsObj.SetBouncyness( bouncyness );
  1410. physicsObj.SetFriction( 0.6f, 0.6f, friction );
  1411. physicsObj.SetGravity( gameLocal.GetGravity() );
  1412. physicsObj.SetContents( CONTENTS_RENDERMODEL );
  1413. physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
  1414. SetPhysics( &physicsObj );
  1415. smoke = NULL;
  1416. smokeTime = 0;
  1417. #ifdef _D3XP
  1418. nextSoundTime = 0;
  1419. #endif
  1420. const char *smokeName = spawnArgs.GetString( "smoke_trail" );
  1421. if ( *smokeName != '\0' ) {
  1422. smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1423. smokeTime = gameLocal.time;
  1424. BecomeActive( TH_UPDATEPARTICLES );
  1425. }
  1426. #ifdef CTF
  1427. repeatSmoke = spawnArgs.GetBool( "repeatSmoke", "0" );
  1428. #endif
  1429. }
  1430. /*
  1431. ================
  1432. idMoveableItem::Think
  1433. ================
  1434. */
  1435. void idMoveableItem::Think( void ) {
  1436. RunPhysics();
  1437. if ( thinkFlags & TH_PHYSICS ) {
  1438. // update trigger position
  1439. trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity );
  1440. }
  1441. if ( thinkFlags & TH_UPDATEPARTICLES ) {
  1442. if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) {
  1443. #ifdef CTF
  1444. if ( !repeatSmoke ) {
  1445. smokeTime = 0;
  1446. BecomeInactive( TH_UPDATEPARTICLES );
  1447. } else {
  1448. smokeTime = gameLocal.time;
  1449. }
  1450. #else
  1451. smokeTime = 0;
  1452. BecomeInactive( TH_UPDATEPARTICLES );
  1453. #endif
  1454. }
  1455. }
  1456. Present();
  1457. }
  1458. #ifdef _D3XP
  1459. /*
  1460. =================
  1461. idMoveableItem::Collide
  1462. =================
  1463. */
  1464. bool idMoveableItem::Collide( const trace_t &collision, const idVec3 &velocity ) {
  1465. float v, f;
  1466. v = -( velocity * collision.c.normal );
  1467. if ( v > 80 && gameLocal.time > nextSoundTime ) {
  1468. f = v > 200 ? 1.0f : idMath::Sqrt( v - 80 ) * 0.091f;
  1469. if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) {
  1470. // don't set the volume unless there is a bounce sound as it overrides the entire channel
  1471. // which causes footsteps on ai's to not honor their shader parms
  1472. SetSoundVolume( f );
  1473. }
  1474. nextSoundTime = gameLocal.time + 500;
  1475. }
  1476. return false;
  1477. }
  1478. #endif
  1479. /*
  1480. ================
  1481. idMoveableItem::Pickup
  1482. ================
  1483. */
  1484. bool idMoveableItem::Pickup( idPlayer *player ) {
  1485. bool ret = idItem::Pickup( player );
  1486. if ( ret ) {
  1487. trigger->SetContents( 0 );
  1488. }
  1489. return ret;
  1490. }
  1491. /*
  1492. ================
  1493. idMoveableItem::DropItem
  1494. ================
  1495. */
  1496. idEntity *idMoveableItem::DropItem( const char *classname, const idVec3 &origin, const idMat3 &axis, const idVec3 &velocity, int activateDelay, int removeDelay ) {
  1497. idDict args;
  1498. idEntity *item;
  1499. args.Set( "classname", classname );
  1500. args.Set( "dropped", "1" );
  1501. // we sometimes drop idMoveables here, so set 'nodrop' to 1 so that it doesn't get put on the floor
  1502. args.Set( "nodrop", "1" );
  1503. if ( activateDelay ) {
  1504. args.SetBool( "triggerFirst", true );
  1505. }
  1506. gameLocal.SpawnEntityDef( args, &item );
  1507. if ( item ) {
  1508. // set item position
  1509. item->GetPhysics()->SetOrigin( origin );
  1510. item->GetPhysics()->SetAxis( axis );
  1511. item->GetPhysics()->SetLinearVelocity( velocity );
  1512. item->UpdateVisuals();
  1513. if ( activateDelay ) {
  1514. item->PostEventMS( &EV_Activate, activateDelay, item );
  1515. }
  1516. if ( !removeDelay ) {
  1517. removeDelay = 5 * 60 * 1000;
  1518. }
  1519. // always remove a dropped item after 5 minutes in case it dropped to an unreachable location
  1520. item->PostEventMS( &EV_Remove, removeDelay );
  1521. }
  1522. return item;
  1523. }
  1524. /*
  1525. ================
  1526. idMoveableItem::DropItems
  1527. The entity should have the following key/value pairs set:
  1528. "def_drop<type>Item" "item def"
  1529. "drop<type>ItemJoint" "joint name"
  1530. "drop<type>ItemRotation" "pitch yaw roll"
  1531. "drop<type>ItemOffset" "x y z"
  1532. "skin_drop<type>" "skin name"
  1533. To drop multiple items the following key/value pairs can be used:
  1534. "def_drop<type>Item<X>" "item def"
  1535. "drop<type>Item<X>Joint" "joint name"
  1536. "drop<type>Item<X>Rotation" "pitch yaw roll"
  1537. "drop<type>Item<X>Offset" "x y z"
  1538. where <X> is an aribtrary string.
  1539. ================
  1540. */
  1541. void idMoveableItem::DropItems( idAnimatedEntity *ent, const char *type, idList<idEntity *> *list ) {
  1542. const idKeyValue *kv;
  1543. const char *skinName, *c, *jointName;
  1544. idStr key, key2;
  1545. idVec3 origin;
  1546. idMat3 axis;
  1547. idAngles angles;
  1548. const idDeclSkin *skin;
  1549. jointHandle_t joint;
  1550. idEntity *item;
  1551. // drop all items
  1552. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), NULL );
  1553. while ( kv ) {
  1554. c = kv->GetKey().c_str() + kv->GetKey().Length();
  1555. if ( idStr::Icmp( c - 5, "Joint" ) != 0 && idStr::Icmp( c - 8, "Rotation" ) != 0 ) {
  1556. key = kv->GetKey().c_str() + 4;
  1557. key2 = key;
  1558. key += "Joint";
  1559. key2 += "Offset";
  1560. jointName = ent->spawnArgs.GetString( key );
  1561. joint = ent->GetAnimator()->GetJointHandle( jointName );
  1562. if ( !ent->GetJointWorldTransform( joint, gameLocal.time, origin, axis ) ) {
  1563. gameLocal.Warning( "%s refers to invalid joint '%s' on entity '%s'\n", key.c_str(), jointName, ent->name.c_str() );
  1564. origin = ent->GetPhysics()->GetOrigin();
  1565. axis = ent->GetPhysics()->GetAxis();
  1566. }
  1567. if ( g_dropItemRotation.GetString()[0] ) {
  1568. angles.Zero();
  1569. sscanf( g_dropItemRotation.GetString(), "%f %f %f", &angles.pitch, &angles.yaw, &angles.roll );
  1570. } else {
  1571. key = kv->GetKey().c_str() + 4;
  1572. key += "Rotation";
  1573. ent->spawnArgs.GetAngles( key, "0 0 0", angles );
  1574. }
  1575. axis = angles.ToMat3() * axis;
  1576. origin += ent->spawnArgs.GetVector( key2, "0 0 0" );
  1577. item = DropItem( kv->GetValue(), origin, axis, vec3_origin, 0, 0 );
  1578. if ( list && item ) {
  1579. list->Append( item );
  1580. }
  1581. }
  1582. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), kv );
  1583. }
  1584. // change the skin to hide all items
  1585. skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) );
  1586. if ( skinName[0] ) {
  1587. skin = declManager->FindSkin( skinName );
  1588. ent->SetSkin( skin );
  1589. }
  1590. }
  1591. /*
  1592. ======================
  1593. idMoveableItem::WriteToSnapshot
  1594. ======================
  1595. */
  1596. void idMoveableItem::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1597. physicsObj.WriteToSnapshot( msg );
  1598. }
  1599. /*
  1600. ======================
  1601. idMoveableItem::ReadFromSnapshot
  1602. ======================
  1603. */
  1604. void idMoveableItem::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1605. physicsObj.ReadFromSnapshot( msg );
  1606. if ( msg.HasChanged() ) {
  1607. UpdateVisuals();
  1608. }
  1609. }
  1610. /*
  1611. ============
  1612. idMoveableItem::Gib
  1613. ============
  1614. */
  1615. void idMoveableItem::Gib( const idVec3 &dir, const char *damageDefName ) {
  1616. // spawn smoke puff
  1617. const char *smokeName = spawnArgs.GetString( "smoke_gib" );
  1618. if ( *smokeName != '\0' ) {
  1619. const idDeclParticle *smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1620. gameLocal.smokeParticles->EmitSmoke( smoke, gameLocal.time, gameLocal.random.CRandomFloat(), renderEntity.origin, renderEntity.axis, timeGroup /*_D3XP*/ );
  1621. }
  1622. // remove the entity
  1623. PostEventMS( &EV_Remove, 0 );
  1624. }
  1625. /*
  1626. ================
  1627. idMoveableItem::Event_DropToFloor
  1628. ================
  1629. */
  1630. void idMoveableItem::Event_DropToFloor( void ) {
  1631. // the physics will drop the moveable to the floor
  1632. }
  1633. /*
  1634. ============
  1635. idMoveableItem::Event_Gib
  1636. ============
  1637. */
  1638. void idMoveableItem::Event_Gib( const char *damageDefName ) {
  1639. Gib( idVec3( 0, 0, 1 ), damageDefName );
  1640. }
  1641. /*
  1642. ===============================================================================
  1643. idMoveablePDAItem
  1644. ===============================================================================
  1645. */
  1646. CLASS_DECLARATION( idMoveableItem, idMoveablePDAItem )
  1647. END_CLASS
  1648. /*
  1649. ================
  1650. idMoveablePDAItem::GiveToPlayer
  1651. ================
  1652. */
  1653. bool idMoveablePDAItem::GiveToPlayer(idPlayer *player) {
  1654. const char *str = spawnArgs.GetString( "pda_name" );
  1655. if ( player ) {
  1656. player->GivePDA( str, &spawnArgs );
  1657. }
  1658. return true;
  1659. }
  1660. /*
  1661. ===============================================================================
  1662. idItemRemover
  1663. ===============================================================================
  1664. */
  1665. CLASS_DECLARATION( idEntity, idItemRemover )
  1666. EVENT( EV_Activate, idItemRemover::Event_Trigger )
  1667. END_CLASS
  1668. /*
  1669. ================
  1670. idItemRemover::Spawn
  1671. ================
  1672. */
  1673. void idItemRemover::Spawn( void ) {
  1674. }
  1675. /*
  1676. ================
  1677. idItemRemover::RemoveItem
  1678. ================
  1679. */
  1680. void idItemRemover::RemoveItem( idPlayer *player ) {
  1681. const char *remove;
  1682. remove = spawnArgs.GetString( "remove" );
  1683. player->RemoveInventoryItem( remove );
  1684. }
  1685. /*
  1686. ================
  1687. idItemRemover::Event_Trigger
  1688. ================
  1689. */
  1690. void idItemRemover::Event_Trigger( idEntity *activator ) {
  1691. if ( activator->IsType( idPlayer::Type ) ) {
  1692. RemoveItem( static_cast<idPlayer *>(activator) );
  1693. }
  1694. }
  1695. /*
  1696. ===============================================================================
  1697. idObjectiveComplete
  1698. ===============================================================================
  1699. */
  1700. CLASS_DECLARATION( idItemRemover, idObjectiveComplete )
  1701. EVENT( EV_Activate, idObjectiveComplete::Event_Trigger )
  1702. EVENT( EV_HideObjective, idObjectiveComplete::Event_HideObjective )
  1703. EVENT( EV_GetPlayerPos, idObjectiveComplete::Event_GetPlayerPos )
  1704. END_CLASS
  1705. /*
  1706. ================
  1707. idObjectiveComplete::idObjectiveComplete
  1708. ================
  1709. */
  1710. idObjectiveComplete::idObjectiveComplete() {
  1711. playerPos.Zero();
  1712. }
  1713. /*
  1714. ================
  1715. idObjectiveComplete::Save
  1716. ================
  1717. */
  1718. void idObjectiveComplete::Save( idSaveGame *savefile ) const {
  1719. savefile->WriteVec3( playerPos );
  1720. }
  1721. /*
  1722. ================
  1723. idObjectiveComplete::Restore
  1724. ================
  1725. */
  1726. void idObjectiveComplete::Restore( idRestoreGame *savefile ) {
  1727. savefile->ReadVec3( playerPos );
  1728. }
  1729. /*
  1730. ================
  1731. idObjectiveComplete::Spawn
  1732. ================
  1733. */
  1734. void idObjectiveComplete::Spawn( void ) {
  1735. spawnArgs.SetBool( "objEnabled", false );
  1736. Hide();
  1737. }
  1738. /*
  1739. ================
  1740. idObjectiveComplete::Event_Trigger
  1741. ================
  1742. */
  1743. void idObjectiveComplete::Event_Trigger( idEntity *activator ) {
  1744. if ( !spawnArgs.GetBool( "objEnabled" ) ) {
  1745. return;
  1746. }
  1747. idPlayer *player = gameLocal.GetLocalPlayer();
  1748. if ( player ) {
  1749. RemoveItem( player );
  1750. if ( spawnArgs.GetString( "inv_objective", NULL ) ) {
  1751. if ( player->hud ) {
  1752. player->hud->SetStateString( "objective", "2");
  1753. player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) );
  1754. #ifdef _D3XP
  1755. player->hud->SetStateString( "objectivecompletetitle", spawnArgs.GetString( "objectivetitle" ) );
  1756. #else
  1757. player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) );
  1758. #endif
  1759. player->CompleteObjective( spawnArgs.GetString( "objectivetitle" ) );
  1760. PostEventMS( &EV_GetPlayerPos, 2000 );
  1761. }
  1762. }
  1763. }
  1764. }
  1765. /*
  1766. ================
  1767. idObjectiveComplete::Event_GetPlayerPos
  1768. ================
  1769. */
  1770. void idObjectiveComplete::Event_GetPlayerPos() {
  1771. idPlayer *player = gameLocal.GetLocalPlayer();
  1772. if ( player ) {
  1773. playerPos = player->GetPhysics()->GetOrigin();
  1774. PostEventMS( &EV_HideObjective, 100, player );
  1775. }
  1776. }
  1777. /*
  1778. ================
  1779. idObjectiveComplete::Event_HideObjective
  1780. ================
  1781. */
  1782. void idObjectiveComplete::Event_HideObjective( idEntity *e ) {
  1783. idPlayer *player = gameLocal.GetLocalPlayer();
  1784. if ( player ) {
  1785. idVec3 v = player->GetPhysics()->GetOrigin();
  1786. v -= playerPos;
  1787. if ( v.Length() > 64.0f ) {
  1788. player->hud->HandleNamedEvent( "closeObjective" );
  1789. PostEventMS( &EV_Remove, 0 );
  1790. } else {
  1791. PostEventMS( &EV_HideObjective, 100, player );
  1792. }
  1793. }
  1794. }