Item.cpp 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457
  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. #define GRAVITYFLOATSPEED 1
  24. #define GRAVITYFLOATANGULAR 4
  25. /*
  26. ===============================================================================
  27. idItem
  28. ===============================================================================
  29. */
  30. const idEventDef EV_DropToFloor( "<dropToFloor>" );
  31. const idEventDef EV_RespawnItem( "respawn" );
  32. const idEventDef EV_RespawnFx( "<respawnFx>" );
  33. const idEventDef EV_GetPlayerPos( "<getplayerpos>" );
  34. const idEventDef EV_HideObjective( "<hideobjective>", "e" );
  35. const idEventDef EV_CamShot( "<camshot>" );
  36. CLASS_DECLARATION( idEntity, idItem )
  37. EVENT( EV_DropToFloor, idItem::Event_DropToFloor )
  38. EVENT( EV_Touch, idItem::Event_Touch )
  39. EVENT( EV_Activate, idItem::Event_Trigger )
  40. EVENT( EV_RespawnItem, idItem::Event_Respawn )
  41. EVENT( EV_RespawnFx, idItem::Event_RespawnFx )
  42. END_CLASS
  43. /*
  44. ================
  45. idItem::idItem
  46. ================
  47. */
  48. idItem::idItem() {
  49. spin = false;
  50. inView = false;
  51. inViewTime = 0;
  52. lastCycle = 0;
  53. lastRenderViewTime = -1;
  54. itemShellHandle = -1;
  55. shellMaterial = NULL;
  56. orgOrigin.Zero();
  57. canPickUp = true;
  58. fl.networkSync = true;
  59. }
  60. /*
  61. ================
  62. idItem::~idItem
  63. ================
  64. */
  65. idItem::~idItem() {
  66. // remove the highlight shell
  67. if ( itemShellHandle != -1 ) {
  68. gameRenderWorld->FreeEntityDef( itemShellHandle );
  69. }
  70. }
  71. /*
  72. ================
  73. idItem::Save
  74. ================
  75. */
  76. void idItem::Save( idSaveGame *savefile ) const {
  77. savefile->WriteVec3( orgOrigin );
  78. savefile->WriteBool( spin );
  79. savefile->WriteBool( pulse );
  80. savefile->WriteBool( canPickUp );
  81. savefile->WriteMaterial( shellMaterial );
  82. savefile->WriteBool( inView );
  83. savefile->WriteInt( inViewTime );
  84. savefile->WriteInt( lastCycle );
  85. savefile->WriteInt( lastRenderViewTime );
  86. //bc
  87. savefile->WriteBool(spin);
  88. }
  89. /*
  90. ================
  91. idItem::Restore
  92. ================
  93. */
  94. void idItem::Restore( idRestoreGame *savefile ) {
  95. savefile->ReadVec3( orgOrigin );
  96. savefile->ReadBool( spin );
  97. savefile->ReadBool( pulse );
  98. savefile->ReadBool( canPickUp );
  99. savefile->ReadMaterial( shellMaterial );
  100. savefile->ReadBool( inView );
  101. savefile->ReadInt( inViewTime );
  102. savefile->ReadInt( lastCycle );
  103. savefile->ReadInt( lastRenderViewTime );
  104. itemShellHandle = -1;
  105. //bc
  106. savefile->ReadBool(spin);
  107. }
  108. /*
  109. ================
  110. idItem::UpdateRenderEntity
  111. ================
  112. */
  113. bool idItem::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const {
  114. if ( lastRenderViewTime == renderView->time ) {
  115. return false;
  116. }
  117. lastRenderViewTime = renderView->time;
  118. // check for glow highlighting if near the center of the view
  119. idVec3 dir = renderEntity->origin - renderView->vieworg;
  120. dir.Normalize();
  121. float d = dir * renderView->viewaxis[0];
  122. // two second pulse cycle
  123. float cycle = ( renderView->time - inViewTime ) / 2000.0f;
  124. if ( d > 0.94f ) {
  125. if ( !inView ) {
  126. inView = true;
  127. if ( cycle > lastCycle ) {
  128. // restart at the beginning
  129. inViewTime = renderView->time;
  130. cycle = 0.0f;
  131. }
  132. }
  133. } else {
  134. if ( inView ) {
  135. inView = false;
  136. lastCycle = ceil( cycle );
  137. }
  138. }
  139. // fade down after the last pulse finishes
  140. if ( !inView && cycle > lastCycle ) {
  141. renderEntity->shaderParms[4] = 0.0f;
  142. } else {
  143. // pulse up in 1/4 second
  144. cycle -= (int)cycle;
  145. if ( cycle < 0.1f ) {
  146. renderEntity->shaderParms[4] = cycle * 10.0f;
  147. } else if ( cycle < 0.2f ) {
  148. renderEntity->shaderParms[4] = 1.0f;
  149. } else if ( cycle < 0.3f ) {
  150. renderEntity->shaderParms[4] = 1.0f - ( cycle - 0.2f ) * 10.0f;
  151. } else {
  152. // stay off between pulses
  153. renderEntity->shaderParms[4] = 0.0f;
  154. }
  155. }
  156. // update every single time this is in view
  157. return true;
  158. }
  159. /*
  160. ================
  161. idItem::ModelCallback
  162. ================
  163. */
  164. bool idItem::ModelCallback( renderEntity_t *renderEntity, const renderView_t *renderView ) {
  165. const idItem *ent;
  166. // this may be triggered by a model trace or other non-view related source
  167. if ( !renderView ) {
  168. return false;
  169. }
  170. ent = static_cast<idItem *>(gameLocal.entities[ renderEntity->entityNum ]);
  171. if ( !ent ) {
  172. gameLocal.Error( "idItem::ModelCallback: callback with NULL game entity" );
  173. }
  174. return ent->UpdateRenderEntity( renderEntity, renderView );
  175. }
  176. /*
  177. ================
  178. idItem::Think
  179. ================
  180. */
  181. void idItem::Think( void ) {
  182. if ( thinkFlags & TH_THINK ) {
  183. if ( spin ) {
  184. idAngles ang;
  185. idVec3 org;
  186. ang.pitch = ang.roll = 0.0f;
  187. ang.yaw = ( gameLocal.time & 4095 ) * 360.0f / -4096.0f;
  188. SetAngles( ang );
  189. float scale = 0.005f + entityNumber * 0.00001f;
  190. org = orgOrigin;
  191. org.z += 4.0f + cos( ( gameLocal.time + 2000 ) * scale ) * 4.0f;
  192. SetOrigin( org );
  193. }
  194. }
  195. Present();
  196. }
  197. /*
  198. ================
  199. idItem::Present
  200. ================
  201. */
  202. void idItem::Present( void ) {
  203. idEntity::Present();
  204. if ( !fl.hidden && pulse ) {
  205. // also add a highlight shell model
  206. renderEntity_t shell;
  207. shell = renderEntity;
  208. // we will mess with shader parms when the item is in view
  209. // to give the "item pulse" effect
  210. shell.callback = idItem::ModelCallback;
  211. shell.entityNum = entityNumber;
  212. shell.customShader = shellMaterial;
  213. if ( itemShellHandle == -1 ) {
  214. itemShellHandle = gameRenderWorld->AddEntityDef( &shell );
  215. } else {
  216. gameRenderWorld->UpdateEntityDef( itemShellHandle, &shell );
  217. }
  218. }
  219. }
  220. /*
  221. ================
  222. idItem::Spawn
  223. ================
  224. */
  225. void idItem::Spawn( void ) {
  226. idStr giveTo;
  227. idEntity * ent;
  228. float tsize;
  229. if ( spawnArgs.GetBool( "dropToFloor" ) ) {
  230. PostEventMS( &EV_DropToFloor, 0 );
  231. }
  232. if ( spawnArgs.GetFloat( "triggersize", "0", tsize ) ) {
  233. GetPhysics()->GetClipModel()->LoadModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) );
  234. GetPhysics()->GetClipModel()->Link( gameLocal.clip );
  235. }
  236. if ( spawnArgs.GetBool( "start_off" ) ) {
  237. GetPhysics()->SetContents( 0 );
  238. Hide();
  239. } else {
  240. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  241. }
  242. giveTo = spawnArgs.GetString( "owner" );
  243. if ( giveTo.Length() ) {
  244. ent = gameLocal.FindEntity( giveTo );
  245. if ( !ent ) {
  246. gameLocal.Error( "Item couldn't find owner '%s'", giveTo.c_str() );
  247. }
  248. PostEventMS( &EV_Touch, 0, ent, NULL );
  249. }
  250. spin = false;
  251. #ifdef CTF
  252. // idItemTeam does not rotate and bob
  253. if ( spawnArgs.GetBool( "spin" ) || (gameLocal.isMultiplayer && !this->IsType( idItemTeam::Type ) ) ) {
  254. spin = true;
  255. BecomeActive( TH_THINK );
  256. }
  257. #else
  258. if ( spawnArgs.GetBool( "spin" ) || gameLocal.isMultiplayer ) {
  259. spin = true;
  260. BecomeActive( TH_THINK );
  261. }
  262. #endif
  263. //pulse = !spawnArgs.GetBool( "nopulse" );
  264. //temp hack for tim
  265. pulse = false;
  266. orgOrigin = GetPhysics()->GetOrigin();
  267. canPickUp = !( spawnArgs.GetBool( "triggerFirst" ) || spawnArgs.GetBool( "no_touch" ) );
  268. inViewTime = -1000;
  269. lastCycle = -1;
  270. itemShellHandle = -1;
  271. shellMaterial = declManager->FindMaterial( "itemHighlightShell" );
  272. }
  273. /*
  274. ================
  275. idItem::GetAttributes
  276. ================
  277. */
  278. void idItem::GetAttributes( idDict &attributes ) {
  279. int i;
  280. const idKeyValue *arg;
  281. for( i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
  282. arg = spawnArgs.GetKeyVal( i );
  283. if ( arg->GetKey().Left( 4 ) == "inv_" ) {
  284. attributes.Set( arg->GetKey().Right( arg->GetKey().Length() - 4 ), arg->GetValue() );
  285. }
  286. }
  287. }
  288. /*
  289. ================
  290. idItem::GiveToPlayer
  291. ================
  292. */
  293. bool idItem::GiveToPlayer( idPlayer *player ) {
  294. if ( player == NULL ) {
  295. return false;
  296. }
  297. if ( spawnArgs.GetBool( "inv_carry" ) ) {
  298. return player->GiveInventoryItem( &spawnArgs );
  299. }
  300. return player->GiveItem( this );
  301. //return false;
  302. }
  303. /*
  304. ================
  305. idItem::Pickup
  306. ================
  307. */
  308. bool idItem::Pickup( idPlayer *player ) {
  309. if ( !GiveToPlayer( player ) ) {
  310. return false;
  311. }
  312. if ( gameLocal.isServer ) {
  313. ServerSendEvent( EVENT_PICKUP, NULL, false, -1 );
  314. }
  315. // play pickup sound
  316. StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL );
  317. // trigger our targets
  318. ActivateTargets( player );
  319. // clear our contents so the object isn't picked up twice
  320. GetPhysics()->SetContents( 0 );
  321. // hide the model
  322. Hide();
  323. // add the highlight shell
  324. if ( itemShellHandle != -1 ) {
  325. gameRenderWorld->FreeEntityDef( itemShellHandle );
  326. itemShellHandle = -1;
  327. }
  328. float respawn = spawnArgs.GetFloat( "respawn" );
  329. bool dropped = spawnArgs.GetBool( "dropped" );
  330. bool no_respawn = spawnArgs.GetBool( "no_respawn" );
  331. if ( gameLocal.isMultiplayer && respawn == 0.0f ) {
  332. respawn = 20.0f;
  333. }
  334. if ( respawn && !dropped && !no_respawn ) {
  335. const char *sfx = spawnArgs.GetString( "fxRespawn" );
  336. if ( sfx && *sfx ) {
  337. PostEventSec( &EV_RespawnFx, respawn - 0.5f );
  338. }
  339. PostEventSec( &EV_RespawnItem, respawn );
  340. } else if ( !spawnArgs.GetBool( "inv_objective" ) && !no_respawn ) {
  341. // give some time for the pickup sound to play
  342. // FIXME: Play on the owner
  343. if ( !spawnArgs.GetBool( "inv_carry" ) ) {
  344. PostEventMS( &EV_Remove, 5000 );
  345. }
  346. }
  347. BecomeInactive( TH_THINK );
  348. return true;
  349. }
  350. /*
  351. ================
  352. idItem::ClientPredictionThink
  353. ================
  354. */
  355. void idItem::ClientPredictionThink( void ) {
  356. // only think forward because the state is not synced through snapshots
  357. if ( !gameLocal.isNewFrame ) {
  358. return;
  359. }
  360. Think();
  361. }
  362. /*
  363. ================
  364. idItem::WriteFromSnapshot
  365. ================
  366. */
  367. void idItem::WriteToSnapshot( idBitMsgDelta &msg ) const {
  368. msg.WriteBits( IsHidden(), 1 );
  369. }
  370. /*
  371. ================
  372. idItem::ReadFromSnapshot
  373. ================
  374. */
  375. void idItem::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  376. if ( msg.ReadBits( 1 ) ) {
  377. Hide();
  378. } else {
  379. Show();
  380. }
  381. }
  382. /*
  383. ================
  384. idItem::ClientReceiveEvent
  385. ================
  386. */
  387. bool idItem::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  388. switch( event ) {
  389. case EVENT_PICKUP: {
  390. // play pickup sound
  391. StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL );
  392. // hide the model
  393. Hide();
  394. // remove the highlight shell
  395. if ( itemShellHandle != -1 ) {
  396. gameRenderWorld->FreeEntityDef( itemShellHandle );
  397. itemShellHandle = -1;
  398. }
  399. return true;
  400. }
  401. case EVENT_RESPAWN: {
  402. Event_Respawn();
  403. return true;
  404. }
  405. case EVENT_RESPAWNFX: {
  406. Event_RespawnFx();
  407. return true;
  408. }
  409. default: {
  410. return idEntity::ClientReceiveEvent( event, time, msg );
  411. }
  412. }
  413. return false;
  414. }
  415. /*
  416. ================
  417. idItem::Event_DropToFloor
  418. ================
  419. */
  420. void idItem::Event_DropToFloor( void ) {
  421. trace_t trace;
  422. // don't drop the floor if bound to another entity
  423. if ( GetBindMaster() != NULL && GetBindMaster() != this ) {
  424. return;
  425. }
  426. gameLocal.clip.TraceBounds( trace, renderEntity.origin, renderEntity.origin - idVec3( 0, 0, 64 ), renderEntity.bounds, MASK_SOLID | CONTENTS_CORPSE, this );
  427. SetOrigin( trace.endpos );
  428. }
  429. /*
  430. ================
  431. idItem::Event_Touch
  432. ================
  433. */
  434. void idItem::Event_Touch( idEntity *other, trace_t *trace ) {
  435. if ( !other->IsType( idPlayer::Type ) ) {
  436. return;
  437. }
  438. if ( !canPickUp ) {
  439. return;
  440. }
  441. Pickup( static_cast<idPlayer *>(other) );
  442. }
  443. /*
  444. ================
  445. idItem::Event_Trigger
  446. ================
  447. */
  448. void idItem::Event_Trigger( idEntity *activator ) {
  449. if ( !canPickUp && spawnArgs.GetBool( "triggerFirst" ) ) {
  450. canPickUp = true;
  451. return;
  452. }
  453. if ( activator && activator->IsType( idPlayer::Type ) ) {
  454. Pickup( static_cast<idPlayer *>( activator ) );
  455. }
  456. }
  457. /*
  458. ================
  459. idItem::Event_Respawn
  460. ================
  461. */
  462. void idItem::Event_Respawn( void ) {
  463. if ( gameLocal.isServer ) {
  464. ServerSendEvent( EVENT_RESPAWN, NULL, false, -1 );
  465. }
  466. BecomeActive( TH_THINK );
  467. Show();
  468. inViewTime = -1000;
  469. lastCycle = -1;
  470. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  471. SetOrigin( orgOrigin );
  472. StartSound( "snd_respawn", SND_CHANNEL_ITEM, 0, false, NULL );
  473. CancelEvents( &EV_RespawnItem ); // don't double respawn
  474. }
  475. /*
  476. ================
  477. idItem::Event_RespawnFx
  478. ================
  479. */
  480. void idItem::Event_RespawnFx( void ) {
  481. if ( gameLocal.isServer ) {
  482. ServerSendEvent( EVENT_RESPAWNFX, NULL, false, -1 );
  483. }
  484. const char *sfx = spawnArgs.GetString( "fxRespawn" );
  485. if ( sfx && *sfx ) {
  486. idEntityFx::StartFx( sfx, NULL, NULL, this, true );
  487. }
  488. }
  489. /*
  490. ===============================================================================
  491. idItemPowerup
  492. ===============================================================================
  493. */
  494. /*
  495. ===============
  496. idItemPowerup
  497. ===============
  498. */
  499. CLASS_DECLARATION( idItem, idItemPowerup )
  500. END_CLASS
  501. /*
  502. ================
  503. idItemPowerup::idItemPowerup
  504. ================
  505. */
  506. idItemPowerup::idItemPowerup() {
  507. time = 0;
  508. type = 0;
  509. }
  510. /*
  511. ================
  512. idItemPowerup::Save
  513. ================
  514. */
  515. void idItemPowerup::Save( idSaveGame *savefile ) const {
  516. savefile->WriteInt( time );
  517. savefile->WriteInt( type );
  518. }
  519. /*
  520. ================
  521. idItemPowerup::Restore
  522. ================
  523. */
  524. void idItemPowerup::Restore( idRestoreGame *savefile ) {
  525. savefile->ReadInt( time );
  526. savefile->ReadInt( type );
  527. }
  528. /*
  529. ================
  530. idItemPowerup::Spawn
  531. ================
  532. */
  533. void idItemPowerup::Spawn( void ) {
  534. time = spawnArgs.GetInt( "time", "30" );
  535. type = spawnArgs.GetInt( "type", "0" );
  536. }
  537. /*
  538. ================
  539. idItemPowerup::GiveToPlayer
  540. ================
  541. */
  542. bool idItemPowerup::GiveToPlayer( idPlayer *player ) {
  543. if ( player->spectating ) {
  544. return false;
  545. }
  546. player->GivePowerUp( type, time * 1000 );
  547. return true;
  548. }
  549. #ifdef CTF
  550. /*
  551. ===============================================================================
  552. idItemTeam
  553. Used for flags in Capture the Flag
  554. ===============================================================================
  555. */
  556. // temporarely removed these events
  557. const idEventDef EV_FlagReturn( "flagreturn", "e" );
  558. const idEventDef EV_TakeFlag( "takeflag", "e" );
  559. const idEventDef EV_DropFlag( "dropflag", "d" );
  560. const idEventDef EV_FlagCapture( "flagcapture" );
  561. CLASS_DECLARATION( idItem, idItemTeam )
  562. EVENT( EV_FlagReturn, idItemTeam::Event_FlagReturn )
  563. EVENT( EV_TakeFlag, idItemTeam::Event_TakeFlag )
  564. EVENT( EV_DropFlag, idItemTeam::Event_DropFlag )
  565. EVENT( EV_FlagCapture, idItemTeam::Event_FlagCapture )
  566. END_CLASS
  567. /*
  568. ===============
  569. idItemTeam::idItemTeam
  570. ===============
  571. */
  572. idItemTeam::idItemTeam() {
  573. team = -1;
  574. carried = false;
  575. dropped = false;
  576. lastDrop = 0;
  577. itemGlowHandle = -1;
  578. skinDefault = NULL;
  579. skinCarried = NULL;
  580. scriptTaken = NULL;
  581. scriptDropped = NULL;
  582. scriptReturned = NULL;
  583. scriptCaptured = NULL;
  584. lastNuggetDrop = 0;
  585. nuggetName = 0;
  586. }
  587. /*
  588. ===============
  589. idItemTeam::~idItemTeam
  590. ===============
  591. */
  592. idItemTeam::~idItemTeam() {
  593. FreeLightDef();
  594. }
  595. /*
  596. ===============
  597. idItemTeam::Spawn
  598. ===============
  599. */
  600. void idItemTeam::Spawn( void ) {
  601. team = spawnArgs.GetInt( "team" );
  602. returnOrigin = GetPhysics()->GetOrigin() + idVec3( 0, 0, 20 );
  603. returnAxis = GetPhysics()->GetAxis();
  604. BecomeActive( TH_THINK );
  605. const char * skinName;
  606. skinName = spawnArgs.GetString( "skin", "" );
  607. if ( skinName[0] )
  608. skinDefault = declManager->FindSkin( skinName );
  609. skinName = spawnArgs.GetString( "skin_carried", "" );
  610. if ( skinName[0] )
  611. skinCarried = declManager->FindSkin( skinName );
  612. nuggetName = spawnArgs.GetString( "nugget_name", "" );
  613. if ( !nuggetName[0] ) {
  614. nuggetName = NULL;
  615. }
  616. scriptTaken = LoadScript( "script_taken" );
  617. scriptDropped = LoadScript( "script_dropped" );
  618. scriptReturned = LoadScript( "script_returned" );
  619. scriptCaptured = LoadScript( "script_captured" );
  620. /* Spawn attached dlight */
  621. /*
  622. idDict args;
  623. idVec3 lightOffset( 0.0f, 20.0f, 0.0f );
  624. // Set up the flag's dynamic light
  625. memset( &itemGlow, 0, sizeof( itemGlow ) );
  626. itemGlow.axis = mat3_identity;
  627. itemGlow.lightRadius.x = 128.0f;
  628. itemGlow.lightRadius.y = itemGlow.lightRadius.z = itemGlow.lightRadius.x;
  629. itemGlow.noShadows = true;
  630. itemGlow.pointLight = true;
  631. itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f;
  632. itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f;
  633. itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f;
  634. itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f;
  635. // Select a shader based on the team
  636. if ( team == 0 )
  637. itemGlow.shader = declManager->FindMaterial( "lights/redflag" );
  638. else
  639. itemGlow.shader = declManager->FindMaterial( "lights/blueflag" );
  640. */
  641. idMoveableItem::Spawn();
  642. physicsObj.SetContents( 0 );
  643. physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
  644. physicsObj.SetGravity( idVec3( 0, 0, spawnArgs.GetInt("gravity", "-30" ) ) );
  645. }
  646. /*
  647. ===============
  648. idItemTeam::LoadScript
  649. ===============
  650. */
  651. function_t * idItemTeam::LoadScript( char * script ) {
  652. function_t * function = NULL;
  653. idStr funcname = spawnArgs.GetString( script, "" );
  654. if ( funcname.Length() ) {
  655. function = gameLocal.program.FindFunction( funcname );
  656. if ( function == NULL ) {
  657. #ifdef _DEBUG
  658. gameLocal.Warning( "idItemTeam '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() );
  659. #endif
  660. }
  661. }
  662. return function;
  663. }
  664. /*
  665. ===============
  666. idItemTeam::Think
  667. ===============
  668. */
  669. void idItemTeam::Think( void ) {
  670. idMoveableItem::Think();
  671. TouchTriggers();
  672. // TODO : only update on updatevisuals
  673. /*idVec3 offset( 0.0f, 0.0f, 20.0f );
  674. itemGlow.origin = GetPhysics()->GetOrigin() + offset;
  675. if ( itemGlowHandle == -1 ) {
  676. itemGlowHandle = gameRenderWorld->AddLightDef( &itemGlow );
  677. } else {
  678. gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );
  679. }*/
  680. #if 1
  681. // should only the server do this?
  682. if ( gameLocal.isServer && nuggetName && carried && ( !lastNuggetDrop || (gameLocal.time - lastNuggetDrop) > spawnArgs.GetInt("nugget_frequency") ) ) {
  683. SpawnNugget( GetPhysics()->GetOrigin() );
  684. lastNuggetDrop = gameLocal.time;
  685. }
  686. #endif
  687. // return dropped flag after si_flagDropTimeLimit seconds
  688. if ( dropped && !carried && lastDrop != 0 && (gameLocal.time - lastDrop) > ( si_flagDropTimeLimit.GetInteger()*1000 ) ) {
  689. Return(); // return flag after 30 seconds on ground
  690. return;
  691. }
  692. }
  693. /*
  694. ===============
  695. idItemTeam::Pickup
  696. ===============
  697. */
  698. bool idItemTeam::Pickup( idPlayer *player ) {
  699. if ( !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */
  700. return false;
  701. if ( gameLocal.mpGame.GetGameState() == idMultiplayerGame::WARMUP ||
  702. gameLocal.mpGame.GetGameState() == idMultiplayerGame::COUNTDOWN )
  703. return false;
  704. // wait 2 seconds after drop before beeing picked up again
  705. if ( lastDrop != 0 && (gameLocal.time - lastDrop) < spawnArgs.GetInt("pickupDelay", "500") )
  706. return false;
  707. if ( carried == false && player->team != this->team ) {
  708. PostEventMS( &EV_TakeFlag, 0, player );
  709. return true;
  710. } else if ( carried == false && dropped == true && player->team == this->team ) {
  711. gameLocal.mpGame.PlayerScoreCTF( player->entityNumber, 5 );
  712. // return flag
  713. PostEventMS( &EV_FlagReturn, 0, player );
  714. return false;
  715. }
  716. return false;
  717. }
  718. /*
  719. ===============
  720. idItemTeam::ClientReceiveEvent
  721. ===============
  722. */
  723. bool idItemTeam::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  724. gameLocal.DPrintf("ClientRecieveEvent: %i\n", event );
  725. switch ( event ) {
  726. case EVENT_TAKEFLAG: {
  727. idPlayer * player = static_cast<idPlayer *>(gameLocal.entities[ msg.ReadBits( GENTITYNUM_BITS ) ]);
  728. if ( player == NULL ) {
  729. gameLocal.Warning( "NULL player takes flag?\n" );
  730. return false;
  731. }
  732. Event_TakeFlag( player );
  733. }
  734. return true;
  735. case EVENT_DROPFLAG : {
  736. bool death = bool( msg.ReadBits( 1 ) == 1 );
  737. Event_DropFlag( death );
  738. }
  739. return true;
  740. case EVENT_FLAGRETURN : {
  741. Hide();
  742. FreeModelDef();
  743. FreeLightDef();
  744. Event_FlagReturn();
  745. }
  746. return true;
  747. case EVENT_FLAGCAPTURE : {
  748. Hide();
  749. FreeModelDef();
  750. FreeLightDef();
  751. Event_FlagCapture();
  752. }
  753. return true;
  754. };
  755. return false;
  756. }
  757. /*
  758. ================
  759. idItemTeam::Drop
  760. ================
  761. */
  762. void idItemTeam::Drop( bool death )
  763. {
  764. // PostEventMS( &EV_DropFlag, 0, int(death == true) );
  765. // had to remove the delayed drop because of drop flag on disconnect
  766. Event_DropFlag( death );
  767. }
  768. /*
  769. ================
  770. idItemTeam::Return
  771. ================
  772. */
  773. void idItemTeam::Return( idPlayer * player )
  774. {
  775. if ( team != 0 && team != 1 )
  776. return;
  777. // PostEventMS( &EV_FlagReturn, 0 );
  778. Event_FlagReturn();
  779. }
  780. /*
  781. ================
  782. idItemTeam::Capture
  783. ================
  784. */
  785. void idItemTeam::Capture( void )
  786. {
  787. if ( team != 0 && team != 1 )
  788. return;
  789. PostEventMS( &EV_FlagCapture, 0 );
  790. }
  791. /*
  792. ================
  793. idItemTeam::PrivateReturn
  794. ================
  795. */
  796. void idItemTeam::PrivateReturn( void )
  797. {
  798. Unbind();
  799. if ( gameLocal.isServer && carried && !dropped ) {
  800. int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team );
  801. if ( playerIdx != -1 ) {
  802. idPlayer * player = static_cast<idPlayer*>( gameLocal.entities[ playerIdx ] );
  803. player->carryingFlag = false;
  804. } else {
  805. gameLocal.Warning( "BUG: carried flag has no carrier before return" );
  806. }
  807. }
  808. dropped = false;
  809. carried = false;
  810. SetOrigin( returnOrigin );
  811. SetAxis( returnAxis );
  812. trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity );
  813. SetSkin( skinDefault );
  814. // Turn off the light
  815. /*itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f;
  816. itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f;
  817. itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f;
  818. itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f;
  819. if ( itemGlowHandle != -1 )
  820. gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/
  821. GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) );
  822. GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) );
  823. }
  824. /*
  825. ================
  826. idItemTeam::Event_TakeFlag
  827. ================
  828. */
  829. void idItemTeam::Event_TakeFlag( idPlayer * player ) {
  830. gameLocal.DPrintf("Event_TakeFlag()!\n");
  831. if ( gameLocal.isServer ) {
  832. idBitMsg msg;
  833. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  834. // Send the event
  835. msg.Init( msgBuf, sizeof( msgBuf ) );
  836. msg.BeginWriting();
  837. msg.WriteBits( player->entityNumber, GENTITYNUM_BITS );
  838. ServerSendEvent( EVENT_TAKEFLAG, &msg, false, -1 );
  839. gameLocal.mpGame.PlayTeamSound( player->team, SND_FLAG_TAKEN_THEIRS );
  840. gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_TAKEN_YOURS );
  841. gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGTAKEN, team, player->entityNumber );
  842. // dont drop a nugget RIGHT away
  843. lastNuggetDrop = gameLocal.time - gameLocal.random.RandomInt( 1000 );
  844. }
  845. BindToJoint( player, g_flagAttachJoint.GetString(), true );
  846. idVec3 origin( g_flagAttachOffsetX.GetFloat(), g_flagAttachOffsetY.GetFloat(), g_flagAttachOffsetZ.GetFloat() );
  847. idAngles angle( g_flagAttachAngleX.GetFloat(), g_flagAttachAngleY.GetFloat(), g_flagAttachAngleZ.GetFloat() );
  848. SetAngles( angle );
  849. SetOrigin( origin );
  850. // Turn the light on
  851. /*itemGlow.shaderParms[ SHADERPARM_RED ] = 1.0f;
  852. itemGlow.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
  853. itemGlow.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
  854. itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 1.0f;
  855. if ( itemGlowHandle != -1 )
  856. gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/
  857. if ( scriptTaken ) {
  858. idThread *thread = new idThread();
  859. thread->CallFunction( scriptTaken, false );
  860. thread->DelayedStart( 0 );
  861. }
  862. dropped = false;
  863. carried = true;
  864. player->carryingFlag = true;
  865. SetSkin( skinCarried );
  866. UpdateVisuals();
  867. UpdateGuis();
  868. if ( gameLocal.isServer ) {
  869. if ( team == 0 )
  870. gameLocal.mpGame.player_red_flag = player->entityNumber;
  871. else
  872. gameLocal.mpGame.player_blue_flag = player->entityNumber;
  873. }
  874. }
  875. /*
  876. ================
  877. idItemTeam::Event_DropFlag
  878. ================
  879. */
  880. void idItemTeam::Event_DropFlag( bool death ) {
  881. gameLocal.DPrintf("Event_DropFlag()!\n");
  882. if ( gameLocal.isServer ) {
  883. idBitMsg msg;
  884. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  885. // Send the event
  886. msg.Init( msgBuf, sizeof( msgBuf ) );
  887. msg.BeginWriting();
  888. msg.WriteBits( death, 1 );
  889. ServerSendEvent( EVENT_DROPFLAG, &msg, false, -1 );
  890. if ( gameLocal.mpGame.IsFlagMsgOn() ) {
  891. gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_DROPPED_THEIRS );
  892. gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_DROPPED_YOURS );
  893. gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGDROP, team );
  894. }
  895. }
  896. lastDrop = gameLocal.time;
  897. BecomeActive( TH_THINK );
  898. Show();
  899. if ( death )
  900. GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) );
  901. else
  902. GetPhysics()->SetLinearVelocity( idVec3(0, 0, 20) );
  903. GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) );
  904. // GetPhysics()->SetLinearVelocity( ( GetPhysics()->GetLinearVelocity() * GetBindMaster()->GetPhysics()->GetAxis() ) + GetBindMaster()->GetPhysics()->GetLinearVelocity() );
  905. if ( GetBindMaster() ) {
  906. const idBounds bounds = GetPhysics()->GetBounds();
  907. idVec3 origin = GetBindMaster()->GetPhysics()->GetOrigin() + idVec3(0, 0, ( bounds[1].z-bounds[0].z )*0.6f );
  908. Unbind();
  909. SetOrigin( origin );
  910. }
  911. idAngles angle = GetPhysics()->GetAxis().ToAngles();
  912. angle.roll = 0;
  913. angle.pitch = 0;
  914. SetAxis( angle.ToMat3() );
  915. dropped = true;
  916. carried = false;
  917. if ( scriptDropped ) {
  918. idThread *thread = new idThread();
  919. thread->CallFunction( scriptDropped, false );
  920. thread->DelayedStart( 0 );
  921. }
  922. SetSkin( skinDefault );
  923. UpdateVisuals();
  924. UpdateGuis();
  925. if ( gameLocal.isServer ) {
  926. if ( team == 0 )
  927. gameLocal.mpGame.player_red_flag = -1;
  928. else
  929. gameLocal.mpGame.player_blue_flag = -1;
  930. }
  931. }
  932. /*
  933. ================
  934. idItemTeam::Event_FlagReturn
  935. ================
  936. */
  937. void idItemTeam::Event_FlagReturn( idPlayer * player ) {
  938. gameLocal.DPrintf("Event_FlagReturn()!\n");
  939. if ( gameLocal.isServer ) {
  940. ServerSendEvent( EVENT_FLAGRETURN, NULL, false, -1 );
  941. if ( gameLocal.mpGame.IsFlagMsgOn() ) {
  942. gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_RETURN );
  943. gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_RETURN );
  944. int entitynum = 255;
  945. if ( player ) {
  946. entitynum = player->entityNumber;
  947. }
  948. gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGRETURN, team, entitynum );
  949. }
  950. }
  951. BecomeActive( TH_THINK );
  952. Show();
  953. PrivateReturn();
  954. if ( scriptReturned ) {
  955. idThread *thread = new idThread();
  956. thread->CallFunction( scriptReturned, false );
  957. thread->DelayedStart( 0 );
  958. }
  959. UpdateVisuals();
  960. UpdateGuis();
  961. // Present();
  962. if ( gameLocal.isServer ) {
  963. if ( team == 0 )
  964. gameLocal.mpGame.player_red_flag = -1;
  965. else
  966. gameLocal.mpGame.player_blue_flag = -1;
  967. }
  968. }
  969. /*
  970. ================
  971. idItemTeam::Event_FlagCapture
  972. ================
  973. */
  974. void idItemTeam::Event_FlagCapture( void ) {
  975. gameLocal.DPrintf("Event_FlagCapture()!\n");
  976. if ( gameLocal.isServer ) {
  977. ServerSendEvent( EVENT_FLAGCAPTURE, NULL, false, -1 );
  978. gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_CAPTURED_THEIRS );
  979. gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_CAPTURED_YOURS );
  980. gameLocal.mpGame.TeamScoreCTF( 1-team, 1 );
  981. int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team );
  982. if ( playerIdx != -1 ) {
  983. gameLocal.mpGame.PlayerScoreCTF( playerIdx, 10 );
  984. } else {
  985. playerIdx = 255;
  986. }
  987. gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGCAPTURE, team, playerIdx );
  988. }
  989. BecomeActive( TH_THINK );
  990. Show();
  991. PrivateReturn();
  992. if ( scriptCaptured ) {
  993. idThread *thread = new idThread();
  994. thread->CallFunction( scriptCaptured, false );
  995. thread->DelayedStart( 0 );
  996. }
  997. UpdateVisuals();
  998. UpdateGuis();
  999. if ( gameLocal.isServer ) {
  1000. if ( team == 0 )
  1001. gameLocal.mpGame.player_red_flag = -1;
  1002. else
  1003. gameLocal.mpGame.player_blue_flag = -1;
  1004. }
  1005. }
  1006. /*
  1007. ================
  1008. idItemTeam::FreeLightDef
  1009. ================
  1010. */
  1011. void idItemTeam::FreeLightDef( void ) {
  1012. if ( itemGlowHandle != -1 ) {
  1013. gameRenderWorld->FreeLightDef( itemGlowHandle );
  1014. itemGlowHandle = -1;
  1015. }
  1016. }
  1017. /*
  1018. ================
  1019. idItemTeam::SpawnNugget
  1020. ================
  1021. */
  1022. void idItemTeam::SpawnNugget( idVec3 pos ) {
  1023. idAngles angle( gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_pitch", "30")), gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_yaw", "360" )), 0 );
  1024. float velocity = float(gameLocal.random.RandomInt( 40 )+15);
  1025. velocity *= spawnArgs.GetFloat("nugget_velocity", "1" );
  1026. idEntity * ent = idMoveableItem::DropItem( nuggetName, pos, GetPhysics()->GetAxis(), angle.ToMat3()*idVec3(velocity, velocity, velocity), 0, spawnArgs.GetInt("nugget_removedelay") );
  1027. idPhysics_RigidBody * physics = static_cast<idPhysics_RigidBody *>( ent->GetPhysics() );
  1028. if ( physics && physics->IsType( idPhysics_RigidBody::Type ) ) {
  1029. physics->DisableImpact();
  1030. }
  1031. }
  1032. /*
  1033. ================
  1034. idItemTeam::Event_FlagCapture
  1035. ================
  1036. */
  1037. void idItemTeam::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1038. msg.WriteBits( carried, 1 );
  1039. msg.WriteBits( dropped, 1 );
  1040. WriteBindToSnapshot( msg );
  1041. idMoveableItem::WriteToSnapshot( msg );
  1042. }
  1043. /*
  1044. ================
  1045. idItemTeam::ReadFromSnapshot
  1046. ================
  1047. */
  1048. void idItemTeam::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1049. carried = msg.ReadBits( 1 ) == 1;
  1050. dropped = msg.ReadBits( 1 ) == 1;
  1051. ReadBindFromSnapshot( msg );
  1052. if ( msg.HasChanged() )
  1053. {
  1054. UpdateGuis();
  1055. if ( carried == true )
  1056. SetSkin( skinCarried );
  1057. else
  1058. SetSkin( skinDefault );
  1059. }
  1060. idMoveableItem::ReadFromSnapshot( msg );
  1061. }
  1062. /*
  1063. ================
  1064. idItemTeam::UpdateGuis
  1065. Update all client's huds wrt the flag status.
  1066. ================
  1067. */
  1068. void idItemTeam::UpdateGuis( void ) {
  1069. idPlayer *player;
  1070. for ( int i = 0; i < gameLocal.numClients; i++ ) {
  1071. player = static_cast<idPlayer *>( gameLocal.entities[ i ] );
  1072. if ( player == NULL || player->hud == NULL )
  1073. continue;
  1074. player->hud->SetStateInt( "red_flagstatus", gameLocal.mpGame.GetFlagStatus( 0 ) );
  1075. player->hud->SetStateInt( "blue_flagstatus", gameLocal.mpGame.GetFlagStatus( 1 ) );
  1076. player->hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints( 0 ) );
  1077. player->hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints( 1 ) );
  1078. }
  1079. }
  1080. /*
  1081. ================
  1082. idItemTeam::Present
  1083. ================
  1084. */
  1085. void idItemTeam::Present( void ) {
  1086. // hide the flag for localplayer if in first person
  1087. if ( carried && GetBindMaster() ) {
  1088. idPlayer * player = static_cast<idPlayer *>( GetBindMaster() );
  1089. if ( player == gameLocal.GetLocalPlayer() && !pm_thirdPerson.GetBool() ) {
  1090. FreeModelDef();
  1091. BecomeActive( TH_UPDATEVISUALS );
  1092. return;
  1093. }
  1094. }
  1095. idEntity::Present();
  1096. }
  1097. #endif
  1098. /*
  1099. ===============================================================================
  1100. idObjective
  1101. ===============================================================================
  1102. */
  1103. CLASS_DECLARATION( idItem, idObjective )
  1104. EVENT( EV_Activate, idObjective::Event_Trigger )
  1105. EVENT( EV_HideObjective, idObjective::Event_HideObjective )
  1106. EVENT( EV_GetPlayerPos, idObjective::Event_GetPlayerPos )
  1107. EVENT( EV_CamShot, idObjective::Event_CamShot )
  1108. END_CLASS
  1109. /*
  1110. ================
  1111. idObjective::idObjective
  1112. ================
  1113. */
  1114. idObjective::idObjective() {
  1115. playerPos.Zero();
  1116. }
  1117. /*
  1118. ================
  1119. idObjective::Save
  1120. ================
  1121. */
  1122. void idObjective::Save( idSaveGame *savefile ) const {
  1123. savefile->WriteVec3( playerPos );
  1124. }
  1125. /*
  1126. ================
  1127. idObjective::Restore
  1128. ================
  1129. */
  1130. void idObjective::Restore( idRestoreGame *savefile ) {
  1131. savefile->ReadVec3( playerPos );
  1132. }
  1133. /*
  1134. ================
  1135. idObjective::Spawn
  1136. ================
  1137. */
  1138. void idObjective::Spawn( void ) {
  1139. Hide();
  1140. if ( cvarSystem->GetCVarBool( "com_makingBuild") ) {
  1141. PostEventMS( &EV_CamShot, 250 );
  1142. }
  1143. }
  1144. /*
  1145. ================
  1146. idObjective::Event_Screenshot
  1147. ================
  1148. */
  1149. void idObjective::Event_CamShot( ) {
  1150. const char *camName;
  1151. idStr shotName = gameLocal.GetMapName();
  1152. shotName.StripFileExtension();
  1153. shotName += "/";
  1154. shotName += spawnArgs.GetString( "screenshot" );
  1155. shotName.SetFileExtension( ".tga" );
  1156. if ( spawnArgs.GetString( "camShot", "", &camName ) ) {
  1157. idEntity *ent = gameLocal.FindEntity( camName );
  1158. if ( ent && ent->cameraTarget ) {
  1159. const renderView_t *view = ent->cameraTarget->GetRenderView();
  1160. renderView_t fullView = *view;
  1161. fullView.width = SCREEN_WIDTH;
  1162. fullView.height = SCREEN_HEIGHT;
  1163. #ifdef _D3XP
  1164. // HACK : always draw sky-portal view if there is one in the map, this isn't real-time
  1165. if ( gameLocal.portalSkyEnt.GetEntity() && g_enablePortalSky.GetBool() ) {
  1166. renderView_t portalView = fullView;
  1167. portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin();
  1168. // setup global fixup projection vars
  1169. if ( 1 ) {
  1170. int vidWidth, vidHeight;
  1171. idVec2 shiftScale;
  1172. renderSystem->GetGLSettings( vidWidth, vidHeight );
  1173. float pot;
  1174. int temp;
  1175. int w = vidWidth;
  1176. for (temp = 1 ; temp < w ; temp<<=1) {
  1177. }
  1178. pot = (float)temp;
  1179. shiftScale.x = (float)w / pot;
  1180. int h = vidHeight;
  1181. for (temp = 1 ; temp < h ; temp<<=1) {
  1182. }
  1183. pot = (float)temp;
  1184. shiftScale.y = (float)h / pot;
  1185. fullView.shaderParms[4] = shiftScale.x;
  1186. fullView.shaderParms[5] = shiftScale.y;
  1187. }
  1188. gameRenderWorld->RenderScene( &portalView );
  1189. renderSystem->CaptureRenderToImage( "_currentRender" );
  1190. }
  1191. #endif
  1192. // draw a view to a texture
  1193. renderSystem->CropRenderSize( 256, 256, true );
  1194. gameRenderWorld->RenderScene( &fullView );
  1195. renderSystem->CaptureRenderToFile( shotName );
  1196. renderSystem->UnCrop();
  1197. }
  1198. }
  1199. }
  1200. /*
  1201. ================
  1202. idObjective::Event_Trigger
  1203. ================
  1204. */
  1205. void idObjective::Event_Trigger( idEntity *activator ) {
  1206. idPlayer *player = gameLocal.GetLocalPlayer();
  1207. if ( player ) {
  1208. //Pickup( player );
  1209. if ( spawnArgs.GetString( "inv_objective", NULL ) ) {
  1210. if ( player && player->hud ) {
  1211. idStr shotName = gameLocal.GetMapName();
  1212. shotName.StripFileExtension();
  1213. shotName += "/";
  1214. shotName += spawnArgs.GetString( "screenshot" );
  1215. shotName.SetFileExtension( ".tga" );
  1216. player->hud->SetStateString( "screenshot", shotName );
  1217. player->hud->SetStateString( "objective", "1" );
  1218. player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) );
  1219. player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) );
  1220. player->GiveObjective( spawnArgs.GetString( "objectivetitle" ), spawnArgs.GetString( "objectivetext" ), shotName );
  1221. // a tad slow but keeps from having to update all objectives in all maps with a name ptr
  1222. for( int i = 0; i < gameLocal.num_entities; i++ ) {
  1223. if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idObjectiveComplete::Type ) ) {
  1224. if ( idStr::Icmp( spawnArgs.GetString( "objectivetitle" ), gameLocal.entities[ i ]->spawnArgs.GetString( "objectivetitle" ) ) == 0 ){
  1225. gameLocal.entities[ i ]->spawnArgs.SetBool( "objEnabled", true );
  1226. break;
  1227. }
  1228. }
  1229. }
  1230. PostEventMS( &EV_GetPlayerPos, 2000 );
  1231. }
  1232. }
  1233. }
  1234. }
  1235. /*
  1236. ================
  1237. idObjective::Event_GetPlayerPos
  1238. ================
  1239. */
  1240. void idObjective::Event_GetPlayerPos() {
  1241. idPlayer *player = gameLocal.GetLocalPlayer();
  1242. if ( player ) {
  1243. playerPos = player->GetPhysics()->GetOrigin();
  1244. PostEventMS( &EV_HideObjective, 100, player );
  1245. }
  1246. }
  1247. /*
  1248. ================
  1249. idObjective::Event_HideObjective
  1250. ================
  1251. */
  1252. void idObjective::Event_HideObjective(idEntity *e) {
  1253. idPlayer *player = gameLocal.GetLocalPlayer();
  1254. if ( player ) {
  1255. idVec3 v = player->GetPhysics()->GetOrigin() - playerPos;
  1256. if ( v.Length() > 64.0f ) {
  1257. player->HideObjective();
  1258. PostEventMS( &EV_Remove, 0 );
  1259. } else {
  1260. PostEventMS( &EV_HideObjective, 100, player );
  1261. }
  1262. }
  1263. }
  1264. /*
  1265. ===============================================================================
  1266. idVideoCDItem
  1267. ===============================================================================
  1268. */
  1269. CLASS_DECLARATION( idItem, idVideoCDItem )
  1270. END_CLASS
  1271. /*
  1272. ================
  1273. idVideoCDItem::Spawn
  1274. ================
  1275. */
  1276. void idVideoCDItem::Spawn( void ) {
  1277. }
  1278. /*
  1279. ================
  1280. idVideoCDItem::GiveToPlayer
  1281. ================
  1282. */
  1283. bool idVideoCDItem::GiveToPlayer( idPlayer *player ) {
  1284. idStr str = spawnArgs.GetString( "video" );
  1285. if ( player && str.Length() ) {
  1286. player->GiveVideo( str, &spawnArgs );
  1287. }
  1288. return true;
  1289. }
  1290. /*
  1291. ===============================================================================
  1292. idPDAItem
  1293. ===============================================================================
  1294. */
  1295. CLASS_DECLARATION( idItem, idPDAItem )
  1296. END_CLASS
  1297. /*
  1298. ================
  1299. idPDAItem::GiveToPlayer
  1300. ================
  1301. */
  1302. bool idPDAItem::GiveToPlayer(idPlayer *player) {
  1303. const char *str = spawnArgs.GetString( "pda_name" );
  1304. if ( player ) {
  1305. player->GivePDA( str, &spawnArgs );
  1306. }
  1307. return true;
  1308. }
  1309. /*
  1310. ===============================================================================
  1311. idMoveableItem
  1312. ===============================================================================
  1313. */
  1314. const idEventDef EV_MoveableItem_updategravity( "updategravity" );
  1315. const idEventDef EV_MoveableItem_toggletrail( "toggletrail", "d" );
  1316. const idEventDef EV_MoveableItem_setFrozen( "setFrozen", "d" );
  1317. CLASS_DECLARATION( idItem, idMoveableItem )
  1318. EVENT( EV_DropToFloor, idMoveableItem::Event_DropToFloor )
  1319. EVENT( EV_Gib, idMoveableItem::Event_Gib )
  1320. EVENT( EV_MoveableItem_updategravity, idMoveableItem::Event_updategravity)
  1321. EVENT( EV_MoveableItem_toggletrail, idMoveableItem::Event_ToggleTrail )
  1322. EVENT( EV_MoveableItem_setFrozen, idMoveableItem::Event_setFrozen )
  1323. END_CLASS
  1324. /*
  1325. ================
  1326. idMoveableItem::idMoveableItem
  1327. ================
  1328. */
  1329. idMoveableItem::idMoveableItem() {
  1330. trigger = NULL;
  1331. smoke = NULL;
  1332. smokeTime = 0;
  1333. #ifdef _D3XP
  1334. nextSoundTime = 0;
  1335. #endif
  1336. #ifdef CTF
  1337. repeatSmoke = false;
  1338. #endif
  1339. }
  1340. /*
  1341. ================
  1342. idMoveableItem::~idMoveableItem
  1343. ================
  1344. */
  1345. idMoveableItem::~idMoveableItem() {
  1346. if ( trigger ) {
  1347. delete trigger;
  1348. }
  1349. }
  1350. /*
  1351. ================
  1352. idMoveableItem::Save
  1353. ================
  1354. */
  1355. void idMoveableItem::Save( idSaveGame *savefile ) const {
  1356. savefile->WriteStaticObject( physicsObj );
  1357. savefile->WriteClipModel( trigger );
  1358. savefile->WriteParticle( smoke );
  1359. savefile->WriteInt( smokeTime );
  1360. #ifdef _D3XP
  1361. savefile->WriteInt( nextSoundTime );
  1362. #endif
  1363. //bc
  1364. savefile->WriteInt(frozen);
  1365. savefile->WriteVec3(originalPosition);
  1366. savefile->WriteMat3(originalAngle);
  1367. forcefieldIgnore.Save(savefile);
  1368. savefile->WriteBool(touchTriggers);
  1369. savefile->WriteInt(nextGravityCheck);
  1370. savefile->WriteBool(lastGravityState);
  1371. savefile->WriteInt(maxSmackCount);
  1372. savefile->WriteInt(smackCount);
  1373. }
  1374. /*
  1375. ================
  1376. idMoveableItem::Restore
  1377. ================
  1378. */
  1379. void idMoveableItem::Restore( idRestoreGame *savefile ) {
  1380. savefile->ReadStaticObject( physicsObj );
  1381. RestorePhysics( &physicsObj );
  1382. savefile->ReadClipModel( trigger );
  1383. savefile->ReadParticle( smoke );
  1384. savefile->ReadInt( smokeTime );
  1385. #ifdef _D3XP
  1386. savefile->ReadInt( nextSoundTime );
  1387. #endif
  1388. //bc
  1389. savefile->ReadInt(frozen);
  1390. savefile->ReadVec3(originalPosition);
  1391. savefile->ReadMat3(originalAngle);
  1392. forcefieldIgnore.Restore(savefile);
  1393. savefile->ReadBool(touchTriggers);
  1394. savefile->ReadInt(nextGravityCheck);
  1395. savefile->ReadBool(lastGravityState);
  1396. savefile->ReadInt(maxSmackCount);
  1397. savefile->ReadInt(smackCount);
  1398. }
  1399. /*
  1400. ================
  1401. idMoveableItem::Spawn
  1402. ================
  1403. */
  1404. void idMoveableItem::Spawn( void ) {
  1405. idTraceModel trm;
  1406. float density, friction, bouncyness, tsize;
  1407. idStr clipModelName;
  1408. idBounds bounds;
  1409. #ifdef _D3XP
  1410. SetTimeState ts( timeGroup );
  1411. #endif
  1412. //bc
  1413. touchTriggers = spawnArgs.GetBool("touchTriggers", "0");
  1414. nextGravityCheck = 0;
  1415. lastGravityState = 0;
  1416. // create a trigger for item pickup
  1417. spawnArgs.GetFloat( "triggersize", "16.0", tsize );
  1418. trigger = new idClipModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) );
  1419. trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
  1420. //trigger->SetContents( CONTENTS_TRIGGER ); //BC remove trigger pickup box.
  1421. trigger->SetContents( 0 );
  1422. // check if a clip model is set
  1423. spawnArgs.GetString( "clipmodel", "", clipModelName );
  1424. if ( !clipModelName[0] ) {
  1425. clipModelName = spawnArgs.GetString( "model" ); // use the visual model
  1426. }
  1427. // load the trace model
  1428. if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) {
  1429. gameLocal.Error( "idMoveableItem '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() );
  1430. return;
  1431. }
  1432. // if the model should be shrinked
  1433. if ( spawnArgs.GetBool( "clipshrink" ) ) {
  1434. trm.Shrink( CM_CLIP_EPSILON );
  1435. }
  1436. // get rigid body properties
  1437. spawnArgs.GetFloat( "density", "0.5", density );
  1438. density = idMath::ClampFloat( 0.001f, 1000.0f, density );
  1439. spawnArgs.GetFloat( "friction", "0.05", friction );
  1440. friction = idMath::ClampFloat( 0.0f, 1.0f, friction );
  1441. spawnArgs.GetFloat( "bouncyness", "0.6", bouncyness );
  1442. bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness );
  1443. // setup the physics
  1444. physicsObj.SetSelf( this );
  1445. physicsObj.SetClipModel( new idClipModel( trm ), density );
  1446. physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
  1447. physicsObj.SetAxis( GetPhysics()->GetAxis() );
  1448. physicsObj.SetBouncyness( bouncyness );
  1449. physicsObj.SetFriction( 0.6f, 0.6f, friction );
  1450. physicsObj.SetGravity( idVec3( 0, 0, spawnArgs.GetInt("gravity", "-1066" ) ) );
  1451. //physicsObj.SetGravity( gameLocal.GetGravity() );
  1452. physicsObj.SetContents( CONTENTS_RENDERMODEL );
  1453. physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
  1454. SetPhysics( &physicsObj );
  1455. smoke = NULL;
  1456. smokeTime = 0;
  1457. #ifdef _D3XP
  1458. nextSoundTime = gameLocal.time + 700; //BC just-spawned items do not immediately make clatter noise or break glass.
  1459. #endif
  1460. const char *smokeName = spawnArgs.GetString( "smoke_trail" );
  1461. if ( *smokeName != '\0' ) {
  1462. smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1463. smokeTime = gameLocal.time;
  1464. BecomeActive( TH_UPDATEPARTICLES );
  1465. }
  1466. #ifdef CTF
  1467. repeatSmoke = spawnArgs.GetBool( "repeatSmoke", "0" );
  1468. #endif
  1469. //bc
  1470. smackCount = 0;
  1471. maxSmackCount = spawnArgs.GetInt("smackcount", "0");
  1472. this->originalPosition = this->GetPhysics()->GetOrigin();
  1473. this->originalAngle = this->GetPhysics()->GetAxis();
  1474. this->forcefieldIgnore = NULL;
  1475. //frozen 0 = not frozen. 1 = is frozen. 2 = WAS frozen, but has been picked up, mark for reset during level reset.
  1476. frozen = spawnArgs.GetInt("frozen", "0");
  1477. if (gameLocal.world->spawnArgs.GetBool("vacuum", "0"))
  1478. {
  1479. BecomeActive(TH_THINK);
  1480. }
  1481. //bc idle sound.
  1482. StartSound( "snd_idle", SND_CHANNEL_ITEM, 0, false, NULL );
  1483. }
  1484. void idMoveableItem::Event_setFrozen(int value)
  1485. {
  1486. frozen = value;
  1487. }
  1488. void idMoveableItem::Event_updategravity( void )
  1489. {
  1490. nextGravityCheck = 0;
  1491. }
  1492. void idMoveableItem::Event_ToggleTrail( int value )
  1493. {
  1494. if (value > 0)
  1495. {
  1496. BecomeActive( TH_UPDATEPARTICLES );
  1497. }
  1498. else
  1499. {
  1500. BecomeInactive( TH_UPDATEPARTICLES );
  1501. }
  1502. }
  1503. /*
  1504. ================
  1505. idMoveableItem::Think
  1506. ================
  1507. */
  1508. void idMoveableItem::Think( void ) {
  1509. //BC 12-20-2013 Things move differently in a vacuum.
  1510. if (gameLocal.time > nextGravityCheck && gameLocal.world->spawnArgs.GetBool("vacuum", "0"))
  1511. {
  1512. bool newAirless = false;
  1513. nextGravityCheck = gameLocal.time + 200;
  1514. if ( gameLocal.vacuumAreaNum != -1 ) {
  1515. int num = GetNumPVSAreas();
  1516. if ( num > 0 ) {
  1517. int areaNum;
  1518. // if the player box spans multiple areas, get the area from the origin point instead,
  1519. // otherwise a rotating player box may poke into an outside area
  1520. if ( num == 1 ) {
  1521. const int *pvsAreas = GetPVSAreas();
  1522. areaNum = pvsAreas[0];
  1523. } else {
  1524. areaNum = gameRenderWorld->PointInArea( this->GetPhysics()->GetOrigin() );
  1525. }
  1526. newAirless = gameRenderWorld->AreasAreConnected( gameLocal.vacuumAreaNum, areaNum, PS_BLOCK_AIR );
  1527. }
  1528. }
  1529. if (newAirless != lastGravityState)
  1530. {
  1531. //state has changed.
  1532. if (newAirless)
  1533. {
  1534. physicsObj.SetGravity( vec3_zero );
  1535. //If object is still, then make it float. Else, inherit current velocity.
  1536. idVec3 curVel = physicsObj.GetLinearVelocity();
  1537. if (curVel.Length() <= 0)
  1538. {
  1539. physicsObj.SetLinearVelocity(idVec3(0,0,GRAVITYFLOATSPEED)); //nudge upward when gravity turns off.
  1540. physicsObj.SetAngularVelocity( idVec3(gameLocal.random.CRandomFloat() * GRAVITYFLOATANGULAR,gameLocal.random.CRandomFloat() * GRAVITYFLOATANGULAR,gameLocal.random.CRandomFloat() * GRAVITYFLOATANGULAR));
  1541. }
  1542. }
  1543. else
  1544. {
  1545. physicsObj.SetGravity( gameLocal.GetGravity() ); //return to normal gravity.
  1546. //physicsObj.SetLinearVelocity(idVec3(0,0,-1024));
  1547. //SetPhysics( &physicsObj );
  1548. }
  1549. lastGravityState = newAirless;
  1550. }
  1551. }
  1552. if (frozen == 0 || frozen == 2)
  1553. {
  1554. RunPhysics();
  1555. }
  1556. if (touchTriggers)
  1557. {
  1558. TouchTriggers();
  1559. }
  1560. if ( thinkFlags & TH_PHYSICS ) {
  1561. // update trigger position
  1562. trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity );
  1563. }
  1564. if ( thinkFlags & TH_UPDATEPARTICLES ) {
  1565. if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) {
  1566. #ifdef CTF
  1567. if ( !repeatSmoke ) {
  1568. smokeTime = 0;
  1569. BecomeInactive( TH_UPDATEPARTICLES );
  1570. } else {
  1571. smokeTime = gameLocal.time;
  1572. }
  1573. #else
  1574. smokeTime = 0;
  1575. BecomeInactive( TH_UPDATEPARTICLES );
  1576. #endif
  1577. }
  1578. }
  1579. Present();
  1580. }
  1581. #ifdef _D3XP
  1582. /*
  1583. =================
  1584. idMoveableItem::Collide
  1585. =================
  1586. */
  1587. bool idMoveableItem::Collide( const trace_t &collision, const idVec3 &velocity ) {
  1588. float v, f;
  1589. int smackValue;
  1590. v = -( velocity * collision.c.normal );
  1591. smackValue = spawnArgs.GetInt( "smack", "0" );
  1592. if ( smackValue > 0 && v > smackValue )
  1593. {
  1594. //item is being Smacked. Check if Smacked item is being held.
  1595. idPlayer *localplayer = gameLocal.GetLocalPlayer();
  1596. int frobnum = -1;
  1597. if (localplayer->pickerState >= 2)
  1598. {
  1599. frobnum = localplayer->pickerWeapon.dragEnt.GetEntity()->entityNumber;
  1600. }
  1601. if (frobnum != this->entityNumber)
  1602. {
  1603. localplayer->UseFrob( this, "onSmack" );
  1604. if (maxSmackCount != 0)
  1605. {
  1606. bool shouldDraw = false;
  1607. if (maxSmackCount < 0)
  1608. {
  1609. shouldDraw = true;
  1610. }
  1611. else
  1612. {
  1613. if (smackCount < maxSmackCount)
  1614. {
  1615. shouldDraw = true;
  1616. }
  1617. }
  1618. if (shouldDraw)
  1619. {
  1620. gameLocal.ProjectDecal( collision.c.point, -collision.c.normal, 0.5f, true, spawnArgs.GetInt("smacksize","16"), spawnArgs.GetString("mtr_smack") );
  1621. smackCount++;
  1622. }
  1623. }
  1624. }
  1625. }
  1626. //bc if object hits surface, then frob it. i.e. for soap dispensers.
  1627. int frobSmack = spawnArgs.GetInt("frobsmack", "0");
  1628. if (frobSmack > 0 && v >= frobSmack)
  1629. {
  1630. //common->Printf("v = %f\n", v);
  1631. idPlayer *localplayer = gameLocal.GetLocalPlayer();
  1632. localplayer->UseFrob( this, "onFrob" );
  1633. }
  1634. if ( v > 40 && gameLocal.time > nextSoundTime )
  1635. {
  1636. idEntity *ent;
  1637. idPlayer *localplayer = gameLocal.GetLocalPlayer();
  1638. int frobnum = -1;
  1639. if (localplayer->pickerState >= 2)
  1640. {
  1641. if (localplayer->pickerWeapon.dragEnt.IsValid())
  1642. {
  1643. frobnum = localplayer->pickerWeapon.dragEnt.GetEntity()->entityNumber;
  1644. }
  1645. }
  1646. f = v > 200 ? 1.0f : idMath::Sqrt( v - 80 ) * 0.091f;
  1647. //play bounce sound only after a short grace period after game start, so that stuff settling down doesn't make such a clatter.
  1648. if (gameLocal.time >= 2000)
  1649. {
  1650. if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ))
  1651. {
  1652. // don't set the volume unless there is a bounce sound as it overrides the entire channel
  1653. // which causes footsteps on ai's to not honor their shader parms
  1654. SetSoundVolume( f );
  1655. }
  1656. }
  1657. //BC particle effect.
  1658. const char *smokeName = spawnArgs.GetString( "smoke_bounce" );
  1659. if ( *smokeName != '\0' )
  1660. {
  1661. const idDeclParticle *smokeFly = NULL;
  1662. smokeFly = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1663. if (smokeFly)
  1664. {
  1665. gameLocal.smokeParticles->EmitSmoke( smokeFly, gameLocal.time, 0,
  1666. collision.endpos, collision.endAxis, timeGroup );
  1667. }
  1668. }
  1669. nextSoundTime = gameLocal.time + 300;
  1670. if (frobnum != this->entityNumber)
  1671. {
  1672. ent = gameLocal.entities[ collision.c.entityNum ];
  1673. if ( ent )
  1674. {
  1675. if (ent->IsType( idBrittleFracture::Type ))
  1676. {
  1677. ent->AddForce(this, this->entityNumber, collision.endpos, collision.c.normal);
  1678. }
  1679. else if (ent->IsType( idQGlass::Type ))
  1680. {
  1681. ent->AddForce(this, this->entityNumber, collision.endpos, collision.c.normal);
  1682. }
  1683. else if (ent->IsType( idTrembler::Type))
  1684. {
  1685. static_cast< idTrembler * >( ent )->Event_Touch(NULL, NULL);
  1686. }
  1687. }
  1688. }
  1689. }
  1690. return false;
  1691. }
  1692. #endif
  1693. /*
  1694. ================
  1695. idMoveableItem::Pickup
  1696. ================
  1697. */
  1698. bool idMoveableItem::Pickup( idPlayer *player ) {
  1699. bool ret = idItem::Pickup( player );
  1700. if ( ret ) {
  1701. trigger->SetContents( 0 );
  1702. }
  1703. return ret;
  1704. }
  1705. /*
  1706. ================
  1707. idMoveableItem::DropItem
  1708. ================
  1709. */
  1710. idEntity *idMoveableItem::DropItem( const char *classname, const idVec3 &origin, const idMat3 &axis, const idVec3 &velocity, int activateDelay, int removeDelay ) {
  1711. idDict args;
  1712. idEntity *item;
  1713. args.Set( "classname", classname );
  1714. args.Set( "dropped", "1" );
  1715. // we sometimes drop idMoveables here, so set 'nodrop' to 1 so that it doesn't get put on the floor
  1716. args.Set( "nodrop", "1" );
  1717. if ( activateDelay ) {
  1718. args.SetBool( "triggerFirst", true );
  1719. }
  1720. gameLocal.SpawnEntityDef( args, &item );
  1721. if ( item ) {
  1722. // set item position
  1723. item->GetPhysics()->SetOrigin( origin );
  1724. item->GetPhysics()->SetAxis( axis );
  1725. item->GetPhysics()->SetLinearVelocity( velocity );
  1726. item->UpdateVisuals();
  1727. if ( activateDelay ) {
  1728. item->PostEventMS( &EV_Activate, activateDelay, item );
  1729. }
  1730. if ( !removeDelay ) {
  1731. removeDelay = 5 * 60 * 1000;
  1732. }
  1733. // always remove a dropped item after 5 minutes in case it dropped to an unreachable location
  1734. item->PostEventMS( &EV_Remove, removeDelay );
  1735. }
  1736. return item;
  1737. }
  1738. /*
  1739. ================
  1740. idMoveableItem::DropItems
  1741. The entity should have the following key/value pairs set:
  1742. "def_drop<type>Item" "item def"
  1743. "drop<type>ItemJoint" "joint name"
  1744. "drop<type>ItemRotation" "pitch yaw roll"
  1745. "drop<type>ItemOffset" "x y z"
  1746. "skin_drop<type>" "skin name"
  1747. To drop multiple items the following key/value pairs can be used:
  1748. "def_drop<type>Item<X>" "item def"
  1749. "drop<type>Item<X>Joint" "joint name"
  1750. "drop<type>Item<X>Rotation" "pitch yaw roll"
  1751. "drop<type>Item<X>Offset" "x y z"
  1752. where <X> is an aribtrary string.
  1753. ================
  1754. */
  1755. void idMoveableItem::DropItems( idAnimatedEntity *ent, const char *type, idList<idEntity *> *list ) {
  1756. const idKeyValue *kv;
  1757. const char *skinName, *c, *jointName;
  1758. idStr key, key2;
  1759. idVec3 origin;
  1760. idMat3 axis;
  1761. idAngles angles;
  1762. const idDeclSkin *skin;
  1763. jointHandle_t joint;
  1764. idEntity *item;
  1765. // drop all items
  1766. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), NULL );
  1767. while ( kv ) {
  1768. c = kv->GetKey().c_str() + kv->GetKey().Length();
  1769. if ( idStr::Icmp( c - 5, "Joint" ) != 0 && idStr::Icmp( c - 8, "Rotation" ) != 0 ) {
  1770. key = kv->GetKey().c_str() + 4;
  1771. key2 = key;
  1772. key += "Joint";
  1773. key2 += "Offset";
  1774. jointName = ent->spawnArgs.GetString( key );
  1775. joint = ent->GetAnimator()->GetJointHandle( jointName );
  1776. if ( !ent->GetJointWorldTransform( joint, gameLocal.time, origin, axis ) ) {
  1777. gameLocal.Warning( "%s refers to invalid joint '%s' on entity '%s'\n", key.c_str(), jointName, ent->name.c_str() );
  1778. origin = ent->GetPhysics()->GetOrigin();
  1779. axis = ent->GetPhysics()->GetAxis();
  1780. }
  1781. if ( g_dropItemRotation.GetString()[0] ) {
  1782. angles.Zero();
  1783. sscanf( g_dropItemRotation.GetString(), "%f %f %f", &angles.pitch, &angles.yaw, &angles.roll );
  1784. } else {
  1785. key = kv->GetKey().c_str() + 4;
  1786. key += "Rotation";
  1787. ent->spawnArgs.GetAngles( key, "0 0 0", angles );
  1788. }
  1789. axis = angles.ToMat3() * axis;
  1790. origin += ent->spawnArgs.GetVector( key2, "0 0 0" );
  1791. item = DropItem( kv->GetValue(), origin, axis, vec3_origin, 0, 0 );
  1792. if ( list && item ) {
  1793. list->Append( item );
  1794. }
  1795. }
  1796. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), kv );
  1797. }
  1798. // change the skin to hide all items
  1799. skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) );
  1800. if ( skinName[0] ) {
  1801. skin = declManager->FindSkin( skinName );
  1802. ent->SetSkin( skin );
  1803. }
  1804. }
  1805. /*
  1806. ======================
  1807. idMoveableItem::WriteToSnapshot
  1808. ======================
  1809. */
  1810. void idMoveableItem::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1811. physicsObj.WriteToSnapshot( msg );
  1812. }
  1813. /*
  1814. ======================
  1815. idMoveableItem::ReadFromSnapshot
  1816. ======================
  1817. */
  1818. void idMoveableItem::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1819. physicsObj.ReadFromSnapshot( msg );
  1820. if ( msg.HasChanged() ) {
  1821. UpdateVisuals();
  1822. }
  1823. }
  1824. /*
  1825. ============
  1826. idMoveableItem::Gib
  1827. ============
  1828. */
  1829. void idMoveableItem::Gib( const idVec3 &dir, const char *damageDefName ) {
  1830. // spawn smoke puff
  1831. const char *smokeName = spawnArgs.GetString( "smoke_gib" );
  1832. if ( *smokeName != '\0' ) {
  1833. const idDeclParticle *smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1834. gameLocal.smokeParticles->EmitSmoke( smoke, gameLocal.time, gameLocal.random.CRandomFloat(), renderEntity.origin, renderEntity.axis, timeGroup /*_D3XP*/ );
  1835. }
  1836. // remove the entity
  1837. PostEventMS( &EV_Remove, 0 );
  1838. }
  1839. /*
  1840. ================
  1841. idMoveableItem::Event_DropToFloor
  1842. ================
  1843. */
  1844. void idMoveableItem::Event_DropToFloor( void ) {
  1845. // the physics will drop the moveable to the floor
  1846. }
  1847. /*
  1848. ============
  1849. idMoveableItem::Event_Gib
  1850. ============
  1851. */
  1852. void idMoveableItem::Event_Gib( const char *damageDefName ) {
  1853. Gib( idVec3( 0, 0, 1 ), damageDefName );
  1854. }
  1855. /*
  1856. ===============================================================================
  1857. idMoveablePDAItem
  1858. ===============================================================================
  1859. */
  1860. CLASS_DECLARATION( idMoveableItem, idMoveablePDAItem )
  1861. END_CLASS
  1862. /*
  1863. ================
  1864. idMoveablePDAItem::GiveToPlayer
  1865. ================
  1866. */
  1867. bool idMoveablePDAItem::GiveToPlayer(idPlayer *player) {
  1868. const char *str = spawnArgs.GetString( "pda_name" );
  1869. if ( player ) {
  1870. player->GivePDA( str, &spawnArgs );
  1871. }
  1872. return true;
  1873. }
  1874. /*
  1875. ===============================================================================
  1876. idItemRemover
  1877. ===============================================================================
  1878. */
  1879. CLASS_DECLARATION( idEntity, idItemRemover )
  1880. EVENT( EV_Activate, idItemRemover::Event_Trigger )
  1881. END_CLASS
  1882. /*
  1883. ================
  1884. idItemRemover::Spawn
  1885. ================
  1886. */
  1887. void idItemRemover::Spawn( void ) {
  1888. }
  1889. /*
  1890. ================
  1891. idItemRemover::RemoveItem
  1892. ================
  1893. */
  1894. void idItemRemover::RemoveItem( idPlayer *player ) {
  1895. const char *remove;
  1896. remove = spawnArgs.GetString( "remove" );
  1897. player->RemoveInventoryItem( remove );
  1898. }
  1899. /*
  1900. ================
  1901. idItemRemover::Event_Trigger
  1902. ================
  1903. */
  1904. void idItemRemover::Event_Trigger( idEntity *activator ) {
  1905. if ( activator->IsType( idPlayer::Type ) ) {
  1906. RemoveItem( static_cast<idPlayer *>(activator) );
  1907. }
  1908. }
  1909. /*
  1910. ===============================================================================
  1911. idObjectiveComplete
  1912. ===============================================================================
  1913. */
  1914. CLASS_DECLARATION( idItemRemover, idObjectiveComplete )
  1915. EVENT( EV_Activate, idObjectiveComplete::Event_Trigger )
  1916. EVENT( EV_HideObjective, idObjectiveComplete::Event_HideObjective )
  1917. EVENT( EV_GetPlayerPos, idObjectiveComplete::Event_GetPlayerPos )
  1918. END_CLASS
  1919. /*
  1920. ================
  1921. idObjectiveComplete::idObjectiveComplete
  1922. ================
  1923. */
  1924. idObjectiveComplete::idObjectiveComplete() {
  1925. playerPos.Zero();
  1926. }
  1927. /*
  1928. ================
  1929. idObjectiveComplete::Save
  1930. ================
  1931. */
  1932. void idObjectiveComplete::Save( idSaveGame *savefile ) const {
  1933. savefile->WriteVec3( playerPos );
  1934. }
  1935. /*
  1936. ================
  1937. idObjectiveComplete::Restore
  1938. ================
  1939. */
  1940. void idObjectiveComplete::Restore( idRestoreGame *savefile ) {
  1941. savefile->ReadVec3( playerPos );
  1942. }
  1943. /*
  1944. ================
  1945. idObjectiveComplete::Spawn
  1946. ================
  1947. */
  1948. void idObjectiveComplete::Spawn( void ) {
  1949. spawnArgs.SetBool( "objEnabled", false );
  1950. Hide();
  1951. }
  1952. /*
  1953. ================
  1954. idObjectiveComplete::Event_Trigger
  1955. ================
  1956. */
  1957. void idObjectiveComplete::Event_Trigger( idEntity *activator ) {
  1958. if ( !spawnArgs.GetBool( "objEnabled" ) ) {
  1959. return;
  1960. }
  1961. idPlayer *player = gameLocal.GetLocalPlayer();
  1962. if ( player ) {
  1963. RemoveItem( player );
  1964. if ( spawnArgs.GetString( "inv_objective", NULL ) ) {
  1965. if ( player->hud ) {
  1966. player->hud->SetStateString( "objective", "2");
  1967. player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) );
  1968. #ifdef _D3XP
  1969. player->hud->SetStateString( "objectivecompletetitle", spawnArgs.GetString( "objectivetitle" ) );
  1970. #else
  1971. player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) );
  1972. #endif
  1973. player->CompleteObjective( spawnArgs.GetString( "objectivetitle" ) );
  1974. PostEventMS( &EV_GetPlayerPos, 2000 );
  1975. }
  1976. }
  1977. }
  1978. }
  1979. /*
  1980. ================
  1981. idObjectiveComplete::Event_GetPlayerPos
  1982. ================
  1983. */
  1984. void idObjectiveComplete::Event_GetPlayerPos() {
  1985. idPlayer *player = gameLocal.GetLocalPlayer();
  1986. if ( player ) {
  1987. playerPos = player->GetPhysics()->GetOrigin();
  1988. PostEventMS( &EV_HideObjective, 100, player );
  1989. }
  1990. }
  1991. /*
  1992. ================
  1993. idObjectiveComplete::Event_HideObjective
  1994. ================
  1995. */
  1996. void idObjectiveComplete::Event_HideObjective( idEntity *e ) {
  1997. idPlayer *player = gameLocal.GetLocalPlayer();
  1998. if ( player ) {
  1999. idVec3 v = player->GetPhysics()->GetOrigin();
  2000. v -= playerPos;
  2001. if ( v.Length() > 64.0f ) {
  2002. player->hud->HandleNamedEvent( "closeObjective" );
  2003. PostEventMS( &EV_Remove, 0 );
  2004. } else {
  2005. PostEventMS( &EV_HideObjective, 100, player );
  2006. }
  2007. }
  2008. }