Misc.cpp 101 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. /*
  21. Various utility objects and functions.
  22. */
  23. #include "../idlib/precompiled.h"
  24. #pragma hdrstop
  25. #include "Game_local.h"
  26. const int JUMPPAD_EFFECT_DELAY = 100;
  27. /*
  28. ===============================================================================
  29. idSpawnableEntity
  30. A simple, spawnable entity with a model and no functionable ability of it's own.
  31. For example, it can be used as a placeholder during development, for marking
  32. locations on maps for script, or for simple placed models without any behavior
  33. that can be bound to other entities. Should not be subclassed.
  34. ===============================================================================
  35. */
  36. CLASS_DECLARATION( idEntity, idSpawnableEntity )
  37. END_CLASS
  38. /*
  39. ======================
  40. idSpawnableEntity::Spawn
  41. ======================
  42. */
  43. void idSpawnableEntity::Spawn() {
  44. // this just holds dict information
  45. }
  46. /*
  47. ===============================================================================
  48. idPlayerStart
  49. ===============================================================================
  50. */
  51. const idEventDef EV_TeleportStage( "<TeleportStage>", "e" );
  52. CLASS_DECLARATION( idEntity, idPlayerStart )
  53. EVENT( EV_Activate, idPlayerStart::Event_TeleportPlayer )
  54. EVENT( EV_TeleportStage, idPlayerStart::Event_TeleportStage )
  55. END_CLASS
  56. /*
  57. ===============
  58. idPlayerStart::idPlayerStart
  59. ================
  60. */
  61. idPlayerStart::idPlayerStart( void ) {
  62. teleportStage = 0;
  63. }
  64. /*
  65. ===============
  66. idPlayerStart::Spawn
  67. ================
  68. */
  69. void idPlayerStart::Spawn( void ) {
  70. teleportStage = 0;
  71. }
  72. /*
  73. ================
  74. idPlayerStart::Save
  75. ================
  76. */
  77. void idPlayerStart::Save( idSaveGame *savefile ) const {
  78. savefile->WriteInt( teleportStage );
  79. }
  80. /*
  81. ================
  82. idPlayerStart::Restore
  83. ================
  84. */
  85. void idPlayerStart::Restore( idRestoreGame *savefile ) {
  86. savefile->ReadInt( teleportStage );
  87. }
  88. /*
  89. ================
  90. idPlayerStart::ClientReceiveEvent
  91. ================
  92. */
  93. bool idPlayerStart::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  94. int entityNumber;
  95. switch( event ) {
  96. case EVENT_TELEPORTPLAYER: {
  97. entityNumber = msg.ReadBits( GENTITYNUM_BITS );
  98. idPlayer *player = static_cast<idPlayer *>( gameLocal.entities[entityNumber] );
  99. if ( player != NULL && player->IsType( idPlayer::Type ) ) {
  100. Event_TeleportPlayer( player );
  101. }
  102. return true;
  103. }
  104. default: {
  105. return idEntity::ClientReceiveEvent( event, time, msg );
  106. }
  107. }
  108. return false;
  109. }
  110. /*
  111. ===============
  112. idPlayerStart::Event_TeleportStage
  113. FIXME: add functionality to fx system ( could be done with player scripting too )
  114. ================
  115. */
  116. void idPlayerStart::Event_TeleportStage( idEntity *_player ) {
  117. idPlayer *player;
  118. if ( !_player->IsType( idPlayer::Type ) ) {
  119. common->Warning( "idPlayerStart::Event_TeleportStage: entity is not an idPlayer\n" );
  120. return;
  121. }
  122. player = static_cast<idPlayer*>(_player);
  123. float teleportDelay = spawnArgs.GetFloat( "teleportDelay" );
  124. switch ( teleportStage ) {
  125. case 0:
  126. player->playerView.Flash( colorWhite, 125 );
  127. player->SetInfluenceLevel( INFLUENCE_LEVEL3 );
  128. player->SetInfluenceView( spawnArgs.GetString( "mtr_teleportFx" ), NULL, 0.0f, NULL );
  129. gameSoundWorld->FadeSoundClasses( 0, -20.0f, teleportDelay );
  130. player->StartSound( "snd_teleport_start", SND_CHANNEL_BODY2, 0, false, NULL );
  131. teleportStage++;
  132. PostEventSec( &EV_TeleportStage, teleportDelay, player );
  133. break;
  134. case 1:
  135. gameSoundWorld->FadeSoundClasses( 0, 0.0f, 0.25f );
  136. teleportStage++;
  137. PostEventSec( &EV_TeleportStage, 0.25f, player );
  138. break;
  139. case 2:
  140. player->SetInfluenceView( NULL, NULL, 0.0f, NULL );
  141. TeleportPlayer( player );
  142. player->StopSound( SND_CHANNEL_BODY2, false );
  143. player->SetInfluenceLevel( INFLUENCE_NONE );
  144. teleportStage = 0;
  145. break;
  146. default:
  147. break;
  148. }
  149. }
  150. /*
  151. ===============
  152. idPlayerStart::TeleportPlayer
  153. ================
  154. */
  155. void idPlayerStart::TeleportPlayer( idPlayer *player ) {
  156. float pushVel = spawnArgs.GetFloat( "push", "300" );
  157. float f = spawnArgs.GetFloat( "visualEffect", "0" );
  158. const char *viewName = spawnArgs.GetString( "visualView", "" );
  159. idEntity *ent = viewName ? gameLocal.FindEntity( viewName ) : NULL;
  160. #ifdef _D3XP
  161. SetTimeState ts( player->timeGroup );
  162. #endif
  163. //BC stop clambering.
  164. player->StopClamber();
  165. if ( f && ent ) {
  166. // place in private camera view for some time
  167. // the entity needs to teleport to where the camera view is to have the PVS right
  168. player->Teleport( ent->GetPhysics()->GetOrigin(), ang_zero, this );
  169. player->StartSound( "snd_teleport_enter", SND_CHANNEL_ANY, 0, false, NULL );
  170. player->SetPrivateCameraView( static_cast<idCamera*>(ent) );
  171. // the player entity knows where to spawn from the previous Teleport call
  172. if ( !gameLocal.isClient ) {
  173. player->PostEventSec( &EV_Player_ExitTeleporter, f );
  174. }
  175. } else {
  176. // direct to exit, Teleport will take care of the killbox
  177. float pitch = spawnArgs.GetFloat("pitch","0");
  178. idAngles ang = GetPhysics()->GetAxis().ToAngles();
  179. ang.pitch = pitch;
  180. player->Teleport( GetPhysics()->GetOrigin(), ang, NULL );
  181. // multiplayer hijacked this entity, so only push the player in multiplayer
  182. if ( gameLocal.isMultiplayer ) {
  183. player->GetPhysics()->SetLinearVelocity( GetPhysics()->GetAxis()[0] * pushVel );
  184. }
  185. }
  186. }
  187. /*
  188. ===============
  189. idPlayerStart::Event_TeleportPlayer
  190. ================
  191. */
  192. void idPlayerStart::Event_TeleportPlayer( idEntity *activator ) {
  193. idPlayer *player;
  194. if ( activator->IsType( idPlayer::Type ) ) {
  195. player = static_cast<idPlayer*>( activator );
  196. } else {
  197. player = gameLocal.GetLocalPlayer();
  198. }
  199. if ( player ) {
  200. if ( spawnArgs.GetBool( "visualFx" ) ) {
  201. teleportStage = 0;
  202. Event_TeleportStage( player );
  203. } else {
  204. if ( gameLocal.isServer ) {
  205. idBitMsg msg;
  206. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  207. msg.Init( msgBuf, sizeof( msgBuf ) );
  208. msg.BeginWriting();
  209. msg.WriteBits( player->entityNumber, GENTITYNUM_BITS );
  210. ServerSendEvent( EVENT_TELEPORTPLAYER, &msg, false, -1 );
  211. }
  212. TeleportPlayer( player );
  213. }
  214. }
  215. }
  216. /*
  217. ===============================================================================
  218. idActivator
  219. ===============================================================================
  220. */
  221. CLASS_DECLARATION( idEntity, idActivator )
  222. EVENT( EV_Activate, idActivator::Event_Activate )
  223. END_CLASS
  224. /*
  225. ===============
  226. idActivator::Save
  227. ================
  228. */
  229. void idActivator::Save( idSaveGame *savefile ) const {
  230. savefile->WriteBool( stay_on );
  231. }
  232. /*
  233. ===============
  234. idActivator::Restore
  235. ================
  236. */
  237. void idActivator::Restore( idRestoreGame *savefile ) {
  238. savefile->ReadBool( stay_on );
  239. if ( stay_on ) {
  240. BecomeActive( TH_THINK );
  241. }
  242. }
  243. /*
  244. ===============
  245. idActivator::Spawn
  246. ================
  247. */
  248. void idActivator::Spawn( void ) {
  249. bool start_off;
  250. spawnArgs.GetBool( "stay_on", "0", stay_on );
  251. spawnArgs.GetBool( "start_off", "0", start_off );
  252. GetPhysics()->SetClipBox( idBounds( vec3_origin ).Expand( 4 ), 1.0f );
  253. GetPhysics()->SetContents( 0 );
  254. if ( !start_off ) {
  255. BecomeActive( TH_THINK );
  256. }
  257. }
  258. /*
  259. ===============
  260. idActivator::Think
  261. ================
  262. */
  263. void idActivator::Think( void ) {
  264. RunPhysics();
  265. if ( thinkFlags & TH_THINK ) {
  266. if ( TouchTriggers() ) {
  267. if ( !stay_on ) {
  268. BecomeInactive( TH_THINK );
  269. }
  270. }
  271. }
  272. Present();
  273. }
  274. /*
  275. ===============
  276. idActivator::Activate
  277. ================
  278. */
  279. void idActivator::Event_Activate( idEntity *activator ) {
  280. if ( thinkFlags & TH_THINK ) {
  281. BecomeInactive( TH_THINK );
  282. } else {
  283. BecomeActive( TH_THINK );
  284. }
  285. }
  286. /*
  287. ===============================================================================
  288. idPathCorner
  289. ===============================================================================
  290. */
  291. CLASS_DECLARATION( idEntity, idPathCorner )
  292. EVENT( AI_RandomPath, idPathCorner::Event_RandomPath )
  293. END_CLASS
  294. /*
  295. =====================
  296. idPathCorner::Spawn
  297. =====================
  298. */
  299. void idPathCorner::Spawn( void ) {
  300. }
  301. /*
  302. =====================
  303. idPathCorner::DrawDebugInfo
  304. =====================
  305. */
  306. void idPathCorner::DrawDebugInfo( void ) {
  307. idEntity *ent;
  308. idBounds bnds( idVec3( -4.0, -4.0f, -8.0f ), idVec3( 4.0, 4.0f, 64.0f ) );
  309. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  310. if ( !ent->IsType( idPathCorner::Type ) ) {
  311. continue;
  312. }
  313. idVec3 org = ent->GetPhysics()->GetOrigin();
  314. gameRenderWorld->DebugBounds( colorRed, bnds, org, 0 );
  315. }
  316. }
  317. /*
  318. ============
  319. idPathCorner::RandomPath
  320. ============
  321. */
  322. idPathCorner *idPathCorner::RandomPath( const idEntity *source, const idEntity *ignore ) {
  323. int i;
  324. int num;
  325. int which;
  326. idEntity *ent;
  327. idPathCorner *path[ MAX_GENTITIES ];
  328. num = 0;
  329. for( i = 0; i < source->targets.Num(); i++ ) {
  330. ent = source->targets[ i ].GetEntity();
  331. if ( ent && ( ent != ignore ) && ent->IsType( idPathCorner::Type ) ) {
  332. path[ num++ ] = static_cast<idPathCorner *>( ent );
  333. if ( num >= MAX_GENTITIES ) {
  334. break;
  335. }
  336. }
  337. }
  338. if ( !num ) {
  339. return NULL;
  340. }
  341. which = gameLocal.random.RandomInt( num );
  342. return path[ which ];
  343. }
  344. /*
  345. =====================
  346. idPathCorner::Event_RandomPath
  347. =====================
  348. */
  349. void idPathCorner::Event_RandomPath( void ) {
  350. idPathCorner *path;
  351. path = RandomPath( this, NULL );
  352. idThread::ReturnEntity( path );
  353. }
  354. /*
  355. ===============================================================================
  356. idDamagable
  357. ===============================================================================
  358. */
  359. const idEventDef EV_RestoreDamagable( "<RestoreDamagable>" );
  360. CLASS_DECLARATION( idEntity, idDamagable )
  361. EVENT( EV_Activate, idDamagable::Event_BecomeBroken )
  362. EVENT( EV_RestoreDamagable, idDamagable::Event_RestoreDamagable )
  363. END_CLASS
  364. /*
  365. ================
  366. idDamagable::idDamagable
  367. ================
  368. */
  369. idDamagable::idDamagable( void ) {
  370. count = 0;
  371. nextTriggerTime = 0;
  372. }
  373. /*
  374. ================
  375. idDamagable::Save
  376. ================
  377. */
  378. void idDamagable::Save( idSaveGame *savefile ) const {
  379. savefile->WriteInt( count );
  380. savefile->WriteInt( nextTriggerTime );
  381. }
  382. /*
  383. ================
  384. idDamagable::Restore
  385. ================
  386. */
  387. void idDamagable::Restore( idRestoreGame *savefile ) {
  388. savefile->ReadInt( count );
  389. savefile->ReadInt( nextTriggerTime );
  390. }
  391. /*
  392. ================
  393. idDamagable::Spawn
  394. ================
  395. */
  396. void idDamagable::Spawn( void ) {
  397. idStr broken;
  398. health = spawnArgs.GetInt( "health", "5" );
  399. spawnArgs.GetInt( "count", "1", count );
  400. nextTriggerTime = 0;
  401. // make sure the model gets cached
  402. spawnArgs.GetString( "broken", "", broken );
  403. if ( broken.Length() && !renderModelManager->CheckModel( broken ) ) {
  404. gameLocal.Error( "idDamagable '%s' at (%s): cannot load broken model '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), broken.c_str() );
  405. }
  406. fl.takedamage = true;
  407. GetPhysics()->SetContents( CONTENTS_SOLID );
  408. }
  409. /*
  410. ================
  411. idDamagable::BecomeBroken
  412. ================
  413. */
  414. void idDamagable::BecomeBroken( idEntity *activator ) {
  415. float forceState;
  416. int numStates;
  417. int cycle;
  418. float wait;
  419. if ( gameLocal.time < nextTriggerTime ) {
  420. return;
  421. }
  422. spawnArgs.GetFloat( "wait", "0.1", wait );
  423. nextTriggerTime = gameLocal.time + SEC2MS( wait );
  424. if ( count > 0 ) {
  425. count--;
  426. if ( !count ) {
  427. fl.takedamage = false;
  428. } else {
  429. health = spawnArgs.GetInt( "health", "5" );
  430. }
  431. }
  432. idStr broken;
  433. spawnArgs.GetString( "broken", "", broken );
  434. if ( broken.Length() ) {
  435. SetModel( broken );
  436. }
  437. // offset the start time of the shader to sync it to the gameLocal time
  438. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  439. spawnArgs.GetInt( "numstates", "1", numStates );
  440. spawnArgs.GetInt( "cycle", "0", cycle );
  441. spawnArgs.GetFloat( "forcestate", "0", forceState );
  442. // set the state parm
  443. if ( cycle ) {
  444. renderEntity.shaderParms[ SHADERPARM_MODE ]++;
  445. if ( renderEntity.shaderParms[ SHADERPARM_MODE ] > numStates ) {
  446. renderEntity.shaderParms[ SHADERPARM_MODE ] = 0;
  447. }
  448. } else if ( forceState ) {
  449. renderEntity.shaderParms[ SHADERPARM_MODE ] = forceState;
  450. } else {
  451. renderEntity.shaderParms[ SHADERPARM_MODE ] = gameLocal.random.RandomInt( numStates ) + 1;
  452. }
  453. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  454. ActivateTargets( activator );
  455. if ( spawnArgs.GetBool( "hideWhenBroken" ) ) {
  456. Hide();
  457. PostEventMS( &EV_RestoreDamagable, nextTriggerTime - gameLocal.time );
  458. BecomeActive( TH_THINK );
  459. }
  460. }
  461. /*
  462. ================
  463. idDamagable::Killed
  464. ================
  465. */
  466. void idDamagable::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  467. if ( gameLocal.time < nextTriggerTime ) {
  468. health += damage;
  469. return;
  470. }
  471. BecomeBroken( attacker );
  472. }
  473. #ifdef _D3XP
  474. /*
  475. ================
  476. idDamagable::Hide
  477. ================
  478. */
  479. void idDamagable::Hide( void ) {
  480. idEntity::Hide();
  481. GetPhysics()->SetContents( 0 );
  482. }
  483. /*
  484. ================
  485. idDamagable::Show
  486. ================
  487. */
  488. void idDamagable::Show( void ) {
  489. idEntity::Show();
  490. GetPhysics()->SetContents( CONTENTS_SOLID );
  491. }
  492. #endif
  493. /*
  494. ================
  495. idDamagable::Event_BecomeBroken
  496. ================
  497. */
  498. void idDamagable::Event_BecomeBroken( idEntity *activator ) {
  499. BecomeBroken( activator );
  500. }
  501. /*
  502. ================
  503. idDamagable::Event_RestoreDamagable
  504. ================
  505. */
  506. void idDamagable::Event_RestoreDamagable( void ) {
  507. health = spawnArgs.GetInt( "health", "5" );
  508. Show();
  509. }
  510. // Jump pad.
  511. // from Raven's Quake 4 source code.
  512. const idEventDef EV_UpdatePeak( "UpdatePeak", NULL );
  513. const idEventDef EV_ActivatePad( "activatepad", "d" );
  514. CLASS_DECLARATION( idForceField, idJumpPad )
  515. EVENT( EV_FindTargets, idJumpPad::Event_FindTargets )
  516. EVENT( EV_UpdatePeak, idJumpPad::Event_UpdatePeak )
  517. EVENT( EV_ActivatePad, idJumpPad::Event_ActivatePad )
  518. END_CLASS
  519. void idJumpPad::Save( idSaveGame *savefile ) const
  520. {
  521. savefile->WriteInt(lastEffectTime);
  522. savefile->WriteBool(activepad);
  523. savefile->WriteMat3(effectAxis);
  524. }
  525. void idJumpPad::Restore( idRestoreGame *savefile )
  526. {
  527. savefile->ReadInt(lastEffectTime);
  528. savefile->ReadBool(activepad);
  529. savefile->ReadMat3(effectAxis);
  530. }
  531. void idJumpPad::Event_ActivatePad( int value )
  532. {
  533. activepad = value;
  534. }
  535. /*
  536. ================
  537. rvJumpPad::Think
  538. ================
  539. */
  540. void idJumpPad::Think( void )
  541. {
  542. if ( !activepad )
  543. return;
  544. //do not launch player if player is holding the launcher.
  545. bool isCarrying = false;
  546. if (gameLocal.GetLocalPlayer()->pickerWeapon.dragEnt.IsValid())
  547. {
  548. if (idStr::Icmp(this->spawnArgs.GetString("owner"), gameLocal.GetLocalPlayer()->pickerWeapon.dragEnt.GetEntity()->GetName()) == 0)
  549. {
  550. isCarrying = true;
  551. }
  552. }
  553. if ( (thinkFlags & TH_THINK) && !isCarrying )
  554. {
  555. // evaluate force
  556. forceField.Evaluate( gameLocal.time );
  557. // If force has been applied to an entity and jump pad effect hasnt been played for a bit
  558. // then play it now.
  559. if ( forceField.GetLastApplyTime ( ) - lastEffectTime > JUMPPAD_EFFECT_DELAY )
  560. {
  561. // start locally
  562. StartSound( "snd_jump", SND_CHANNEL_ITEM, 0, false, NULL );
  563. const char *smokeName = spawnArgs.GetString( "smoke_jump" );
  564. if ( *smokeName != '\0' )
  565. {
  566. const idDeclParticle *smokeFly = NULL;
  567. smokeFly = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  568. if (smokeFly)
  569. {
  570. gameLocal.smokeParticles->EmitSmoke( smokeFly, gameLocal.time, 0,
  571. renderEntity.origin, effectAxis, timeGroup );
  572. }
  573. }
  574. /*
  575. if ( spawnArgs.GetString( "fx_jump" )[ 0 ] )
  576. {
  577. PlayEffect( "fx_jump", renderEntity.origin, effectAxis, false, vec3_origin, false );
  578. }
  579. */
  580. this->lastEffectTime = gameLocal.time;
  581. }
  582. }
  583. Present();
  584. forceField.clipModel->SetPosition(this->GetPhysics()->GetOrigin(), this->GetPhysics()->GetAxis());
  585. }
  586. /*
  587. ================
  588. rvJumpPad::Spawn
  589. ================
  590. */
  591. void idJumpPad::Spawn( void ) {
  592. forceField.SetApplyType( FORCEFIELD_APPLY_VELOCITY );
  593. //forceField.SetOwner( this );
  594. this->lastEffectTime = 100;
  595. this->thinkFlags |= TH_THINK;
  596. //call this manually for the Launcher scriptobject.
  597. Event_FindTargets();
  598. forceField.owner = this;
  599. activepad = 1;
  600. if ( spawnArgs.GetBool("start_off", "0"))
  601. {
  602. activepad = 0;
  603. }
  604. }
  605. /*
  606. ================
  607. rvJumpPad::Event_FindTargets
  608. ================
  609. */
  610. void idJumpPad::Event_FindTargets( void ) {
  611. FindTargets();
  612. RemoveNullTargets();
  613. if ( targets.Num() )
  614. {
  615. idEntity* ent;
  616. ent = targets[0].GetEntity();
  617. assert( ent );
  618. idVec3 vert;
  619. idVec3 diff;
  620. idVec3 vel;
  621. idVec3 localGravity( ent->GetPhysics()->GetGravity() );
  622. idVec3 localGravityNormal = ent->GetPhysics()->GetGravityNormal();
  623. float time;
  624. float dist;
  625. // Find the distance along the gravity vector between the jump pad and its target
  626. diff = (ent->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin());
  627. vert = (diff * localGravityNormal) * localGravityNormal;
  628. // Determine how long it would take to cover the distance along the gravity vector
  629. time = idMath::Sqrt( vert.Length() / (0.5f * localGravity.Length()) );
  630. if ( !time )
  631. {
  632. PostEventMS( &EV_Remove, 0 );
  633. return;
  634. }
  635. // The final velocity is the direction between the jump pad and its target using
  636. // the travel time to determine the forward vector and adding in an inverse gravity vector.
  637. vel = diff - vert;
  638. dist = vel.Normalize();
  639. vel = vel * (dist / time);
  640. vel += (localGravity * -time);
  641. forceField.Uniform( vel );
  642. // calculate a coordinate axis where the vector to the jumppad target is forward
  643. // use this to play the fx_jump fx
  644. diff.Normalize();
  645. effectAxis = diff.ToMat3();
  646. }
  647. }
  648. void idJumpPad::Event_UpdateMultiplier(float value)
  649. {
  650. forceField.forceMultiplier = value;
  651. }
  652. void idJumpPad::Event_UpdatePeak( void )
  653. {
  654. Event_FindTargets();
  655. }
  656. /*
  657. ===============
  658. rvJumpPad::ClientReceiveEvent
  659. ===============
  660. */
  661. bool idJumpPad::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  662. switch ( event ) {
  663. case EVENT_JUMPFX: {
  664. /*
  665. if ( spawnArgs.GetString( "fx_jump" )[ 0 ] )
  666. {
  667. PlayEffect( "fx_jump", renderEntity.origin, effectAxis, false, vec3_origin, false );
  668. }
  669. */
  670. StartSound( "snd_jump", SND_CHANNEL_ITEM, 0, false, NULL );
  671. return true;
  672. }
  673. default:
  674. return idEntity::ClientReceiveEvent( event, time, msg );
  675. }
  676. }
  677. /* idAttractor ================================================================ */
  678. const idEventDef EV_attractortoggle( "attractortoggle", "d" );
  679. CLASS_DECLARATION( idTarget, idAttractor )
  680. EVENT( EV_attractortoggle, idAttractor::Event_attractortoggle)
  681. END_CLASS
  682. void idAttractor::Spawn( void )
  683. {
  684. idStr jointName;
  685. idStr entName;
  686. jointName = spawnArgs.GetString("joint", "");
  687. if (jointName.Length() <= 0)
  688. {
  689. common->Warning("Warning: idAttractor %s is missing 'joint' field.\n", this->name.c_str() );
  690. delete this;
  691. return;
  692. }
  693. entName = spawnArgs.GetString("entity", "");
  694. if (entName.Length() <= 0)
  695. {
  696. common->Warning("Warning: idAttractor %s is missing 'entity' field.\n", this->name.c_str() );
  697. delete this;
  698. return;
  699. }
  700. this->targEnt = gameLocal.FindEntity( entName );
  701. if (!this->targEnt.IsValid())
  702. {
  703. common->Warning("Warning: idAttractor %s couldn't find entity: %s\n", this->name.c_str() , entName.c_str() );
  704. delete this;
  705. return;
  706. }
  707. this->contactID = this->targEnt.GetEntity()->GetAnimator()->GetJointHandle( jointName );
  708. if (!this->contactID)
  709. {
  710. common->Warning("Warning: idAttractor couldn't find joint: %s on entity: %s\n", jointName.c_str(), this->name.c_str() );
  711. delete this;
  712. return;
  713. }
  714. if ( developer.GetBool() )
  715. gameRenderWorld->DebugLine(colorYellow, this->GetPhysics()->GetOrigin(), this->GetPhysics()->GetOrigin() + idVec3(0,0,2), 200);
  716. isActive = 1;
  717. }
  718. void idAttractor::Event_attractortoggle(int value)
  719. {
  720. isActive = value;
  721. }
  722. void idAttractor::Think( void )
  723. {
  724. if (!isActive)
  725. return;
  726. idVec3 forceDir, v, objectCenter;
  727. float forceAmt;
  728. float mass;
  729. float distanceToGoal;
  730. float damping = 0.5f;
  731. if (!this->targEnt.IsValid())
  732. {
  733. common->Warning("Warning: idAttractor couldn't find targEnt.\n");
  734. //common->Warning("Warning: idAttractor %s couldn't find targEnt. TargEnt was deleted?\n", this->name );
  735. delete this;
  736. return;
  737. }
  738. objectCenter = this->targEnt.GetEntity()->GetPhysics()->GetAbsBounds(this->contactID).GetCenter();
  739. mass = this->targEnt.GetEntity()->GetPhysics()->GetMass(this->contactID);
  740. forceDir = this->GetPhysics()->GetOrigin() - objectCenter;
  741. distanceToGoal = forceDir.Length();
  742. forceDir.Normalize();
  743. forceAmt = (1000.f * mass) + (3000.f * distanceToGoal * mass);
  744. this->targEnt.GetEntity()->GetPhysics()->AddForce( this->contactID, objectCenter, forceDir * forceAmt );
  745. //v = this->targEnt.GetEntity()->GetPhysics()->GetLinearVelocity( this->contactID );
  746. //this->targEnt.GetEntity()->GetPhysics()->SetLinearVelocity( v * damping, this->contactID );
  747. if (distanceToGoal <= 1 && spawnArgs.GetBool("auto_remove", "1"))
  748. {
  749. idStr callbackEntName = spawnArgs.GetString("callbackEnt", "");
  750. idStr callbackFuncName = spawnArgs.GetString("callbackFunc", "");
  751. if (callbackEntName.Length() > 0 && callbackFuncName.Length() > 0)
  752. {
  753. idEntity *callbackEnt = gameLocal.FindEntity( callbackEntName );
  754. if (callbackEnt)
  755. {
  756. gameLocal.GetLocalPlayer()->UseFrob( callbackEnt, callbackFuncName );
  757. }
  758. }
  759. //common->Printf("dist: %f\n", distanceToGoal);
  760. //gameRenderWorld->DebugCircle(idVec4(1,0,0,1), objectCenter, idVec3(0,0,1), 0.5, 4, 20000);
  761. //gameRenderWorld->DebugArrow(idVec4(1,0,0,1), objectCenter, this->GetPhysics()->GetOrigin(), 1, 20000);
  762. ActivateTargets( this );
  763. delete this;
  764. return;
  765. }
  766. }
  767. /*
  768. ===============================================================================
  769. idExplodable
  770. ===============================================================================
  771. */
  772. CLASS_DECLARATION( idEntity, idExplodable )
  773. EVENT( EV_Activate, idExplodable::Event_Explode )
  774. END_CLASS
  775. /*
  776. ================
  777. idExplodable::Spawn
  778. ================
  779. */
  780. void idExplodable::Spawn( void ) {
  781. Hide();
  782. bool startoff;
  783. this->spawnArgs.GetBool( "start_off", "1", startoff );
  784. if (!startoff)
  785. {
  786. Event_Explode( NULL );
  787. }
  788. }
  789. /*
  790. ================
  791. idExplodable::Event_Explode
  792. ================
  793. */
  794. void idExplodable::Event_Explode( idEntity *activator ) {
  795. const char *temp;
  796. if ( spawnArgs.GetString( "def_damage", "damage_explosion", &temp ) ) {
  797. gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), activator, activator, this, this, temp );
  798. }
  799. StartSound( "snd_explode", SND_CHANNEL_ANY, 0, false, NULL );
  800. // Show() calls UpdateVisuals, so we don't need to call it ourselves after setting the shaderParms
  801. renderEntity.shaderParms[SHADERPARM_RED] = 1.0f;
  802. renderEntity.shaderParms[SHADERPARM_GREEN] = 1.0f;
  803. renderEntity.shaderParms[SHADERPARM_BLUE] = 1.0f;
  804. renderEntity.shaderParms[SHADERPARM_ALPHA] = 1.0f;
  805. renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
  806. renderEntity.shaderParms[SHADERPARM_DIVERSITY] = 0.0f;
  807. Show();
  808. PostEventMS( &EV_Remove, 12000 );
  809. ActivateTargets( activator );
  810. }
  811. /*
  812. ===============================================================================
  813. idSpring
  814. ===============================================================================
  815. */
  816. CLASS_DECLARATION( idEntity, idSpring )
  817. EVENT( EV_PostSpawn, idSpring::Event_LinkSpring )
  818. END_CLASS
  819. /*
  820. ================
  821. idSpring::Think
  822. ================
  823. */
  824. void idSpring::Think( void ) {
  825. idVec3 start, end, origin;
  826. idMat3 axis;
  827. // run physics
  828. RunPhysics();
  829. if ( thinkFlags & TH_THINK ) {
  830. // evaluate force
  831. spring.Evaluate( gameLocal.time );
  832. start = p1;
  833. if ( ent1->GetPhysics() ) {
  834. axis = ent1->GetPhysics()->GetAxis();
  835. origin = ent1->GetPhysics()->GetOrigin();
  836. start = origin + start * axis;
  837. }
  838. end = p2;
  839. if ( ent2->GetPhysics() ) {
  840. axis = ent2->GetPhysics()->GetAxis();
  841. origin = ent2->GetPhysics()->GetOrigin();
  842. end = origin + p2 * axis;
  843. }
  844. gameRenderWorld->DebugLine( idVec4(1, 1, 0, 1), start, end, 0, true );
  845. }
  846. Present();
  847. }
  848. /*
  849. ================
  850. idSpring::Event_LinkSpring
  851. ================
  852. */
  853. void idSpring::Event_LinkSpring( void ) {
  854. idStr name1, name2;
  855. spawnArgs.GetString( "ent1", "", name1 );
  856. spawnArgs.GetString( "ent2", "", name2 );
  857. if ( name1.Length() ) {
  858. ent1 = gameLocal.FindEntity( name1 );
  859. if ( !ent1 ) {
  860. gameLocal.Error( "idSpring '%s' at (%s): cannot find first entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name1.c_str() );
  861. }
  862. }
  863. else {
  864. ent1 = gameLocal.entities[ENTITYNUM_WORLD];
  865. }
  866. if ( name2.Length() ) {
  867. ent2 = gameLocal.FindEntity( name2 );
  868. if ( !ent2 ) {
  869. gameLocal.Error( "idSpring '%s' at (%s): cannot find second entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name2.c_str() );
  870. }
  871. }
  872. else {
  873. ent2 = gameLocal.entities[ENTITYNUM_WORLD];
  874. }
  875. spring.SetPosition( ent1->GetPhysics(), id1, p1, ent2->GetPhysics(), id2, p2 );
  876. BecomeActive( TH_THINK );
  877. }
  878. /*
  879. ================
  880. idSpring::Spawn
  881. ================
  882. */
  883. void idSpring::Spawn( void ) {
  884. float Kstretch, damping, restLength;
  885. float Kcompression;
  886. spawnArgs.GetInt( "id1", "0", id1 );
  887. spawnArgs.GetInt( "id2", "0", id2 );
  888. spawnArgs.GetVector( "point1", "0 0 0", p1 );
  889. spawnArgs.GetVector( "point2", "0 0 0", p2 );
  890. spawnArgs.GetFloat( "constant", "100.0f", Kstretch );
  891. spawnArgs.GetFloat( "constant", "100.0f", Kcompression );
  892. spawnArgs.GetFloat( "damping", "10.0f", damping );
  893. spawnArgs.GetFloat( "restlength", "0.0f", restLength );
  894. spring.InitSpring( Kstretch, Kcompression, damping, restLength );
  895. ent1 = ent2 = NULL;
  896. PostEventMS( &EV_PostSpawn, 0 );
  897. }
  898. /*
  899. ===============================================================================
  900. idForceField
  901. ===============================================================================
  902. */
  903. const idEventDef EV_Toggle( "Toggle", NULL );
  904. CLASS_DECLARATION( idEntity, idForceField )
  905. EVENT( EV_Activate, idForceField::Event_Activate )
  906. EVENT( EV_Toggle, idForceField::Event_Toggle )
  907. EVENT( EV_FindTargets, idForceField::Event_FindTargets )
  908. END_CLASS
  909. /*
  910. ===============
  911. idForceField::Toggle
  912. ================
  913. */
  914. void idForceField::Toggle( void ) {
  915. if ( thinkFlags & TH_THINK ) {
  916. BecomeInactive( TH_THINK );
  917. } else {
  918. BecomeActive( TH_THINK );
  919. }
  920. }
  921. /*
  922. ================
  923. idForceField::Think
  924. ================
  925. */
  926. void idForceField::Think( void ) {
  927. if ( thinkFlags & TH_THINK ) {
  928. // evaluate force
  929. forceField.Evaluate( gameLocal.time );
  930. }
  931. Present();
  932. }
  933. /*
  934. ================
  935. idForceField::Save
  936. ================
  937. */
  938. void idForceField::Save( idSaveGame *savefile ) const {
  939. savefile->WriteStaticObject( forceField );
  940. }
  941. /*
  942. ================
  943. idForceField::Restore
  944. ================
  945. */
  946. void idForceField::Restore( idRestoreGame *savefile ) {
  947. savefile->ReadStaticObject( forceField );
  948. }
  949. /*
  950. ================
  951. idForceField::Spawn
  952. ================
  953. */
  954. void idForceField::Spawn( void ) {
  955. idVec3 uniform;
  956. float explosion, implosion, randomTorque;
  957. if ( spawnArgs.GetVector( "uniform", "0 0 0", uniform ) ) {
  958. forceField.Uniform( uniform );
  959. } else if ( spawnArgs.GetFloat( "explosion", "0", explosion ) ) {
  960. forceField.Explosion( explosion );
  961. } else if ( spawnArgs.GetFloat( "implosion", "0", implosion ) ) {
  962. forceField.Implosion( implosion );
  963. }
  964. if ( spawnArgs.GetFloat( "randomTorque", "0", randomTorque ) ) {
  965. forceField.RandomTorque( randomTorque );
  966. }
  967. if ( spawnArgs.GetBool( "applyForce", "0" ) ) {
  968. forceField.SetApplyType( FORCEFIELD_APPLY_FORCE );
  969. } else if ( spawnArgs.GetBool( "applyImpulse", "0" ) ) {
  970. forceField.SetApplyType( FORCEFIELD_APPLY_IMPULSE );
  971. } else {
  972. forceField.SetApplyType( FORCEFIELD_APPLY_VELOCITY );
  973. }
  974. forceField.SetPlayerOnly( spawnArgs.GetBool( "playerOnly", "0" ) );
  975. forceField.SetMonsterOnly( spawnArgs.GetBool( "monsterOnly", "0" ) );
  976. // set the collision model on the force field
  977. forceField.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ) );
  978. // remove the collision model from the physics object
  979. GetPhysics()->SetClipModel( NULL, 1.0f );
  980. if ( spawnArgs.GetBool( "start_on" ) ) {
  981. BecomeActive( TH_THINK );
  982. }
  983. }
  984. /*
  985. ===============
  986. idForceField::Event_Toggle
  987. ================
  988. */
  989. void idForceField::Event_Toggle( void ) {
  990. Toggle();
  991. }
  992. /*
  993. ================
  994. idForceField::Event_Activate
  995. ================
  996. */
  997. void idForceField::Event_Activate( idEntity *activator ) {
  998. float wait;
  999. Toggle();
  1000. if ( spawnArgs.GetFloat( "wait", "0.01", wait ) ) {
  1001. PostEventSec( &EV_Toggle, wait );
  1002. }
  1003. }
  1004. /*
  1005. ================
  1006. idForceField::Event_FindTargets
  1007. ================
  1008. */
  1009. void idForceField::Event_FindTargets( void ) {
  1010. FindTargets();
  1011. RemoveNullTargets();
  1012. if ( targets.Num() ) {
  1013. forceField.Uniform( targets[0].GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() );
  1014. }
  1015. }
  1016. /*
  1017. ===============================================================================
  1018. idAnimated
  1019. ===============================================================================
  1020. */
  1021. const idEventDef EV_AnimStart( "startAnim" );
  1022. const idEventDef EV_Animated_Start( "<start>" );
  1023. const idEventDef EV_LaunchMissiles( "launchMissiles", "ssssdf" );
  1024. const idEventDef EV_LaunchMissilesUpdate( "<launchMissiles>", "dddd" );
  1025. const idEventDef EV_AnimDone( "<AnimDone>", "d" );
  1026. const idEventDef EV_StartRagdoll( "startRagdoll" );
  1027. #ifdef _D3XP
  1028. const idEventDef EV_SetAnimation( "setAnimation", "s" );
  1029. const idEventDef EV_GetAnimationLength( "getAnimationLength", NULL, 'f' );
  1030. #endif
  1031. CLASS_DECLARATION( idAFEntity_Gibbable, idAnimated )
  1032. EVENT( EV_Activate, idAnimated::Event_Activate )
  1033. EVENT( EV_AnimStart, idAnimated::Event_Start )
  1034. EVENT( EV_Animated_Start, idAnimated::Event_Start )
  1035. EVENT( EV_StartRagdoll, idAnimated::Event_StartRagdoll )
  1036. EVENT( EV_AnimDone, idAnimated::Event_AnimDone )
  1037. EVENT( EV_Footstep, idAnimated::Event_Footstep )
  1038. EVENT( EV_FootstepLeft, idAnimated::Event_Footstep )
  1039. EVENT( EV_FootstepRight, idAnimated::Event_Footstep )
  1040. EVENT( EV_LaunchMissiles, idAnimated::Event_LaunchMissiles )
  1041. EVENT( EV_LaunchMissilesUpdate, idAnimated::Event_LaunchMissilesUpdate )
  1042. #ifdef _D3XP
  1043. EVENT( EV_SetAnimation, idAnimated::Event_SetAnimation )
  1044. EVENT( EV_GetAnimationLength, idAnimated::Event_GetAnimationLength )
  1045. #endif
  1046. END_CLASS
  1047. /*
  1048. ===============
  1049. idAnimated::idAnimated
  1050. ================
  1051. */
  1052. idAnimated::idAnimated() {
  1053. anim = 0;
  1054. blendFrames = 0;
  1055. soundJoint = INVALID_JOINT;
  1056. activated = false;
  1057. combatModel = NULL;
  1058. activator = NULL;
  1059. current_anim_index = 0;
  1060. num_anims = 0;
  1061. }
  1062. /*
  1063. ===============
  1064. idAnimated::idAnimated
  1065. ================
  1066. */
  1067. idAnimated::~idAnimated() {
  1068. delete combatModel;
  1069. combatModel = NULL;
  1070. }
  1071. /*
  1072. ===============
  1073. idAnimated::Save
  1074. ================
  1075. */
  1076. void idAnimated::Save( idSaveGame *savefile ) const {
  1077. savefile->WriteInt( current_anim_index );
  1078. savefile->WriteInt( num_anims );
  1079. savefile->WriteInt( anim );
  1080. savefile->WriteInt( blendFrames );
  1081. savefile->WriteJoint( soundJoint );
  1082. activator.Save( savefile );
  1083. savefile->WriteBool( activated );
  1084. }
  1085. /*
  1086. ===============
  1087. idAnimated::Restore
  1088. ================
  1089. */
  1090. void idAnimated::Restore( idRestoreGame *savefile ) {
  1091. savefile->ReadInt( current_anim_index );
  1092. savefile->ReadInt( num_anims );
  1093. savefile->ReadInt( anim );
  1094. savefile->ReadInt( blendFrames );
  1095. savefile->ReadJoint( soundJoint );
  1096. activator.Restore( savefile );
  1097. savefile->ReadBool( activated );
  1098. }
  1099. /*
  1100. ===============
  1101. idAnimated::Spawn
  1102. ================
  1103. */
  1104. void idAnimated::Spawn( void ) {
  1105. idStr animname;
  1106. int anim2;
  1107. float wait;
  1108. const char *joint;
  1109. joint = spawnArgs.GetString( "sound_bone", "origin" );
  1110. soundJoint = animator.GetJointHandle( joint );
  1111. if ( soundJoint == INVALID_JOINT ) {
  1112. gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString(0), joint );
  1113. }
  1114. LoadAF();
  1115. // allow bullets to collide with a combat model
  1116. if ( spawnArgs.GetBool( "combatModel", "0" ) ) {
  1117. combatModel = new idClipModel( modelDefHandle );
  1118. }
  1119. // allow the entity to take damage
  1120. if ( spawnArgs.GetBool( "takeDamage", "0" ) ) {
  1121. fl.takedamage = true;
  1122. }
  1123. blendFrames = 0;
  1124. current_anim_index = 0;
  1125. spawnArgs.GetInt( "num_anims", "0", num_anims );
  1126. blendFrames = spawnArgs.GetInt( "blend_in" );
  1127. animname = spawnArgs.GetString( num_anims ? "anim1" : "anim" );
  1128. if ( !animname.Length() ) {
  1129. anim = 0;
  1130. } else {
  1131. anim = animator.GetAnim( animname );
  1132. if ( !anim ) {
  1133. gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animname.c_str() );
  1134. }
  1135. }
  1136. if ( spawnArgs.GetBool( "hide" ) ) {
  1137. Hide();
  1138. if ( !num_anims ) {
  1139. blendFrames = 0;
  1140. }
  1141. } else if ( spawnArgs.GetString( "start_anim", "", animname ) ) {
  1142. anim2 = animator.GetAnim( animname );
  1143. if ( !anim2 ) {
  1144. gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animname.c_str() );
  1145. }
  1146. animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, 0 );
  1147. } else if ( anim ) {
  1148. // init joints to the first frame of the animation
  1149. animator.SetFrame( ANIMCHANNEL_ALL, anim, 1, gameLocal.time, 0 );
  1150. if ( !num_anims ) {
  1151. blendFrames = 0;
  1152. }
  1153. }
  1154. if (spawnArgs.GetInt("corpse", "0"))
  1155. {
  1156. //GetPhysics()->SetContents( CONTENTS_CORPSE );
  1157. GetPhysics()->SetContents( CONTENTS_RENDERMODEL );
  1158. GetPhysics()->SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
  1159. }
  1160. spawnArgs.GetFloat( "wait", "-1", wait );
  1161. //bc
  1162. StartSound( "snd_ambient", SND_CHANNEL_AMBIENT, 0, false, NULL );
  1163. if ( wait >= 0 ) {
  1164. PostEventSec( &EV_Activate, wait, this );
  1165. }
  1166. }
  1167. /*
  1168. ===============
  1169. idAnimated::LoadAF
  1170. ===============
  1171. */
  1172. bool idAnimated::LoadAF( void ) {
  1173. idStr fileName;
  1174. if ( !spawnArgs.GetString( "ragdoll", "*unknown*", fileName ) ) {
  1175. return false;
  1176. }
  1177. af.SetAnimator( GetAnimator() );
  1178. return af.Load( this, fileName );
  1179. }
  1180. /*
  1181. ===============
  1182. idAnimated::GetPhysicsToSoundTransform
  1183. ===============
  1184. */
  1185. bool idAnimated::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
  1186. animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis );
  1187. axis = renderEntity.axis;
  1188. return true;
  1189. }
  1190. /*
  1191. ================
  1192. idAnimated::StartRagdoll
  1193. ================
  1194. */
  1195. bool idAnimated::StartRagdoll( void ) {
  1196. // if no AF loaded
  1197. if ( !af.IsLoaded() ) {
  1198. return false;
  1199. }
  1200. // if the AF is already active
  1201. if ( af.IsActive() ) {
  1202. return true;
  1203. }
  1204. // disable any collision model used
  1205. GetPhysics()->DisableClip();
  1206. // start using the AF
  1207. af.StartFromCurrentPose( spawnArgs.GetInt( "velocityTime", "0" ) );
  1208. return true;
  1209. }
  1210. /*
  1211. =====================
  1212. idAnimated::PlayNextAnim
  1213. =====================
  1214. */
  1215. void idAnimated::PlayNextAnim( void ) {
  1216. const char *animname;
  1217. int len;
  1218. int cycle;
  1219. if ( current_anim_index >= num_anims ) {
  1220. Hide();
  1221. if ( spawnArgs.GetBool( "remove" ) ) {
  1222. PostEventMS( &EV_Remove, 0 );
  1223. } else {
  1224. current_anim_index = 0;
  1225. }
  1226. return;
  1227. }
  1228. Show();
  1229. current_anim_index++;
  1230. spawnArgs.GetString( va( "anim%d", current_anim_index ), NULL, &animname );
  1231. if ( !animname ) {
  1232. anim = 0;
  1233. animator.Clear( ANIMCHANNEL_ALL, gameLocal.time, FRAME2MS( blendFrames ) );
  1234. return;
  1235. }
  1236. anim = animator.GetAnim( animname );
  1237. if ( !anim ) {
  1238. gameLocal.Warning( "missing anim '%s' on %s", animname, name.c_str() );
  1239. return;
  1240. }
  1241. if ( g_debugCinematic.GetBool() ) {
  1242. gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animname );
  1243. }
  1244. spawnArgs.GetInt( "cycle", "1", cycle );
  1245. if ( ( current_anim_index == num_anims ) && spawnArgs.GetBool( "loop_last_anim" ) ) {
  1246. cycle = -1;
  1247. }
  1248. animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  1249. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
  1250. len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength();
  1251. if ( len >= 0 ) {
  1252. PostEventMS( &EV_AnimDone, len, current_anim_index );
  1253. }
  1254. // offset the start time of the shader to sync it to the game time
  1255. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  1256. animator.ForceUpdate();
  1257. UpdateAnimation();
  1258. UpdateVisuals();
  1259. Present();
  1260. }
  1261. /*
  1262. ===============
  1263. idAnimated::Event_StartRagdoll
  1264. ================
  1265. */
  1266. void idAnimated::Event_StartRagdoll( void ) {
  1267. StartRagdoll();
  1268. }
  1269. /*
  1270. ===============
  1271. idAnimated::Event_AnimDone
  1272. ================
  1273. */
  1274. void idAnimated::Event_AnimDone( int animindex ) {
  1275. if ( g_debugCinematic.GetBool() ) {
  1276. const idAnim *animPtr = animator.GetAnim( anim );
  1277. gameLocal.Printf( "%d: '%s' end anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" );
  1278. }
  1279. if ( ( animindex >= num_anims ) && spawnArgs.GetBool( "remove" ) ) {
  1280. Hide();
  1281. PostEventMS( &EV_Remove, 0 );
  1282. } else if ( spawnArgs.GetBool( "auto_advance" ) ) {
  1283. PlayNextAnim();
  1284. }
  1285. else if ( spawnArgs.GetBool( "cycle" ) )
  1286. {
  1287. //bc if cycle is set, then repeat the last played animation.
  1288. animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, 0 );
  1289. }
  1290. else {
  1291. activated = false;
  1292. }
  1293. if (spawnArgs.GetBool( "notriggeronanim" ))
  1294. return;
  1295. ActivateTargets( activator.GetEntity() );
  1296. }
  1297. /*
  1298. ===============
  1299. idAnimated::Event_Activate
  1300. ================
  1301. */
  1302. void idAnimated::Event_Activate( idEntity *_activator ) {
  1303. gameLocal.GetLocalPlayer()->UseFrob( this, "onActivate" );
  1304. if ( num_anims ) {
  1305. PlayNextAnim();
  1306. activator = _activator;
  1307. return;
  1308. }
  1309. if ( activated ) {
  1310. // already activated
  1311. return;
  1312. }
  1313. activated = true;
  1314. activator = _activator;
  1315. ProcessEvent( &EV_Animated_Start );
  1316. }
  1317. /*
  1318. ===============
  1319. idAnimated::Event_Start
  1320. ================
  1321. */
  1322. void idAnimated::Event_Start( void ) {
  1323. int cycle;
  1324. int len;
  1325. Show();
  1326. if ( num_anims ) {
  1327. PlayNextAnim();
  1328. return;
  1329. }
  1330. if ( anim ) {
  1331. if ( g_debugCinematic.GetBool() ) {
  1332. const idAnim *animPtr = animator.GetAnim( anim );
  1333. gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" );
  1334. }
  1335. spawnArgs.GetInt( "cycle", "1", cycle );
  1336. animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  1337. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
  1338. len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength();
  1339. if ( len >= 0 ) {
  1340. PostEventMS( &EV_AnimDone, len, 1 );
  1341. }
  1342. }
  1343. // offset the start time of the shader to sync it to the game time
  1344. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  1345. animator.ForceUpdate();
  1346. UpdateAnimation();
  1347. UpdateVisuals();
  1348. Present();
  1349. }
  1350. /*
  1351. ===============
  1352. idAnimated::Event_Footstep
  1353. ===============
  1354. */
  1355. void idAnimated::Event_Footstep( void ) {
  1356. StartSound( "snd_footstep", SND_CHANNEL_BODY, 0, false, NULL );
  1357. }
  1358. /*
  1359. =====================
  1360. idAnimated::Event_LaunchMissilesUpdate
  1361. =====================
  1362. */
  1363. void idAnimated::Event_LaunchMissilesUpdate( int launchjoint, int targetjoint, int numshots, int framedelay ) {
  1364. idVec3 launchPos;
  1365. idVec3 targetPos;
  1366. idMat3 axis;
  1367. idVec3 dir;
  1368. idEntity * ent;
  1369. idProjectile * projectile;
  1370. const idDict * projectileDef;
  1371. const char * projectilename;
  1372. projectilename = spawnArgs.GetString( "projectilename" );
  1373. projectileDef = gameLocal.FindEntityDefDict( projectilename, false );
  1374. if ( !projectileDef ) {
  1375. gameLocal.Warning( "idAnimated '%s' at (%s): 'launchMissiles' called with unknown projectile '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename );
  1376. return;
  1377. }
  1378. StartSound( "snd_missile", SND_CHANNEL_WEAPON, 0, false, NULL );
  1379. animator.GetJointTransform( ( jointHandle_t )launchjoint, gameLocal.time, launchPos, axis );
  1380. launchPos = renderEntity.origin + launchPos * renderEntity.axis;
  1381. animator.GetJointTransform( ( jointHandle_t )targetjoint, gameLocal.time, targetPos, axis );
  1382. targetPos = renderEntity.origin + targetPos * renderEntity.axis;
  1383. dir = targetPos - launchPos;
  1384. dir.Normalize();
  1385. gameLocal.SpawnEntityDef( *projectileDef, &ent, false );
  1386. if ( !ent || !ent->IsType( idProjectile::Type ) ) {
  1387. gameLocal.Error( "idAnimated '%s' at (%s): in 'launchMissiles' call '%s' is not an idProjectile", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename );
  1388. }
  1389. projectile = ( idProjectile * )ent;
  1390. projectile->Create( this, launchPos, dir );
  1391. projectile->Launch( launchPos, dir, vec3_origin );
  1392. if ( numshots > 0 ) {
  1393. PostEventMS( &EV_LaunchMissilesUpdate, FRAME2MS( framedelay ), launchjoint, targetjoint, numshots - 1, framedelay );
  1394. }
  1395. }
  1396. /*
  1397. =====================
  1398. idAnimated::Event_LaunchMissiles
  1399. =====================
  1400. */
  1401. void idAnimated::Event_LaunchMissiles( const char *projectilename, const char *sound, const char *launchjoint, const char *targetjoint, int numshots, int framedelay ) {
  1402. const idDict * projectileDef;
  1403. jointHandle_t launch;
  1404. jointHandle_t target;
  1405. projectileDef = gameLocal.FindEntityDefDict( projectilename, false );
  1406. if ( !projectileDef ) {
  1407. gameLocal.Warning( "idAnimated '%s' at (%s): unknown projectile '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename );
  1408. return;
  1409. }
  1410. launch = animator.GetJointHandle( launchjoint );
  1411. if ( launch == INVALID_JOINT ) {
  1412. gameLocal.Warning( "idAnimated '%s' at (%s): unknown launch joint '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), launchjoint );
  1413. gameLocal.Error( "Unknown joint '%s'", launchjoint );
  1414. }
  1415. target = animator.GetJointHandle( targetjoint );
  1416. if ( target == INVALID_JOINT ) {
  1417. gameLocal.Warning( "idAnimated '%s' at (%s): unknown target joint '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), targetjoint );
  1418. }
  1419. spawnArgs.Set( "projectilename", projectilename );
  1420. spawnArgs.Set( "missilesound", sound );
  1421. CancelEvents( &EV_LaunchMissilesUpdate );
  1422. ProcessEvent( &EV_LaunchMissilesUpdate, launch, target, numshots - 1, framedelay );
  1423. }
  1424. #ifdef _D3XP
  1425. /*
  1426. =====================
  1427. idAnimated::Event_SetAnimation
  1428. =====================
  1429. */
  1430. void idAnimated::Event_SetAnimation( const char *animName ) {
  1431. //BSM Nerve: Need to add some error checking so we don't change the animation
  1432. //in the middle of the existing animation
  1433. anim = animator.GetAnim( animName );
  1434. if ( !anim ) {
  1435. gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animName );
  1436. }
  1437. //bc force the next animation to trigger.
  1438. activated = false;
  1439. }
  1440. /*
  1441. =====================
  1442. idAnimated::Event_GetAnimationLength
  1443. =====================
  1444. */
  1445. void idAnimated::Event_GetAnimationLength() {
  1446. float length = 0;
  1447. if(anim) {
  1448. length = (float)(animator.AnimLength( anim )) / 1000.f;
  1449. }
  1450. idThread::ReturnFloat(length);
  1451. }
  1452. #endif
  1453. /*
  1454. ===============================================================================
  1455. idStaticEntity
  1456. Some static entities may be optimized into inline geometry by dmap
  1457. ===============================================================================
  1458. */
  1459. CLASS_DECLARATION( idEntity, idStaticEntity )
  1460. EVENT( EV_Activate, idStaticEntity::Event_Activate )
  1461. END_CLASS
  1462. /*
  1463. ===============
  1464. idStaticEntity::idStaticEntity
  1465. ===============
  1466. */
  1467. idStaticEntity::idStaticEntity( void ) {
  1468. spawnTime = 0;
  1469. active = false;
  1470. fadeFrom.Set( 1, 1, 1, 1 );
  1471. fadeTo.Set( 1, 1, 1, 1 );
  1472. fadeStart = 0;
  1473. fadeEnd = 0;
  1474. runGui = false;
  1475. isCam = false;
  1476. spinning = false;
  1477. }
  1478. /*
  1479. ===============
  1480. idStaticEntity::Save
  1481. ===============
  1482. */
  1483. void idStaticEntity::Save( idSaveGame *savefile ) const {
  1484. savefile->WriteInt( spawnTime );
  1485. savefile->WriteBool( active );
  1486. savefile->WriteVec4( fadeFrom );
  1487. savefile->WriteVec4( fadeTo );
  1488. savefile->WriteInt( fadeStart );
  1489. savefile->WriteInt( fadeEnd );
  1490. savefile->WriteBool( runGui );
  1491. //bc
  1492. savefile->WriteBool(spinning);
  1493. savefile->WriteBool(isCam);
  1494. }
  1495. /*
  1496. ===============
  1497. idStaticEntity::Restore
  1498. ===============
  1499. */
  1500. void idStaticEntity::Restore( idRestoreGame *savefile ) {
  1501. savefile->ReadInt( spawnTime );
  1502. savefile->ReadBool( active );
  1503. savefile->ReadVec4( fadeFrom );
  1504. savefile->ReadVec4( fadeTo );
  1505. savefile->ReadInt( fadeStart );
  1506. savefile->ReadInt( fadeEnd );
  1507. savefile->ReadBool( runGui );
  1508. //bc
  1509. savefile->ReadBool(spinning);
  1510. savefile->ReadBool(isCam);
  1511. }
  1512. /*
  1513. ===============
  1514. idStaticEntity::Spawn
  1515. ===============
  1516. */
  1517. void idStaticEntity::Spawn( void ) {
  1518. bool solid;
  1519. bool hidden;
  1520. bool corpse;
  1521. isCam = false;
  1522. spinning = false;
  1523. // an inline static model will not do anything at all
  1524. if ( spawnArgs.GetBool( "inline" ) || gameLocal.world->spawnArgs.GetBool( "inlineAllStatics" ) ) {
  1525. Hide();
  1526. return;
  1527. }
  1528. solid = spawnArgs.GetBool( "solid" );
  1529. hidden = spawnArgs.GetBool( "hide" );
  1530. if ( solid && !hidden ) {
  1531. GetPhysics()->SetContents( CONTENTS_SOLID );
  1532. } else {
  1533. GetPhysics()->SetContents( 0 );
  1534. }
  1535. corpse = spawnArgs.GetBool("corpse");
  1536. if (corpse && !hidden)
  1537. {
  1538. //GetPhysics()->SetContents( CONTENTS_CORPSE );
  1539. GetPhysics()->SetContents( CONTENTS_RENDERMODEL );
  1540. GetPhysics()->SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
  1541. }
  1542. spawnTime = gameLocal.time;
  1543. active = false;
  1544. idStr model = spawnArgs.GetString( "model" );
  1545. if ( model.Find( ".prt" ) >= 0 ) {
  1546. // we want the parametric particles out of sync with each other
  1547. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = gameLocal.random.RandomInt( 32767 );
  1548. }
  1549. fadeFrom.Set( 1, 1, 1, 1 );
  1550. fadeTo.Set( 1, 1, 1, 1 );
  1551. fadeStart = 0;
  1552. fadeEnd = 0;
  1553. // NOTE: this should be used very rarely because it is expensive
  1554. runGui = spawnArgs.GetBool( "runGui" );
  1555. if ( runGui ) {
  1556. BecomeActive( TH_THINK );
  1557. }
  1558. //BC 12-20-2013 add this to make idstaticentity update its cameraviews
  1559. idStr cameraName = spawnArgs.GetString( "cameraTarget" );
  1560. if ( cameraName.Length() > 0)
  1561. {
  1562. BecomeActive( TH_THINK );
  1563. this->isCam = true;
  1564. }
  1565. spinning = spawnArgs.GetBool( "spin" );
  1566. if ( spinning )
  1567. {
  1568. BecomeActive( TH_THINK );
  1569. }
  1570. //hide splines
  1571. if (spawnArgs.FindKeyIndex("curve_Nurbs") >= 0 || spawnArgs.FindKeyIndex("curve_CatmullRomSpline") >= 0)
  1572. {
  1573. this->Hide();
  1574. }
  1575. }
  1576. /*
  1577. ================
  1578. idStaticEntity::ShowEditingDialog
  1579. ================
  1580. */
  1581. void idStaticEntity::ShowEditingDialog( void ) {
  1582. common->InitTool( EDITOR_PARTICLE, &spawnArgs );
  1583. }
  1584. /*
  1585. ================
  1586. idStaticEntity::Think
  1587. ================
  1588. */
  1589. void idStaticEntity::Think( void ) {
  1590. idEntity::Think();
  1591. if (isCam)
  1592. {
  1593. UpdateVisuals();
  1594. }
  1595. if ( thinkFlags & TH_THINK ) {
  1596. if ( runGui && renderEntity.gui[0] ) {
  1597. idPlayer *player = gameLocal.GetLocalPlayer();
  1598. if ( player ) {
  1599. if ( !player->objectiveSystemOpen ) {
  1600. renderEntity.gui[0]->StateChanged( gameLocal.time, true );
  1601. if ( renderEntity.gui[1] ) {
  1602. renderEntity.gui[1]->StateChanged( gameLocal.time, true );
  1603. }
  1604. if ( renderEntity.gui[2] ) {
  1605. renderEntity.gui[2]->StateChanged( gameLocal.time, true );
  1606. }
  1607. }
  1608. }
  1609. }
  1610. if ( fadeEnd > 0 ) {
  1611. idVec4 color;
  1612. if ( gameLocal.time < fadeEnd ) {
  1613. color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) );
  1614. } else {
  1615. color = fadeTo;
  1616. fadeEnd = 0;
  1617. BecomeInactive( TH_THINK );
  1618. }
  1619. SetColor( color );
  1620. }
  1621. }
  1622. if (spinning)
  1623. {
  1624. idAngles ang;
  1625. idVec3 org;
  1626. ang.pitch = ang.roll = 0.0f;
  1627. ang.yaw = ( gameLocal.time & 4095 ) * 360.0f / -4096.0f;
  1628. SetAngles( ang );
  1629. }
  1630. }
  1631. /*
  1632. ================
  1633. idStaticEntity::Fade
  1634. ================
  1635. */
  1636. void idStaticEntity::Fade( const idVec4 &to, float fadeTime ) {
  1637. GetColor( fadeFrom );
  1638. fadeTo = to;
  1639. fadeStart = gameLocal.time;
  1640. fadeEnd = gameLocal.time + SEC2MS( fadeTime );
  1641. BecomeActive( TH_THINK );
  1642. }
  1643. /*
  1644. ================
  1645. idStaticEntity::Hide
  1646. ================
  1647. */
  1648. void idStaticEntity::Hide( void ) {
  1649. idEntity::Hide();
  1650. GetPhysics()->SetContents( 0 );
  1651. }
  1652. /*
  1653. ================
  1654. idStaticEntity::Show
  1655. ================
  1656. */
  1657. void idStaticEntity::Show( void ) {
  1658. idEntity::Show();
  1659. if ( spawnArgs.GetBool( "solid" ) ) {
  1660. GetPhysics()->SetContents( CONTENTS_SOLID );
  1661. }
  1662. }
  1663. /*
  1664. ================
  1665. idStaticEntity::Event_Activate
  1666. ================
  1667. */
  1668. void idStaticEntity::Event_Activate( idEntity *activator ) {
  1669. idStr activateGui;
  1670. if (spawnArgs.GetBool( "scripttriggered", "1" ))
  1671. {
  1672. gameLocal.GetLocalPlayer()->UseFrob( this, "onActivate" );
  1673. return;
  1674. }
  1675. spawnTime = gameLocal.time;
  1676. active = !active;
  1677. const idKeyValue *kv = spawnArgs.FindKey( "hide" );
  1678. if ( kv ) {
  1679. if ( IsHidden() ) {
  1680. Show();
  1681. } else {
  1682. Hide();
  1683. }
  1684. }
  1685. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( spawnTime );
  1686. renderEntity.shaderParms[5] = active;
  1687. // this change should be a good thing, it will automatically turn on
  1688. // lights etc.. when triggered so that does not have to be specifically done
  1689. // with trigger parms.. it MIGHT break things so need to keep an eye on it
  1690. renderEntity.shaderParms[ SHADERPARM_MODE ] = ( renderEntity.shaderParms[ SHADERPARM_MODE ] ) ? 0.0f : 1.0f;
  1691. BecomeActive( TH_UPDATEVISUALS );
  1692. }
  1693. /*
  1694. ================
  1695. idStaticEntity::WriteToSnapshot
  1696. ================
  1697. */
  1698. void idStaticEntity::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1699. GetPhysics()->WriteToSnapshot( msg );
  1700. WriteBindToSnapshot( msg );
  1701. WriteColorToSnapshot( msg );
  1702. WriteGUIToSnapshot( msg );
  1703. msg.WriteBits( IsHidden()?1:0, 1 );
  1704. }
  1705. /*
  1706. ================
  1707. idStaticEntity::ReadFromSnapshot
  1708. ================
  1709. */
  1710. void idStaticEntity::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1711. bool hidden;
  1712. GetPhysics()->ReadFromSnapshot( msg );
  1713. ReadBindFromSnapshot( msg );
  1714. ReadColorFromSnapshot( msg );
  1715. ReadGUIFromSnapshot( msg );
  1716. hidden = msg.ReadBits( 1 ) == 1;
  1717. if ( hidden != IsHidden() ) {
  1718. if ( hidden ) {
  1719. Hide();
  1720. } else {
  1721. Show();
  1722. }
  1723. }
  1724. if ( msg.HasChanged() ) {
  1725. UpdateVisuals();
  1726. }
  1727. }
  1728. /*
  1729. ===============================================================================
  1730. idFuncEmitter
  1731. ===============================================================================
  1732. */
  1733. const idEventDef EV_emitter_isenabled( "isemitterenabled", NULL, 'd' );
  1734. const idEventDef EV_emitter_enable( "emitterenable", "d" );
  1735. CLASS_DECLARATION( idStaticEntity, idFuncEmitter )
  1736. EVENT( EV_Activate, idFuncEmitter::Event_Activate )
  1737. EVENT( EV_emitter_enable, idFuncEmitter::Event_Enable )
  1738. EVENT( EV_emitter_isenabled, idFuncEmitter::Event_IsEnabled )
  1739. END_CLASS
  1740. /*
  1741. ===============
  1742. idFuncEmitter::idFuncEmitter
  1743. ===============
  1744. */
  1745. idFuncEmitter::idFuncEmitter( void ) {
  1746. hidden = false;
  1747. }
  1748. /*
  1749. ===============
  1750. idFuncEmitter::Spawn
  1751. ===============
  1752. */
  1753. void idFuncEmitter::Spawn( void ) {
  1754. if ( spawnArgs.GetBool( "start_off" ) ) {
  1755. hidden = true;
  1756. renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( 1 );
  1757. UpdateVisuals();
  1758. } else {
  1759. hidden = false;
  1760. }
  1761. }
  1762. /*
  1763. ===============
  1764. idFuncEmitter::Save
  1765. ===============
  1766. */
  1767. void idFuncEmitter::Save( idSaveGame *savefile ) const {
  1768. savefile->WriteBool( hidden );
  1769. }
  1770. /*
  1771. ===============
  1772. idFuncEmitter::Restore
  1773. ===============
  1774. */
  1775. void idFuncEmitter::Restore( idRestoreGame *savefile ) {
  1776. savefile->ReadBool( hidden );
  1777. }
  1778. void idFuncEmitter::Event_IsEnabled( )
  1779. {
  1780. if (hidden)
  1781. idThread::ReturnInt( 0 );
  1782. else
  1783. idThread::ReturnInt( 1 );
  1784. }
  1785. void idFuncEmitter::Event_Enable( int value )
  1786. {
  1787. if (value > 0 && hidden == false)
  1788. return;
  1789. if (value <= 0 && hidden == true)
  1790. return;
  1791. if (value > 0)
  1792. {
  1793. hidden = true;
  1794. }
  1795. else
  1796. {
  1797. hidden = false;
  1798. }
  1799. Event_Activate(NULL);
  1800. }
  1801. /*
  1802. ================
  1803. idFuncEmitter::Event_Activate
  1804. ================
  1805. */
  1806. void idFuncEmitter::Event_Activate( idEntity *activator ) {
  1807. if ( hidden || spawnArgs.GetBool( "cycleTrigger" ) ) {
  1808. renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = 0;
  1809. renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
  1810. hidden = false;
  1811. } else {
  1812. renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( gameLocal.time );
  1813. hidden = true;
  1814. }
  1815. UpdateVisuals();
  1816. }
  1817. /*
  1818. ================
  1819. idFuncEmitter::WriteToSnapshot
  1820. ================
  1821. */
  1822. void idFuncEmitter::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1823. msg.WriteBits( hidden ? 1 : 0, 1 );
  1824. msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] );
  1825. msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] );
  1826. }
  1827. /*
  1828. ================
  1829. idFuncEmitter::ReadFromSnapshot
  1830. ================
  1831. */
  1832. void idFuncEmitter::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1833. hidden = msg.ReadBits( 1 ) != 0;
  1834. renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] = msg.ReadFloat();
  1835. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = msg.ReadFloat();
  1836. if ( msg.HasChanged() ) {
  1837. UpdateVisuals();
  1838. }
  1839. }
  1840. /*
  1841. ===============================================================================
  1842. idFuncSplat
  1843. ===============================================================================
  1844. */
  1845. const idEventDef EV_Splat( "<Splat>" );
  1846. CLASS_DECLARATION( idFuncEmitter, idFuncSplat )
  1847. EVENT( EV_Activate, idFuncSplat::Event_Activate )
  1848. EVENT( EV_Splat, idFuncSplat::Event_Splat )
  1849. END_CLASS
  1850. /*
  1851. ===============
  1852. idFuncSplat::idFuncSplat
  1853. ===============
  1854. */
  1855. idFuncSplat::idFuncSplat( void ) {
  1856. }
  1857. /*
  1858. ===============
  1859. idFuncSplat::Spawn
  1860. ===============
  1861. */
  1862. void idFuncSplat::Spawn( void ) {
  1863. }
  1864. /*
  1865. ================
  1866. idFuncSplat::Event_Splat
  1867. ================
  1868. */
  1869. void idFuncSplat::Event_Splat( void ) {
  1870. const char *splat = NULL;
  1871. int count = spawnArgs.GetInt( "splatCount", "1" );
  1872. for ( int i = 0; i < count; i++ ) {
  1873. splat = spawnArgs.RandomPrefix( "mtr_splat", gameLocal.random );
  1874. if ( splat && *splat ) {
  1875. float size = spawnArgs.GetFloat( "splatSize", "128" );
  1876. float dist = spawnArgs.GetFloat( "splatDistance", "128" );
  1877. float angle = spawnArgs.GetFloat( "splatAngle", "0" );
  1878. gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[2], dist, true, size, splat, angle );
  1879. }
  1880. }
  1881. StartSound( "snd_splat", SND_CHANNEL_ANY, 0, false, NULL );
  1882. }
  1883. /*
  1884. ================
  1885. idFuncSplat::Event_Activate
  1886. ================
  1887. */
  1888. void idFuncSplat::Event_Activate( idEntity *activator ) {
  1889. idFuncEmitter::Event_Activate( activator );
  1890. PostEventSec( &EV_Splat, spawnArgs.GetFloat( "splatDelay", "0.25" ) );
  1891. StartSound( "snd_spurt", SND_CHANNEL_ANY, 0, false, NULL );
  1892. }
  1893. /*
  1894. ===============================================================================
  1895. idFuncSmoke
  1896. ===============================================================================
  1897. */
  1898. CLASS_DECLARATION( idEntity, idFuncSmoke )
  1899. EVENT( EV_Activate, idFuncSmoke::Event_Activate )
  1900. END_CLASS
  1901. /*
  1902. ===============
  1903. idFuncSmoke::idFuncSmoke
  1904. ===============
  1905. */
  1906. idFuncSmoke::idFuncSmoke() {
  1907. smokeTime = 0;
  1908. smoke = NULL;
  1909. restart = false;
  1910. }
  1911. /*
  1912. ===============
  1913. idFuncSmoke::Save
  1914. ===============
  1915. */
  1916. void idFuncSmoke::Save( idSaveGame *savefile ) const {
  1917. savefile->WriteInt( smokeTime );
  1918. savefile->WriteParticle( smoke );
  1919. savefile->WriteBool( restart );
  1920. }
  1921. /*
  1922. ===============
  1923. idFuncSmoke::Restore
  1924. ===============
  1925. */
  1926. void idFuncSmoke::Restore( idRestoreGame *savefile ) {
  1927. savefile->ReadInt( smokeTime );
  1928. savefile->ReadParticle( smoke );
  1929. savefile->ReadBool( restart );
  1930. }
  1931. /*
  1932. ===============
  1933. idFuncSmoke::Spawn
  1934. ===============
  1935. */
  1936. void idFuncSmoke::Spawn( void ) {
  1937. const char *smokeName = spawnArgs.GetString( "smoke" );
  1938. if ( *smokeName != '\0' ) {
  1939. smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1940. } else {
  1941. smoke = NULL;
  1942. }
  1943. if ( spawnArgs.GetBool( "start_off" ) ) {
  1944. smokeTime = 0;
  1945. restart = false;
  1946. } else if ( smoke ) {
  1947. smokeTime = gameLocal.time;
  1948. BecomeActive( TH_UPDATEPARTICLES );
  1949. restart = true;
  1950. }
  1951. GetPhysics()->SetContents( 0 );
  1952. }
  1953. /*
  1954. ================
  1955. idFuncSmoke::Event_Activate
  1956. ================
  1957. */
  1958. void idFuncSmoke::Event_Activate( idEntity *activator ) {
  1959. if ( thinkFlags & TH_UPDATEPARTICLES ) {
  1960. restart = false;
  1961. return;
  1962. } else {
  1963. BecomeActive( TH_UPDATEPARTICLES );
  1964. restart = true;
  1965. smokeTime = gameLocal.time;
  1966. }
  1967. }
  1968. /*
  1969. ===============
  1970. idFuncSmoke::Think
  1971. ================
  1972. */
  1973. void idFuncSmoke::Think( void ) {
  1974. // if we are completely closed off from the player, don't do anything at all
  1975. if ( CheckDormant() || smoke == NULL || smokeTime == -1 ) {
  1976. return;
  1977. }
  1978. if ( ( thinkFlags & TH_UPDATEPARTICLES) && !IsHidden() ) {
  1979. if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) {
  1980. if ( restart ) {
  1981. smokeTime = gameLocal.time;
  1982. } else {
  1983. smokeTime = 0;
  1984. BecomeInactive( TH_UPDATEPARTICLES );
  1985. }
  1986. }
  1987. }
  1988. }
  1989. /*
  1990. ===============================================================================
  1991. idTextEntity
  1992. ===============================================================================
  1993. */
  1994. CLASS_DECLARATION( idEntity, idTextEntity )
  1995. END_CLASS
  1996. /*
  1997. ================
  1998. idTextEntity::Spawn
  1999. ================
  2000. */
  2001. void idTextEntity::Spawn( void ) {
  2002. // these are cached as the are used each frame
  2003. text = spawnArgs.GetString( "text" );
  2004. playerOriented = spawnArgs.GetBool( "playerOriented" );
  2005. bool force = spawnArgs.GetBool( "force" );
  2006. if ( developer.GetBool() || force ) {
  2007. BecomeActive(TH_THINK);
  2008. }
  2009. }
  2010. /*
  2011. ================
  2012. idTextEntity::Save
  2013. ================
  2014. */
  2015. void idTextEntity::Save( idSaveGame *savefile ) const {
  2016. savefile->WriteString( text );
  2017. savefile->WriteBool( playerOriented );
  2018. }
  2019. /*
  2020. ================
  2021. idTextEntity::Restore
  2022. ================
  2023. */
  2024. void idTextEntity::Restore( idRestoreGame *savefile ) {
  2025. savefile->ReadString( text );
  2026. savefile->ReadBool( playerOriented );
  2027. }
  2028. /*
  2029. ================
  2030. idTextEntity::Think
  2031. ================
  2032. */
  2033. void idTextEntity::Think( void ) {
  2034. if ( thinkFlags & TH_THINK ) {
  2035. gameRenderWorld->DrawText( text, GetPhysics()->GetOrigin(), 0.25, colorWhite, playerOriented ? gameLocal.GetLocalPlayer()->viewAngles.ToMat3() : GetPhysics()->GetAxis().Transpose(), 1 );
  2036. for ( int i = 0; i < targets.Num(); i++ ) {
  2037. if ( targets[i].GetEntity() ) {
  2038. gameRenderWorld->DebugArrow( colorBlue, GetPhysics()->GetOrigin(), targets[i].GetEntity()->GetPhysics()->GetOrigin(), 1 );
  2039. }
  2040. }
  2041. } else {
  2042. BecomeInactive( TH_ALL );
  2043. }
  2044. }
  2045. /*
  2046. ===============================================================================
  2047. idVacuumSeperatorEntity
  2048. Can be triggered to let vacuum through a portal (blown out window)
  2049. ===============================================================================
  2050. */
  2051. const idEventDef EV_VacuumToggle( "vacuumtoggle", "d" );
  2052. CLASS_DECLARATION( idEntity, idVacuumSeparatorEntity )
  2053. EVENT( EV_Activate, idVacuumSeparatorEntity::Event_Activate )
  2054. EVENT( EV_VacuumToggle, idVacuumSeparatorEntity::Event_VacuumToggle )
  2055. END_CLASS
  2056. /*
  2057. ================
  2058. idVacuumSeparatorEntity::idVacuumSeparatorEntity
  2059. ================
  2060. */
  2061. idVacuumSeparatorEntity::idVacuumSeparatorEntity( void ) {
  2062. portal = 0;
  2063. }
  2064. /*
  2065. ================
  2066. idVacuumSeparatorEntity::Save
  2067. ================
  2068. */
  2069. void idVacuumSeparatorEntity::Save( idSaveGame *savefile ) const {
  2070. savefile->WriteInt( (int)portal );
  2071. savefile->WriteInt( gameRenderWorld->GetPortalState( portal ) );
  2072. }
  2073. /*
  2074. ================
  2075. idVacuumSeparatorEntity::Restore
  2076. ================
  2077. */
  2078. void idVacuumSeparatorEntity::Restore( idRestoreGame *savefile ) {
  2079. int state;
  2080. savefile->ReadInt( (int &)portal );
  2081. savefile->ReadInt( state );
  2082. gameLocal.SetPortalState( portal, state );
  2083. }
  2084. /*
  2085. ================
  2086. idVacuumSeparatorEntity::Spawn
  2087. ================
  2088. */
  2089. void idVacuumSeparatorEntity::Spawn() {
  2090. idBounds b;
  2091. b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 );
  2092. portal = gameRenderWorld->FindPortal( b );
  2093. if ( !portal ) {
  2094. gameLocal.Warning( "VacuumSeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) );
  2095. return;
  2096. }
  2097. gameLocal.SetPortalState( portal, PS_BLOCK_AIR | PS_BLOCK_LOCATION );
  2098. }
  2099. /*
  2100. ================
  2101. idVacuumSeparatorEntity::Event_Activate
  2102. ================
  2103. */
  2104. void idVacuumSeparatorEntity::Event_Activate( idEntity *activator ) {
  2105. if ( !portal ) {
  2106. return;
  2107. }
  2108. gameLocal.SetPortalState( portal, PS_BLOCK_NONE );
  2109. }
  2110. void idVacuumSeparatorEntity::Event_VacuumToggle(int value)
  2111. {
  2112. if ( !portal ) {
  2113. return;
  2114. }
  2115. gameLocal.SetPortalState( portal, value ? (PS_BLOCK_AIR | PS_BLOCK_LOCATION) : PS_BLOCK_NONE );
  2116. }
  2117. /*
  2118. ===============================================================================
  2119. idLocationSeparatorEntity
  2120. ===============================================================================
  2121. */
  2122. CLASS_DECLARATION( idEntity, idLocationSeparatorEntity )
  2123. END_CLASS
  2124. /*
  2125. ================
  2126. idLocationSeparatorEntity::Spawn
  2127. ================
  2128. */
  2129. void idLocationSeparatorEntity::Spawn() {
  2130. idBounds b;
  2131. b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 );
  2132. qhandle_t portal = gameRenderWorld->FindPortal( b );
  2133. if ( !portal ) {
  2134. gameLocal.Warning( "LocationSeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) );
  2135. }
  2136. gameLocal.SetPortalState( portal, PS_BLOCK_LOCATION );
  2137. }
  2138. /*
  2139. ===============================================================================
  2140. idVacuumEntity
  2141. Levels should only have a single vacuum entity.
  2142. ===============================================================================
  2143. */
  2144. CLASS_DECLARATION( idEntity, idVacuumEntity )
  2145. END_CLASS
  2146. /*
  2147. ================
  2148. idVacuumEntity::Spawn
  2149. ================
  2150. */
  2151. void idVacuumEntity::Spawn() {
  2152. if ( gameLocal.vacuumAreaNum != -1 ) {
  2153. gameLocal.Warning( "idVacuumEntity::Spawn: multiple idVacuumEntity in level" );
  2154. return;
  2155. }
  2156. idVec3 org = spawnArgs.GetVector( "origin" );
  2157. gameLocal.vacuumAreaNum = gameRenderWorld->PointInArea( org );
  2158. }
  2159. /*
  2160. ===============================================================================
  2161. idLocationEntity
  2162. ===============================================================================
  2163. */
  2164. CLASS_DECLARATION( idEntity, idLocationEntity )
  2165. END_CLASS
  2166. /*
  2167. ======================
  2168. idLocationEntity::Spawn
  2169. ======================
  2170. */
  2171. void idLocationEntity::Spawn() {
  2172. idStr realName;
  2173. // this just holds dict information
  2174. // if "location" not already set, use the entity name.
  2175. if ( !spawnArgs.GetString( "location", "", realName ) ) {
  2176. spawnArgs.Set( "location", name );
  2177. }
  2178. }
  2179. /*
  2180. ======================
  2181. idLocationEntity::GetLocation
  2182. ======================
  2183. */
  2184. const char *idLocationEntity::GetLocation( void ) const {
  2185. return spawnArgs.GetString( "location" );
  2186. }
  2187. /*
  2188. ===============================================================================
  2189. idBeam
  2190. ===============================================================================
  2191. */
  2192. const idEventDef EV_SetWidth( "SetWidth", "f" );
  2193. CLASS_DECLARATION( idEntity, idBeam )
  2194. EVENT( EV_PostSpawn, idBeam::Event_MatchTarget )
  2195. EVENT( EV_Activate, idBeam::Event_Activate )
  2196. EVENT( EV_SetWidth, idBeam::Event_SetWidth )
  2197. END_CLASS
  2198. /*
  2199. ===============
  2200. idBeam::idBeam
  2201. ===============
  2202. */
  2203. idBeam::idBeam() {
  2204. target = NULL;
  2205. master = NULL;
  2206. }
  2207. /*
  2208. ===============
  2209. idBeam::Save
  2210. ===============
  2211. */
  2212. void idBeam::Save( idSaveGame *savefile ) const {
  2213. target.Save( savefile );
  2214. master.Save( savefile );
  2215. }
  2216. /*
  2217. ===============
  2218. idBeam::Restore
  2219. ===============
  2220. */
  2221. void idBeam::Restore( idRestoreGame *savefile ) {
  2222. target.Restore( savefile );
  2223. master.Restore( savefile );
  2224. }
  2225. /*
  2226. ===============
  2227. idBeam::Spawn
  2228. ===============
  2229. */
  2230. void idBeam::Spawn( void ) {
  2231. float width;
  2232. if ( spawnArgs.GetFloat( "width", "0", width ) ) {
  2233. renderEntity.shaderParms[ SHADERPARM_BEAM_WIDTH ] = width;
  2234. }
  2235. SetModel( "_BEAM" );
  2236. Hide();
  2237. PostEventMS( &EV_PostSpawn, 0 );
  2238. }
  2239. /*
  2240. ================
  2241. idBeam::Think
  2242. ================
  2243. */
  2244. void idBeam::Think( void ) {
  2245. idBeam *masterEnt;
  2246. if ( !IsHidden() && !target.GetEntity() ) {
  2247. // hide if our target is removed
  2248. Hide();
  2249. }
  2250. RunPhysics();
  2251. masterEnt = master.GetEntity();
  2252. if ( masterEnt ) {
  2253. const idVec3 &origin = GetPhysics()->GetOrigin();
  2254. masterEnt->SetBeamTarget( origin );
  2255. }
  2256. Present();
  2257. }
  2258. /*
  2259. ================
  2260. idBeam::SetMaster
  2261. ================
  2262. */
  2263. void idBeam::SetMaster( idBeam *masterbeam ) {
  2264. master = masterbeam;
  2265. }
  2266. /*
  2267. ================
  2268. idBeam::SetBeamTarget
  2269. ================
  2270. */
  2271. void idBeam::SetBeamTarget( const idVec3 &origin ) {
  2272. if ( ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] != origin.x ) || ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] != origin.y ) || ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] != origin.z ) ) {
  2273. renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] = origin.x;
  2274. renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] = origin.y;
  2275. renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] = origin.z;
  2276. UpdateVisuals();
  2277. }
  2278. }
  2279. /*
  2280. ================
  2281. idBeam::Show
  2282. ================
  2283. */
  2284. void idBeam::Show( void ) {
  2285. idBeam *targetEnt;
  2286. idEntity::Show();
  2287. targetEnt = target.GetEntity();
  2288. if ( targetEnt ) {
  2289. const idVec3 &origin = targetEnt->GetPhysics()->GetOrigin();
  2290. SetBeamTarget( origin );
  2291. }
  2292. }
  2293. void idBeam::Event_SetWidth( float value )
  2294. {
  2295. renderEntity.shaderParms[ SHADERPARM_BEAM_WIDTH ] = value;
  2296. UpdateVisuals();
  2297. }
  2298. /*
  2299. ================
  2300. idBeam::Event_MatchTarget
  2301. ================
  2302. */
  2303. void idBeam::Event_MatchTarget( void ) {
  2304. int i;
  2305. idEntity *targetEnt;
  2306. idBeam *targetBeam;
  2307. if ( !targets.Num() ) {
  2308. return;
  2309. }
  2310. targetBeam = NULL;
  2311. for( i = 0; i < targets.Num(); i++ ) {
  2312. targetEnt = targets[ i ].GetEntity();
  2313. if ( targetEnt && targetEnt->IsType( idBeam::Type ) ) {
  2314. targetBeam = static_cast<idBeam *>( targetEnt );
  2315. break;
  2316. }
  2317. }
  2318. if ( !targetBeam ) {
  2319. gameLocal.Error( "Could not find valid beam target for '%s'", name.c_str() );
  2320. }
  2321. target = targetBeam;
  2322. targetBeam->SetMaster( this );
  2323. if ( !spawnArgs.GetBool( "start_off" ) ) {
  2324. Show();
  2325. }
  2326. }
  2327. /*
  2328. ================
  2329. idBeam::Event_Activate
  2330. ================
  2331. */
  2332. void idBeam::Event_Activate( idEntity *activator ) {
  2333. if ( IsHidden() ) {
  2334. Show();
  2335. } else {
  2336. Hide();
  2337. }
  2338. }
  2339. /*
  2340. ================
  2341. idBeam::WriteToSnapshot
  2342. ================
  2343. */
  2344. void idBeam::WriteToSnapshot( idBitMsgDelta &msg ) const {
  2345. GetPhysics()->WriteToSnapshot( msg );
  2346. WriteBindToSnapshot( msg );
  2347. WriteColorToSnapshot( msg );
  2348. msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_X] );
  2349. msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_Y] );
  2350. msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_Z] );
  2351. }
  2352. /*
  2353. ================
  2354. idBeam::ReadFromSnapshot
  2355. ================
  2356. */
  2357. void idBeam::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  2358. GetPhysics()->ReadFromSnapshot( msg );
  2359. ReadBindFromSnapshot( msg );
  2360. ReadColorFromSnapshot( msg );
  2361. renderEntity.shaderParms[SHADERPARM_BEAM_END_X] = msg.ReadFloat();
  2362. renderEntity.shaderParms[SHADERPARM_BEAM_END_Y] = msg.ReadFloat();
  2363. renderEntity.shaderParms[SHADERPARM_BEAM_END_Z] = msg.ReadFloat();
  2364. if ( msg.HasChanged() ) {
  2365. UpdateVisuals();
  2366. }
  2367. }
  2368. /*
  2369. ===============================================================================
  2370. idLiquid
  2371. ===============================================================================
  2372. */
  2373. CLASS_DECLARATION( idEntity, idLiquid )
  2374. EVENT( EV_Touch, idLiquid::Event_Touch )
  2375. END_CLASS
  2376. /*
  2377. ================
  2378. idLiquid::Save
  2379. ================
  2380. */
  2381. void idLiquid::Save( idSaveGame *savefile ) const {
  2382. // Nothing to save
  2383. }
  2384. /*
  2385. ================
  2386. idLiquid::Restore
  2387. ================
  2388. */
  2389. void idLiquid::Restore( idRestoreGame *savefile ) {
  2390. //FIXME: NO!
  2391. Spawn();
  2392. }
  2393. /*
  2394. ================
  2395. idLiquid::Spawn
  2396. ================
  2397. */
  2398. void idLiquid::Spawn() {
  2399. /*
  2400. model = dynamic_cast<idRenderModelLiquid *>( renderEntity.hModel );
  2401. if ( !model ) {
  2402. gameLocal.Error( "Entity '%s' must have liquid model", name.c_str() );
  2403. }
  2404. model->Reset();
  2405. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  2406. */
  2407. }
  2408. /*
  2409. ================
  2410. idLiquid::Event_Touch
  2411. ================
  2412. */
  2413. void idLiquid::Event_Touch( idEntity *other, trace_t *trace ) {
  2414. // FIXME: for QuakeCon
  2415. /*
  2416. idVec3 pos;
  2417. pos = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  2418. model->IntersectBounds( other->GetPhysics()->GetBounds().Translate( pos ), -10.0f );
  2419. */
  2420. }
  2421. /*
  2422. ===============================================================================
  2423. idShaking
  2424. ===============================================================================
  2425. */
  2426. CLASS_DECLARATION( idEntity, idShaking )
  2427. EVENT( EV_Activate, idShaking::Event_Activate )
  2428. END_CLASS
  2429. /*
  2430. ===============
  2431. idShaking::idShaking
  2432. ===============
  2433. */
  2434. idShaking::idShaking() {
  2435. active = false;
  2436. }
  2437. /*
  2438. ===============
  2439. idShaking::Save
  2440. ===============
  2441. */
  2442. void idShaking::Save( idSaveGame *savefile ) const {
  2443. savefile->WriteBool( active );
  2444. savefile->WriteStaticObject( physicsObj );
  2445. }
  2446. /*
  2447. ===============
  2448. idShaking::Restore
  2449. ===============
  2450. */
  2451. void idShaking::Restore( idRestoreGame *savefile ) {
  2452. savefile->ReadBool( active );
  2453. savefile->ReadStaticObject( physicsObj );
  2454. RestorePhysics( &physicsObj );
  2455. }
  2456. /*
  2457. ===============
  2458. idShaking::Spawn
  2459. ===============
  2460. */
  2461. void idShaking::Spawn( void ) {
  2462. physicsObj.SetSelf( this );
  2463. physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f );
  2464. physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
  2465. physicsObj.SetAxis( GetPhysics()->GetAxis() );
  2466. physicsObj.SetClipMask( MASK_SOLID );
  2467. SetPhysics( &physicsObj );
  2468. active = false;
  2469. if ( !spawnArgs.GetBool( "start_off" ) ) {
  2470. BeginShaking();
  2471. }
  2472. }
  2473. /*
  2474. ================
  2475. idShaking::BeginShaking
  2476. ================
  2477. */
  2478. void idShaking::BeginShaking( void ) {
  2479. int phase;
  2480. idAngles shake;
  2481. int period;
  2482. active = true;
  2483. phase = gameLocal.random.RandomInt( 1000 );
  2484. shake = spawnArgs.GetAngles( "shake", "0.5 0.5 0.5" );
  2485. period = spawnArgs.GetFloat( "period", "0.05" ) * 1000;
  2486. physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_DECELSINE|EXTRAPOLATION_NOSTOP), phase, period * 0.25f, GetPhysics()->GetAxis().ToAngles(), shake, ang_zero );
  2487. }
  2488. /*
  2489. ================
  2490. idShaking::Event_Activate
  2491. ================
  2492. */
  2493. void idShaking::Event_Activate( idEntity *activator ) {
  2494. if ( !active ) {
  2495. BeginShaking();
  2496. } else {
  2497. active = false;
  2498. physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, physicsObj.GetAxis().ToAngles(), ang_zero, ang_zero );
  2499. }
  2500. }
  2501. /*
  2502. ===============================================================================
  2503. idEarthQuake
  2504. ===============================================================================
  2505. */
  2506. CLASS_DECLARATION( idEntity, idEarthQuake )
  2507. EVENT( EV_Activate, idEarthQuake::Event_Activate )
  2508. END_CLASS
  2509. /*
  2510. ===============
  2511. idEarthQuake::idEarthQuake
  2512. ===============
  2513. */
  2514. idEarthQuake::idEarthQuake() {
  2515. wait = 0.0f;
  2516. random = 0.0f;
  2517. nextTriggerTime = 0;
  2518. shakeStopTime = 0;
  2519. triggered = false;
  2520. playerOriented = false;
  2521. disabled = false;
  2522. shakeTime = 0.0f;
  2523. }
  2524. /*
  2525. ===============
  2526. idEarthQuake::Save
  2527. ===============
  2528. */
  2529. void idEarthQuake::Save( idSaveGame *savefile ) const {
  2530. savefile->WriteInt( nextTriggerTime );
  2531. savefile->WriteInt( shakeStopTime );
  2532. savefile->WriteFloat( wait );
  2533. savefile->WriteFloat( random );
  2534. savefile->WriteBool( triggered );
  2535. savefile->WriteBool( playerOriented );
  2536. savefile->WriteBool( disabled );
  2537. savefile->WriteFloat( shakeTime );
  2538. }
  2539. /*
  2540. ===============
  2541. idEarthQuake::Restore
  2542. ===============
  2543. */
  2544. void idEarthQuake::Restore( idRestoreGame *savefile ) {
  2545. savefile->ReadInt( nextTriggerTime );
  2546. savefile->ReadInt( shakeStopTime );
  2547. savefile->ReadFloat( wait );
  2548. savefile->ReadFloat( random );
  2549. savefile->ReadBool( triggered );
  2550. savefile->ReadBool( playerOriented );
  2551. savefile->ReadBool( disabled );
  2552. savefile->ReadFloat( shakeTime );
  2553. if ( shakeStopTime > gameLocal.time ) {
  2554. BecomeActive( TH_THINK );
  2555. }
  2556. }
  2557. /*
  2558. ===============
  2559. idEarthQuake::Spawn
  2560. ===============
  2561. */
  2562. void idEarthQuake::Spawn( void ) {
  2563. nextTriggerTime = 0;
  2564. shakeStopTime = 0;
  2565. wait = spawnArgs.GetFloat( "wait", "15" );
  2566. random = spawnArgs.GetFloat( "random", "5" );
  2567. triggered = spawnArgs.GetBool( "triggered" );
  2568. playerOriented = spawnArgs.GetBool( "playerOriented" );
  2569. disabled = false;
  2570. shakeTime = spawnArgs.GetFloat( "shakeTime", "0" );
  2571. if ( !triggered ){
  2572. PostEventSec( &EV_Activate, spawnArgs.GetFloat( "wait" ), this );
  2573. }
  2574. BecomeInactive( TH_THINK );
  2575. }
  2576. /*
  2577. ================
  2578. idEarthQuake::Event_Activate
  2579. ================
  2580. */
  2581. void idEarthQuake::Event_Activate( idEntity *activator ) {
  2582. if ( nextTriggerTime > gameLocal.time ) {
  2583. return;
  2584. }
  2585. if ( disabled && activator == this ) {
  2586. return;
  2587. }
  2588. idPlayer *player = gameLocal.GetLocalPlayer();
  2589. if ( player == NULL ) {
  2590. return;
  2591. }
  2592. nextTriggerTime = 0;
  2593. if ( !triggered && activator != this ){
  2594. // if we are not triggered ( i.e. random ), disable or enable
  2595. disabled ^= 1;
  2596. if (disabled) {
  2597. return;
  2598. } else {
  2599. PostEventSec( &EV_Activate, wait + random * gameLocal.random.CRandomFloat(), this );
  2600. }
  2601. }
  2602. ActivateTargets( activator );
  2603. const idSoundShader *shader = declManager->FindSound( spawnArgs.GetString( "snd_quake" ) );
  2604. if ( playerOriented ) {
  2605. player->StartSoundShader( shader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
  2606. } else {
  2607. StartSoundShader( shader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
  2608. }
  2609. if ( shakeTime > 0.0f ) {
  2610. shakeStopTime = gameLocal.time + SEC2MS( shakeTime );
  2611. BecomeActive( TH_THINK );
  2612. }
  2613. if ( wait > 0.0f ) {
  2614. if ( !triggered ) {
  2615. PostEventSec( &EV_Activate, wait + random * gameLocal.random.CRandomFloat(), this );
  2616. } else {
  2617. nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() );
  2618. }
  2619. } else if ( shakeTime == 0.0f ) {
  2620. PostEventMS( &EV_Remove, 0 );
  2621. }
  2622. }
  2623. /*
  2624. ===============
  2625. idEarthQuake::Think
  2626. ================
  2627. */
  2628. void idEarthQuake::Think( void ) {
  2629. if ( thinkFlags & TH_THINK ) {
  2630. if ( gameLocal.time > shakeStopTime ) {
  2631. BecomeInactive( TH_THINK );
  2632. if ( wait <= 0.0f ) {
  2633. PostEventMS( &EV_Remove, 0 );
  2634. }
  2635. return;
  2636. }
  2637. float shakeVolume = gameSoundWorld->CurrentShakeAmplitudeForPosition( gameLocal.time, gameLocal.GetLocalPlayer()->firstPersonViewOrigin );
  2638. gameLocal.RadiusPush( GetPhysics()->GetOrigin(), 256, 1500 * shakeVolume, this, this, 1.0f, true );
  2639. }
  2640. BecomeInactive( TH_UPDATEVISUALS );
  2641. }
  2642. /*
  2643. ===============================================================================
  2644. idFuncPortal
  2645. ===============================================================================
  2646. */
  2647. const idEventDef EV_portal_activate( "portalactivate", "d" );
  2648. CLASS_DECLARATION( idEntity, idFuncPortal )
  2649. EVENT( EV_Activate, idFuncPortal::Event_Activate )
  2650. EVENT( EV_portal_activate, idFuncPortal::Event_portalactivate)
  2651. END_CLASS
  2652. /*
  2653. ===============
  2654. idFuncPortal::idFuncPortal
  2655. ===============
  2656. */
  2657. idFuncPortal::idFuncPortal() {
  2658. portal = 0;
  2659. state = false;
  2660. }
  2661. /*
  2662. ===============
  2663. idFuncPortal::Save
  2664. ===============
  2665. */
  2666. void idFuncPortal::Save( idSaveGame *savefile ) const {
  2667. savefile->WriteInt( (int)portal );
  2668. savefile->WriteBool( state );
  2669. }
  2670. /*
  2671. ===============
  2672. idFuncPortal::Restore
  2673. ===============
  2674. */
  2675. void idFuncPortal::Restore( idRestoreGame *savefile ) {
  2676. savefile->ReadInt( (int &)portal );
  2677. savefile->ReadBool( state );
  2678. gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  2679. }
  2680. /*
  2681. ===============
  2682. idFuncPortal::Spawn
  2683. ===============
  2684. */
  2685. void idFuncPortal::Spawn( void ) {
  2686. portal = gameRenderWorld->FindPortal( GetPhysics()->GetAbsBounds().Expand( 32.0f ) );
  2687. if ( portal > 0 ) {
  2688. state = spawnArgs.GetBool( "start_on" );
  2689. gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  2690. }
  2691. }
  2692. /*
  2693. ================
  2694. idFuncPortal::Event_Activate
  2695. ================
  2696. */
  2697. void idFuncPortal::Event_Activate( idEntity *activator ) {
  2698. if ( portal > 0 ) {
  2699. state = !state;
  2700. gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  2701. }
  2702. }
  2703. void idFuncPortal::Event_portalactivate( int value )
  2704. {
  2705. if (value <= 0)
  2706. {
  2707. gameLocal.SetPortalState( portal, PS_BLOCK_NONE );
  2708. }
  2709. else
  2710. {
  2711. gameLocal.SetPortalState( portal, PS_BLOCK_ALL );
  2712. }
  2713. }
  2714. /*
  2715. ===============================================================================
  2716. idFuncAASPortal
  2717. ===============================================================================
  2718. */
  2719. CLASS_DECLARATION( idEntity, idFuncAASPortal )
  2720. EVENT( EV_Activate, idFuncAASPortal::Event_Activate )
  2721. END_CLASS
  2722. /*
  2723. ===============
  2724. idFuncAASPortal::idFuncAASPortal
  2725. ===============
  2726. */
  2727. idFuncAASPortal::idFuncAASPortal() {
  2728. state = false;
  2729. }
  2730. /*
  2731. ===============
  2732. idFuncAASPortal::Save
  2733. ===============
  2734. */
  2735. void idFuncAASPortal::Save( idSaveGame *savefile ) const {
  2736. savefile->WriteBool( state );
  2737. }
  2738. /*
  2739. ===============
  2740. idFuncAASPortal::Restore
  2741. ===============
  2742. */
  2743. void idFuncAASPortal::Restore( idRestoreGame *savefile ) {
  2744. savefile->ReadBool( state );
  2745. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  2746. }
  2747. /*
  2748. ===============
  2749. idFuncAASPortal::Spawn
  2750. ===============
  2751. */
  2752. void idFuncAASPortal::Spawn( void ) {
  2753. state = spawnArgs.GetBool( "start_on" );
  2754. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  2755. }
  2756. /*
  2757. ================
  2758. idFuncAASPortal::Event_Activate
  2759. ================
  2760. */
  2761. void idFuncAASPortal::Event_Activate( idEntity *activator ) {
  2762. state ^= 1;
  2763. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  2764. }
  2765. /*
  2766. ===============================================================================
  2767. idFuncAASObstacle
  2768. ===============================================================================
  2769. */
  2770. CLASS_DECLARATION( idEntity, idFuncAASObstacle )
  2771. EVENT( EV_Activate, idFuncAASObstacle::Event_Activate )
  2772. END_CLASS
  2773. /*
  2774. ===============
  2775. idFuncAASObstacle::idFuncAASObstacle
  2776. ===============
  2777. */
  2778. idFuncAASObstacle::idFuncAASObstacle() {
  2779. state = false;
  2780. }
  2781. /*
  2782. ===============
  2783. idFuncAASObstacle::Save
  2784. ===============
  2785. */
  2786. void idFuncAASObstacle::Save( idSaveGame *savefile ) const {
  2787. savefile->WriteBool( state );
  2788. }
  2789. /*
  2790. ===============
  2791. idFuncAASObstacle::Restore
  2792. ===============
  2793. */
  2794. void idFuncAASObstacle::Restore( idRestoreGame *savefile ) {
  2795. savefile->ReadBool( state );
  2796. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  2797. }
  2798. /*
  2799. ===============
  2800. idFuncAASObstacle::Spawn
  2801. ===============
  2802. */
  2803. void idFuncAASObstacle::Spawn( void ) {
  2804. state = spawnArgs.GetBool( "start_on" );
  2805. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  2806. }
  2807. /*
  2808. ================
  2809. idFuncAASObstacle::Event_Activate
  2810. ================
  2811. */
  2812. void idFuncAASObstacle::Event_Activate( idEntity *activator ) {
  2813. state ^= 1;
  2814. gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  2815. }
  2816. /*
  2817. ===============================================================================
  2818. idFuncRadioChatter
  2819. ===============================================================================
  2820. */
  2821. const idEventDef EV_ResetRadioHud( "<resetradiohud>", "e" );
  2822. CLASS_DECLARATION( idEntity, idFuncRadioChatter )
  2823. EVENT( EV_Activate, idFuncRadioChatter::Event_Activate )
  2824. EVENT( EV_ResetRadioHud, idFuncRadioChatter::Event_ResetRadioHud )
  2825. END_CLASS
  2826. /*
  2827. ===============
  2828. idFuncRadioChatter::idFuncRadioChatter
  2829. ===============
  2830. */
  2831. idFuncRadioChatter::idFuncRadioChatter() {
  2832. time = 0.0;
  2833. }
  2834. /*
  2835. ===============
  2836. idFuncRadioChatter::Save
  2837. ===============
  2838. */
  2839. void idFuncRadioChatter::Save( idSaveGame *savefile ) const {
  2840. savefile->WriteFloat( time );
  2841. }
  2842. /*
  2843. ===============
  2844. idFuncRadioChatter::Restore
  2845. ===============
  2846. */
  2847. void idFuncRadioChatter::Restore( idRestoreGame *savefile ) {
  2848. savefile->ReadFloat( time );
  2849. }
  2850. /*
  2851. ===============
  2852. idFuncRadioChatter::Spawn
  2853. ===============
  2854. */
  2855. void idFuncRadioChatter::Spawn( void ) {
  2856. time = spawnArgs.GetFloat( "time", "5.0" );
  2857. }
  2858. /*
  2859. ================
  2860. idFuncRadioChatter::Event_Activate
  2861. ================
  2862. */
  2863. void idFuncRadioChatter::Event_Activate( idEntity *activator ) {
  2864. idPlayer *player;
  2865. const char *sound;
  2866. const idSoundShader *shader;
  2867. int length;
  2868. if ( activator->IsType( idPlayer::Type ) ) {
  2869. player = static_cast<idPlayer *>( activator );
  2870. } else {
  2871. player = gameLocal.GetLocalPlayer();
  2872. }
  2873. player->hud->HandleNamedEvent( "radioChatterUp" );
  2874. sound = spawnArgs.GetString( "snd_radiochatter", "" );
  2875. if ( sound && *sound ) {
  2876. shader = declManager->FindSound( sound );
  2877. player->StartSoundShader( shader, SND_CHANNEL_RADIO, SSF_GLOBAL, false, &length );
  2878. time = MS2SEC( length + 150 );
  2879. }
  2880. // we still put the hud up because this is used with no sound on
  2881. // certain frame commands when the chatter is triggered
  2882. PostEventSec( &EV_ResetRadioHud, time, player );
  2883. }
  2884. /*
  2885. ================
  2886. idFuncRadioChatter::Event_ResetRadioHud
  2887. ================
  2888. */
  2889. void idFuncRadioChatter::Event_ResetRadioHud( idEntity *activator ) {
  2890. idPlayer *player = ( activator->IsType( idPlayer::Type ) ) ? static_cast<idPlayer *>( activator ) : gameLocal.GetLocalPlayer();
  2891. player->hud->HandleNamedEvent( "radioChatterDown" );
  2892. ActivateTargets( activator );
  2893. }
  2894. /*
  2895. ===============================================================================
  2896. idPhantomObjects
  2897. ===============================================================================
  2898. */
  2899. CLASS_DECLARATION( idEntity, idPhantomObjects )
  2900. EVENT( EV_Activate, idPhantomObjects::Event_Activate )
  2901. END_CLASS
  2902. /*
  2903. ===============
  2904. idPhantomObjects::idPhantomObjects
  2905. ===============
  2906. */
  2907. idPhantomObjects::idPhantomObjects() {
  2908. target = NULL;
  2909. end_time = 0;
  2910. throw_time = 0.0f;
  2911. shake_time = 0.0f;
  2912. shake_ang.Zero();
  2913. speed = 0.0f;
  2914. min_wait = 0;
  2915. max_wait = 0;
  2916. fl.neverDormant = false;
  2917. }
  2918. /*
  2919. ===============
  2920. idPhantomObjects::Save
  2921. ===============
  2922. */
  2923. void idPhantomObjects::Save( idSaveGame *savefile ) const {
  2924. int i;
  2925. savefile->WriteInt( end_time );
  2926. savefile->WriteFloat( throw_time );
  2927. savefile->WriteFloat( shake_time );
  2928. savefile->WriteVec3( shake_ang );
  2929. savefile->WriteFloat( speed );
  2930. savefile->WriteInt( min_wait );
  2931. savefile->WriteInt( max_wait );
  2932. target.Save( savefile );
  2933. savefile->WriteInt( targetTime.Num() );
  2934. for( i = 0; i < targetTime.Num(); i++ ) {
  2935. savefile->WriteInt( targetTime[ i ] );
  2936. }
  2937. for( i = 0; i < lastTargetPos.Num(); i++ ) {
  2938. savefile->WriteVec3( lastTargetPos[ i ] );
  2939. }
  2940. }
  2941. /*
  2942. ===============
  2943. idPhantomObjects::Restore
  2944. ===============
  2945. */
  2946. void idPhantomObjects::Restore( idRestoreGame *savefile ) {
  2947. int num;
  2948. int i;
  2949. savefile->ReadInt( end_time );
  2950. savefile->ReadFloat( throw_time );
  2951. savefile->ReadFloat( shake_time );
  2952. savefile->ReadVec3( shake_ang );
  2953. savefile->ReadFloat( speed );
  2954. savefile->ReadInt( min_wait );
  2955. savefile->ReadInt( max_wait );
  2956. target.Restore( savefile );
  2957. savefile->ReadInt( num );
  2958. targetTime.SetGranularity( 1 );
  2959. targetTime.SetNum( num );
  2960. lastTargetPos.SetGranularity( 1 );
  2961. lastTargetPos.SetNum( num );
  2962. for( i = 0; i < num; i++ ) {
  2963. savefile->ReadInt( targetTime[ i ] );
  2964. }
  2965. for( i = 0; i < num; i++ ) {
  2966. savefile->ReadVec3( lastTargetPos[ i ] );
  2967. }
  2968. }
  2969. /*
  2970. ===============
  2971. idPhantomObjects::Spawn
  2972. ===============
  2973. */
  2974. void idPhantomObjects::Spawn( void ) {
  2975. throw_time = spawnArgs.GetFloat( "time", "5" );
  2976. speed = spawnArgs.GetFloat( "speed", "1200" );
  2977. shake_time = spawnArgs.GetFloat( "shake_time", "1" );
  2978. throw_time -= shake_time;
  2979. if ( throw_time < 0.0f ) {
  2980. throw_time = 0.0f;
  2981. }
  2982. min_wait = SEC2MS( spawnArgs.GetFloat( "min_wait", "1" ) );
  2983. max_wait = SEC2MS( spawnArgs.GetFloat( "max_wait", "3" ) );
  2984. shake_ang = spawnArgs.GetVector( "shake_ang", "65 65 65" );
  2985. Hide();
  2986. GetPhysics()->SetContents( 0 );
  2987. }
  2988. /*
  2989. ================
  2990. idPhantomObjects::Event_Activate
  2991. ================
  2992. */
  2993. void idPhantomObjects::Event_Activate( idEntity *activator ) {
  2994. int i;
  2995. float time;
  2996. float frac;
  2997. float scale;
  2998. if ( thinkFlags & TH_THINK ) {
  2999. BecomeInactive( TH_THINK );
  3000. return;
  3001. }
  3002. RemoveNullTargets();
  3003. if ( !targets.Num() ) {
  3004. return;
  3005. }
  3006. if ( !activator || !activator->IsType( idActor::Type ) ) {
  3007. target = gameLocal.GetLocalPlayer();
  3008. } else {
  3009. target = static_cast<idActor *>( activator );
  3010. }
  3011. end_time = gameLocal.time + SEC2MS( spawnArgs.GetFloat( "end_time", "0" ) );
  3012. targetTime.SetNum( targets.Num() );
  3013. lastTargetPos.SetNum( targets.Num() );
  3014. const idVec3 &toPos = target.GetEntity()->GetEyePosition();
  3015. // calculate the relative times of all the objects
  3016. time = 0.0f;
  3017. for( i = 0; i < targetTime.Num(); i++ ) {
  3018. targetTime[ i ] = SEC2MS( time );
  3019. lastTargetPos[ i ] = toPos;
  3020. frac = 1.0f - ( float )i / ( float )targetTime.Num();
  3021. time += ( gameLocal.random.RandomFloat() + 1.0f ) * 0.5f * frac + 0.1f;
  3022. }
  3023. // scale up the times to fit within throw_time
  3024. scale = throw_time / time;
  3025. for( i = 0; i < targetTime.Num(); i++ ) {
  3026. targetTime[ i ] = gameLocal.time + SEC2MS( shake_time )+ targetTime[ i ] * scale;
  3027. }
  3028. BecomeActive( TH_THINK );
  3029. }
  3030. /*
  3031. ===============
  3032. idPhantomObjects::Think
  3033. ================
  3034. */
  3035. void idPhantomObjects::Think( void ) {
  3036. int i;
  3037. int num;
  3038. float time;
  3039. idVec3 vel;
  3040. idVec3 ang;
  3041. idEntity *ent;
  3042. idActor *targetEnt;
  3043. idPhysics *entPhys;
  3044. trace_t tr;
  3045. // if we are completely closed off from the player, don't do anything at all
  3046. if ( CheckDormant() ) {
  3047. return;
  3048. }
  3049. if ( !( thinkFlags & TH_THINK ) ) {
  3050. BecomeInactive( thinkFlags & ~TH_THINK );
  3051. return;
  3052. }
  3053. targetEnt = target.GetEntity();
  3054. if ( !targetEnt || ( targetEnt->health <= 0 ) || ( end_time && ( gameLocal.time > end_time ) ) || gameLocal.inCinematic ) {
  3055. BecomeInactive( TH_THINK );
  3056. }
  3057. const idVec3 &toPos = targetEnt->GetEyePosition();
  3058. num = 0;
  3059. for ( i = 0; i < targets.Num(); i++ ) {
  3060. ent = targets[ i ].GetEntity();
  3061. if ( !ent ) {
  3062. continue;
  3063. }
  3064. if ( ent->fl.hidden ) {
  3065. // don't throw hidden objects
  3066. continue;
  3067. }
  3068. if ( !targetTime[ i ] ) {
  3069. // already threw this object
  3070. continue;
  3071. }
  3072. num++;
  3073. time = MS2SEC( targetTime[ i ] - gameLocal.time );
  3074. if ( time > shake_time ) {
  3075. continue;
  3076. }
  3077. entPhys = ent->GetPhysics();
  3078. const idVec3 &entOrg = entPhys->GetOrigin();
  3079. gameLocal.clip.TracePoint( tr, entOrg, toPos, MASK_OPAQUE, ent );
  3080. if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == targetEnt ) ) {
  3081. lastTargetPos[ i ] = toPos;
  3082. }
  3083. if ( time < 0.0f ) {
  3084. idAI::PredictTrajectory( entPhys->GetOrigin(), lastTargetPos[ i ], speed, entPhys->GetGravity(),
  3085. entPhys->GetClipModel(), entPhys->GetClipMask(), 256.0f, ent, targetEnt, ai_debugTrajectory.GetBool() ? 1 : 0, vel );
  3086. vel *= speed;
  3087. entPhys->SetLinearVelocity( vel );
  3088. if ( !end_time ) {
  3089. targetTime[ i ] = 0;
  3090. } else {
  3091. targetTime[ i ] = gameLocal.time + gameLocal.random.RandomInt( max_wait - min_wait ) + min_wait;
  3092. }
  3093. if ( ent->IsType( idMoveable::Type ) ) {
  3094. idMoveable *ment = static_cast<idMoveable*>( ent );
  3095. ment->EnableDamage( true, 2.5f );
  3096. }
  3097. } else {
  3098. // this is not the right way to set the angular velocity, but the effect is nice, so I'm keeping it. :)
  3099. ang.Set( gameLocal.random.CRandomFloat() * shake_ang.x, gameLocal.random.CRandomFloat() * shake_ang.y, gameLocal.random.CRandomFloat() * shake_ang.z );
  3100. ang *= ( 1.0f - time / shake_time );
  3101. entPhys->SetAngularVelocity( ang );
  3102. }
  3103. }
  3104. if ( !num ) {
  3105. BecomeInactive( TH_THINK );
  3106. }
  3107. }
  3108. #ifdef _D3XP
  3109. /*
  3110. ===============================================================================
  3111. idShockwave
  3112. ===============================================================================
  3113. */
  3114. CLASS_DECLARATION( idEntity, idShockwave )
  3115. EVENT( EV_Activate, idShockwave::Event_Activate )
  3116. END_CLASS
  3117. /*
  3118. ===============
  3119. idShockwave::idShockwave
  3120. ===============
  3121. */
  3122. idShockwave::idShockwave() {
  3123. isActive = false;
  3124. startTime = 0;
  3125. duration = 0;
  3126. startSize = 0.f;
  3127. endSize = 0.f;
  3128. currentSize = 0.f;
  3129. magnitude = 0.f;
  3130. height = 0.0f;
  3131. playerDamaged = false;
  3132. playerDamageSize = 0.0f;
  3133. }
  3134. /*
  3135. ===============
  3136. idShockwave::~idShockwave
  3137. ===============
  3138. */
  3139. idShockwave::~idShockwave() {
  3140. }
  3141. /*
  3142. ===============
  3143. idShockwave::Save
  3144. ===============
  3145. */
  3146. void idShockwave::Save( idSaveGame *savefile ) const {
  3147. savefile->WriteBool( isActive );
  3148. savefile->WriteInt( startTime );
  3149. savefile->WriteInt( duration );
  3150. savefile->WriteFloat( startSize );
  3151. savefile->WriteFloat( endSize );
  3152. savefile->WriteFloat( currentSize );
  3153. savefile->WriteFloat( magnitude );
  3154. savefile->WriteFloat( height );
  3155. savefile->WriteBool( playerDamaged );
  3156. savefile->WriteFloat( playerDamageSize );
  3157. }
  3158. /*
  3159. ===============
  3160. idShockwave::Restore
  3161. ===============
  3162. */
  3163. void idShockwave::Restore( idRestoreGame *savefile ) {
  3164. savefile->ReadBool( isActive );
  3165. savefile->ReadInt( startTime );
  3166. savefile->ReadInt( duration );
  3167. savefile->ReadFloat( startSize );
  3168. savefile->ReadFloat( endSize );
  3169. savefile->ReadFloat( currentSize );
  3170. savefile->ReadFloat( magnitude );
  3171. savefile->ReadFloat( height );
  3172. savefile->ReadBool( playerDamaged );
  3173. savefile->ReadFloat( playerDamageSize );
  3174. }
  3175. /*
  3176. ===============
  3177. idShockwave::Spawn
  3178. ===============
  3179. */
  3180. void idShockwave::Spawn() {
  3181. spawnArgs.GetInt( "duration", "1000", duration );
  3182. spawnArgs.GetFloat( "startsize", "8", startSize );
  3183. spawnArgs.GetFloat( "endsize", "512", endSize );
  3184. spawnArgs.GetFloat( "magnitude", "100", magnitude );
  3185. spawnArgs.GetFloat( "height", "0", height);
  3186. spawnArgs.GetFloat( "player_damage_size", "20", playerDamageSize);
  3187. if ( spawnArgs.GetBool( "start_on" ) ) {
  3188. ProcessEvent( &EV_Activate, this );
  3189. }
  3190. }
  3191. /*
  3192. ===============
  3193. idShockwave::Think
  3194. ===============
  3195. */
  3196. void idShockwave::Think() {
  3197. int endTime;
  3198. if ( !isActive ) {
  3199. BecomeInactive( TH_THINK );
  3200. return;
  3201. }
  3202. endTime = startTime + duration;
  3203. if ( gameLocal.time < endTime ) {
  3204. float u;
  3205. float newSize;
  3206. // Expand shockwave
  3207. u = (float)(gameLocal.time - startTime) / (float)duration;
  3208. newSize = startSize + u * (endSize - startSize);
  3209. // Find all clipmodels between currentSize and newSize
  3210. idVec3 pos, end;
  3211. idClipModel *clipModelList[ MAX_GENTITIES ];
  3212. idClipModel *clip;
  3213. idEntity *ent;
  3214. int i, listedClipModels;
  3215. // Set bounds
  3216. pos = GetPhysics()->GetOrigin();
  3217. float zVal;
  3218. if(!height) {
  3219. zVal = newSize;
  3220. } else {
  3221. zVal = height/2.0f;
  3222. }
  3223. //Expand in a sphere
  3224. end = pos + idVec3( newSize, newSize, zVal );
  3225. idBounds bounds( end );
  3226. end = pos + idVec3( -newSize, -newSize, -zVal );
  3227. bounds.AddPoint( end );
  3228. if(g_debugShockwave.GetBool()) {
  3229. gameRenderWorld->DebugBounds(colorRed, bounds, vec3_origin);
  3230. }
  3231. listedClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
  3232. for ( i = 0; i < listedClipModels; i++ ) {
  3233. clip = clipModelList[ i ];
  3234. ent = clip->GetEntity();
  3235. if ( ent->IsHidden() ) {
  3236. continue;
  3237. }
  3238. if ( !ent->IsType( idMoveable::Type ) && !ent->IsType( idAFEntity_Base::Type ) && !ent->IsType( idPlayer::Type )) {
  3239. continue;
  3240. }
  3241. idVec3 point = ent->GetPhysics()->GetOrigin();
  3242. idVec3 force = point - pos;
  3243. float dist = force.Normalize();
  3244. if(ent->IsType( idPlayer::Type )) {
  3245. if(ent->GetPhysics()->GetAbsBounds().IntersectsBounds(bounds)) {
  3246. //For player damage we check the current radius and a specified player damage ring size
  3247. if ( dist <= newSize && dist > newSize-playerDamageSize ) {
  3248. idStr damageDef = spawnArgs.GetString("def_player_damage", "");
  3249. if(damageDef.Length() > 0 && !playerDamaged) {
  3250. playerDamaged = true; //Only damage once per shockwave
  3251. idPlayer* player = static_cast< idPlayer* >( ent );
  3252. idVec3 dir = ent->GetPhysics()->GetOrigin() - pos;
  3253. dir.NormalizeFast();
  3254. player->Damage(NULL, NULL, dir, damageDef, 1.0f, INVALID_JOINT);
  3255. }
  3256. }
  3257. }
  3258. } else {
  3259. // If the object is inside the current expansion...
  3260. if ( dist <= newSize && dist > currentSize ) {
  3261. force.z += 4.f;
  3262. force.NormalizeFast();
  3263. if ( ent->IsType( idAFEntity_Base::Type ) ) {
  3264. force = force * (ent->GetPhysics()->GetMass() * magnitude * 0.01f);
  3265. } else {
  3266. force = force * ent->GetPhysics()->GetMass() * magnitude;
  3267. }
  3268. // Kick it up, move force point off object origin
  3269. float rad = ent->GetPhysics()->GetBounds().GetRadius();
  3270. point.x += gameLocal.random.CRandomFloat() * rad;
  3271. point.y += gameLocal.random.CRandomFloat() * rad;
  3272. int j;
  3273. for( j=0; j < ent->GetPhysics()->GetNumClipModels(); j++ ) {
  3274. ent->GetPhysics()->AddForce( j, point, force );
  3275. }
  3276. }
  3277. }
  3278. }
  3279. // Update currentSize for next frame
  3280. currentSize = newSize;
  3281. } else {
  3282. // turn off
  3283. isActive = false;
  3284. }
  3285. }
  3286. /*
  3287. ===============
  3288. idShockwave::Event_Activate
  3289. ===============
  3290. */
  3291. void idShockwave::Event_Activate( idEntity *activator ) {
  3292. isActive = true;
  3293. startTime = gameLocal.time;
  3294. playerDamaged = false;
  3295. BecomeActive( TH_THINK );
  3296. }
  3297. /*
  3298. ===============================================================================
  3299. idFuncMountedObject
  3300. ===============================================================================
  3301. */
  3302. CLASS_DECLARATION( idEntity, idFuncMountedObject )
  3303. EVENT( EV_Touch, idFuncMountedObject::Event_Touch )
  3304. EVENT( EV_Activate, idFuncMountedObject::Event_Activate )
  3305. END_CLASS
  3306. /*
  3307. ===============
  3308. idFuncMountedObject::idFuncMountedObject
  3309. ===============
  3310. */
  3311. idFuncMountedObject::idFuncMountedObject() {
  3312. isMounted = false;
  3313. scriptFunction = NULL;
  3314. mountedPlayer = NULL;
  3315. harc = 0;
  3316. varc = 0;
  3317. }
  3318. /*
  3319. ===============
  3320. idFuncMountedObject::idFuncMountedObject
  3321. ===============
  3322. */
  3323. idFuncMountedObject::~idFuncMountedObject() {
  3324. }
  3325. /*
  3326. ===============
  3327. idFuncMountedObject::Spawn
  3328. ===============
  3329. */
  3330. void idFuncMountedObject::Spawn( void ) {
  3331. // Get viewOffset
  3332. spawnArgs.GetInt( "harc", "45", harc );
  3333. spawnArgs.GetInt( "varc", "30", varc );
  3334. // Get script function
  3335. idStr funcName = spawnArgs.GetString( "call", "" );
  3336. if ( funcName.Length() ) {
  3337. scriptFunction = gameLocal.program.FindFunction( funcName );
  3338. if ( scriptFunction == NULL ) {
  3339. gameLocal.Warning( "idFuncMountedObject '%s' at (%s) calls unknown function '%s'\n", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcName.c_str() );
  3340. }
  3341. }
  3342. BecomeActive( TH_THINK );
  3343. }
  3344. /*
  3345. ================
  3346. idFuncMountedObject::Think
  3347. ================
  3348. */
  3349. void idFuncMountedObject::Think( void ) {
  3350. idEntity::Think();
  3351. }
  3352. /*
  3353. ================
  3354. idFuncMountedObject::GetViewInfo
  3355. ================
  3356. */
  3357. void idFuncMountedObject::GetAngleRestrictions( int &yaw_min, int &yaw_max, int &pitch ) {
  3358. idMat3 axis;
  3359. idAngles angs;
  3360. axis = GetPhysics()->GetAxis();
  3361. angs = axis.ToAngles();
  3362. yaw_min = angs.yaw - harc;
  3363. yaw_min = idMath::AngleNormalize180( yaw_min );
  3364. yaw_max = angs.yaw + harc;
  3365. yaw_max = idMath::AngleNormalize180( yaw_max );
  3366. pitch = varc;
  3367. }
  3368. /*
  3369. ================
  3370. idFuncMountedObject::Event_Touch
  3371. ================
  3372. */
  3373. void idFuncMountedObject::Event_Touch( idEntity *other, trace_t *trace ) {
  3374. ProcessEvent( &EV_Activate, other );
  3375. }
  3376. /*
  3377. ================
  3378. idFuncMountedObject::Event_Activate
  3379. ================
  3380. */
  3381. void idFuncMountedObject::Event_Activate( idEntity *activator ) {
  3382. if ( !isMounted && activator->IsType( idPlayer::Type ) ) {
  3383. idPlayer *client = (idPlayer *)activator;
  3384. mountedPlayer = client;
  3385. /*
  3386. // Place player at path_corner targeted by mounted object
  3387. int i;
  3388. idPathCorner *spot;
  3389. for ( i = 0; i < targets.Num(); i++ ) {
  3390. if ( targets[i]->IsType( idPathCorner::Type ) ) {
  3391. spot = (idPathCorner*)targets[i];
  3392. break;
  3393. }
  3394. }
  3395. mountedPlayer->GetPhysics()->SetOrigin( spot->GetPhysics()->GetOrigin() );
  3396. mountedPlayer->GetPhysics()->SetAxis( spot->GetPhysics()->GetAxis() );
  3397. */
  3398. mountedPlayer->Bind( this, true );
  3399. mountedPlayer->mountedObject = this;
  3400. // Call a script function
  3401. idThread *mountthread;
  3402. if ( scriptFunction ) {
  3403. mountthread = new idThread( scriptFunction );
  3404. mountthread->DelayedStart( 0 );
  3405. }
  3406. isMounted = true;
  3407. }
  3408. }
  3409. /*
  3410. ===============================================================================
  3411. idFuncMountedWeapon
  3412. ===============================================================================
  3413. */
  3414. CLASS_DECLARATION( idFuncMountedObject, idFuncMountedWeapon )
  3415. EVENT( EV_PostSpawn, idFuncMountedWeapon::Event_PostSpawn )
  3416. END_CLASS
  3417. idFuncMountedWeapon::idFuncMountedWeapon() {
  3418. turret = NULL;
  3419. weaponLastFireTime = 0;
  3420. weaponFireDelay = 0;
  3421. projectile = NULL;
  3422. }
  3423. idFuncMountedWeapon::~idFuncMountedWeapon() {
  3424. }
  3425. void idFuncMountedWeapon::Spawn( void ) {
  3426. // Get projectile info
  3427. projectile = gameLocal.FindEntityDefDict( spawnArgs.GetString( "def_projectile" ), false );
  3428. if ( !projectile ) {
  3429. gameLocal.Warning( "Invalid projectile on func_mountedweapon." );
  3430. }
  3431. float firerate;
  3432. spawnArgs.GetFloat( "firerate", "3", firerate );
  3433. weaponFireDelay = 1000.f / firerate;
  3434. // Get the firing sound
  3435. idStr fireSound;
  3436. spawnArgs.GetString( "snd_fire", "", fireSound );
  3437. soundFireWeapon = declManager->FindSound( fireSound );
  3438. PostEventMS( &EV_PostSpawn, 0 );
  3439. }
  3440. void idFuncMountedWeapon::Think( void ) {
  3441. if ( isMounted && turret ) {
  3442. idVec3 vec = mountedPlayer->viewAngles.ToForward();
  3443. idAngles ang = mountedPlayer->GetLocalVector( vec ).ToAngles();
  3444. turret->GetPhysics()->SetAxis( ang.ToMat3() );
  3445. turret->UpdateVisuals();
  3446. // Check for firing
  3447. if ( mountedPlayer->usercmd.buttons & BUTTON_ATTACK && ( gameLocal.time > weaponLastFireTime + weaponFireDelay ) ) {
  3448. // FIRE!
  3449. idEntity *ent;
  3450. idProjectile *proj;
  3451. idBounds projBounds;
  3452. idVec3 dir;
  3453. gameLocal.SpawnEntityDef( *projectile, &ent );
  3454. if ( !ent || !ent->IsType( idProjectile::Type ) ) {
  3455. const char *projectileName = spawnArgs.GetString( "def_projectile" );
  3456. gameLocal.Error( "'%s' is not an idProjectile", projectileName );
  3457. }
  3458. mountedPlayer->GetViewPos( muzzleOrigin, muzzleAxis );
  3459. muzzleOrigin += ( muzzleAxis[0] * 128 );
  3460. muzzleOrigin -= ( muzzleAxis[2] * 20 );
  3461. dir = muzzleAxis[0];
  3462. proj = static_cast<idProjectile *>(ent);
  3463. proj->Create( this, muzzleOrigin, dir );
  3464. projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() );
  3465. proj->Launch( muzzleOrigin, dir, vec3_origin );
  3466. StartSoundShader( soundFireWeapon, SND_CHANNEL_WEAPON, SSF_GLOBAL, false, NULL );
  3467. weaponLastFireTime = gameLocal.time;
  3468. }
  3469. }
  3470. idFuncMountedObject::Think();
  3471. }
  3472. void idFuncMountedWeapon::Event_PostSpawn( void ) {
  3473. if ( targets.Num() >= 1 ) {
  3474. for ( int i=0; i < targets.Num(); i++ ) {
  3475. if ( targets[i].GetEntity()->IsType( idStaticEntity::Type ) ) {
  3476. turret = targets[i].GetEntity();
  3477. break;
  3478. }
  3479. }
  3480. } else {
  3481. gameLocal.Warning( "idFuncMountedWeapon::Spawn: Please target one model for a turret\n" );
  3482. }
  3483. }
  3484. /*
  3485. ===============================================================================
  3486. idPortalSky
  3487. ===============================================================================
  3488. */
  3489. CLASS_DECLARATION( idEntity, idPortalSky )
  3490. EVENT( EV_PostSpawn, idPortalSky::Event_PostSpawn )
  3491. EVENT( EV_Activate, idPortalSky::Event_Activate )
  3492. END_CLASS
  3493. /*
  3494. ===============
  3495. idPortalSky::idPortalSky
  3496. ===============
  3497. */
  3498. idPortalSky::idPortalSky( void ) {
  3499. }
  3500. /*
  3501. ===============
  3502. idPortalSky::~idPortalSky
  3503. ===============
  3504. */
  3505. idPortalSky::~idPortalSky( void ) {
  3506. }
  3507. /*
  3508. ===============
  3509. idPortalSky::Spawn
  3510. ===============
  3511. */
  3512. void idPortalSky::Spawn( void ) {
  3513. if ( !spawnArgs.GetBool( "triggered" ) ) {
  3514. PostEventMS( &EV_PostSpawn, 1 );
  3515. }
  3516. }
  3517. /*
  3518. ================
  3519. idPortalSky::Event_PostSpawn
  3520. ================
  3521. */
  3522. void idPortalSky::Event_PostSpawn() {
  3523. gameLocal.SetPortalSkyEnt( this );
  3524. }
  3525. /*
  3526. ================
  3527. idPortalSky::Event_Activate
  3528. ================
  3529. */
  3530. void idPortalSky::Event_Activate( idEntity *activator ) {
  3531. gameLocal.SetPortalSkyEnt( this );
  3532. }
  3533. #endif /* _D3XP */