Entity.cpp 143 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. /*
  24. ===============================================================================
  25. idEntity
  26. ===============================================================================
  27. */
  28. idCVar net_errorSmoothingMaxDecay( "net_errorSmoothingMaxDecay", "25.0", CVAR_FLOAT, "Max rate at which origin error smoothing decays (in units per game frame)" );
  29. idCVar net_errorSmoothingDecay( "net_errorSmoothingDecay", "0.06", CVAR_FLOAT, "Rate at which error smoothing decays (in percent per game frame)" );
  30. // overridable events
  31. const idEventDef EV_PostSpawn( "<postspawn>", NULL );
  32. const idEventDef EV_FindTargets( "<findTargets>", NULL );
  33. const idEventDef EV_Touch( "<touch>", "et" );
  34. const idEventDef EV_GetName( "getName", NULL, 's' );
  35. const idEventDef EV_SetName( "setName", "s" );
  36. const idEventDef EV_Activate( "activate", "e" );
  37. const idEventDef EV_ActivateTargets( "activateTargets", "e" );
  38. const idEventDef EV_NumTargets( "numTargets", NULL, 'f' );
  39. const idEventDef EV_GetTarget( "getTarget", "f", 'e' );
  40. const idEventDef EV_RandomTarget( "randomTarget", "s", 'e' );
  41. const idEventDef EV_Bind( "bind", "e" );
  42. const idEventDef EV_BindPosition( "bindPosition", "e" );
  43. const idEventDef EV_BindToJoint( "bindToJoint", "esf" );
  44. const idEventDef EV_Unbind( "unbind", NULL );
  45. const idEventDef EV_RemoveBinds( "removeBinds" );
  46. const idEventDef EV_SpawnBind( "<spawnbind>", NULL );
  47. const idEventDef EV_SetOwner( "setOwner", "e" );
  48. const idEventDef EV_SetModel( "setModel", "s" );
  49. const idEventDef EV_SetSkin( "setSkin", "s" );
  50. const idEventDef EV_GetWorldOrigin( "getWorldOrigin", NULL, 'v' );
  51. const idEventDef EV_SetWorldOrigin( "setWorldOrigin", "v" );
  52. const idEventDef EV_GetOrigin( "getOrigin", NULL, 'v' );
  53. const idEventDef EV_SetOrigin( "setOrigin", "v" );
  54. const idEventDef EV_GetAngles( "getAngles", NULL, 'v' );
  55. const idEventDef EV_SetAngles( "setAngles", "v" );
  56. const idEventDef EV_GetLinearVelocity( "getLinearVelocity", NULL, 'v' );
  57. const idEventDef EV_SetLinearVelocity( "setLinearVelocity", "v" );
  58. const idEventDef EV_GetAngularVelocity( "getAngularVelocity", NULL, 'v' );
  59. const idEventDef EV_SetAngularVelocity( "setAngularVelocity", "v" );
  60. const idEventDef EV_GetSize( "getSize", NULL, 'v' );
  61. const idEventDef EV_SetSize( "setSize", "vv" );
  62. const idEventDef EV_GetMins( "getMins", NULL, 'v' );
  63. const idEventDef EV_GetMaxs( "getMaxs", NULL, 'v' );
  64. const idEventDef EV_IsHidden( "isHidden", NULL, 'd' );
  65. const idEventDef EV_Hide( "hide", NULL );
  66. const idEventDef EV_Show( "show", NULL );
  67. const idEventDef EV_Touches( "touches", "E", 'd' );
  68. const idEventDef EV_ClearSignal( "clearSignal", "d" );
  69. const idEventDef EV_GetShaderParm( "getShaderParm", "d", 'f' );
  70. const idEventDef EV_SetShaderParm( "setShaderParm", "df" );
  71. const idEventDef EV_SetShaderParms( "setShaderParms", "ffff" );
  72. const idEventDef EV_SetColor( "setColor", "fff" );
  73. const idEventDef EV_GetColor( "getColor", NULL, 'v' );
  74. const idEventDef EV_CacheSoundShader( "cacheSoundShader", "s" );
  75. const idEventDef EV_StartSoundShader( "startSoundShader", "sd", 'f' );
  76. const idEventDef EV_StartSound( "startSound", "sdd", 'f' );
  77. const idEventDef EV_StopSound( "stopSound", "dd" );
  78. const idEventDef EV_FadeSound( "fadeSound", "dff" );
  79. const idEventDef EV_SetGuiParm( "setGuiParm", "ss" );
  80. const idEventDef EV_SetGuiFloat( "setGuiFloat", "sf" );
  81. const idEventDef EV_GetNextKey( "getNextKey", "ss", 's' );
  82. const idEventDef EV_SetKey( "setKey", "ss" );
  83. const idEventDef EV_GetKey( "getKey", "s", 's' );
  84. const idEventDef EV_GetIntKey( "getIntKey", "s", 'f' );
  85. const idEventDef EV_GetFloatKey( "getFloatKey", "s", 'f' );
  86. const idEventDef EV_GetVectorKey( "getVectorKey", "s", 'v' );
  87. const idEventDef EV_GetEntityKey( "getEntityKey", "s", 'e' );
  88. const idEventDef EV_RestorePosition( "restorePosition" );
  89. const idEventDef EV_UpdateCameraTarget( "<updateCameraTarget>", NULL );
  90. const idEventDef EV_DistanceTo( "distanceTo", "E", 'f' );
  91. const idEventDef EV_DistanceToPoint( "distanceToPoint", "v", 'f' );
  92. const idEventDef EV_StartFx( "startFx", "s" );
  93. const idEventDef EV_HasFunction( "hasFunction", "s", 'd' );
  94. const idEventDef EV_CallFunction( "callFunction", "s" );
  95. const idEventDef EV_SetNeverDormant( "setNeverDormant", "d" );
  96. const idEventDef EV_SetGui ( "setGui", "ds" );
  97. const idEventDef EV_PrecacheGui ( "precacheGui", "s" );
  98. const idEventDef EV_GetGuiParm ( "getGuiParm", "ds", 's' );
  99. const idEventDef EV_GetGuiParmFloat ( "getGuiParmFloat", "ds", 'f' );
  100. const idEventDef EV_MotionBlurOn( "motionBlurOn" );
  101. const idEventDef EV_MotionBlurOff( "motionBlurOff" );
  102. const idEventDef EV_GuiNamedEvent ( "guiNamedEvent", "ds" );
  103. ABSTRACT_DECLARATION( idClass, idEntity )
  104. EVENT( EV_GetName, idEntity::Event_GetName )
  105. EVENT( EV_SetName, idEntity::Event_SetName )
  106. EVENT( EV_FindTargets, idEntity::Event_FindTargets )
  107. EVENT( EV_ActivateTargets, idEntity::Event_ActivateTargets )
  108. EVENT( EV_NumTargets, idEntity::Event_NumTargets )
  109. EVENT( EV_GetTarget, idEntity::Event_GetTarget )
  110. EVENT( EV_RandomTarget, idEntity::Event_RandomTarget )
  111. EVENT( EV_BindToJoint, idEntity::Event_BindToJoint )
  112. EVENT( EV_RemoveBinds, idEntity::Event_RemoveBinds )
  113. EVENT( EV_Bind, idEntity::Event_Bind )
  114. EVENT( EV_BindPosition, idEntity::Event_BindPosition )
  115. EVENT( EV_Unbind, idEntity::Event_Unbind )
  116. EVENT( EV_SpawnBind, idEntity::Event_SpawnBind )
  117. EVENT( EV_SetOwner, idEntity::Event_SetOwner )
  118. EVENT( EV_SetModel, idEntity::Event_SetModel )
  119. EVENT( EV_SetSkin, idEntity::Event_SetSkin )
  120. EVENT( EV_GetShaderParm, idEntity::Event_GetShaderParm )
  121. EVENT( EV_SetShaderParm, idEntity::Event_SetShaderParm )
  122. EVENT( EV_SetShaderParms, idEntity::Event_SetShaderParms )
  123. EVENT( EV_SetColor, idEntity::Event_SetColor )
  124. EVENT( EV_GetColor, idEntity::Event_GetColor )
  125. EVENT( EV_IsHidden, idEntity::Event_IsHidden )
  126. EVENT( EV_Hide, idEntity::Event_Hide )
  127. EVENT( EV_Show, idEntity::Event_Show )
  128. EVENT( EV_CacheSoundShader, idEntity::Event_CacheSoundShader )
  129. EVENT( EV_StartSoundShader, idEntity::Event_StartSoundShader )
  130. EVENT( EV_StartSound, idEntity::Event_StartSound )
  131. EVENT( EV_StopSound, idEntity::Event_StopSound )
  132. EVENT( EV_FadeSound, idEntity::Event_FadeSound )
  133. EVENT( EV_GetWorldOrigin, idEntity::Event_GetWorldOrigin )
  134. EVENT( EV_SetWorldOrigin, idEntity::Event_SetWorldOrigin )
  135. EVENT( EV_GetOrigin, idEntity::Event_GetOrigin )
  136. EVENT( EV_SetOrigin, idEntity::Event_SetOrigin )
  137. EVENT( EV_GetAngles, idEntity::Event_GetAngles )
  138. EVENT( EV_SetAngles, idEntity::Event_SetAngles )
  139. EVENT( EV_GetLinearVelocity, idEntity::Event_GetLinearVelocity )
  140. EVENT( EV_SetLinearVelocity, idEntity::Event_SetLinearVelocity )
  141. EVENT( EV_GetAngularVelocity, idEntity::Event_GetAngularVelocity )
  142. EVENT( EV_SetAngularVelocity, idEntity::Event_SetAngularVelocity )
  143. EVENT( EV_GetSize, idEntity::Event_GetSize )
  144. EVENT( EV_SetSize, idEntity::Event_SetSize )
  145. EVENT( EV_GetMins, idEntity::Event_GetMins)
  146. EVENT( EV_GetMaxs, idEntity::Event_GetMaxs )
  147. EVENT( EV_Touches, idEntity::Event_Touches )
  148. EVENT( EV_SetGuiParm, idEntity::Event_SetGuiParm )
  149. EVENT( EV_SetGuiFloat, idEntity::Event_SetGuiFloat )
  150. EVENT( EV_GetNextKey, idEntity::Event_GetNextKey )
  151. EVENT( EV_SetKey, idEntity::Event_SetKey )
  152. EVENT( EV_GetKey, idEntity::Event_GetKey )
  153. EVENT( EV_GetIntKey, idEntity::Event_GetIntKey )
  154. EVENT( EV_GetFloatKey, idEntity::Event_GetFloatKey )
  155. EVENT( EV_GetVectorKey, idEntity::Event_GetVectorKey )
  156. EVENT( EV_GetEntityKey, idEntity::Event_GetEntityKey )
  157. EVENT( EV_RestorePosition, idEntity::Event_RestorePosition )
  158. EVENT( EV_UpdateCameraTarget, idEntity::Event_UpdateCameraTarget )
  159. EVENT( EV_DistanceTo, idEntity::Event_DistanceTo )
  160. EVENT( EV_DistanceToPoint, idEntity::Event_DistanceToPoint )
  161. EVENT( EV_StartFx, idEntity::Event_StartFx )
  162. EVENT( EV_Thread_WaitFrame, idEntity::Event_WaitFrame )
  163. EVENT( EV_Thread_Wait, idEntity::Event_Wait )
  164. EVENT( EV_HasFunction, idEntity::Event_HasFunction )
  165. EVENT( EV_CallFunction, idEntity::Event_CallFunction )
  166. EVENT( EV_SetNeverDormant, idEntity::Event_SetNeverDormant )
  167. EVENT( EV_SetGui, idEntity::Event_SetGui )
  168. EVENT( EV_PrecacheGui, idEntity::Event_PrecacheGui )
  169. EVENT( EV_GetGuiParm, idEntity::Event_GetGuiParm )
  170. EVENT( EV_GetGuiParmFloat, idEntity::Event_GetGuiParmFloat )
  171. EVENT( EV_GuiNamedEvent, idEntity::Event_GuiNamedEvent )
  172. END_CLASS
  173. /*
  174. ================
  175. UpdateGuiParms
  176. ================
  177. */
  178. void UpdateGuiParms( idUserInterface *gui, const idDict *args ) {
  179. if ( gui == NULL || args == NULL ) {
  180. return;
  181. }
  182. const idKeyValue *kv = args->MatchPrefix( "gui_parm", NULL );
  183. while( kv ) {
  184. gui->SetStateString( kv->GetKey(), kv->GetValue() );
  185. kv = args->MatchPrefix( "gui_parm", kv );
  186. }
  187. gui->SetStateBool( "noninteractive", args->GetBool( "gui_noninteractive" ) ) ;
  188. gui->StateChanged( gameLocal.time );
  189. }
  190. /*
  191. ================
  192. AddRenderGui
  193. ================
  194. */
  195. void AddRenderGui( const char *name, idUserInterface **gui, const idDict *args ) {
  196. const idKeyValue *kv = args->MatchPrefix( "gui_parm", NULL );
  197. *gui = uiManager->FindGui( name, true, ( kv != NULL ) );
  198. UpdateGuiParms( *gui, args );
  199. }
  200. /*
  201. ================
  202. idGameEdit::ParseSpawnArgsToRenderEntity
  203. parse the static model parameters
  204. this is the canonical renderEntity parm parsing,
  205. which should be used by dmap and the editor
  206. ================
  207. */
  208. void idGameEdit::ParseSpawnArgsToRenderEntity( const idDict *args, renderEntity_t *renderEntity ) {
  209. int i;
  210. const char *temp;
  211. idVec3 color;
  212. float angle;
  213. const idDeclModelDef *modelDef;
  214. memset( renderEntity, 0, sizeof( *renderEntity ) );
  215. temp = args->GetString( "model" );
  216. modelDef = NULL;
  217. if ( temp[0] != '\0' ) {
  218. modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, temp, false ) );
  219. if ( modelDef ) {
  220. renderEntity->hModel = modelDef->ModelHandle();
  221. }
  222. if ( !renderEntity->hModel ) {
  223. renderEntity->hModel = renderModelManager->FindModel( temp );
  224. }
  225. }
  226. if ( renderEntity->hModel ) {
  227. renderEntity->bounds = renderEntity->hModel->Bounds( renderEntity );
  228. } else {
  229. renderEntity->bounds.Zero();
  230. }
  231. temp = args->GetString( "skin" );
  232. if ( temp[0] != '\0' ) {
  233. renderEntity->customSkin = declManager->FindSkin( temp );
  234. } else if ( modelDef ) {
  235. renderEntity->customSkin = modelDef->GetDefaultSkin();
  236. }
  237. temp = args->GetString( "shader" );
  238. if ( temp[0] != '\0' ) {
  239. renderEntity->customShader = declManager->FindMaterial( temp );
  240. }
  241. args->GetVector( "origin", "0 0 0", renderEntity->origin );
  242. // get the rotation matrix in either full form, or single angle form
  243. if ( !args->GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", renderEntity->axis ) ) {
  244. angle = args->GetFloat( "angle" );
  245. if ( angle != 0.0f ) {
  246. renderEntity->axis = idAngles( 0.0f, angle, 0.0f ).ToMat3();
  247. } else {
  248. renderEntity->axis.Identity();
  249. }
  250. }
  251. renderEntity->referenceSound = NULL;
  252. // get shader parms
  253. args->GetVector( "_color", "1 1 1", color );
  254. renderEntity->shaderParms[ SHADERPARM_RED ] = color[0];
  255. renderEntity->shaderParms[ SHADERPARM_GREEN ] = color[1];
  256. renderEntity->shaderParms[ SHADERPARM_BLUE ] = color[2];
  257. renderEntity->shaderParms[ 3 ] = args->GetFloat( "shaderParm3", "1" );
  258. renderEntity->shaderParms[ 4 ] = args->GetFloat( "shaderParm4", "0" );
  259. renderEntity->shaderParms[ 5 ] = args->GetFloat( "shaderParm5", "0" );
  260. renderEntity->shaderParms[ 6 ] = args->GetFloat( "shaderParm6", "0" );
  261. renderEntity->shaderParms[ 7 ] = args->GetFloat( "shaderParm7", "0" );
  262. renderEntity->shaderParms[ 8 ] = args->GetFloat( "shaderParm8", "0" );
  263. renderEntity->shaderParms[ 9 ] = args->GetFloat( "shaderParm9", "0" );
  264. renderEntity->shaderParms[ 10 ] = args->GetFloat( "shaderParm10", "0" );
  265. renderEntity->shaderParms[ 11 ] = args->GetFloat( "shaderParm11", "0" );
  266. // check noDynamicInteractions flag
  267. renderEntity->noDynamicInteractions = args->GetBool( "noDynamicInteractions" );
  268. // check noshadows flag
  269. renderEntity->noShadow = args->GetBool( "noshadows" );
  270. // check noselfshadows flag
  271. renderEntity->noSelfShadow = args->GetBool( "noselfshadows" );
  272. // init any guis, including entity-specific states
  273. for( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
  274. temp = args->GetString( i == 0 ? "gui" : va( "gui%d", i + 1 ) );
  275. if ( temp[ 0 ] != '\0' ) {
  276. AddRenderGui( temp, &renderEntity->gui[ i ], args );
  277. }
  278. }
  279. }
  280. /*
  281. ================
  282. idGameEdit::ParseSpawnArgsToRefSound
  283. parse the sound parameters
  284. this is the canonical refSound parm parsing,
  285. which should be used by dmap and the editor
  286. ================
  287. */
  288. void idGameEdit::ParseSpawnArgsToRefSound( const idDict *args, refSound_t *refSound ) {
  289. const char *temp;
  290. memset( refSound, 0, sizeof( *refSound ) );
  291. refSound->parms.minDistance = args->GetFloat( "s_mindistance" );
  292. refSound->parms.maxDistance = args->GetFloat( "s_maxdistance" );
  293. refSound->parms.volume = args->GetFloat( "s_volume" );
  294. refSound->parms.shakes = args->GetFloat( "s_shakes" );
  295. args->GetVector( "origin", "0 0 0", refSound->origin );
  296. refSound->referenceSound = NULL;
  297. // if a diversity is not specified, every sound start will make
  298. // a random one. Specifying diversity is usefull to make multiple
  299. // lights all share the same buzz sound offset, for instance.
  300. refSound->diversity = args->GetFloat( "s_diversity", "-1" );
  301. refSound->waitfortrigger = args->GetBool( "s_waitfortrigger" );
  302. if ( args->GetBool( "s_omni" ) ) {
  303. refSound->parms.soundShaderFlags |= SSF_OMNIDIRECTIONAL;
  304. }
  305. if ( args->GetBool( "s_looping" ) ) {
  306. refSound->parms.soundShaderFlags |= SSF_LOOPING;
  307. }
  308. if ( args->GetBool( "s_occlusion" ) ) {
  309. refSound->parms.soundShaderFlags |= SSF_NO_OCCLUSION;
  310. }
  311. if ( args->GetBool( "s_global" ) ) {
  312. refSound->parms.soundShaderFlags |= SSF_GLOBAL;
  313. }
  314. if ( args->GetBool( "s_unclamped" ) ) {
  315. refSound->parms.soundShaderFlags |= SSF_UNCLAMPED;
  316. }
  317. refSound->parms.soundClass = args->GetInt( "s_soundClass" );
  318. temp = args->GetString( "s_shader" );
  319. if ( temp[0] != '\0' ) {
  320. refSound->shader = declManager->FindSound( temp );
  321. }
  322. }
  323. /*
  324. ===============
  325. idEntity::UpdateChangeableSpawnArgs
  326. Any key val pair that might change during the course of the game ( via a gui or whatever )
  327. should be initialize here so a gui or other trigger can change something and have it updated
  328. properly. An optional source may be provided if the values reside in an outside dictionary and
  329. first need copied over to spawnArgs
  330. ===============
  331. */
  332. void idEntity::UpdateChangeableSpawnArgs( const idDict *source ) {
  333. int i;
  334. const char *target;
  335. if ( !source ) {
  336. source = &spawnArgs;
  337. }
  338. cameraTarget = NULL;
  339. target = source->GetString( "cameraTarget" );
  340. if ( target != NULL && target[0] != NULL ) {
  341. // update the camera taget
  342. PostEventMS( &EV_UpdateCameraTarget, 0 );
  343. }
  344. for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
  345. UpdateGuiParms( renderEntity.gui[ i ], source );
  346. }
  347. }
  348. /*
  349. ================
  350. idEntity::idEntity
  351. ================
  352. */
  353. idEntity::idEntity():
  354. useClientInterpolation( true ),
  355. predictionKey( INVALID_PREDICTION_KEY ),
  356. originDelta( vec3_zero ),
  357. axisDelta( mat3_identity ),
  358. interpolationBehavior( USE_NO_INTERPOLATION ) {
  359. entityNumber = ENTITYNUM_NONE;
  360. entityDefNumber = -1;
  361. spawnNode.SetOwner( this );
  362. activeNode.SetOwner( this );
  363. snapshotNode.SetOwner( this );
  364. snapshotChanged = -1;
  365. snapshotStale = false;
  366. snapshotBits = 0;
  367. thinkFlags = 0;
  368. dormantStart = 0;
  369. cinematic = false;
  370. renderView = NULL;
  371. cameraTarget = NULL;
  372. health = 0;
  373. physics = NULL;
  374. bindMaster = NULL;
  375. bindJoint = INVALID_JOINT;
  376. bindBody = -1;
  377. teamMaster = NULL;
  378. teamChain = NULL;
  379. signals = NULL;
  380. snapshotsReceived = 0;
  381. memset( PVSAreas, 0, sizeof( PVSAreas ) );
  382. numPVSAreas = -1;
  383. memset( &fl, 0, sizeof( fl ) );
  384. fl.neverDormant = true; // most entities never go dormant
  385. memset( &renderEntity, 0, sizeof( renderEntity ) );
  386. modelDefHandle = -1;
  387. memset( &refSound, 0, sizeof( refSound ) );
  388. mpGUIState = -1;
  389. memset( &xrayEntity, 0, sizeof( xrayEntity ) );
  390. timeGroup = TIME_GROUP1;
  391. xrayEntityHandle = -1;
  392. xraySkin = NULL;
  393. noGrab = false;
  394. }
  395. /*
  396. ================
  397. idEntity::FixupLocalizedStrings
  398. ================
  399. */
  400. void idEntity::FixupLocalizedStrings() {
  401. for ( int i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
  402. const idKeyValue *kv = spawnArgs.GetKeyVal( i );
  403. if ( idStr::Cmpn( kv->GetValue(), STRTABLE_ID, STRTABLE_ID_LENGTH ) == 0 ){
  404. spawnArgs.Set( kv->GetKey(), idLocalization::GetString( kv->GetValue() ) );
  405. }
  406. }
  407. }
  408. /*
  409. ================
  410. idEntity::Spawn
  411. ================
  412. */
  413. void idEntity::Spawn() {
  414. int i;
  415. const char *temp;
  416. idVec3 origin;
  417. idMat3 axis;
  418. const idKeyValue *networkSync;
  419. const char *classname;
  420. const char *scriptObjectName;
  421. gameLocal.RegisterEntity( this, -1, gameLocal.GetSpawnArgs() );
  422. spawnArgs.GetString( "classname", NULL, &classname );
  423. const idDeclEntityDef *def = gameLocal.FindEntityDef( classname, false );
  424. if ( def ) {
  425. entityDefNumber = def->Index();
  426. }
  427. FixupLocalizedStrings();
  428. // parse static models the same way the editor display does
  429. gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &renderEntity );
  430. renderEntity.entityNum = entityNumber;
  431. noGrab = spawnArgs.GetBool( "noGrab", "0" );
  432. xraySkin = NULL;
  433. renderEntity.xrayIndex = 1;
  434. idStr str;
  435. if ( spawnArgs.GetString( "skin_xray", "", str ) ) {
  436. xraySkin = declManager->FindSkin( str.c_str() );
  437. }
  438. // go dormant within 100ms so that when the map starts most monsters are dormant
  439. dormantStart = gameLocal.time - DELAY_DORMANT_TIME + 100;
  440. origin = renderEntity.origin;
  441. axis = renderEntity.axis;
  442. // do the audio parsing the same way dmap and the editor do
  443. gameEdit->ParseSpawnArgsToRefSound( &spawnArgs, &refSound );
  444. // only play SCHANNEL_PRIVATE when sndworld->PlaceListener() is called with this listenerId
  445. // don't spatialize sounds from the same entity
  446. refSound.listenerId = entityNumber + 1;
  447. cameraTarget = NULL;
  448. temp = spawnArgs.GetString( "cameraTarget" );
  449. if ( temp != NULL && temp[0] != NULL ) {
  450. // update the camera taget
  451. PostEventMS( &EV_UpdateCameraTarget, 0 );
  452. }
  453. for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
  454. UpdateGuiParms( renderEntity.gui[ i ], &spawnArgs );
  455. }
  456. fl.solidForTeam = spawnArgs.GetBool( "solidForTeam", "0" );
  457. fl.neverDormant = spawnArgs.GetBool( "neverDormant", "0" );
  458. fl.hidden = spawnArgs.GetBool( "hide", "0" );
  459. if ( fl.hidden ) {
  460. // make sure we're hidden, since a spawn function might not set it up right
  461. PostEventMS( &EV_Hide, 0 );
  462. }
  463. cinematic = spawnArgs.GetBool( "cinematic", "0" );
  464. networkSync = spawnArgs.FindKey( "networkSync" );
  465. if ( networkSync ) {
  466. fl.networkSync = ( atoi( networkSync->GetValue() ) != 0 );
  467. }
  468. #if 0
  469. if ( !common->IsClient() ) {
  470. // common->DPrintf( "NET: DBG %s - %s is synced: %s\n", spawnArgs.GetString( "classname", "" ), GetType()->classname, fl.networkSync ? "true" : "false" );
  471. if ( spawnArgs.GetString( "classname", "" )[ 0 ] == '\0' && !fl.networkSync ) {
  472. common->DPrintf( "NET: WRN %s entity, no classname, and no networkSync?\n", GetType()->classname );
  473. }
  474. }
  475. #endif
  476. // every object will have a unique name
  477. temp = spawnArgs.GetString( "name", va( "%s_%s_%d", GetClassname(), spawnArgs.GetString( "classname" ), entityNumber ) );
  478. SetName( temp );
  479. // if we have targets, wait until all entities are spawned to get them
  480. if ( spawnArgs.MatchPrefix( "target" ) || spawnArgs.MatchPrefix( "guiTarget" ) ) {
  481. if ( gameLocal.GameState() == GAMESTATE_STARTUP ) {
  482. PostEventMS( &EV_FindTargets, 0 );
  483. } else {
  484. // not during spawn, so it's ok to get the targets
  485. FindTargets();
  486. }
  487. }
  488. health = spawnArgs.GetInt( "health" );
  489. InitDefaultPhysics( origin, axis );
  490. SetOrigin( origin );
  491. SetAxis( axis );
  492. temp = spawnArgs.GetString( "model" );
  493. if ( temp != NULL && *temp != NULL ) {
  494. SetModel( temp );
  495. }
  496. if ( spawnArgs.GetString( "bind", "", &temp ) ) {
  497. PostEventMS( &EV_SpawnBind, 0 );
  498. }
  499. // auto-start a sound on the entity
  500. if ( refSound.shader && !refSound.waitfortrigger ) {
  501. StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
  502. }
  503. // setup script object
  504. if ( ShouldConstructScriptObjectAtSpawn() && spawnArgs.GetString( "scriptobject", NULL, &scriptObjectName ) ) {
  505. if ( !scriptObject.SetType( scriptObjectName ) ) {
  506. gameLocal.Error( "Script object '%s' not found on entity '%s'.", scriptObjectName, name.c_str() );
  507. }
  508. ConstructScriptObject();
  509. }
  510. // determine time group
  511. DetermineTimeGroup( spawnArgs.GetBool( "slowmo", "1" ) );
  512. }
  513. /*
  514. ================
  515. idEntity::~idEntity
  516. ================
  517. */
  518. idEntity::~idEntity() {
  519. DeconstructScriptObject();
  520. scriptObject.Free();
  521. if ( thinkFlags ) {
  522. BecomeInactive( thinkFlags );
  523. }
  524. activeNode.Remove();
  525. Signal( SIG_REMOVED );
  526. // we have to set back the default physics object before unbinding because the entity
  527. // specific physics object might be an entity variable and as such could already be destroyed.
  528. SetPhysics( NULL );
  529. // remove any entities that are bound to me
  530. RemoveBinds();
  531. // unbind from master
  532. Unbind();
  533. QuitTeam();
  534. gameLocal.RemoveEntityFromHash( name.c_str(), this );
  535. delete renderView;
  536. renderView = NULL;
  537. delete signals;
  538. signals = NULL;
  539. FreeModelDef();
  540. FreeSoundEmitter( false );
  541. if ( xrayEntityHandle != -1) {
  542. gameRenderWorld->FreeEntityDef( xrayEntityHandle );
  543. xrayEntityHandle = -1;
  544. }
  545. gameLocal.UnregisterEntity( this );
  546. }
  547. /*
  548. ================
  549. idEntity::Save
  550. ================
  551. */
  552. void idEntity::Save( idSaveGame *savefile ) const {
  553. int i, j;
  554. savefile->WriteInt( entityNumber );
  555. savefile->WriteInt( entityDefNumber );
  556. // spawnNode and activeNode are restored by gameLocal
  557. savefile->WriteDict( &spawnArgs );
  558. savefile->WriteString( name );
  559. scriptObject.Save( savefile );
  560. savefile->WriteInt( thinkFlags );
  561. savefile->WriteInt( dormantStart );
  562. savefile->WriteBool( cinematic );
  563. savefile->WriteObject( cameraTarget );
  564. savefile->WriteInt( health );
  565. savefile->WriteInt( targets.Num() );
  566. for( i = 0; i < targets.Num(); i++ ) {
  567. targets[ i ].Save( savefile );
  568. }
  569. entityFlags_s flags = fl;
  570. LittleBitField( &flags, sizeof( flags ) );
  571. savefile->Write( &flags, sizeof( flags ) );
  572. savefile->WriteInt( timeGroup );
  573. savefile->WriteBool( noGrab );
  574. savefile->WriteRenderEntity( xrayEntity );
  575. savefile->WriteInt( xrayEntityHandle );
  576. savefile->WriteSkin( xraySkin );
  577. savefile->WriteRenderEntity( renderEntity );
  578. savefile->WriteInt( modelDefHandle );
  579. savefile->WriteRefSound( refSound );
  580. savefile->WriteObject( bindMaster );
  581. savefile->WriteJoint( bindJoint );
  582. savefile->WriteInt( bindBody );
  583. savefile->WriteObject( teamMaster );
  584. savefile->WriteObject( teamChain );
  585. savefile->WriteStaticObject( defaultPhysicsObj );
  586. savefile->WriteInt( numPVSAreas );
  587. for( i = 0; i < MAX_PVS_AREAS; i++ ) {
  588. savefile->WriteInt( PVSAreas[ i ] );
  589. }
  590. if ( !signals ) {
  591. savefile->WriteBool( false );
  592. } else {
  593. savefile->WriteBool( true );
  594. for( i = 0; i < NUM_SIGNALS; i++ ) {
  595. savefile->WriteInt( signals->signal[ i ].Num() );
  596. for( j = 0; j < signals->signal[ i ].Num(); j++ ) {
  597. savefile->WriteInt( signals->signal[ i ][ j ].threadnum );
  598. savefile->WriteString( signals->signal[ i ][ j ].function->Name() );
  599. }
  600. }
  601. }
  602. savefile->WriteInt( mpGUIState );
  603. }
  604. /*
  605. ================
  606. idEntity::Restore
  607. ================
  608. */
  609. void idEntity::Restore( idRestoreGame *savefile ) {
  610. int i, j;
  611. int num;
  612. idStr funcname;
  613. savefile->ReadInt( entityNumber );
  614. savefile->ReadInt( entityDefNumber );
  615. // spawnNode and activeNode are restored by gameLocal
  616. savefile->ReadDict( &spawnArgs );
  617. savefile->ReadString( name );
  618. SetName( name );
  619. scriptObject.Restore( savefile );
  620. savefile->ReadInt( thinkFlags );
  621. savefile->ReadInt( dormantStart );
  622. savefile->ReadBool( cinematic );
  623. savefile->ReadObject( reinterpret_cast<idClass *&>( cameraTarget ) );
  624. savefile->ReadInt( health );
  625. targets.Clear();
  626. savefile->ReadInt( num );
  627. targets.SetNum( num );
  628. for( i = 0; i < num; i++ ) {
  629. targets[ i ].Restore( savefile );
  630. }
  631. savefile->Read( &fl, sizeof( fl ) );
  632. LittleBitField( &fl, sizeof( fl ) );
  633. savefile->ReadInt( timeGroup );
  634. savefile->ReadBool( noGrab );
  635. savefile->ReadRenderEntity( xrayEntity );
  636. savefile->ReadInt( xrayEntityHandle );
  637. if ( xrayEntityHandle != -1 ) {
  638. xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity );
  639. }
  640. savefile->ReadSkin( xraySkin );
  641. savefile->ReadRenderEntity( renderEntity );
  642. savefile->ReadInt( modelDefHandle );
  643. savefile->ReadRefSound( refSound );
  644. savefile->ReadObject( reinterpret_cast<idClass *&>( bindMaster ) );
  645. savefile->ReadJoint( bindJoint );
  646. savefile->ReadInt( bindBody );
  647. savefile->ReadObject( reinterpret_cast<idClass *&>( teamMaster ) );
  648. savefile->ReadObject( reinterpret_cast<idClass *&>( teamChain ) );
  649. savefile->ReadStaticObject( defaultPhysicsObj );
  650. RestorePhysics( &defaultPhysicsObj );
  651. savefile->ReadInt( numPVSAreas );
  652. for( i = 0; i < MAX_PVS_AREAS; i++ ) {
  653. savefile->ReadInt( PVSAreas[ i ] );
  654. }
  655. bool readsignals;
  656. savefile->ReadBool( readsignals );
  657. if ( readsignals ) {
  658. signals = new (TAG_ENTITY) signalList_t;
  659. for( i = 0; i < NUM_SIGNALS; i++ ) {
  660. savefile->ReadInt( num );
  661. signals->signal[ i ].SetNum( num );
  662. for( j = 0; j < num; j++ ) {
  663. savefile->ReadInt( signals->signal[ i ][ j ].threadnum );
  664. savefile->ReadString( funcname );
  665. signals->signal[ i ][ j ].function = gameLocal.program.FindFunction( funcname );
  666. if ( !signals->signal[ i ][ j ].function ) {
  667. savefile->Error( "Function '%s' not found", funcname.c_str() );
  668. }
  669. }
  670. }
  671. }
  672. savefile->ReadInt( mpGUIState );
  673. // restore must retrieve modelDefHandle from the renderer
  674. if ( modelDefHandle != -1 ) {
  675. modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
  676. }
  677. }
  678. /*
  679. ================
  680. idEntity::GetEntityDefName
  681. ================
  682. */
  683. const char * idEntity::GetEntityDefName() const {
  684. if ( entityDefNumber < 0 ) {
  685. return "*unknown*";
  686. }
  687. return declManager->DeclByIndex( DECL_ENTITYDEF, entityDefNumber, false )->GetName();
  688. }
  689. /*
  690. ================
  691. idEntity::SetName
  692. ================
  693. */
  694. void idEntity::SetName( const char *newname ) {
  695. if ( name.Length() ) {
  696. gameLocal.RemoveEntityFromHash( name.c_str(), this );
  697. gameLocal.program.SetEntity( name, NULL );
  698. }
  699. name = newname;
  700. if ( name.Length() ) {
  701. if ( ( name == "NULL" ) || ( name == "null_entity" ) ) {
  702. gameLocal.Error( "Cannot name entity '%s'. '%s' is reserved for script.", name.c_str(), name.c_str() );
  703. }
  704. gameLocal.AddEntityToHash( name.c_str(), this );
  705. gameLocal.program.SetEntity( name, this );
  706. }
  707. }
  708. /*
  709. ================
  710. idEntity::GetName
  711. ================
  712. */
  713. const char * idEntity::GetName() const {
  714. return name.c_str();
  715. }
  716. /***********************************************************************
  717. Thinking
  718. ***********************************************************************/
  719. /*
  720. ================
  721. idEntity::Think
  722. ================
  723. */
  724. void idEntity::Think() {
  725. RunPhysics();
  726. Present();
  727. }
  728. /*
  729. ================
  730. idEntity::DoDormantTests
  731. Monsters and other expensive entities that are completely closed
  732. off from the player can skip all of their work
  733. ================
  734. */
  735. bool idEntity::DoDormantTests() {
  736. if ( fl.neverDormant ) {
  737. return false;
  738. }
  739. // if the monster area is not topologically connected to a player
  740. if ( !gameLocal.InPlayerConnectedArea( this ) ) {
  741. if ( dormantStart == 0 ) {
  742. dormantStart = gameLocal.time;
  743. }
  744. if ( gameLocal.time - dormantStart < DELAY_DORMANT_TIME ) {
  745. // just got closed off, don't go dormant yet
  746. return false;
  747. }
  748. return true;
  749. } else {
  750. // the monster area is topologically connected to a player, but if
  751. // the monster hasn't been woken up before, do the more precise PVS check
  752. if ( !fl.hasAwakened ) {
  753. if ( !gameLocal.InPlayerPVS( this ) ) {
  754. return true; // stay dormant
  755. }
  756. }
  757. // wake up
  758. dormantStart = 0;
  759. fl.hasAwakened = true; // only go dormant when area closed off now, not just out of PVS
  760. return false;
  761. }
  762. }
  763. /*
  764. ================
  765. idEntity::CheckDormant
  766. Monsters and other expensive entities that are completely closed
  767. off from the player can skip all of their work
  768. ================
  769. */
  770. bool idEntity::CheckDormant() {
  771. bool dormant;
  772. dormant = DoDormantTests();
  773. if ( dormant && !fl.isDormant ) {
  774. fl.isDormant = true;
  775. DormantBegin();
  776. } else if ( !dormant && fl.isDormant ) {
  777. fl.isDormant = false;
  778. DormantEnd();
  779. }
  780. return dormant;
  781. }
  782. /*
  783. ================
  784. idEntity::DormantBegin
  785. called when entity becomes dormant
  786. ================
  787. */
  788. void idEntity::DormantBegin() {
  789. }
  790. /*
  791. ================
  792. idEntity::DormantEnd
  793. called when entity wakes from being dormant
  794. ================
  795. */
  796. void idEntity::DormantEnd() {
  797. }
  798. /*
  799. ================
  800. idEntity::IsActive
  801. ================
  802. */
  803. bool idEntity::IsActive() const {
  804. return activeNode.InList();
  805. }
  806. /*
  807. ================
  808. idEntity::BecomeActive
  809. ================
  810. */
  811. void idEntity::BecomeActive( int flags ) {
  812. if ( ( flags & TH_PHYSICS ) ) {
  813. // enable the team master if this entity is part of a physics team
  814. if ( teamMaster && teamMaster != this ) {
  815. teamMaster->BecomeActive( TH_PHYSICS );
  816. } else if ( !( thinkFlags & TH_PHYSICS ) ) {
  817. // if this is a pusher
  818. if ( physics->IsType( idPhysics_Parametric::Type ) || physics->IsType( idPhysics_Actor::Type ) ) {
  819. gameLocal.sortPushers = true;
  820. }
  821. }
  822. }
  823. int oldFlags = thinkFlags;
  824. thinkFlags |= flags;
  825. if ( thinkFlags ) {
  826. if ( !IsActive() ) {
  827. activeNode.AddToEnd( gameLocal.activeEntities );
  828. } else if ( !oldFlags ) {
  829. // we became inactive this frame, so we have to decrease the count of entities to deactivate
  830. gameLocal.numEntitiesToDeactivate--;
  831. }
  832. }
  833. }
  834. /*
  835. ================
  836. idEntity::BecomeInactive
  837. ================
  838. */
  839. void idEntity::BecomeInactive( int flags ) {
  840. if ( ( flags & TH_PHYSICS ) ) {
  841. // may only disable physics on a team master if no team members are running physics or bound to a joints
  842. if ( teamMaster == this ) {
  843. for ( idEntity *ent = teamMaster->teamChain; ent; ent = ent->teamChain ) {
  844. if ( ( ent->thinkFlags & TH_PHYSICS ) || ( ( ent->bindMaster == this ) && ( ent->bindJoint != INVALID_JOINT ) ) ) {
  845. flags &= ~TH_PHYSICS;
  846. break;
  847. }
  848. }
  849. }
  850. }
  851. if ( thinkFlags ) {
  852. thinkFlags &= ~flags;
  853. if ( !thinkFlags && IsActive() ) {
  854. gameLocal.numEntitiesToDeactivate++;
  855. }
  856. }
  857. if ( ( flags & TH_PHYSICS ) ) {
  858. // if this entity has a team master
  859. if ( teamMaster && teamMaster != this ) {
  860. // if the team master is at rest
  861. if ( teamMaster->IsAtRest() ) {
  862. teamMaster->BecomeInactive( TH_PHYSICS );
  863. }
  864. }
  865. // Becoming inactive automagically turns on motion blur again
  866. renderEntity.skipMotionBlur = false;
  867. BecomeActive( TH_UPDATEVISUALS );
  868. }
  869. }
  870. /***********************************************************************
  871. Visuals
  872. ***********************************************************************/
  873. /*
  874. ================
  875. idEntity::SetShaderParm
  876. ================
  877. */
  878. void idEntity::SetShaderParm( int parmnum, float value ) {
  879. if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
  880. gameLocal.Warning( "shader parm index (%d) out of range", parmnum );
  881. return;
  882. }
  883. renderEntity.shaderParms[ parmnum ] = value;
  884. UpdateVisuals();
  885. }
  886. /*
  887. ================
  888. idEntity::SetColor
  889. ================
  890. */
  891. void idEntity::SetColor( float red, float green, float blue ) {
  892. renderEntity.shaderParms[ SHADERPARM_RED ] = red;
  893. renderEntity.shaderParms[ SHADERPARM_GREEN ] = green;
  894. renderEntity.shaderParms[ SHADERPARM_BLUE ] = blue;
  895. UpdateVisuals();
  896. }
  897. /*
  898. ================
  899. idEntity::SetColor
  900. ================
  901. */
  902. void idEntity::SetColor( const idVec3 &color ) {
  903. SetColor( color[ 0 ], color[ 1 ], color[ 2 ] );
  904. UpdateVisuals();
  905. }
  906. /*
  907. ================
  908. idEntity::GetColor
  909. ================
  910. */
  911. void idEntity::GetColor( idVec3 &out ) const {
  912. out[ 0 ] = renderEntity.shaderParms[ SHADERPARM_RED ];
  913. out[ 1 ] = renderEntity.shaderParms[ SHADERPARM_GREEN ];
  914. out[ 2 ] = renderEntity.shaderParms[ SHADERPARM_BLUE ];
  915. }
  916. /*
  917. ================
  918. idEntity::SetColor
  919. ================
  920. */
  921. void idEntity::SetColor( const idVec4 &color ) {
  922. renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
  923. renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ];
  924. renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
  925. renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
  926. UpdateVisuals();
  927. }
  928. /*
  929. ================
  930. idEntity::GetColor
  931. ================
  932. */
  933. void idEntity::GetColor( idVec4 &out ) const {
  934. out[ 0 ] = renderEntity.shaderParms[ SHADERPARM_RED ];
  935. out[ 1 ] = renderEntity.shaderParms[ SHADERPARM_GREEN ];
  936. out[ 2 ] = renderEntity.shaderParms[ SHADERPARM_BLUE ];
  937. out[ 3 ] = renderEntity.shaderParms[ SHADERPARM_ALPHA ];
  938. }
  939. /*
  940. ================
  941. idEntity::UpdateAnimationControllers
  942. ================
  943. */
  944. bool idEntity::UpdateAnimationControllers() {
  945. // any ragdoll and IK animation controllers should be updated here
  946. return false;
  947. }
  948. /*
  949. ================
  950. idEntity::SetModel
  951. ================
  952. */
  953. void idEntity::SetModel( const char *modelname ) {
  954. assert( modelname );
  955. FreeModelDef();
  956. renderEntity.hModel = renderModelManager->FindModel( modelname );
  957. if ( renderEntity.hModel ) {
  958. renderEntity.hModel->Reset();
  959. }
  960. renderEntity.callback = NULL;
  961. renderEntity.numJoints = 0;
  962. renderEntity.joints = NULL;
  963. if ( renderEntity.hModel ) {
  964. renderEntity.bounds = renderEntity.hModel->Bounds( &renderEntity );
  965. } else {
  966. renderEntity.bounds.Zero();
  967. }
  968. UpdateVisuals();
  969. }
  970. /*
  971. ================
  972. idEntity::SetSkin
  973. ================
  974. */
  975. void idEntity::SetSkin( const idDeclSkin *skin ) {
  976. renderEntity.customSkin = skin;
  977. UpdateVisuals();
  978. }
  979. /*
  980. ================
  981. idEntity::GetSkin
  982. ================
  983. */
  984. const idDeclSkin *idEntity::GetSkin() const {
  985. return renderEntity.customSkin;
  986. }
  987. /*
  988. ================
  989. idEntity::FreeModelDef
  990. ================
  991. */
  992. void idEntity::FreeModelDef() {
  993. if ( modelDefHandle != -1 ) {
  994. gameRenderWorld->FreeEntityDef( modelDefHandle );
  995. modelDefHandle = -1;
  996. }
  997. }
  998. /*
  999. ================
  1000. idEntity::FreeLightDef
  1001. ================
  1002. */
  1003. void idEntity::FreeLightDef() {
  1004. }
  1005. /*
  1006. ================
  1007. idEntity::IsHidden
  1008. ================
  1009. */
  1010. bool idEntity::IsHidden() const {
  1011. return fl.hidden;
  1012. }
  1013. /*
  1014. ================
  1015. idEntity::Hide
  1016. ================
  1017. */
  1018. void idEntity::Hide() {
  1019. if ( !IsHidden() ) {
  1020. fl.hidden = true;
  1021. FreeModelDef();
  1022. UpdateVisuals();
  1023. }
  1024. }
  1025. /*
  1026. ================
  1027. idEntity::Show
  1028. ================
  1029. */
  1030. void idEntity::Show() {
  1031. if ( IsHidden() ) {
  1032. fl.hidden = false;
  1033. UpdateVisuals();
  1034. }
  1035. }
  1036. /*
  1037. ================
  1038. idEntity::UpdateModelTransform
  1039. ================
  1040. */
  1041. void idEntity::UpdateModelTransform() {
  1042. idVec3 origin;
  1043. idMat3 axis;
  1044. if ( GetPhysicsToVisualTransform( origin, axis ) ) {
  1045. renderEntity.axis = axis * GetPhysics()->GetAxis();
  1046. renderEntity.origin = GetPhysics()->GetOrigin() + origin * renderEntity.axis;
  1047. } else {
  1048. // Add the deltas here, used for projectiles in MP. These deltas should only affect the visuals.
  1049. renderEntity.axis = GetPhysics()->GetAxis() * axisDelta;
  1050. renderEntity.origin = GetPhysics()->GetOrigin() + originDelta;
  1051. }
  1052. }
  1053. /*
  1054. ================
  1055. idEntity::UpdateModel
  1056. ================
  1057. */
  1058. void idEntity::UpdateModel() {
  1059. renderEntity.timeGroup = timeGroup;
  1060. UpdateModelTransform();
  1061. // check if the entity has an MD5 model
  1062. idAnimator *animator = GetAnimator();
  1063. if ( animator != NULL && animator->ModelHandle() != NULL ) {
  1064. // set the callback to update the joints
  1065. renderEntity.callback = idEntity::ModelCallback;
  1066. }
  1067. // set to invalid number to force an update the next time the PVS areas are retrieved
  1068. ClearPVSAreas();
  1069. // ensure that we call Present this frame
  1070. BecomeActive( TH_UPDATEVISUALS );
  1071. // If the entity has an xray skin, go ahead and add it
  1072. if ( xraySkin != NULL ) {
  1073. xrayEntity = renderEntity;
  1074. xrayEntity.xrayIndex = 2;
  1075. xrayEntity.customSkin = xraySkin;
  1076. if ( xrayEntityHandle == -1 ) {
  1077. xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity );
  1078. } else {
  1079. gameRenderWorld->UpdateEntityDef( xrayEntityHandle, &xrayEntity );
  1080. }
  1081. }
  1082. }
  1083. /*
  1084. ================
  1085. idEntity::UpdateVisuals
  1086. ================
  1087. */
  1088. void idEntity::UpdateVisuals() {
  1089. UpdateModel();
  1090. UpdateSound();
  1091. }
  1092. /*
  1093. ================
  1094. idEntity::UpdatePVSAreas
  1095. ================
  1096. */
  1097. void idEntity::UpdatePVSAreas() {
  1098. int localNumPVSAreas, localPVSAreas[32];
  1099. idBounds modelAbsBounds;
  1100. int i;
  1101. modelAbsBounds.FromTransformedBounds( renderEntity.bounds, renderEntity.origin, renderEntity.axis );
  1102. localNumPVSAreas = gameLocal.pvs.GetPVSAreas( modelAbsBounds, localPVSAreas, sizeof( localPVSAreas ) / sizeof( localPVSAreas[0] ) );
  1103. // FIXME: some particle systems may have huge bounds and end up in many PVS areas
  1104. // the first MAX_PVS_AREAS may not be visible to a network client and as a result the particle system may not show up when it should
  1105. if ( localNumPVSAreas > MAX_PVS_AREAS ) {
  1106. localNumPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( renderEntity.origin ).Expand( 64.0f ), localPVSAreas, sizeof( localPVSAreas ) / sizeof( localPVSAreas[0] ) );
  1107. }
  1108. for ( numPVSAreas = 0; numPVSAreas < MAX_PVS_AREAS && numPVSAreas < localNumPVSAreas; numPVSAreas++ ) {
  1109. PVSAreas[numPVSAreas] = localPVSAreas[numPVSAreas];
  1110. }
  1111. for( i = numPVSAreas; i < MAX_PVS_AREAS; i++ ) {
  1112. PVSAreas[ i ] = 0;
  1113. }
  1114. }
  1115. /*
  1116. ================
  1117. idEntity::UpdatePVSAreas
  1118. ================
  1119. */
  1120. void idEntity::UpdatePVSAreas( const idVec3 &pos ) {
  1121. int i;
  1122. numPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( pos ), PVSAreas, MAX_PVS_AREAS );
  1123. i = numPVSAreas;
  1124. while ( i < MAX_PVS_AREAS ) {
  1125. PVSAreas[ i++ ] = 0;
  1126. }
  1127. }
  1128. /*
  1129. ================
  1130. idEntity::GetNumPVSAreas
  1131. ================
  1132. */
  1133. int idEntity::GetNumPVSAreas() {
  1134. if ( numPVSAreas < 0 ) {
  1135. UpdatePVSAreas();
  1136. }
  1137. return numPVSAreas;
  1138. }
  1139. /*
  1140. ================
  1141. idEntity::GetPVSAreas
  1142. ================
  1143. */
  1144. const int *idEntity::GetPVSAreas() {
  1145. if ( numPVSAreas < 0 ) {
  1146. UpdatePVSAreas();
  1147. }
  1148. return PVSAreas;
  1149. }
  1150. /*
  1151. ================
  1152. idEntity::ClearPVSAreas
  1153. ================
  1154. */
  1155. void idEntity::ClearPVSAreas() {
  1156. numPVSAreas = -1;
  1157. }
  1158. /*
  1159. ================
  1160. idEntity::PhysicsTeamInPVS
  1161. FIXME: for networking also return true if any of the entity shadows is in the PVS
  1162. ================
  1163. */
  1164. bool idEntity::PhysicsTeamInPVS( pvsHandle_t pvsHandle ) {
  1165. idEntity *part;
  1166. if ( teamMaster ) {
  1167. for ( part = teamMaster; part; part = part->teamChain ) {
  1168. if ( gameLocal.pvs.InCurrentPVS( pvsHandle, part->GetPVSAreas(), part->GetNumPVSAreas() ) ) {
  1169. return true;
  1170. }
  1171. }
  1172. } else {
  1173. return gameLocal.pvs.InCurrentPVS( pvsHandle, GetPVSAreas(), GetNumPVSAreas() );
  1174. }
  1175. return false;
  1176. }
  1177. /*
  1178. ==============
  1179. idEntity::BecomeReplicated
  1180. ==============
  1181. */
  1182. void idEntity::BecomeReplicated() {
  1183. fl.skipReplication = false;
  1184. if ( GetPhysics() ) {
  1185. GetPhysics()->ResetInterpolationState( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
  1186. }
  1187. }
  1188. /*
  1189. ==============
  1190. idEntity::ProjectOverlay
  1191. ==============
  1192. */
  1193. void idEntity::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
  1194. float s, c;
  1195. idMat3 axis, axistemp;
  1196. idVec3 localOrigin, localAxis[2];
  1197. idPlane localPlane[2];
  1198. // make sure the entity has a valid model handle
  1199. if ( modelDefHandle < 0 ) {
  1200. return;
  1201. }
  1202. // only do this on dynamic md5 models
  1203. if ( renderEntity.hModel->IsDynamicModel() != DM_CACHED ) {
  1204. return;
  1205. }
  1206. idMath::SinCos16( gameLocal.random.RandomFloat() * idMath::TWO_PI, s, c );
  1207. axis[2] = -dir;
  1208. axis[2].NormalVectors( axistemp[0], axistemp[1] );
  1209. axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s;
  1210. axis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c;
  1211. renderEntity.axis.ProjectVector( origin - renderEntity.origin, localOrigin );
  1212. renderEntity.axis.ProjectVector( axis[0], localAxis[0] );
  1213. renderEntity.axis.ProjectVector( axis[1], localAxis[1] );
  1214. size = 1.0f / size;
  1215. localAxis[0] *= size;
  1216. localAxis[1] *= size;
  1217. localPlane[0] = localAxis[0];
  1218. localPlane[0][3] = -( localOrigin * localAxis[0] ) + 0.5f;
  1219. localPlane[1] = localAxis[1];
  1220. localPlane[1][3] = -( localOrigin * localAxis[1] ) + 0.5f;
  1221. const idMaterial *mtr = declManager->FindMaterial( material );
  1222. // project an overlay onto the model
  1223. gameRenderWorld->ProjectOverlay( modelDefHandle, localPlane, mtr, gameLocal.slow.time );
  1224. // make sure non-animating models update their overlay
  1225. UpdateVisuals();
  1226. }
  1227. /*
  1228. ================
  1229. idEntity::Present
  1230. Present is called to allow entities to generate refEntities, lights, etc for the renderer.
  1231. ================
  1232. */
  1233. void idEntity::Present() {
  1234. if ( !gameLocal.isNewFrame ) {
  1235. return;
  1236. }
  1237. // don't present to the renderer if the entity hasn't changed
  1238. if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  1239. return;
  1240. }
  1241. BecomeInactive( TH_UPDATEVISUALS );
  1242. // camera target for remote render views
  1243. if ( cameraTarget && gameLocal.InPlayerPVS( this ) ) {
  1244. renderEntity.remoteRenderView = cameraTarget->GetRenderView();
  1245. }
  1246. // if set to invisible, skip
  1247. if ( !renderEntity.hModel || IsHidden() ) {
  1248. return;
  1249. }
  1250. // add to refresh list
  1251. if ( modelDefHandle == -1 ) {
  1252. modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
  1253. } else {
  1254. gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
  1255. }
  1256. }
  1257. /*
  1258. ================
  1259. idEntity::GetRenderEntity
  1260. ================
  1261. */
  1262. renderEntity_t *idEntity::GetRenderEntity() {
  1263. return &renderEntity;
  1264. }
  1265. /*
  1266. ================
  1267. idEntity::GetModelDefHandle
  1268. ================
  1269. */
  1270. int idEntity::GetModelDefHandle() {
  1271. return modelDefHandle;
  1272. }
  1273. /*
  1274. ================
  1275. idEntity::UpdateRenderEntity
  1276. ================
  1277. */
  1278. bool idEntity::UpdateRenderEntity( renderEntity_s * renderEntity, const renderView_t * renderView ) {
  1279. idAnimator * animator = GetAnimator();
  1280. if ( animator != NULL ) {
  1281. SetTimeState ts( timeGroup );
  1282. int currentTime = gameLocal.time;
  1283. if ( renderEntity != NULL ) {
  1284. currentTime = gameLocal.GetTimeGroupTime( renderEntity->timeGroup );
  1285. }
  1286. return animator->CreateFrame( currentTime, false );
  1287. }
  1288. return false;
  1289. }
  1290. /*
  1291. ================
  1292. idEntity::ModelCallback
  1293. NOTE: may not change the game state whatsoever!
  1294. ================
  1295. */
  1296. bool idEntity::ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ) {
  1297. idEntity *ent;
  1298. ent = gameLocal.entities[ renderEntity->entityNum ];
  1299. if ( ent == NULL ) {
  1300. gameLocal.Error( "idEntity::ModelCallback: callback with NULL game entity" );
  1301. return false;
  1302. }
  1303. return ent->UpdateRenderEntity( renderEntity, renderView );
  1304. }
  1305. /*
  1306. ================
  1307. idEntity::GetAnimator
  1308. Subclasses will be responsible for allocating animator.
  1309. ================
  1310. */
  1311. idAnimator *idEntity::GetAnimator() {
  1312. return NULL;
  1313. }
  1314. /*
  1315. =============
  1316. idEntity::GetRenderView
  1317. This is used by remote camera views to look from an entity
  1318. =============
  1319. */
  1320. renderView_t *idEntity::GetRenderView() {
  1321. if ( !renderView ) {
  1322. renderView = new (TAG_ENTITY) renderView_t;
  1323. }
  1324. memset( renderView, 0, sizeof( *renderView ) );
  1325. renderView->vieworg = GetPhysics()->GetOrigin();
  1326. renderView->fov_x = 120;
  1327. renderView->fov_y = 120;
  1328. renderView->viewaxis = GetPhysics()->GetAxis();
  1329. // copy global shader parms
  1330. for( int i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
  1331. renderView->shaderParms[ i ] = gameLocal.globalShaderParms[ i ];
  1332. }
  1333. renderView->globalMaterial = gameLocal.GetGlobalMaterial();
  1334. renderView->time[0] = gameLocal.slow.time;
  1335. renderView->time[1] = gameLocal.fast.time;
  1336. return renderView;
  1337. }
  1338. /***********************************************************************
  1339. Sound
  1340. ***********************************************************************/
  1341. /*
  1342. ================
  1343. idEntity::CanPlayChatterSounds
  1344. Used for playing chatter sounds on monsters.
  1345. ================
  1346. */
  1347. bool idEntity::CanPlayChatterSounds() const {
  1348. return true;
  1349. }
  1350. /*
  1351. ================
  1352. idEntity::StartSound
  1353. ================
  1354. */
  1355. bool idEntity::StartSound( const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ) {
  1356. const idSoundShader *shader;
  1357. const char *sound;
  1358. if ( length ) {
  1359. *length = 0;
  1360. }
  1361. // we should ALWAYS be playing sounds from the def.
  1362. // hardcoded sounds MUST be avoided at all times because they won't get precached.
  1363. assert( idStr::Icmpn( soundName, "snd_", 4 ) == 0 );
  1364. if ( !spawnArgs.GetString( soundName, "", &sound ) ) {
  1365. return false;
  1366. }
  1367. if ( sound[0] == '\0' ) {
  1368. return false;
  1369. }
  1370. if ( !gameLocal.isNewFrame ) {
  1371. // don't play the sound, but don't report an error
  1372. return true;
  1373. }
  1374. shader = declManager->FindSound( sound );
  1375. return StartSoundShader( shader, channel, soundShaderFlags, broadcast, length );
  1376. }
  1377. /*
  1378. ================
  1379. idEntity::StartSoundShader
  1380. ================
  1381. */
  1382. bool idEntity::StartSoundShader( const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ) {
  1383. float diversity;
  1384. int len;
  1385. if ( length ) {
  1386. *length = 0;
  1387. }
  1388. if ( !shader ) {
  1389. return false;
  1390. }
  1391. if ( !gameLocal.isNewFrame ) {
  1392. return true;
  1393. }
  1394. if ( common->IsServer() && broadcast ) {
  1395. idBitMsg msg;
  1396. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  1397. msg.InitWrite( msgBuf, sizeof( msgBuf ) );
  1398. msg.BeginWriting();
  1399. msg.WriteLong( gameLocal.ServerRemapDecl( -1, DECL_SOUND, shader->Index() ) );
  1400. msg.WriteByte( channel );
  1401. ServerSendEvent( EVENT_STARTSOUNDSHADER, &msg, false );
  1402. }
  1403. // set a random value for diversity unless one was parsed from the entity
  1404. if ( refSound.diversity < 0.0f ) {
  1405. diversity = gameLocal.random.RandomFloat();
  1406. } else {
  1407. diversity = refSound.diversity;
  1408. }
  1409. // if we don't have a soundEmitter allocated yet, get one now
  1410. if ( !refSound.referenceSound ) {
  1411. refSound.referenceSound = gameSoundWorld->AllocSoundEmitter();
  1412. }
  1413. UpdateSound();
  1414. len = refSound.referenceSound->StartSound( shader, channel, diversity, soundShaderFlags, !timeGroup /*_D3XP*/ );
  1415. if ( length ) {
  1416. *length = len;
  1417. }
  1418. // set reference to the sound for shader synced effects
  1419. renderEntity.referenceSound = refSound.referenceSound;
  1420. return true;
  1421. }
  1422. /*
  1423. ================
  1424. idEntity::StopSound
  1425. ================
  1426. */
  1427. void idEntity::StopSound( const s_channelType channel, bool broadcast ) {
  1428. if ( !gameLocal.isNewFrame ) {
  1429. return;
  1430. }
  1431. if ( common->IsServer() && broadcast ) {
  1432. idBitMsg msg;
  1433. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  1434. msg.InitWrite( msgBuf, sizeof( msgBuf ) );
  1435. msg.BeginWriting();
  1436. msg.WriteByte( channel );
  1437. ServerSendEvent( EVENT_STOPSOUNDSHADER, &msg, false );
  1438. }
  1439. if ( refSound.referenceSound ) {
  1440. refSound.referenceSound->StopSound( channel );
  1441. }
  1442. }
  1443. /*
  1444. ================
  1445. idEntity::SetSoundVolume
  1446. Must be called before starting a new sound.
  1447. ================
  1448. */
  1449. void idEntity::SetSoundVolume( float volume ) {
  1450. refSound.parms.volume = volume;
  1451. }
  1452. /*
  1453. ================
  1454. idEntity::UpdateSound
  1455. ================
  1456. */
  1457. void idEntity::UpdateSound() {
  1458. if ( refSound.referenceSound ) {
  1459. idVec3 origin;
  1460. idMat3 axis;
  1461. if ( GetPhysicsToSoundTransform( origin, axis ) ) {
  1462. refSound.origin = GetPhysics()->GetOrigin() + origin * axis;
  1463. } else {
  1464. refSound.origin = GetPhysics()->GetOrigin();
  1465. }
  1466. refSound.referenceSound->UpdateEmitter( refSound.origin, refSound.listenerId, &refSound.parms );
  1467. }
  1468. }
  1469. /*
  1470. ================
  1471. idEntity::GetListenerId
  1472. ================
  1473. */
  1474. int idEntity::GetListenerId() const {
  1475. return refSound.listenerId;
  1476. }
  1477. /*
  1478. ================
  1479. idEntity::GetSoundEmitter
  1480. ================
  1481. */
  1482. idSoundEmitter *idEntity::GetSoundEmitter() const {
  1483. return refSound.referenceSound;
  1484. }
  1485. /*
  1486. ================
  1487. idEntity::FreeSoundEmitter
  1488. ================
  1489. */
  1490. void idEntity::FreeSoundEmitter( bool immediate ) {
  1491. if ( refSound.referenceSound ) {
  1492. refSound.referenceSound->Free( immediate );
  1493. refSound.referenceSound = NULL;
  1494. }
  1495. }
  1496. /***********************************************************************
  1497. entity binding
  1498. ***********************************************************************/
  1499. /*
  1500. ================
  1501. idEntity::PreBind
  1502. ================
  1503. */
  1504. void idEntity::PreBind() {
  1505. }
  1506. /*
  1507. ================
  1508. idEntity::PostBind
  1509. ================
  1510. */
  1511. void idEntity::PostBind() {
  1512. }
  1513. /*
  1514. ================
  1515. idEntity::PreUnbind
  1516. ================
  1517. */
  1518. void idEntity::PreUnbind() {
  1519. }
  1520. /*
  1521. ================
  1522. idEntity::PostUnbind
  1523. ================
  1524. */
  1525. void idEntity::PostUnbind() {
  1526. }
  1527. /*
  1528. ================
  1529. idEntity::InitBind
  1530. ================
  1531. */
  1532. bool idEntity::InitBind( idEntity *master ) {
  1533. if ( master == this ) {
  1534. gameLocal.Error( "Tried to bind an object to itself." );
  1535. return false;
  1536. }
  1537. if ( this == gameLocal.world ) {
  1538. gameLocal.Error( "Tried to bind world to another entity" );
  1539. return false;
  1540. }
  1541. // unbind myself from my master
  1542. Unbind();
  1543. // add any bind constraints to an articulated figure
  1544. if ( master && IsType( idAFEntity_Base::Type ) ) {
  1545. static_cast<idAFEntity_Base *>(this)->AddBindConstraints();
  1546. }
  1547. if ( !master || master == gameLocal.world ) {
  1548. // this can happen in scripts, so safely exit out.
  1549. return false;
  1550. }
  1551. return true;
  1552. }
  1553. /*
  1554. ================
  1555. idEntity::FinishBind
  1556. ================
  1557. */
  1558. void idEntity::FinishBind() {
  1559. // set the master on the physics object
  1560. physics->SetMaster( bindMaster, fl.bindOrientated );
  1561. // We are now separated from our previous team and are either
  1562. // an individual, or have a team of our own. Now we can join
  1563. // the new bindMaster's team. Bindmaster must be set before
  1564. // joining the team, or we will be placed in the wrong position
  1565. // on the team.
  1566. JoinTeam( bindMaster );
  1567. // if our bindMaster is enabled during a cinematic, we must be, too
  1568. cinematic = bindMaster->cinematic;
  1569. // make sure the team master is active so that physics get run
  1570. teamMaster->BecomeActive( TH_PHYSICS );
  1571. }
  1572. /*
  1573. ================
  1574. idEntity::Bind
  1575. bind relative to the visual position of the master
  1576. ================
  1577. */
  1578. void idEntity::Bind( idEntity *master, bool orientated ) {
  1579. if ( !InitBind( master ) ) {
  1580. return;
  1581. }
  1582. PreBind();
  1583. bindJoint = INVALID_JOINT;
  1584. bindBody = -1;
  1585. bindMaster = master;
  1586. fl.bindOrientated = orientated;
  1587. FinishBind();
  1588. PostBind( );
  1589. }
  1590. /*
  1591. ================
  1592. idEntity::BindToJoint
  1593. bind relative to a joint of the md5 model used by the master
  1594. ================
  1595. */
  1596. void idEntity::BindToJoint( idEntity *master, const char *jointname, bool orientated ) {
  1597. jointHandle_t jointnum;
  1598. idAnimator *masterAnimator;
  1599. if ( !InitBind( master ) ) {
  1600. return;
  1601. }
  1602. masterAnimator = master->GetAnimator();
  1603. if ( !masterAnimator ) {
  1604. gameLocal.Warning( "idEntity::BindToJoint: entity '%s' cannot support skeletal models.", master->GetName() );
  1605. return;
  1606. }
  1607. jointnum = masterAnimator->GetJointHandle( jointname );
  1608. if ( jointnum == INVALID_JOINT ) {
  1609. gameLocal.Warning( "idEntity::BindToJoint: joint '%s' not found on entity '%s'.", jointname, master->GetName() );
  1610. }
  1611. PreBind();
  1612. bindJoint = jointnum;
  1613. bindBody = -1;
  1614. bindMaster = master;
  1615. fl.bindOrientated = orientated;
  1616. FinishBind();
  1617. PostBind();
  1618. }
  1619. /*
  1620. ================
  1621. idEntity::BindToJoint
  1622. bind relative to a joint of the md5 model used by the master
  1623. ================
  1624. */
  1625. void idEntity::BindToJoint( idEntity *master, jointHandle_t jointnum, bool orientated ) {
  1626. if ( !InitBind( master ) ) {
  1627. return;
  1628. }
  1629. PreBind();
  1630. bindJoint = jointnum;
  1631. bindBody = -1;
  1632. bindMaster = master;
  1633. fl.bindOrientated = orientated;
  1634. FinishBind();
  1635. PostBind();
  1636. }
  1637. /*
  1638. ================
  1639. idEntity::BindToBody
  1640. bind relative to a collision model used by the physics of the master
  1641. ================
  1642. */
  1643. void idEntity::BindToBody( idEntity *master, int bodyId, bool orientated ) {
  1644. if ( !InitBind( master ) ) {
  1645. return;
  1646. }
  1647. if ( bodyId < 0 ) {
  1648. gameLocal.Warning( "idEntity::BindToBody: body '%d' not found.", bodyId );
  1649. }
  1650. PreBind();
  1651. bindJoint = INVALID_JOINT;
  1652. bindBody = bodyId;
  1653. bindMaster = master;
  1654. fl.bindOrientated = orientated;
  1655. FinishBind();
  1656. PostBind();
  1657. }
  1658. /*
  1659. ================
  1660. idEntity::Unbind
  1661. ================
  1662. */
  1663. void idEntity::Unbind() {
  1664. idEntity * prev;
  1665. idEntity * next;
  1666. idEntity * last;
  1667. idEntity * ent;
  1668. // remove any bind constraints from an articulated figure
  1669. if ( IsType( idAFEntity_Base::Type ) ) {
  1670. static_cast<idAFEntity_Base *>(this)->RemoveBindConstraints();
  1671. }
  1672. if ( !bindMaster ) {
  1673. return;
  1674. }
  1675. if ( !teamMaster ) {
  1676. // Teammaster already has been freed
  1677. bindMaster = NULL;
  1678. return;
  1679. }
  1680. PreUnbind();
  1681. if ( physics ) {
  1682. physics->SetMaster( NULL, fl.bindOrientated );
  1683. }
  1684. // We're still part of a team, so that means I have to extricate myself
  1685. // and any entities that are bound to me from the old team.
  1686. // Find the node previous to me in the team
  1687. prev = teamMaster;
  1688. for( ent = teamMaster->teamChain; ent && ( ent != this ); ent = ent->teamChain ) {
  1689. prev = ent;
  1690. }
  1691. assert( ent == this ); // If ent is not pointing to this, then something is very wrong.
  1692. // Find the last node in my team that is bound to me.
  1693. // Also find the first node not bound to me, if one exists.
  1694. last = this;
  1695. for( next = teamChain; next != NULL; next = next->teamChain ) {
  1696. if ( !next->IsBoundTo( this ) ) {
  1697. break;
  1698. }
  1699. // Tell them I'm now the teamMaster
  1700. next->teamMaster = this;
  1701. last = next;
  1702. }
  1703. // disconnect the last member of our team from the old team
  1704. last->teamChain = NULL;
  1705. // connect up the previous member of the old team to the node that
  1706. // follow the last node bound to me (if one exists).
  1707. if ( teamMaster != this ) {
  1708. prev->teamChain = next;
  1709. if ( !next && ( teamMaster == prev ) ) {
  1710. prev->teamMaster = NULL;
  1711. }
  1712. } else if ( next ) {
  1713. // If we were the teamMaster, then the nodes that were not bound to me are now
  1714. // a disconnected chain. Make them into their own team.
  1715. for( ent = next; ent->teamChain != NULL; ent = ent->teamChain ) {
  1716. ent->teamMaster = next;
  1717. }
  1718. next->teamMaster = next;
  1719. }
  1720. // If we don't have anyone on our team, then clear the team variables.
  1721. if ( teamChain ) {
  1722. // make myself my own team
  1723. teamMaster = this;
  1724. } else {
  1725. // no longer a team
  1726. teamMaster = NULL;
  1727. }
  1728. bindJoint = INVALID_JOINT;
  1729. bindBody = -1;
  1730. bindMaster = NULL;
  1731. PostUnbind();
  1732. }
  1733. /*
  1734. ================
  1735. idEntity::RemoveBinds
  1736. ================
  1737. */
  1738. void idEntity::RemoveBinds() {
  1739. idEntity *ent;
  1740. idEntity *next;
  1741. for( ent = teamChain; ent != NULL; ent = next ) {
  1742. next = ent->teamChain;
  1743. if ( ent->bindMaster == this ) {
  1744. ent->Unbind();
  1745. ent->PostEventMS( &EV_Remove, 0 );
  1746. next = teamChain;
  1747. }
  1748. }
  1749. }
  1750. /*
  1751. ================
  1752. idEntity::IsBound
  1753. ================
  1754. */
  1755. bool idEntity::IsBound() const {
  1756. if ( bindMaster ) {
  1757. return true;
  1758. }
  1759. return false;
  1760. }
  1761. /*
  1762. ================
  1763. idEntity::IsBoundTo
  1764. ================
  1765. */
  1766. bool idEntity::IsBoundTo( idEntity *master ) const {
  1767. idEntity *ent;
  1768. if ( !bindMaster ) {
  1769. return false;
  1770. }
  1771. for ( ent = bindMaster; ent != NULL; ent = ent->bindMaster ) {
  1772. if ( ent == master ) {
  1773. return true;
  1774. }
  1775. }
  1776. return false;
  1777. }
  1778. /*
  1779. ================
  1780. idEntity::GetBindMaster
  1781. ================
  1782. */
  1783. idEntity *idEntity::GetBindMaster() const {
  1784. return bindMaster;
  1785. }
  1786. /*
  1787. ================
  1788. idEntity::GetBindJoint
  1789. ================
  1790. */
  1791. jointHandle_t idEntity::GetBindJoint() const {
  1792. return bindJoint;
  1793. }
  1794. /*
  1795. ================
  1796. idEntity::GetBindBody
  1797. ================
  1798. */
  1799. int idEntity::GetBindBody() const {
  1800. return bindBody;
  1801. }
  1802. /*
  1803. ================
  1804. idEntity::GetTeamMaster
  1805. ================
  1806. */
  1807. idEntity *idEntity::GetTeamMaster() const {
  1808. return teamMaster;
  1809. }
  1810. /*
  1811. ================
  1812. idEntity::GetNextTeamEntity
  1813. ================
  1814. */
  1815. idEntity *idEntity::GetNextTeamEntity() const {
  1816. return teamChain;
  1817. }
  1818. /*
  1819. =====================
  1820. idEntity::ConvertLocalToWorldTransform
  1821. =====================
  1822. */
  1823. void idEntity::ConvertLocalToWorldTransform( idVec3 &offset, idMat3 &axis ) {
  1824. UpdateModelTransform();
  1825. offset = renderEntity.origin + offset * renderEntity.axis;
  1826. axis *= renderEntity.axis;
  1827. }
  1828. /*
  1829. ================
  1830. idEntity::GetLocalVector
  1831. Takes a vector in worldspace and transforms it into the parent
  1832. object's localspace.
  1833. Note: Does not take origin into acount. Use getLocalCoordinate to
  1834. convert coordinates.
  1835. ================
  1836. */
  1837. idVec3 idEntity::GetLocalVector( const idVec3 &vec ) const {
  1838. idVec3 pos;
  1839. if ( !bindMaster ) {
  1840. return vec;
  1841. }
  1842. idVec3 masterOrigin;
  1843. idMat3 masterAxis;
  1844. GetMasterPosition( masterOrigin, masterAxis );
  1845. masterAxis.ProjectVector( vec, pos );
  1846. return pos;
  1847. }
  1848. /*
  1849. ================
  1850. idEntity::GetLocalCoordinates
  1851. Takes a vector in world coordinates and transforms it into the parent
  1852. object's local coordinates.
  1853. ================
  1854. */
  1855. idVec3 idEntity::GetLocalCoordinates( const idVec3 &vec ) const {
  1856. idVec3 pos;
  1857. if ( !bindMaster ) {
  1858. return vec;
  1859. }
  1860. idVec3 masterOrigin;
  1861. idMat3 masterAxis;
  1862. GetMasterPosition( masterOrigin, masterAxis );
  1863. masterAxis.ProjectVector( vec - masterOrigin, pos );
  1864. return pos;
  1865. }
  1866. /*
  1867. ================
  1868. idEntity::GetWorldVector
  1869. Takes a vector in the parent object's local coordinates and transforms
  1870. it into world coordinates.
  1871. Note: Does not take origin into acount. Use getWorldCoordinate to
  1872. convert coordinates.
  1873. ================
  1874. */
  1875. idVec3 idEntity::GetWorldVector( const idVec3 &vec ) const {
  1876. idVec3 pos;
  1877. if ( !bindMaster ) {
  1878. return vec;
  1879. }
  1880. idVec3 masterOrigin;
  1881. idMat3 masterAxis;
  1882. GetMasterPosition( masterOrigin, masterAxis );
  1883. masterAxis.UnprojectVector( vec, pos );
  1884. return pos;
  1885. }
  1886. /*
  1887. ================
  1888. idEntity::GetWorldCoordinates
  1889. Takes a vector in the parent object's local coordinates and transforms
  1890. it into world coordinates.
  1891. ================
  1892. */
  1893. idVec3 idEntity::GetWorldCoordinates( const idVec3 &vec ) const {
  1894. idVec3 pos;
  1895. if ( !bindMaster ) {
  1896. return vec;
  1897. }
  1898. idVec3 masterOrigin;
  1899. idMat3 masterAxis;
  1900. GetMasterPosition( masterOrigin, masterAxis );
  1901. masterAxis.UnprojectVector( vec, pos );
  1902. pos += masterOrigin;
  1903. return pos;
  1904. }
  1905. /*
  1906. ================
  1907. idEntity::GetMasterPosition
  1908. ================
  1909. */
  1910. bool idEntity::GetMasterPosition( idVec3 &masterOrigin, idMat3 &masterAxis ) const {
  1911. idVec3 localOrigin;
  1912. idMat3 localAxis;
  1913. idAnimator *masterAnimator;
  1914. if ( bindMaster ) {
  1915. // if bound to a joint of an animated model
  1916. if ( bindJoint != INVALID_JOINT ) {
  1917. masterAnimator = bindMaster->GetAnimator();
  1918. if ( !masterAnimator ) {
  1919. masterOrigin = vec3_origin;
  1920. masterAxis = mat3_identity;
  1921. return false;
  1922. } else {
  1923. masterAnimator->GetJointTransform( bindJoint, gameLocal.time, masterOrigin, masterAxis );
  1924. masterAxis *= bindMaster->renderEntity.axis;
  1925. masterOrigin = bindMaster->renderEntity.origin + masterOrigin * bindMaster->renderEntity.axis;
  1926. }
  1927. } else if ( bindBody >= 0 && bindMaster->GetPhysics() ) {
  1928. masterOrigin = bindMaster->GetPhysics()->GetOrigin( bindBody );
  1929. masterAxis = bindMaster->GetPhysics()->GetAxis( bindBody );
  1930. } else {
  1931. masterOrigin = bindMaster->renderEntity.origin;
  1932. masterAxis = bindMaster->renderEntity.axis;
  1933. }
  1934. return true;
  1935. } else {
  1936. masterOrigin = vec3_origin;
  1937. masterAxis = mat3_identity;
  1938. return false;
  1939. }
  1940. }
  1941. /*
  1942. ================
  1943. idEntity::GetWorldVelocities
  1944. ================
  1945. */
  1946. void idEntity::GetWorldVelocities( idVec3 &linearVelocity, idVec3 &angularVelocity ) const {
  1947. linearVelocity = physics->GetLinearVelocity();
  1948. angularVelocity = physics->GetAngularVelocity();
  1949. if ( bindMaster ) {
  1950. idVec3 masterOrigin, masterLinearVelocity, masterAngularVelocity;
  1951. idMat3 masterAxis;
  1952. // get position of master
  1953. GetMasterPosition( masterOrigin, masterAxis );
  1954. // get master velocities
  1955. bindMaster->GetWorldVelocities( masterLinearVelocity, masterAngularVelocity );
  1956. // linear velocity relative to master plus master linear and angular velocity
  1957. linearVelocity = linearVelocity * masterAxis + masterLinearVelocity +
  1958. masterAngularVelocity.Cross( GetPhysics()->GetOrigin() - masterOrigin );
  1959. }
  1960. }
  1961. /*
  1962. ================
  1963. idEntity::JoinTeam
  1964. ================
  1965. */
  1966. void idEntity::JoinTeam( idEntity *teammember ) {
  1967. idEntity *ent;
  1968. idEntity *master;
  1969. idEntity *prev;
  1970. idEntity *next;
  1971. // if we're already on a team, quit it so we can join this one
  1972. if ( teamMaster && ( teamMaster != this ) ) {
  1973. QuitTeam();
  1974. }
  1975. assert( teammember );
  1976. if ( teammember == this ) {
  1977. teamMaster = this;
  1978. return;
  1979. }
  1980. // check if our new team mate is already on a team
  1981. master = teammember->teamMaster;
  1982. if ( !master ) {
  1983. // he's not on a team, so he's the new teamMaster
  1984. master = teammember;
  1985. teammember->teamMaster = teammember;
  1986. teammember->teamChain = this;
  1987. // make anyone who's bound to me part of the new team
  1988. for( ent = teamChain; ent != NULL; ent = ent->teamChain ) {
  1989. ent->teamMaster = master;
  1990. }
  1991. } else {
  1992. // skip past the chain members bound to the entity we're teaming up with
  1993. prev = teammember;
  1994. next = teammember->teamChain;
  1995. if ( bindMaster ) {
  1996. // if we have a bindMaster, join after any entities bound to the entity
  1997. // we're joining
  1998. while( next && next->IsBoundTo( teammember ) ) {
  1999. prev = next;
  2000. next = next->teamChain;
  2001. }
  2002. } else {
  2003. // if we're not bound to someone, then put us at the end of the team
  2004. while( next ) {
  2005. prev = next;
  2006. next = next->teamChain;
  2007. }
  2008. }
  2009. // make anyone who's bound to me part of the new team and
  2010. // also find the last member of my team
  2011. for( ent = this; ent->teamChain != NULL; ent = ent->teamChain ) {
  2012. ent->teamChain->teamMaster = master;
  2013. }
  2014. prev->teamChain = this;
  2015. ent->teamChain = next;
  2016. }
  2017. teamMaster = master;
  2018. // reorder the active entity list
  2019. gameLocal.sortTeamMasters = true;
  2020. }
  2021. /*
  2022. ================
  2023. idEntity::QuitTeam
  2024. ================
  2025. */
  2026. void idEntity::QuitTeam() {
  2027. idEntity *ent;
  2028. if ( !teamMaster ) {
  2029. return;
  2030. }
  2031. // check if I'm the teamMaster
  2032. if ( teamMaster == this ) {
  2033. // do we have more than one teammate?
  2034. if ( !teamChain->teamChain ) {
  2035. // no, break up the team
  2036. teamChain->teamMaster = NULL;
  2037. } else {
  2038. // yes, so make the first teammate the teamMaster
  2039. for( ent = teamChain; ent; ent = ent->teamChain ) {
  2040. ent->teamMaster = teamChain;
  2041. }
  2042. }
  2043. } else {
  2044. assert( teamMaster );
  2045. assert( teamMaster->teamChain );
  2046. // find the previous member of the teamChain
  2047. ent = teamMaster;
  2048. while( ent->teamChain != this ) {
  2049. assert( ent->teamChain ); // this should never happen
  2050. ent = ent->teamChain;
  2051. }
  2052. // remove this from the teamChain
  2053. ent->teamChain = teamChain;
  2054. // if no one is left on the team, break it up
  2055. if ( !teamMaster->teamChain ) {
  2056. teamMaster->teamMaster = NULL;
  2057. }
  2058. }
  2059. teamMaster = NULL;
  2060. teamChain = NULL;
  2061. }
  2062. /***********************************************************************
  2063. Physics.
  2064. ***********************************************************************/
  2065. /*
  2066. ================
  2067. idEntity::InitDefaultPhysics
  2068. ================
  2069. */
  2070. void idEntity::InitDefaultPhysics( const idVec3 &origin, const idMat3 &axis ) {
  2071. const char *temp;
  2072. idClipModel *clipModel = NULL;
  2073. // check if a clipmodel key/value pair is set
  2074. if ( spawnArgs.GetString( "clipmodel", "", &temp ) ) {
  2075. if ( idClipModel::CheckModel( temp ) ) {
  2076. clipModel = new (TAG_PHYSICS_CLIP_ENTITY) idClipModel( temp );
  2077. }
  2078. }
  2079. if ( !spawnArgs.GetBool( "noclipmodel", "0" ) ) {
  2080. // check if mins/maxs or size key/value pairs are set
  2081. if ( !clipModel ) {
  2082. idVec3 size;
  2083. idBounds bounds;
  2084. bool setClipModel = false;
  2085. if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) &&
  2086. spawnArgs.GetVector( "maxs", NULL, bounds[1] ) ) {
  2087. setClipModel = true;
  2088. if ( bounds[0][0] > bounds[1][0] || bounds[0][1] > bounds[1][1] || bounds[0][2] > bounds[1][2] ) {
  2089. gameLocal.Error( "Invalid bounds '%s'-'%s' on entity '%s'", bounds[0].ToString(), bounds[1].ToString(), name.c_str() );
  2090. }
  2091. } else if ( spawnArgs.GetVector( "size", NULL, size ) ) {
  2092. if ( ( size.x < 0.0f ) || ( size.y < 0.0f ) || ( size.z < 0.0f ) ) {
  2093. gameLocal.Error( "Invalid size '%s' on entity '%s'", size.ToString(), name.c_str() );
  2094. }
  2095. bounds[0].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
  2096. bounds[1].Set( size.x * 0.5f, size.y * 0.5f, size.z );
  2097. setClipModel = true;
  2098. }
  2099. if ( setClipModel ) {
  2100. int numSides;
  2101. idTraceModel trm;
  2102. if ( spawnArgs.GetInt( "cylinder", "0", numSides ) && numSides > 0 ) {
  2103. trm.SetupCylinder( bounds, numSides < 3 ? 3 : numSides );
  2104. } else if ( spawnArgs.GetInt( "cone", "0", numSides ) && numSides > 0 ) {
  2105. trm.SetupCone( bounds, numSides < 3 ? 3 : numSides );
  2106. } else {
  2107. trm.SetupBox( bounds );
  2108. }
  2109. clipModel = new (TAG_PHYSICS_CLIP_ENTITY) idClipModel( trm );
  2110. }
  2111. }
  2112. // check if the visual model can be used as collision model
  2113. if ( !clipModel ) {
  2114. temp = spawnArgs.GetString( "model" );
  2115. if ( ( temp != NULL ) && ( *temp != 0 ) ) {
  2116. if ( idClipModel::CheckModel( temp ) ) {
  2117. clipModel = new (TAG_PHYSICS_CLIP_ENTITY) idClipModel( temp );
  2118. }
  2119. }
  2120. }
  2121. }
  2122. defaultPhysicsObj.SetSelf( this );
  2123. defaultPhysicsObj.SetClipModel( clipModel, 1.0f );
  2124. defaultPhysicsObj.SetOrigin( origin );
  2125. defaultPhysicsObj.SetAxis( axis );
  2126. physics = &defaultPhysicsObj;
  2127. }
  2128. /*
  2129. ================
  2130. idEntity::SetPhysics
  2131. ================
  2132. */
  2133. void idEntity::SetPhysics( idPhysics *phys ) {
  2134. // clear any contacts the current physics object has
  2135. if ( physics ) {
  2136. physics->ClearContacts();
  2137. }
  2138. // set new physics object or set the default physics if NULL
  2139. if ( phys != NULL ) {
  2140. defaultPhysicsObj.SetClipModel( NULL, 1.0f );
  2141. physics = phys;
  2142. physics->Activate();
  2143. } else {
  2144. physics = &defaultPhysicsObj;
  2145. }
  2146. physics->UpdateTime( gameLocal.time );
  2147. physics->SetMaster( bindMaster, fl.bindOrientated );
  2148. }
  2149. /*
  2150. ================
  2151. idEntity::RestorePhysics
  2152. ================
  2153. */
  2154. void idEntity::RestorePhysics( idPhysics *phys ) {
  2155. assert( phys != NULL );
  2156. // restore physics pointer
  2157. physics = phys;
  2158. }
  2159. /*
  2160. ================
  2161. idEntity::GetPhysics
  2162. ================
  2163. */
  2164. idPhysics *idEntity::GetPhysics() const {
  2165. return physics;
  2166. }
  2167. /*
  2168. ================
  2169. idEntity::RunPhysics
  2170. ================
  2171. */
  2172. bool idEntity::RunPhysics() {
  2173. int i, reachedTime;
  2174. idEntity * part = NULL, *blockedPart = NULL, *blockingEntity = NULL;
  2175. trace_t results;
  2176. bool moved;
  2177. // don't run physics if not enabled
  2178. if ( !( thinkFlags & TH_PHYSICS ) ) {
  2179. // however do update any animation controllers
  2180. if ( UpdateAnimationControllers() ) {
  2181. BecomeActive( TH_ANIMATE );
  2182. }
  2183. return false;
  2184. }
  2185. // if this entity is a team slave don't do anything because the team master will handle everything
  2186. if ( teamMaster && teamMaster != this ) {
  2187. return false;
  2188. }
  2189. const int startTime = gameLocal.previousTime;
  2190. const int endTime = gameLocal.time;
  2191. gameLocal.push.InitSavingPushedEntityPositions();
  2192. blockedPart = NULL;
  2193. // save the physics state of the whole team and disable the team for collision detection
  2194. for ( part = this; part != NULL; part = part->teamChain ) {
  2195. if ( part->physics ) {
  2196. if ( !part->fl.solidForTeam ) {
  2197. part->physics->DisableClip();
  2198. }
  2199. part->physics->SaveState();
  2200. }
  2201. }
  2202. // move the whole team
  2203. for ( part = this; part != NULL; part = part->teamChain ) {
  2204. if ( part->physics ) {
  2205. // run physics
  2206. moved = part->physics->Evaluate( GetPhysicsTimeStep(), endTime );
  2207. // check if the object is blocked
  2208. blockingEntity = part->physics->GetBlockingEntity();
  2209. if ( blockingEntity ) {
  2210. blockedPart = part;
  2211. break;
  2212. }
  2213. // if moved or forced to update the visual position and orientation from the physics
  2214. if ( moved || part->fl.forcePhysicsUpdate ) {
  2215. part->UpdateFromPhysics( false );
  2216. }
  2217. // update any animation controllers here so an entity bound
  2218. // to a joint of this entity gets the correct position
  2219. if ( part->UpdateAnimationControllers() ) {
  2220. part->BecomeActive( TH_ANIMATE );
  2221. }
  2222. }
  2223. }
  2224. // enable the whole team for collision detection
  2225. for ( part = this; part != NULL; part = part->teamChain ) {
  2226. if ( part->physics ) {
  2227. if ( !part->fl.solidForTeam ) {
  2228. part->physics->EnableClip();
  2229. }
  2230. }
  2231. }
  2232. // if one of the team entities is a pusher and blocked
  2233. if ( blockedPart ) {
  2234. // move the parts back to the previous position
  2235. for ( part = this; part != blockedPart; part = part->teamChain ) {
  2236. if ( part->physics ) {
  2237. // restore the physics state
  2238. part->physics->RestoreState();
  2239. // move back the visual position and orientation
  2240. part->UpdateFromPhysics( true );
  2241. }
  2242. }
  2243. for ( part = this; part != NULL; part = part->teamChain ) {
  2244. if ( part->physics ) {
  2245. // update the physics time without moving
  2246. part->physics->UpdateTime( endTime );
  2247. }
  2248. }
  2249. // restore the positions of any pushed entities
  2250. gameLocal.push.RestorePushedEntityPositions();
  2251. if ( common->IsClient() ) {
  2252. return false;
  2253. }
  2254. // if the master pusher has a "blocked" function, call it
  2255. Signal( SIG_BLOCKED );
  2256. ProcessEvent( &EV_TeamBlocked, blockedPart, blockingEntity );
  2257. // call the blocked function on the blocked part
  2258. blockedPart->ProcessEvent( &EV_PartBlocked, blockingEntity );
  2259. return false;
  2260. }
  2261. // This is to hack around an issue when reloading a game saved on certain movers would
  2262. // eject the player randomly through the world due to the first couple of frames imparting
  2263. // large pushVelocities.
  2264. const bool useAbnormalVelocityHack = ( idStr::Cmp( name, "houndola" ) == 0 );
  2265. // Disable motion blur if this object pushes the local player
  2266. renderEntity.skipMotionBlur = false;
  2267. // set pushed
  2268. for ( i = 0; i < gameLocal.push.GetNumPushedEntities(); i++ ) {
  2269. idEntity *ent = gameLocal.push.GetPushedEntity( i );
  2270. if ( ent->physics->IsType( idPhysics_Player::Type ) ) {
  2271. if ( gameLocal.GetLocalClientNum() == ent->entityNumber ) {
  2272. renderEntity.skipMotionBlur = true;
  2273. }
  2274. if ( useAbnormalVelocityHack ) {
  2275. idPhysics_Player * physics = static_cast< idPhysics_Player * >( ent->physics );
  2276. physics->SetPushedWithAbnormalVelocityHack( GetPhysicsTimeStep() );
  2277. } else {
  2278. ent->physics->SetPushed( endTime - startTime );
  2279. }
  2280. } else {
  2281. ent->physics->SetPushed( endTime - startTime );
  2282. }
  2283. }
  2284. // Propogate skipMotionBlur to all team members
  2285. for ( part = this; part != NULL; part = part->teamChain ) {
  2286. part->renderEntity.skipMotionBlur = renderEntity.skipMotionBlur;
  2287. }
  2288. if ( common->IsClient() ) {
  2289. return true;
  2290. }
  2291. // post reached event if the current time is at or past the end point of the motion
  2292. for ( part = this; part != NULL; part = part->teamChain ) {
  2293. if ( part->physics ) {
  2294. reachedTime = part->physics->GetLinearEndTime();
  2295. if ( startTime < reachedTime && endTime >= reachedTime ) {
  2296. part->ProcessEvent( &EV_ReachedPos );
  2297. }
  2298. reachedTime = part->physics->GetAngularEndTime();
  2299. if ( startTime < reachedTime && endTime >= reachedTime ) {
  2300. part->ProcessEvent( &EV_ReachedAng );
  2301. }
  2302. }
  2303. }
  2304. return true;
  2305. }
  2306. /*
  2307. ================
  2308. idEntity::InterpolatePhysics
  2309. ================
  2310. */
  2311. void idEntity::InterpolatePhysics( const float fraction ) {
  2312. int i, startTime, endTime;
  2313. idEntity * part = NULL, *blockedPart = NULL, *blockingEntity = NULL;
  2314. trace_t results;
  2315. bool moved;
  2316. // don't run physics if not enabled
  2317. if ( !( thinkFlags & TH_PHYSICS ) ) {
  2318. // however do update any animation controllers
  2319. if ( UpdateAnimationControllers() ) {
  2320. BecomeActive( TH_ANIMATE );
  2321. }
  2322. return;
  2323. }
  2324. // if this entity is a team slave, we still need to interpolate it's current position from the snapshot.
  2325. // The team master probably depends on the current physics state, and may be unaware of prev/next or interpolation.
  2326. if ( teamMaster && teamMaster != this ) {
  2327. if ( physics != NULL && useClientInterpolation ) {
  2328. if ( physics->Interpolate( fraction ) ) {
  2329. UpdateFromPhysics( false );
  2330. }
  2331. }
  2332. return;
  2333. }
  2334. startTime = gameLocal.previousTime;
  2335. endTime = gameLocal.time;
  2336. gameLocal.push.InitSavingPushedEntityPositions();
  2337. blockedPart = NULL;
  2338. // save the physics state of the whole team and disable the team for collision detection
  2339. for ( part = this; part != NULL; part = part->teamChain ) {
  2340. if ( part->physics ) {
  2341. if ( !part->fl.solidForTeam ) {
  2342. part->physics->DisableClip();
  2343. }
  2344. part->physics->SaveState();
  2345. }
  2346. }
  2347. // move the whole team
  2348. for ( part = this; part != NULL; part = part->teamChain ) {
  2349. if ( part->physics ) {
  2350. // run physics
  2351. moved = part->physics->Evaluate( GetPhysicsTimeStep(), endTime );
  2352. // check if the object is blocked
  2353. blockingEntity = part->physics->GetBlockingEntity();
  2354. if ( blockingEntity ) {
  2355. blockedPart = part;
  2356. break;
  2357. }
  2358. // if moved or forced to update the visual position and orientation from the physics
  2359. if ( moved || part->fl.forcePhysicsUpdate ) {
  2360. part->UpdateFromPhysics( false );
  2361. }
  2362. // update any animation controllers here so an entity bound
  2363. // to a joint of this entity gets the correct position
  2364. if ( part->UpdateAnimationControllers() ) {
  2365. part->BecomeActive( TH_ANIMATE );
  2366. }
  2367. }
  2368. }
  2369. // enable the whole team for collision detection
  2370. for ( part = this; part != NULL; part = part->teamChain ) {
  2371. if ( part->physics ) {
  2372. if ( !part->fl.solidForTeam ) {
  2373. part->physics->EnableClip();
  2374. }
  2375. }
  2376. }
  2377. // if one of the team entities is a pusher and blocked
  2378. if ( blockedPart ) {
  2379. // move the parts back to the previous position
  2380. for ( part = this; part != blockedPart; part = part->teamChain ) {
  2381. if ( part->physics ) {
  2382. // restore the physics state
  2383. part->physics->RestoreState();
  2384. // move back the visual position and orientation
  2385. part->UpdateFromPhysics( true );
  2386. }
  2387. }
  2388. for ( part = this; part != NULL; part = part->teamChain ) {
  2389. if ( part->physics ) {
  2390. // update the physics time without moving
  2391. part->physics->UpdateTime( endTime );
  2392. }
  2393. }
  2394. // restore the positions of any pushed entities
  2395. gameLocal.push.RestorePushedEntityPositions();
  2396. }
  2397. // set pushed
  2398. for ( i = 0; i < gameLocal.push.GetNumPushedEntities(); i++ ) {
  2399. idEntity *ent = gameLocal.push.GetPushedEntity( i );
  2400. ent->physics->SetPushed( GetPhysicsTimeStep() );
  2401. }
  2402. if ( physics && useClientInterpolation ) {
  2403. if ( physics->Interpolate( fraction ) ) {
  2404. UpdateFromPhysics( false );
  2405. }
  2406. }
  2407. }
  2408. /*
  2409. ================
  2410. idEntity::InterpolatePhysicsOnly
  2411. ================
  2412. */
  2413. void idEntity::InterpolatePhysicsOnly( const float fraction, bool updateTeam ) {
  2414. if ( physics && useClientInterpolation ) {
  2415. if ( physics->Interpolate( fraction ) ) {
  2416. UpdateFromPhysics( false );
  2417. }
  2418. }
  2419. if( updateTeam ) {
  2420. int endTime = gameLocal.time;
  2421. // move the whole team
  2422. for ( idEntity* part = this; part != NULL; part = part->teamChain ) {
  2423. if ( part->physics && part != this ) {
  2424. // run physics
  2425. bool moved = part->physics->Evaluate( GetPhysicsTimeStep(), endTime );
  2426. // if moved or forced to update the visual position and orientation from the physics
  2427. if ( moved || part->fl.forcePhysicsUpdate ) {
  2428. part->UpdateFromPhysics( false );
  2429. }
  2430. // update any animation controllers here so an entity bound
  2431. // to a joint of this entity gets the correct position
  2432. if ( part->UpdateAnimationControllers() ) {
  2433. part->BecomeActive( TH_ANIMATE );
  2434. }
  2435. }
  2436. }
  2437. }
  2438. }
  2439. /*
  2440. ================
  2441. idEntity::UpdateFromPhysics
  2442. ================
  2443. */
  2444. void idEntity::UpdateFromPhysics( bool moveBack ) {
  2445. if ( IsType( idActor::Type ) ) {
  2446. idActor *actor = static_cast<idActor *>( this );
  2447. // set master delta angles for actors
  2448. if ( GetBindMaster() ) {
  2449. idAngles delta = actor->GetDeltaViewAngles();
  2450. if ( moveBack ) {
  2451. delta.yaw -= static_cast<idPhysics_Actor *>(physics)->GetMasterDeltaYaw();
  2452. } else {
  2453. delta.yaw += static_cast<idPhysics_Actor *>(physics)->GetMasterDeltaYaw();
  2454. }
  2455. actor->SetDeltaViewAngles( delta );
  2456. }
  2457. }
  2458. UpdateVisuals();
  2459. }
  2460. /*
  2461. ================
  2462. idEntity::GetPhysicsTimeStep
  2463. ================
  2464. */
  2465. int idEntity::GetPhysicsTimeStep() const {
  2466. return gameLocal.time - gameLocal.previousTime;
  2467. }
  2468. /*
  2469. ================
  2470. idEntity::SetOrigin
  2471. ================
  2472. */
  2473. void idEntity::SetOrigin( const idVec3 &org ) {
  2474. GetPhysics()->SetOrigin( org );
  2475. UpdateVisuals();
  2476. }
  2477. /*
  2478. ================
  2479. idEntity::SetAxis
  2480. ================
  2481. */
  2482. void idEntity::SetAxis( const idMat3 &axis ) {
  2483. if ( GetPhysics()->IsType( idPhysics_Actor::Type ) ) {
  2484. static_cast<idActor *>(this)->viewAxis = axis;
  2485. } else {
  2486. GetPhysics()->SetAxis( axis );
  2487. }
  2488. UpdateVisuals();
  2489. }
  2490. /*
  2491. ================
  2492. idEntity::SetAngles
  2493. ================
  2494. */
  2495. void idEntity::SetAngles( const idAngles &ang ) {
  2496. SetAxis( ang.ToMat3() );
  2497. }
  2498. /*
  2499. ================
  2500. idEntity::GetFloorPos
  2501. ================
  2502. */
  2503. bool idEntity::GetFloorPos( float max_dist, idVec3 &floorpos ) const {
  2504. trace_t result;
  2505. if ( !GetPhysics()->HasGroundContacts() ) {
  2506. GetPhysics()->ClipTranslation( result, GetPhysics()->GetGravityNormal() * max_dist, NULL );
  2507. if ( result.fraction < 1.0f ) {
  2508. floorpos = result.endpos;
  2509. return true;
  2510. } else {
  2511. floorpos = GetPhysics()->GetOrigin();
  2512. return false;
  2513. }
  2514. } else {
  2515. floorpos = GetPhysics()->GetOrigin();
  2516. return true;
  2517. }
  2518. }
  2519. /*
  2520. ================
  2521. idEntity::GetPhysicsToVisualTransform
  2522. ================
  2523. */
  2524. bool idEntity::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
  2525. return false;
  2526. }
  2527. /*
  2528. ================
  2529. idEntity::GetPhysicsToSoundTransform
  2530. ================
  2531. */
  2532. bool idEntity::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
  2533. // by default play the sound at the center of the bounding box of the first clip model
  2534. if ( GetPhysics()->GetNumClipModels() > 0 ) {
  2535. origin = GetPhysics()->GetBounds().GetCenter();
  2536. axis.Identity();
  2537. return true;
  2538. }
  2539. return false;
  2540. }
  2541. /*
  2542. ================
  2543. idEntity::Collide
  2544. ================
  2545. */
  2546. bool idEntity::Collide( const trace_t &collision, const idVec3 &velocity ) {
  2547. // this entity collides with collision.c.entityNum
  2548. return false;
  2549. }
  2550. /*
  2551. ================
  2552. idEntity::GetImpactInfo
  2553. ================
  2554. */
  2555. void idEntity::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
  2556. GetPhysics()->GetImpactInfo( id, point, info );
  2557. }
  2558. /*
  2559. ================
  2560. idEntity::ApplyImpulse
  2561. ================
  2562. */
  2563. void idEntity::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) {
  2564. GetPhysics()->ApplyImpulse( id, point, impulse );
  2565. }
  2566. /*
  2567. ================
  2568. idEntity::AddForce
  2569. ================
  2570. */
  2571. void idEntity::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
  2572. GetPhysics()->AddForce( id, point, force );
  2573. }
  2574. /*
  2575. ================
  2576. idEntity::ActivatePhysics
  2577. ================
  2578. */
  2579. void idEntity::ActivatePhysics( idEntity *ent ) {
  2580. GetPhysics()->Activate();
  2581. }
  2582. /*
  2583. ================
  2584. idEntity::IsAtRest
  2585. ================
  2586. */
  2587. bool idEntity::IsAtRest() const {
  2588. return GetPhysics()->IsAtRest();
  2589. }
  2590. /*
  2591. ================
  2592. idEntity::GetRestStartTime
  2593. ================
  2594. */
  2595. int idEntity::GetRestStartTime() const {
  2596. return GetPhysics()->GetRestStartTime();
  2597. }
  2598. /*
  2599. ================
  2600. idEntity::AddContactEntity
  2601. ================
  2602. */
  2603. void idEntity::AddContactEntity( idEntity *ent ) {
  2604. GetPhysics()->AddContactEntity( ent );
  2605. }
  2606. /*
  2607. ================
  2608. idEntity::RemoveContactEntity
  2609. ================
  2610. */
  2611. void idEntity::RemoveContactEntity( idEntity *ent ) {
  2612. GetPhysics()->RemoveContactEntity( ent );
  2613. }
  2614. /***********************************************************************
  2615. Damage
  2616. ***********************************************************************/
  2617. /*
  2618. ============
  2619. idEntity::CanDamage
  2620. Returns true if the inflictor can directly damage the target. Used for
  2621. explosions and melee attacks.
  2622. ============
  2623. */
  2624. bool idEntity::CanDamage( const idVec3 &origin, idVec3 &damagePoint ) const {
  2625. idVec3 dest;
  2626. trace_t tr;
  2627. idVec3 midpoint;
  2628. // use the midpoint of the bounds instead of the origin, because
  2629. // bmodels may have their origin at 0,0,0
  2630. midpoint = ( GetPhysics()->GetAbsBounds()[0] + GetPhysics()->GetAbsBounds()[1] ) * 0.5;
  2631. dest = midpoint;
  2632. gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
  2633. if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
  2634. damagePoint = tr.endpos;
  2635. return true;
  2636. }
  2637. // this should probably check in the plane of projection, rather than in world coordinate
  2638. dest = midpoint;
  2639. dest[0] += 15.0;
  2640. dest[1] += 15.0;
  2641. gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
  2642. if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
  2643. damagePoint = tr.endpos;
  2644. return true;
  2645. }
  2646. dest = midpoint;
  2647. dest[0] += 15.0;
  2648. dest[1] -= 15.0;
  2649. gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
  2650. if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
  2651. damagePoint = tr.endpos;
  2652. return true;
  2653. }
  2654. dest = midpoint;
  2655. dest[0] -= 15.0;
  2656. dest[1] += 15.0;
  2657. gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
  2658. if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
  2659. damagePoint = tr.endpos;
  2660. return true;
  2661. }
  2662. dest = midpoint;
  2663. dest[0] -= 15.0;
  2664. dest[1] -= 15.0;
  2665. gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
  2666. if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
  2667. damagePoint = tr.endpos;
  2668. return true;
  2669. }
  2670. dest = midpoint;
  2671. dest[2] += 15.0;
  2672. gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
  2673. if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
  2674. damagePoint = tr.endpos;
  2675. return true;
  2676. }
  2677. dest = midpoint;
  2678. dest[2] -= 15.0;
  2679. gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
  2680. if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
  2681. damagePoint = tr.endpos;
  2682. return true;
  2683. }
  2684. return false;
  2685. }
  2686. /*
  2687. ================
  2688. idEntity::DamageFeedback
  2689. callback function for when another entity received damage from this entity. damage can be adjusted and returned to the caller.
  2690. ================
  2691. */
  2692. void idEntity::DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ) {
  2693. // implemented in subclasses
  2694. }
  2695. /*
  2696. ============
  2697. Damage
  2698. this entity that is being damaged
  2699. inflictor entity that is causing the damage
  2700. attacker entity that caused the inflictor to damage targ
  2701. example: this=monster, inflictor=rocket, attacker=player
  2702. dir direction of the attack for knockback in global space
  2703. point point at which the damage is being inflicted, used for headshots
  2704. damage amount of damage being inflicted
  2705. inflictor, attacker, dir, and point can be NULL for environmental effects
  2706. ============
  2707. */
  2708. void idEntity::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir,
  2709. const char *damageDefName, const float damageScale, const int location ) {
  2710. if ( !fl.takedamage ) {
  2711. return;
  2712. }
  2713. SetTimeState ts( timeGroup );
  2714. if ( !inflictor ) {
  2715. inflictor = gameLocal.world;
  2716. }
  2717. if ( !attacker ) {
  2718. attacker = gameLocal.world;
  2719. }
  2720. const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
  2721. if ( damageDef == NULL ) {
  2722. gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName );
  2723. return;
  2724. }
  2725. int damage = damageDef->GetInt( "damage" );
  2726. // inform the attacker that they hit someone
  2727. attacker->DamageFeedback( this, inflictor, damage );
  2728. if ( damage ) {
  2729. // do the damage
  2730. health -= damage;
  2731. if ( health <= 0 ) {
  2732. if ( health < -999 ) {
  2733. health = -999;
  2734. }
  2735. Killed( inflictor, attacker, damage, dir, location );
  2736. } else {
  2737. Pain( inflictor, attacker, damage, dir, location );
  2738. }
  2739. }
  2740. }
  2741. /*
  2742. ================
  2743. idEntity::AddDamageEffect
  2744. ================
  2745. */
  2746. void idEntity::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) {
  2747. const char *sound, *decal, *key;
  2748. const idDeclEntityDef *def = gameLocal.FindEntityDef( damageDefName, false );
  2749. if ( def == NULL ) {
  2750. return;
  2751. }
  2752. const char *materialType = gameLocal.sufaceTypeNames[ collision.c.material->GetSurfaceType() ];
  2753. // start impact sound based on material type
  2754. key = va( "snd_%s", materialType );
  2755. sound = spawnArgs.GetString( key );
  2756. if ( *sound == '\0' ) {
  2757. sound = def->dict.GetString( key );
  2758. }
  2759. if ( *sound != '\0' ) {
  2760. StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL );
  2761. }
  2762. if ( g_decals.GetBool() ) {
  2763. // place a wound overlay on the model
  2764. key = va( "mtr_wound_%s", materialType );
  2765. decal = spawnArgs.RandomPrefix( key, gameLocal.random );
  2766. if ( *decal == '\0' ) {
  2767. decal = def->dict.RandomPrefix( key, gameLocal.random );
  2768. }
  2769. if ( *decal != '\0' ) {
  2770. idVec3 dir = velocity;
  2771. dir.Normalize();
  2772. ProjectOverlay( collision.c.point, dir, 20.0f, decal );
  2773. }
  2774. }
  2775. }
  2776. /*
  2777. ============
  2778. idEntity::Pain
  2779. Called whenever an entity recieves damage. Returns whether the entity responds to the pain.
  2780. This is a virtual function that subclasses are expected to implement.
  2781. ============
  2782. */
  2783. bool idEntity::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  2784. return false;
  2785. }
  2786. /*
  2787. ============
  2788. idEntity::Killed
  2789. Called whenever an entity's health is reduced to 0 or less.
  2790. This is a virtual function that subclasses are expected to implement.
  2791. ============
  2792. */
  2793. void idEntity::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  2794. }
  2795. /***********************************************************************
  2796. Script functions
  2797. ***********************************************************************/
  2798. /*
  2799. ================
  2800. idEntity::ShouldConstructScriptObjectAtSpawn
  2801. Called during idEntity::Spawn to see if it should construct the script object or not.
  2802. Overridden by subclasses that need to spawn the script object themselves.
  2803. ================
  2804. */
  2805. bool idEntity::ShouldConstructScriptObjectAtSpawn() const {
  2806. return true;
  2807. }
  2808. /*
  2809. ================
  2810. idEntity::ConstructScriptObject
  2811. Called during idEntity::Spawn. Calls the constructor on the script object.
  2812. Can be overridden by subclasses when a thread doesn't need to be allocated.
  2813. ================
  2814. */
  2815. idThread *idEntity::ConstructScriptObject() {
  2816. idThread *thread;
  2817. const function_t *constructor;
  2818. // init the script object's data
  2819. scriptObject.ClearObject();
  2820. // call script object's constructor
  2821. constructor = scriptObject.GetConstructor();
  2822. if ( constructor ) {
  2823. // start a thread that will initialize after Spawn is done being called
  2824. thread = new idThread();
  2825. thread->SetThreadName( name.c_str() );
  2826. thread->CallFunction( this, constructor, true );
  2827. thread->DelayedStart( 0 );
  2828. } else {
  2829. thread = NULL;
  2830. }
  2831. // clear out the object's memory
  2832. scriptObject.ClearObject();
  2833. return thread;
  2834. }
  2835. /*
  2836. ================
  2837. idEntity::DeconstructScriptObject
  2838. Called during idEntity::~idEntity. Calls the destructor on the script object.
  2839. Can be overridden by subclasses when a thread doesn't need to be allocated.
  2840. Not called during idGameLocal::MapShutdown.
  2841. ================
  2842. */
  2843. void idEntity::DeconstructScriptObject() {
  2844. idThread *thread;
  2845. const function_t *destructor;
  2846. // don't bother calling the script object's destructor on map shutdown
  2847. if ( gameLocal.GameState() == GAMESTATE_SHUTDOWN ) {
  2848. return;
  2849. }
  2850. // call script object's destructor
  2851. destructor = scriptObject.GetDestructor();
  2852. if ( destructor ) {
  2853. // start a thread that will run immediately and be destroyed
  2854. thread = new idThread();
  2855. thread->SetThreadName( name.c_str() );
  2856. thread->CallFunction( this, destructor, true );
  2857. thread->Execute();
  2858. delete thread;
  2859. }
  2860. }
  2861. /*
  2862. ================
  2863. idEntity::HasSignal
  2864. ================
  2865. */
  2866. bool idEntity::HasSignal( signalNum_t signalnum ) const {
  2867. if ( !signals ) {
  2868. return false;
  2869. }
  2870. assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) );
  2871. return ( signals->signal[ signalnum ].Num() > 0 );
  2872. }
  2873. /*
  2874. ================
  2875. idEntity::SetSignal
  2876. ================
  2877. */
  2878. void idEntity::SetSignal( signalNum_t signalnum, idThread *thread, const function_t *function ) {
  2879. int i;
  2880. int num;
  2881. signal_t sig;
  2882. int threadnum;
  2883. assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) );
  2884. if ( !signals ) {
  2885. signals = new (TAG_ENTITY) signalList_t;
  2886. }
  2887. assert( thread );
  2888. threadnum = thread->GetThreadNum();
  2889. num = signals->signal[ signalnum ].Num();
  2890. for( i = 0; i < num; i++ ) {
  2891. if ( signals->signal[ signalnum ][ i ].threadnum == threadnum ) {
  2892. signals->signal[ signalnum ][ i ].function = function;
  2893. return;
  2894. }
  2895. }
  2896. if ( num >= MAX_SIGNAL_THREADS ) {
  2897. thread->Error( "Exceeded maximum number of signals per object" );
  2898. }
  2899. sig.threadnum = threadnum;
  2900. sig.function = function;
  2901. signals->signal[ signalnum ].Append( sig );
  2902. }
  2903. /*
  2904. ================
  2905. idEntity::ClearSignal
  2906. ================
  2907. */
  2908. void idEntity::ClearSignal( idThread *thread, signalNum_t signalnum ) {
  2909. assert( thread );
  2910. if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) {
  2911. gameLocal.Error( "Signal out of range" );
  2912. return;
  2913. }
  2914. if ( signals == NULL ) {
  2915. return;
  2916. }
  2917. signals->signal[ signalnum ].Clear();
  2918. }
  2919. /*
  2920. ================
  2921. idEntity::ClearSignalThread
  2922. ================
  2923. */
  2924. void idEntity::ClearSignalThread( signalNum_t signalnum, idThread *thread ) {
  2925. int i;
  2926. int num;
  2927. int threadnum;
  2928. assert( thread );
  2929. if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) {
  2930. gameLocal.Error( "Signal out of range" );
  2931. return;
  2932. }
  2933. if ( signals == NULL ) {
  2934. return;
  2935. }
  2936. threadnum = thread->GetThreadNum();
  2937. num = signals->signal[ signalnum ].Num();
  2938. for( i = 0; i < num; i++ ) {
  2939. if ( signals->signal[ signalnum ][ i ].threadnum == threadnum ) {
  2940. signals->signal[ signalnum ].RemoveIndex( i );
  2941. return;
  2942. }
  2943. }
  2944. }
  2945. /*
  2946. ================
  2947. idEntity::Signal
  2948. ================
  2949. */
  2950. void idEntity::Signal( signalNum_t signalnum ) {
  2951. int i;
  2952. int num;
  2953. signal_t sigs[ MAX_SIGNAL_THREADS ];
  2954. idThread *thread;
  2955. assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) );
  2956. if ( !signals ) {
  2957. return;
  2958. }
  2959. // we copy the signal list since each thread has the potential
  2960. // to end any of the threads in the list. By copying the list
  2961. // we don't have to worry about the list changing as we're
  2962. // processing it.
  2963. num = signals->signal[ signalnum ].Num();
  2964. for( i = 0; i < num; i++ ) {
  2965. sigs[ i ] = signals->signal[ signalnum ][ i ];
  2966. }
  2967. // clear out the signal list so that we don't get into an infinite loop
  2968. signals->signal[ signalnum ].Clear();
  2969. for( i = 0; i < num; i++ ) {
  2970. thread = idThread::GetThread( sigs[ i ].threadnum );
  2971. if ( thread ) {
  2972. thread->CallFunction( this, sigs[ i ].function, true );
  2973. thread->Execute();
  2974. }
  2975. }
  2976. }
  2977. /*
  2978. ================
  2979. idEntity::SignalEvent
  2980. ================
  2981. */
  2982. void idEntity::SignalEvent( idThread *thread, signalNum_t signalnum ) {
  2983. if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) {
  2984. gameLocal.Error( "Signal out of range" );
  2985. }
  2986. if ( !signals ) {
  2987. return;
  2988. }
  2989. Signal( signalnum );
  2990. }
  2991. /***********************************************************************
  2992. Guis.
  2993. ***********************************************************************/
  2994. /*
  2995. ================
  2996. idEntity::TriggerGuis
  2997. ================
  2998. */
  2999. void idEntity::TriggerGuis() {
  3000. int i;
  3001. for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
  3002. if ( renderEntity.gui[ i ] ) {
  3003. renderEntity.gui[ i ]->Trigger( gameLocal.time );
  3004. }
  3005. }
  3006. }
  3007. /*
  3008. ================
  3009. idEntity::HandleGuiCommands
  3010. ================
  3011. */
  3012. bool idEntity::HandleGuiCommands( idEntity *entityGui, const char *cmds ) {
  3013. idEntity *targetEnt;
  3014. bool ret = false;
  3015. if ( entityGui && cmds && *cmds ) {
  3016. idLexer src;
  3017. idToken token, token2, token3, token4;
  3018. src.LoadMemory( cmds, strlen( cmds ), "guiCommands" );
  3019. while( 1 ) {
  3020. if ( !src.ReadToken( &token ) ) {
  3021. return ret;
  3022. }
  3023. if ( token == ";" ) {
  3024. continue;
  3025. }
  3026. if ( token.Icmp( "activate" ) == 0 ) {
  3027. bool targets = true;
  3028. if ( src.ReadToken( &token2 ) ) {
  3029. if ( token2 == ";" ) {
  3030. src.UnreadToken( &token2 );
  3031. } else {
  3032. targets = false;
  3033. }
  3034. }
  3035. if ( targets ) {
  3036. entityGui->ActivateTargets( this );
  3037. } else {
  3038. idEntity *ent = gameLocal.FindEntity( token2 );
  3039. if ( ent ) {
  3040. ent->Signal( SIG_TRIGGER );
  3041. ent->PostEventMS( &EV_Activate, 0, this );
  3042. }
  3043. }
  3044. entityGui->renderEntity.shaderParms[ SHADERPARM_MODE ] = 1.0f;
  3045. continue;
  3046. }
  3047. if ( token.Icmp( "runScript" ) == 0 ) {
  3048. if ( src.ReadToken( &token2 ) ) {
  3049. while( src.CheckTokenString( "::" ) ) {
  3050. idToken token3;
  3051. if ( !src.ReadToken( &token3 ) ) {
  3052. gameLocal.Error( "Expecting function name following '::' in gui for entity '%s'", entityGui->name.c_str() );
  3053. }
  3054. token2 += "::" + token3;
  3055. }
  3056. const function_t *func = gameLocal.program.FindFunction( token2 );
  3057. if ( !func ) {
  3058. gameLocal.Error( "Can't find function '%s' for gui in entity '%s'", token2.c_str(), entityGui->name.c_str() );
  3059. } else {
  3060. idThread *thread = new idThread( func );
  3061. thread->DelayedStart( 0 );
  3062. }
  3063. }
  3064. continue;
  3065. }
  3066. if ( token.Icmp("play") == 0 ) {
  3067. if ( src.ReadToken( &token2 ) ) {
  3068. const idSoundShader *shader = declManager->FindSound(token2);
  3069. entityGui->StartSoundShader( shader, SND_CHANNEL_ANY, 0, false, NULL );
  3070. }
  3071. continue;
  3072. }
  3073. if ( token.Icmp( "setkeyval" ) == 0 ) {
  3074. if ( src.ReadToken( &token2 ) && src.ReadToken(&token3) && src.ReadToken( &token4 ) ) {
  3075. idEntity *ent = gameLocal.FindEntity( token2 );
  3076. if ( ent ) {
  3077. ent->spawnArgs.Set( token3, token4 );
  3078. ent->UpdateChangeableSpawnArgs( NULL );
  3079. ent->UpdateVisuals();
  3080. }
  3081. }
  3082. continue;
  3083. }
  3084. if ( token.Icmp( "setshaderparm" ) == 0 ) {
  3085. if ( src.ReadToken( &token2 ) && src.ReadToken(&token3) ) {
  3086. entityGui->SetShaderParm( atoi( token2 ), atof( token3 ) );
  3087. entityGui->UpdateVisuals();
  3088. }
  3089. continue;
  3090. }
  3091. if ( token.Icmp("close") == 0 ) {
  3092. ret = true;
  3093. continue;
  3094. }
  3095. if ( !token.Icmp( "turkeyscore" ) ) {
  3096. if ( src.ReadToken( &token2 ) && entityGui->renderEntity.gui[0] ) {
  3097. int score = entityGui->renderEntity.gui[0]->State().GetInt( "score" );
  3098. score += atoi( token2 );
  3099. entityGui->renderEntity.gui[0]->SetStateInt( "score", score );
  3100. if ( gameLocal.GetLocalPlayer() && score >= 25000 ) {
  3101. gameLocal.GetLocalPlayer()->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_SCORE_25000_TURKEY_PUNCHER );
  3102. gameLocal.GetLocalPlayer()->GiveEmail( static_cast<const idDeclEmail *>( declManager->FindType( DECL_EMAIL, "highScore", false ) ) );
  3103. }
  3104. }
  3105. continue;
  3106. }
  3107. if ( !token.Icmp( "martianbuddycomplete" ) ) {
  3108. gameLocal.GetLocalPlayer()->GiveEmail( static_cast<const idDeclEmail *>( declManager->FindType( DECL_EMAIL, "MartianBuddyGameComplete", false ) ) );
  3109. continue;
  3110. }
  3111. // handy for debugging GUI stuff
  3112. if ( !token.Icmp( "print" ) ) {
  3113. idStr msg;
  3114. while ( src.ReadToken( &token2 ) ) {
  3115. if ( token2 == ";" ) {
  3116. src.UnreadToken( &token2 );
  3117. break;
  3118. }
  3119. msg += token2.c_str();
  3120. }
  3121. common->Printf( "ent gui 0x%x '%s': %s\n", entityNumber, name.c_str(), msg.c_str() );
  3122. continue;
  3123. }
  3124. // if we get to this point we don't know how to handle it
  3125. src.UnreadToken(&token);
  3126. if ( !HandleSingleGuiCommand( entityGui, &src ) ) {
  3127. // not handled there see if entity or any of its targets can handle it
  3128. // this will only work for one target atm
  3129. if ( entityGui->HandleSingleGuiCommand( entityGui, &src ) ) {
  3130. continue;
  3131. }
  3132. int c = entityGui->targets.Num();
  3133. int i;
  3134. for ( i = 0; i < c; i++) {
  3135. targetEnt = entityGui->targets[ i ].GetEntity();
  3136. if ( targetEnt && targetEnt->HandleSingleGuiCommand( entityGui, &src ) ) {
  3137. break;
  3138. }
  3139. }
  3140. if ( i == c ) {
  3141. // not handled
  3142. common->DPrintf( "idEntity::HandleGuiCommands: '%s' not handled\n", token.c_str() );
  3143. src.ReadToken( &token );
  3144. }
  3145. }
  3146. }
  3147. }
  3148. return ret;
  3149. }
  3150. /*
  3151. ================
  3152. idEntity::HandleSingleGuiCommand
  3153. ================
  3154. */
  3155. bool idEntity::HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ) {
  3156. return false;
  3157. }
  3158. /***********************************************************************
  3159. Targets
  3160. ***********************************************************************/
  3161. /*
  3162. ===============
  3163. idEntity::FindTargets
  3164. We have to wait until all entities are spawned
  3165. Used to build lists of targets after the entity is spawned. Since not all entities
  3166. have been spawned when the entity is created at map load time, we have to wait
  3167. ===============
  3168. */
  3169. void idEntity::FindTargets() {
  3170. int i;
  3171. // targets can be a list of multiple names
  3172. gameLocal.GetTargets( spawnArgs, targets, "target" );
  3173. // ensure that we don't target ourselves since that could cause an infinite loop when activating entities
  3174. for( i = 0; i < targets.Num(); i++ ) {
  3175. if ( targets[ i ].GetEntity() == this ) {
  3176. gameLocal.Error( "Entity '%s' is targeting itself", name.c_str() );
  3177. }
  3178. }
  3179. }
  3180. /*
  3181. ================
  3182. idEntity::RemoveNullTargets
  3183. ================
  3184. */
  3185. void idEntity::RemoveNullTargets() {
  3186. int i;
  3187. for( i = targets.Num() - 1; i >= 0; i-- ) {
  3188. if ( !targets[ i ].GetEntity() ) {
  3189. targets.RemoveIndex( i );
  3190. }
  3191. }
  3192. }
  3193. /*
  3194. ==============================
  3195. idEntity::ActivateTargets
  3196. "activator" should be set to the entity that initiated the firing.
  3197. ==============================
  3198. */
  3199. void idEntity::ActivateTargets( idEntity *activator ) const {
  3200. idEntity *ent;
  3201. int i, j;
  3202. for( i = 0; i < targets.Num(); i++ ) {
  3203. ent = targets[ i ].GetEntity();
  3204. if ( !ent ) {
  3205. continue;
  3206. }
  3207. if ( ent->RespondsTo( EV_Activate ) || ent->HasSignal( SIG_TRIGGER ) ) {
  3208. ent->Signal( SIG_TRIGGER );
  3209. ent->ProcessEvent( &EV_Activate, activator );
  3210. }
  3211. for ( j = 0; j < MAX_RENDERENTITY_GUI; j++ ) {
  3212. if ( ent->renderEntity.gui[ j ] ) {
  3213. ent->renderEntity.gui[ j ]->Trigger( gameLocal.time );
  3214. }
  3215. }
  3216. }
  3217. }
  3218. /***********************************************************************
  3219. Misc.
  3220. ***********************************************************************/
  3221. /*
  3222. ================
  3223. idEntity::Teleport
  3224. ================
  3225. */
  3226. void idEntity::Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ) {
  3227. GetPhysics()->SetOrigin( origin );
  3228. GetPhysics()->SetAxis( angles.ToMat3() );
  3229. UpdateVisuals();
  3230. }
  3231. /*
  3232. ============
  3233. idEntity::TouchTriggers
  3234. Activate all trigger entities touched at the current position.
  3235. ============
  3236. */
  3237. bool idEntity::TouchTriggers() const {
  3238. int i, numClipModels, numEntities;
  3239. idClipModel * cm;
  3240. idClipModel * clipModels[ MAX_GENTITIES ];
  3241. idEntity * ent;
  3242. trace_t trace;
  3243. memset( &trace, 0, sizeof( trace ) );
  3244. trace.endpos = GetPhysics()->GetOrigin();
  3245. trace.endAxis = GetPhysics()->GetAxis();
  3246. numClipModels = gameLocal.clip.ClipModelsTouchingBounds( GetPhysics()->GetAbsBounds(), CONTENTS_TRIGGER, clipModels, MAX_GENTITIES );
  3247. numEntities = 0;
  3248. for ( i = 0; i < numClipModels; i++ ) {
  3249. cm = clipModels[ i ];
  3250. // don't touch it if we're the owner
  3251. if ( cm->GetOwner() == this ) {
  3252. continue;
  3253. }
  3254. ent = cm->GetEntity();
  3255. if ( !ent->RespondsTo( EV_Touch ) && !ent->HasSignal( SIG_TOUCH ) ) {
  3256. continue;
  3257. }
  3258. if ( !GetPhysics()->ClipContents( cm ) ) {
  3259. continue;
  3260. }
  3261. SetTimeState ts( ent->timeGroup );
  3262. numEntities++;
  3263. trace.c.contents = cm->GetContents();
  3264. trace.c.entityNum = cm->GetEntity()->entityNumber;
  3265. trace.c.id = cm->GetId();
  3266. ent->Signal( SIG_TOUCH );
  3267. ent->ProcessEvent( &EV_Touch, this, &trace );
  3268. if ( !gameLocal.entities[ entityNumber ] ) {
  3269. gameLocal.Printf( "entity was removed while touching triggers\n" );
  3270. return true;
  3271. }
  3272. }
  3273. return ( numEntities != 0 );
  3274. }
  3275. /*
  3276. ================
  3277. idEntity::GetSpline
  3278. ================
  3279. */
  3280. idCurve_Spline<idVec3> *idEntity::GetSpline() const {
  3281. int i, numPoints, t;
  3282. const idKeyValue *kv;
  3283. idLexer lex;
  3284. idVec3 v;
  3285. idCurve_Spline<idVec3> *spline;
  3286. const char *curveTag = "curve_";
  3287. kv = spawnArgs.MatchPrefix( curveTag );
  3288. if ( !kv ) {
  3289. return NULL;
  3290. }
  3291. idStr str = kv->GetKey().Right( kv->GetKey().Length() - strlen( curveTag ) );
  3292. if ( str.Icmp( "CatmullRomSpline" ) == 0 ) {
  3293. spline = new (TAG_ENTITY) idCurve_CatmullRomSpline<idVec3>();
  3294. } else if ( str.Icmp( "nubs" ) == 0 ) {
  3295. spline = new (TAG_ENTITY) idCurve_NonUniformBSpline<idVec3>();
  3296. } else if ( str.Icmp( "nurbs" ) == 0 ) {
  3297. spline = new (TAG_ENTITY) idCurve_NURBS<idVec3>();
  3298. } else {
  3299. spline = new (TAG_ENTITY) idCurve_BSpline<idVec3>();
  3300. }
  3301. spline->SetBoundaryType( idCurve_Spline<idVec3>::BT_CLAMPED );
  3302. lex.LoadMemory( kv->GetValue(), kv->GetValue().Length(), curveTag );
  3303. numPoints = lex.ParseInt();
  3304. lex.ExpectTokenString( "(" );
  3305. for ( t = i = 0; i < numPoints; i++, t += 100 ) {
  3306. v.x = lex.ParseFloat();
  3307. v.y = lex.ParseFloat();
  3308. v.z = lex.ParseFloat();
  3309. spline->AddValue( t, v );
  3310. }
  3311. lex.ExpectTokenString( ")" );
  3312. return spline;
  3313. }
  3314. /*
  3315. ===============
  3316. idEntity::ShowEditingDialog
  3317. ===============
  3318. */
  3319. void idEntity::ShowEditingDialog() {
  3320. }
  3321. /***********************************************************************
  3322. Events
  3323. ***********************************************************************/
  3324. /*
  3325. ================
  3326. idEntity::Event_GetName
  3327. ================
  3328. */
  3329. void idEntity::Event_GetName() {
  3330. idThread::ReturnString( name.c_str() );
  3331. }
  3332. /*
  3333. ================
  3334. idEntity::Event_SetName
  3335. ================
  3336. */
  3337. void idEntity::Event_SetName( const char *newname ) {
  3338. SetName( newname );
  3339. }
  3340. /*
  3341. ===============
  3342. idEntity::Event_FindTargets
  3343. ===============
  3344. */
  3345. void idEntity::Event_FindTargets() {
  3346. FindTargets();
  3347. }
  3348. /*
  3349. ============
  3350. idEntity::Event_ActivateTargets
  3351. Activates any entities targeted by this entity. Mainly used as an
  3352. event to delay activating targets.
  3353. ============
  3354. */
  3355. void idEntity::Event_ActivateTargets( idEntity *activator ) {
  3356. ActivateTargets( activator );
  3357. }
  3358. /*
  3359. ================
  3360. idEntity::Event_NumTargets
  3361. ================
  3362. */
  3363. void idEntity::Event_NumTargets() {
  3364. idThread::ReturnFloat( targets.Num() );
  3365. }
  3366. /*
  3367. ================
  3368. idEntity::Event_GetTarget
  3369. ================
  3370. */
  3371. void idEntity::Event_GetTarget( float index ) {
  3372. int i;
  3373. i = ( int )index;
  3374. if ( ( i < 0 ) || i >= targets.Num() ) {
  3375. idThread::ReturnEntity( NULL );
  3376. } else {
  3377. idThread::ReturnEntity( targets[ i ].GetEntity() );
  3378. }
  3379. }
  3380. /*
  3381. ================
  3382. idEntity::Event_RandomTarget
  3383. ================
  3384. */
  3385. void idEntity::Event_RandomTarget( const char *ignore ) {
  3386. int num;
  3387. idEntity *ent;
  3388. int i;
  3389. int ignoreNum;
  3390. RemoveNullTargets();
  3391. if ( !targets.Num() ) {
  3392. idThread::ReturnEntity( NULL );
  3393. return;
  3394. }
  3395. ignoreNum = -1;
  3396. if ( ignore && ( ignore[ 0 ] != 0 ) && ( targets.Num() > 1 ) ) {
  3397. for( i = 0; i < targets.Num(); i++ ) {
  3398. ent = targets[ i ].GetEntity();
  3399. if ( ent && ( ent->name == ignore ) ) {
  3400. ignoreNum = i;
  3401. break;
  3402. }
  3403. }
  3404. }
  3405. if ( ignoreNum >= 0 ) {
  3406. num = gameLocal.random.RandomInt( targets.Num() - 1 );
  3407. if ( num >= ignoreNum ) {
  3408. num++;
  3409. }
  3410. } else {
  3411. num = gameLocal.random.RandomInt( targets.Num() );
  3412. }
  3413. ent = targets[ num ].GetEntity();
  3414. idThread::ReturnEntity( ent );
  3415. }
  3416. /*
  3417. ================
  3418. idEntity::Event_BindToJoint
  3419. ================
  3420. */
  3421. void idEntity::Event_BindToJoint( idEntity *master, const char *jointname, float orientated ) {
  3422. BindToJoint( master, jointname, ( orientated != 0.0f ) );
  3423. }
  3424. /*
  3425. ================
  3426. idEntity::Event_RemoveBinds
  3427. ================
  3428. */
  3429. void idEntity::Event_RemoveBinds() {
  3430. RemoveBinds();
  3431. }
  3432. /*
  3433. ================
  3434. idEntity::Event_Bind
  3435. ================
  3436. */
  3437. void idEntity::Event_Bind( idEntity *master ) {
  3438. Bind( master, true );
  3439. }
  3440. /*
  3441. ================
  3442. idEntity::Event_BindPosition
  3443. ================
  3444. */
  3445. void idEntity::Event_BindPosition( idEntity *master ) {
  3446. Bind( master, false );
  3447. }
  3448. /*
  3449. ================
  3450. idEntity::Event_Unbind
  3451. ================
  3452. */
  3453. void idEntity::Event_Unbind() {
  3454. Unbind();
  3455. }
  3456. /*
  3457. ================
  3458. idEntity::Event_SpawnBind
  3459. ================
  3460. */
  3461. void idEntity::Event_SpawnBind() {
  3462. idEntity *parent;
  3463. const char *bind, *joint, *bindanim;
  3464. jointHandle_t bindJoint;
  3465. bool bindOrientated;
  3466. int id;
  3467. const idAnim *anim;
  3468. int animNum;
  3469. idAnimator *parentAnimator;
  3470. if ( spawnArgs.GetString( "bind", "", &bind ) ) {
  3471. if ( idStr::Icmp( bind, "worldspawn" ) == 0 ) {
  3472. //FIXME: Completely unneccessary since the worldspawn is called "world"
  3473. parent = gameLocal.world;
  3474. } else {
  3475. parent = gameLocal.FindEntity( bind );
  3476. }
  3477. bindOrientated = spawnArgs.GetBool( "bindOrientated", "1" );
  3478. if ( parent ) {
  3479. // bind to a joint of the skeletal model of the parent
  3480. if ( spawnArgs.GetString( "bindToJoint", "", &joint ) && *joint ) {
  3481. parentAnimator = parent->GetAnimator();
  3482. if ( parentAnimator == NULL ) {
  3483. gameLocal.Error( "Cannot bind to joint '%s' on '%s'. Entity does not support skeletal models.", joint, name.c_str() );
  3484. return;
  3485. }
  3486. bindJoint = parentAnimator->GetJointHandle( joint );
  3487. if ( bindJoint == INVALID_JOINT ) {
  3488. gameLocal.Error( "Joint '%s' not found for bind on '%s'", joint, name.c_str() );
  3489. }
  3490. // bind it relative to a specific anim
  3491. if ( ( parent->spawnArgs.GetString( "bindanim", "", &bindanim ) || parent->spawnArgs.GetString( "anim", "", &bindanim ) ) && *bindanim ) {
  3492. animNum = parentAnimator->GetAnim( bindanim );
  3493. if ( !animNum ) {
  3494. gameLocal.Error( "Anim '%s' not found for bind on '%s'", bindanim, name.c_str() );
  3495. }
  3496. anim = parentAnimator->GetAnim( animNum );
  3497. if ( !anim ) {
  3498. gameLocal.Error( "Anim '%s' not found for bind on '%s'", bindanim, name.c_str() );
  3499. }
  3500. // make sure parent's render origin has been set
  3501. parent->UpdateModelTransform();
  3502. //FIXME: need a BindToJoint that accepts a joint position
  3503. parentAnimator->CreateFrame( gameLocal.time, true );
  3504. idJointMat *frame = parent->renderEntity.joints;
  3505. gameEdit->ANIM_CreateAnimFrame( parentAnimator->ModelHandle(), anim->MD5Anim( 0 ), parent->renderEntity.numJoints, frame, 0, parentAnimator->ModelDef()->GetVisualOffset(), parentAnimator->RemoveOrigin() );
  3506. BindToJoint( parent, joint, bindOrientated );
  3507. parentAnimator->ForceUpdate();
  3508. } else {
  3509. BindToJoint( parent, joint, bindOrientated );
  3510. }
  3511. }
  3512. // bind to a body of the physics object of the parent
  3513. else if ( spawnArgs.GetInt( "bindToBody", "0", id ) ) {
  3514. BindToBody( parent, id, bindOrientated );
  3515. }
  3516. // bind to the parent
  3517. else {
  3518. Bind( parent, bindOrientated );
  3519. }
  3520. }
  3521. }
  3522. }
  3523. /*
  3524. ================
  3525. idEntity::Event_SetOwner
  3526. ================
  3527. */
  3528. void idEntity::Event_SetOwner( idEntity *owner ) {
  3529. int i;
  3530. for ( i = 0; i < GetPhysics()->GetNumClipModels(); i++ ) {
  3531. GetPhysics()->GetClipModel( i )->SetOwner( owner );
  3532. }
  3533. }
  3534. /*
  3535. ================
  3536. idEntity::Event_SetModel
  3537. ================
  3538. */
  3539. void idEntity::Event_SetModel( const char *modelname ) {
  3540. SetModel( modelname );
  3541. }
  3542. /*
  3543. ================
  3544. idEntity::Event_SetSkin
  3545. ================
  3546. */
  3547. void idEntity::Event_SetSkin( const char *skinname ) {
  3548. renderEntity.customSkin = declManager->FindSkin( skinname );
  3549. UpdateVisuals();
  3550. }
  3551. /*
  3552. ================
  3553. idEntity::Event_GetShaderParm
  3554. ================
  3555. */
  3556. void idEntity::Event_GetShaderParm( int parmnum ) {
  3557. if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
  3558. gameLocal.Error( "shader parm index (%d) out of range", parmnum );
  3559. return;
  3560. }
  3561. idThread::ReturnFloat( renderEntity.shaderParms[ parmnum ] );
  3562. }
  3563. /*
  3564. ================
  3565. idEntity::Event_SetShaderParm
  3566. ================
  3567. */
  3568. void idEntity::Event_SetShaderParm( int parmnum, float value ) {
  3569. SetShaderParm( parmnum, value );
  3570. }
  3571. /*
  3572. ================
  3573. idEntity::Event_SetShaderParms
  3574. ================
  3575. */
  3576. void idEntity::Event_SetShaderParms( float parm0, float parm1, float parm2, float parm3 ) {
  3577. renderEntity.shaderParms[ SHADERPARM_RED ] = parm0;
  3578. renderEntity.shaderParms[ SHADERPARM_GREEN ] = parm1;
  3579. renderEntity.shaderParms[ SHADERPARM_BLUE ] = parm2;
  3580. renderEntity.shaderParms[ SHADERPARM_ALPHA ] = parm3;
  3581. UpdateVisuals();
  3582. }
  3583. /*
  3584. ================
  3585. idEntity::Event_SetColor
  3586. ================
  3587. */
  3588. void idEntity::Event_SetColor( float red, float green, float blue ) {
  3589. SetColor( red, green, blue );
  3590. }
  3591. /*
  3592. ================
  3593. idEntity::Event_GetColor
  3594. ================
  3595. */
  3596. void idEntity::Event_GetColor() {
  3597. idVec3 out;
  3598. GetColor( out );
  3599. idThread::ReturnVector( out );
  3600. }
  3601. /*
  3602. ================
  3603. idEntity::Event_IsHidden
  3604. ================
  3605. */
  3606. void idEntity::Event_IsHidden() {
  3607. idThread::ReturnInt( fl.hidden );
  3608. }
  3609. /*
  3610. ================
  3611. idEntity::Event_Hide
  3612. ================
  3613. */
  3614. void idEntity::Event_Hide() {
  3615. Hide();
  3616. }
  3617. /*
  3618. ================
  3619. idEntity::Event_Show
  3620. ================
  3621. */
  3622. void idEntity::Event_Show() {
  3623. Show();
  3624. }
  3625. /*
  3626. ================
  3627. idEntity::Event_CacheSoundShader
  3628. ================
  3629. */
  3630. void idEntity::Event_CacheSoundShader( const char *soundName ) {
  3631. declManager->FindSound( soundName );
  3632. }
  3633. /*
  3634. ================
  3635. idEntity::Event_StartSoundShader
  3636. ================
  3637. */
  3638. void idEntity::Event_StartSoundShader( const char *soundName, int channel ) {
  3639. int length = 0;
  3640. if ( soundName == NULL || soundName[0] == 0 ) {
  3641. StopSound( channel, false );
  3642. } else {
  3643. StartSoundShader( declManager->FindSound( soundName ), (s_channelType)channel, 0, false, &length );
  3644. }
  3645. idThread::ReturnFloat( MS2SEC( length ) );
  3646. }
  3647. /*
  3648. ================
  3649. idEntity::Event_StopSound
  3650. ================
  3651. */
  3652. void idEntity::Event_StopSound( int channel, int netSync ) {
  3653. StopSound( channel, ( netSync != 0 ) );
  3654. }
  3655. /*
  3656. ================
  3657. idEntity::Event_StartSound
  3658. ================
  3659. */
  3660. void idEntity::Event_StartSound( const char *soundName, int channel, int netSync ) {
  3661. int time;
  3662. StartSound( soundName, ( s_channelType )channel, 0, ( netSync != 0 ), &time );
  3663. idThread::ReturnFloat( MS2SEC( time ) );
  3664. }
  3665. /*
  3666. ================
  3667. idEntity::Event_FadeSound
  3668. ================
  3669. */
  3670. void idEntity::Event_FadeSound( int channel, float to, float over ) {
  3671. if ( refSound.referenceSound ) {
  3672. refSound.referenceSound->FadeSound( channel, to, over );
  3673. }
  3674. }
  3675. /*
  3676. ================
  3677. idEntity::Event_GetWorldOrigin
  3678. ================
  3679. */
  3680. void idEntity::Event_GetWorldOrigin() {
  3681. idThread::ReturnVector( GetPhysics()->GetOrigin() );
  3682. }
  3683. /*
  3684. ================
  3685. idEntity::Event_SetWorldOrigin
  3686. ================
  3687. */
  3688. void idEntity::Event_SetWorldOrigin( idVec3 const &org ) {
  3689. idVec3 neworg = GetLocalCoordinates( org );
  3690. SetOrigin( neworg );
  3691. }
  3692. /*
  3693. ================
  3694. idEntity::Event_SetOrigin
  3695. ================
  3696. */
  3697. void idEntity::Event_SetOrigin( idVec3 const &org ) {
  3698. SetOrigin( org );
  3699. }
  3700. /*
  3701. ================
  3702. idEntity::Event_GetOrigin
  3703. ================
  3704. */
  3705. void idEntity::Event_GetOrigin() {
  3706. idThread::ReturnVector( GetLocalCoordinates( GetPhysics()->GetOrigin() ) );
  3707. }
  3708. /*
  3709. ================
  3710. idEntity::Event_SetAngles
  3711. ================
  3712. */
  3713. void idEntity::Event_SetAngles( idAngles const &ang ) {
  3714. SetAngles( ang );
  3715. }
  3716. /*
  3717. ================
  3718. idEntity::Event_GetAngles
  3719. ================
  3720. */
  3721. void idEntity::Event_GetAngles() {
  3722. idAngles ang = GetPhysics()->GetAxis().ToAngles();
  3723. idThread::ReturnVector( idVec3( ang[0], ang[1], ang[2] ) );
  3724. }
  3725. /*
  3726. ================
  3727. idEntity::Event_SetLinearVelocity
  3728. ================
  3729. */
  3730. void idEntity::Event_SetLinearVelocity( const idVec3 &velocity ) {
  3731. GetPhysics()->SetLinearVelocity( velocity );
  3732. }
  3733. /*
  3734. ================
  3735. idEntity::Event_GetLinearVelocity
  3736. ================
  3737. */
  3738. void idEntity::Event_GetLinearVelocity() {
  3739. idThread::ReturnVector( GetPhysics()->GetLinearVelocity() );
  3740. }
  3741. /*
  3742. ================
  3743. idEntity::Event_SetAngularVelocity
  3744. ================
  3745. */
  3746. void idEntity::Event_SetAngularVelocity( const idVec3 &velocity ) {
  3747. GetPhysics()->SetAngularVelocity( velocity );
  3748. }
  3749. /*
  3750. ================
  3751. idEntity::Event_GetAngularVelocity
  3752. ================
  3753. */
  3754. void idEntity::Event_GetAngularVelocity() {
  3755. idThread::ReturnVector( GetPhysics()->GetAngularVelocity() );
  3756. }
  3757. /*
  3758. ================
  3759. idEntity::Event_SetSize
  3760. ================
  3761. */
  3762. void idEntity::Event_SetSize( idVec3 const &mins, idVec3 const &maxs ) {
  3763. GetPhysics()->SetClipBox( idBounds( mins, maxs ), 1.0f );
  3764. }
  3765. /*
  3766. ================
  3767. idEntity::Event_GetSize
  3768. ================
  3769. */
  3770. void idEntity::Event_GetSize() {
  3771. idBounds bounds;
  3772. bounds = GetPhysics()->GetBounds();
  3773. idThread::ReturnVector( bounds[1] - bounds[0] );
  3774. }
  3775. /*
  3776. ================
  3777. idEntity::Event_GetMins
  3778. ================
  3779. */
  3780. void idEntity::Event_GetMins() {
  3781. idThread::ReturnVector( GetPhysics()->GetBounds()[0] );
  3782. }
  3783. /*
  3784. ================
  3785. idEntity::Event_GetMaxs
  3786. ================
  3787. */
  3788. void idEntity::Event_GetMaxs() {
  3789. idThread::ReturnVector( GetPhysics()->GetBounds()[1] );
  3790. }
  3791. /*
  3792. ================
  3793. idEntity::Event_Touches
  3794. ================
  3795. */
  3796. void idEntity::Event_Touches( idEntity *ent ) {
  3797. if ( !ent ) {
  3798. idThread::ReturnInt( false );
  3799. return;
  3800. }
  3801. const idBounds &myBounds = GetPhysics()->GetAbsBounds();
  3802. const idBounds &entBounds = ent->GetPhysics()->GetAbsBounds();
  3803. idThread::ReturnInt( myBounds.IntersectsBounds( entBounds ) );
  3804. }
  3805. /*
  3806. ================
  3807. idEntity::Event_SetGuiParm
  3808. ================
  3809. */
  3810. void idEntity::Event_SetGuiParm( const char *key, const char *val ) {
  3811. for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
  3812. if ( renderEntity.gui[ i ] ) {
  3813. if ( idStr::Icmpn( key, "gui_", 4 ) == 0 ) {
  3814. spawnArgs.Set( key, val );
  3815. }
  3816. renderEntity.gui[ i ]->SetStateString( key, val );
  3817. renderEntity.gui[ i ]->StateChanged( gameLocal.time );
  3818. }
  3819. }
  3820. }
  3821. /*
  3822. ================
  3823. idEntity::Event_SetGuiParm
  3824. ================
  3825. */
  3826. void idEntity::Event_SetGuiFloat( const char *key, float f ) {
  3827. for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
  3828. if ( renderEntity.gui[ i ] ) {
  3829. renderEntity.gui[ i ]->SetStateString( key, va( "%f", f ) );
  3830. renderEntity.gui[ i ]->StateChanged( gameLocal.time );
  3831. }
  3832. }
  3833. }
  3834. /*
  3835. ================
  3836. idEntity::Event_GetNextKey
  3837. ================
  3838. */
  3839. void idEntity::Event_GetNextKey( const char *prefix, const char *lastMatch ) {
  3840. const idKeyValue *kv;
  3841. const idKeyValue *previous;
  3842. if ( *lastMatch ) {
  3843. previous = spawnArgs.FindKey( lastMatch );
  3844. } else {
  3845. previous = NULL;
  3846. }
  3847. kv = spawnArgs.MatchPrefix( prefix, previous );
  3848. if ( !kv ) {
  3849. idThread::ReturnString( "" );
  3850. } else {
  3851. idThread::ReturnString( kv->GetKey() );
  3852. }
  3853. }
  3854. /*
  3855. ================
  3856. idEntity::Event_SetKey
  3857. ================
  3858. */
  3859. void idEntity::Event_SetKey( const char *key, const char *value ) {
  3860. spawnArgs.Set( key, value );
  3861. UpdateChangeableSpawnArgs( NULL );
  3862. }
  3863. /*
  3864. ================
  3865. idEntity::Event_GetKey
  3866. ================
  3867. */
  3868. void idEntity::Event_GetKey( const char *key ) {
  3869. const char *value;
  3870. spawnArgs.GetString( key, "", &value );
  3871. idThread::ReturnString( value );
  3872. }
  3873. /*
  3874. ================
  3875. idEntity::Event_GetIntKey
  3876. ================
  3877. */
  3878. void idEntity::Event_GetIntKey( const char *key ) {
  3879. int value;
  3880. spawnArgs.GetInt( key, "0", value );
  3881. // scripts only support floats
  3882. idThread::ReturnFloat( value );
  3883. }
  3884. /*
  3885. ================
  3886. idEntity::Event_GetFloatKey
  3887. ================
  3888. */
  3889. void idEntity::Event_GetFloatKey( const char *key ) {
  3890. float value;
  3891. spawnArgs.GetFloat( key, "0", value );
  3892. idThread::ReturnFloat( value );
  3893. }
  3894. /*
  3895. ================
  3896. idEntity::Event_GetVectorKey
  3897. ================
  3898. */
  3899. void idEntity::Event_GetVectorKey( const char *key ) {
  3900. idVec3 value;
  3901. spawnArgs.GetVector( key, "0 0 0", value );
  3902. idThread::ReturnVector( value );
  3903. }
  3904. /*
  3905. ================
  3906. idEntity::Event_GetEntityKey
  3907. ================
  3908. */
  3909. void idEntity::Event_GetEntityKey( const char *key ) {
  3910. idEntity *ent;
  3911. const char *entname;
  3912. if ( !spawnArgs.GetString( key, NULL, &entname ) ) {
  3913. idThread::ReturnEntity( NULL );
  3914. return;
  3915. }
  3916. ent = gameLocal.FindEntity( entname );
  3917. if ( !ent ) {
  3918. gameLocal.Warning( "Couldn't find entity '%s' specified in '%s' key in entity '%s'", entname, key, name.c_str() );
  3919. }
  3920. idThread::ReturnEntity( ent );
  3921. }
  3922. /*
  3923. ================
  3924. idEntity::Event_RestorePosition
  3925. ================
  3926. */
  3927. void idEntity::Event_RestorePosition() {
  3928. idVec3 org;
  3929. idAngles angles;
  3930. idMat3 axis;
  3931. idEntity * part;
  3932. spawnArgs.GetVector( "origin", "0 0 0", org );
  3933. // get the rotation matrix in either full form, or single angle form
  3934. if ( spawnArgs.GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", axis ) ) {
  3935. angles = axis.ToAngles();
  3936. } else {
  3937. angles[ 0 ] = 0;
  3938. angles[ 1 ] = spawnArgs.GetFloat( "angle" );
  3939. angles[ 2 ] = 0;
  3940. }
  3941. Teleport( org, angles, NULL );
  3942. for ( part = teamChain; part != NULL; part = part->teamChain ) {
  3943. if ( part->bindMaster != this ) {
  3944. continue;
  3945. }
  3946. if ( part->GetPhysics()->IsType( idPhysics_Parametric::Type ) ) {
  3947. if ( static_cast<idPhysics_Parametric *>(part->GetPhysics())->IsPusher() ) {
  3948. gameLocal.Warning( "teleported '%s' which has the pushing mover '%s' bound to it\n", GetName(), part->GetName() );
  3949. }
  3950. } else if ( part->GetPhysics()->IsType( idPhysics_AF::Type ) ) {
  3951. gameLocal.Warning( "teleported '%s' which has the articulated figure '%s' bound to it\n", GetName(), part->GetName() );
  3952. }
  3953. }
  3954. }
  3955. /*
  3956. ================
  3957. idEntity::Event_UpdateCameraTarget
  3958. ================
  3959. */
  3960. void idEntity::Event_UpdateCameraTarget() {
  3961. const char *target;
  3962. const idKeyValue *kv;
  3963. idVec3 dir;
  3964. target = spawnArgs.GetString( "cameraTarget" );
  3965. cameraTarget = gameLocal.FindEntity( target );
  3966. if ( cameraTarget != NULL ) {
  3967. kv = cameraTarget->spawnArgs.MatchPrefix( "target", NULL );
  3968. while( kv ) {
  3969. idEntity *ent = gameLocal.FindEntity( kv->GetValue() );
  3970. if ( ent != NULL && idStr::Icmp( ent->GetEntityDefName(), "target_null" ) == 0) {
  3971. dir = ent->GetPhysics()->GetOrigin() - cameraTarget->GetPhysics()->GetOrigin();
  3972. dir.Normalize();
  3973. cameraTarget->SetAxis( dir.ToMat3() );
  3974. SetAxis(dir.ToMat3());
  3975. break;
  3976. }
  3977. kv = cameraTarget->spawnArgs.MatchPrefix( "target", kv );
  3978. }
  3979. }
  3980. UpdateVisuals();
  3981. }
  3982. /*
  3983. ================
  3984. idEntity::Event_DistanceTo
  3985. ================
  3986. */
  3987. void idEntity::Event_DistanceTo( idEntity *ent ) {
  3988. if ( !ent ) {
  3989. // just say it's really far away
  3990. idThread::ReturnFloat( MAX_WORLD_SIZE );
  3991. } else {
  3992. float dist = ( GetPhysics()->GetOrigin() - ent->GetPhysics()->GetOrigin() ).LengthFast();
  3993. idThread::ReturnFloat( dist );
  3994. }
  3995. }
  3996. /*
  3997. ================
  3998. idEntity::Event_DistanceToPoint
  3999. ================
  4000. */
  4001. void idEntity::Event_DistanceToPoint( const idVec3 &point ) {
  4002. float dist = ( GetPhysics()->GetOrigin() - point ).LengthFast();
  4003. idThread::ReturnFloat( dist );
  4004. }
  4005. /*
  4006. ================
  4007. idEntity::Event_StartFx
  4008. ================
  4009. */
  4010. void idEntity::Event_StartFx( const char *fx ) {
  4011. idEntityFx::StartFx( fx, NULL, NULL, this, true );
  4012. }
  4013. /*
  4014. ================
  4015. idEntity::Event_WaitFrame
  4016. ================
  4017. */
  4018. void idEntity::Event_WaitFrame() {
  4019. idThread *thread;
  4020. thread = idThread::CurrentThread();
  4021. if ( thread ) {
  4022. thread->WaitFrame();
  4023. }
  4024. }
  4025. /*
  4026. =====================
  4027. idEntity::Event_Wait
  4028. =====================
  4029. */
  4030. void idEntity::Event_Wait( float time ) {
  4031. idThread *thread = idThread::CurrentThread();
  4032. if ( thread == NULL ) {
  4033. gameLocal.Error( "Event 'wait' called from outside thread" );
  4034. return;
  4035. }
  4036. thread->WaitSec( time );
  4037. }
  4038. /*
  4039. =====================
  4040. idEntity::Event_HasFunction
  4041. =====================
  4042. */
  4043. void idEntity::Event_HasFunction( const char *name ) {
  4044. const function_t *func;
  4045. func = scriptObject.GetFunction( name );
  4046. if ( func ) {
  4047. idThread::ReturnInt( true );
  4048. } else {
  4049. idThread::ReturnInt( false );
  4050. }
  4051. }
  4052. /*
  4053. =====================
  4054. idEntity::Event_CallFunction
  4055. =====================
  4056. */
  4057. void idEntity::Event_CallFunction( const char *funcname ) {
  4058. const function_t *func;
  4059. idThread *thread;
  4060. thread = idThread::CurrentThread();
  4061. if ( thread == NULL ) {
  4062. gameLocal.Error( "Event 'callFunction' called from outside thread" );
  4063. return;
  4064. }
  4065. func = scriptObject.GetFunction( funcname );
  4066. if ( func == NULL ) {
  4067. gameLocal.Error( "Unknown function '%s' in '%s'", funcname, scriptObject.GetTypeName() );
  4068. return;
  4069. }
  4070. if ( func->type->NumParameters() != 1 ) {
  4071. gameLocal.Error( "Function '%s' has the wrong number of parameters for 'callFunction'", funcname );
  4072. return;
  4073. }
  4074. if ( !scriptObject.GetTypeDef()->Inherits( func->type->GetParmType( 0 ) ) ) {
  4075. gameLocal.Error( "Function '%s' is the wrong type for 'callFunction'", funcname );
  4076. return;
  4077. }
  4078. // function args will be invalid after this call
  4079. thread->CallFunction( this, func, false );
  4080. }
  4081. /*
  4082. ================
  4083. idEntity::Event_SetNeverDormant
  4084. ================
  4085. */
  4086. void idEntity::Event_SetNeverDormant( int enable ) {
  4087. fl.neverDormant = ( enable != 0 );
  4088. dormantStart = 0;
  4089. }
  4090. /*
  4091. ================
  4092. idEntity::Event_SetGui
  4093. ================
  4094. * BSM Nerve: Allows guis to be changed at runtime. Guis that are
  4095. * loaded after the level loads should be precahced using PrecacheGui.
  4096. */
  4097. void idEntity::Event_SetGui( int guiNum, const char *guiName) {
  4098. idUserInterface** gui = NULL;
  4099. if ( guiNum >= 1 && guiNum <= MAX_RENDERENTITY_GUI ) {
  4100. gui = &renderEntity.gui[ guiNum-1 ];
  4101. }
  4102. if( gui ) {
  4103. *gui = uiManager->FindGui( guiName, true, false );
  4104. UpdateGuiParms( *gui, &spawnArgs );
  4105. UpdateChangeableSpawnArgs( NULL );
  4106. gameRenderWorld->UpdateEntityDef(modelDefHandle, &renderEntity);
  4107. } else {
  4108. gameLocal.Error( "Entity '%s' doesn't have a GUI %d", name.c_str(), guiNum );
  4109. }
  4110. }
  4111. /*
  4112. ================
  4113. idEntity::Event_PrecacheGui
  4114. ================
  4115. * BSM Nerve: Forces the engine to initialize a gui even if it is not specified as used in a level.
  4116. * This is useful for preventing load hitches when switching guis during the game using "setGui"
  4117. */
  4118. void idEntity::Event_PrecacheGui( const char *guiName ) {
  4119. uiManager->FindGui( guiName, true, true );
  4120. }
  4121. void idEntity::Event_GetGuiParm(int guiNum, const char *key) {
  4122. if(renderEntity.gui[guiNum-1]) {
  4123. idThread::ReturnString(renderEntity.gui[guiNum-1]->GetStateString(key));
  4124. return;
  4125. }
  4126. idThread::ReturnString("");
  4127. }
  4128. void idEntity::Event_GetGuiParmFloat(int guiNum, const char *key) {
  4129. if(renderEntity.gui[guiNum-1]) {
  4130. idThread::ReturnFloat(renderEntity.gui[guiNum-1]->GetStateFloat(key));
  4131. return;
  4132. }
  4133. idThread::ReturnFloat(0.0f);
  4134. }
  4135. void idEntity::Event_GuiNamedEvent(int guiNum, const char *event) {
  4136. if(renderEntity.gui[guiNum-1]) {
  4137. renderEntity.gui[guiNum-1]->HandleNamedEvent(event);
  4138. }
  4139. }
  4140. /***********************************************************************
  4141. Network
  4142. ***********************************************************************/
  4143. /*
  4144. ================
  4145. idEntity::ClientThink
  4146. ================
  4147. */
  4148. void idEntity::ClientThink( const int curTime, const float fraction, const bool predict ) {
  4149. InterpolatePhysics( fraction );
  4150. Present();
  4151. }
  4152. /*
  4153. ================
  4154. idEntity::ClientPredictionThink
  4155. ================
  4156. */
  4157. void idEntity::ClientPredictionThink() {
  4158. RunPhysics();
  4159. Present();
  4160. }
  4161. /*
  4162. ================
  4163. idEntity::WriteBindToSnapshot
  4164. ================
  4165. */
  4166. void idEntity::WriteBindToSnapshot( idBitMsg &msg ) const {
  4167. int bindInfo;
  4168. if ( bindMaster ) {
  4169. bindInfo = bindMaster->entityNumber;
  4170. bindInfo |= ( fl.bindOrientated & 1 ) << GENTITYNUM_BITS;
  4171. if ( bindJoint != INVALID_JOINT ) {
  4172. bindInfo |= 1 << ( GENTITYNUM_BITS + 1 );
  4173. bindInfo |= bindJoint << ( 3 + GENTITYNUM_BITS );
  4174. } else if ( bindBody != -1 ) {
  4175. bindInfo |= 2 << ( GENTITYNUM_BITS + 1 );
  4176. bindInfo |= bindBody << ( 3 + GENTITYNUM_BITS );
  4177. }
  4178. } else {
  4179. bindInfo = ENTITYNUM_NONE;
  4180. }
  4181. msg.WriteBits( bindInfo, GENTITYNUM_BITS + 3 + 9 );
  4182. }
  4183. /*
  4184. ================
  4185. idEntity::ReadBindFromSnapshot
  4186. ================
  4187. */
  4188. void idEntity::ReadBindFromSnapshot( const idBitMsg &msg ) {
  4189. int bindInfo, bindEntityNum, bindPos;
  4190. bool bindOrientated;
  4191. idEntity *master;
  4192. bindInfo = msg.ReadBits( GENTITYNUM_BITS + 3 + 9 );
  4193. bindEntityNum = bindInfo & ( ( 1 << GENTITYNUM_BITS ) - 1 );
  4194. if ( ( bindEntityNum != ENTITYNUM_NONE ) && ( bindEntityNum < MAX_GENTITIES ) ) {
  4195. master = gameLocal.entities[ bindEntityNum ];
  4196. bindOrientated = ( bindInfo >> GENTITYNUM_BITS ) & 1;
  4197. bindPos = ( bindInfo >> ( GENTITYNUM_BITS + 3 ) );
  4198. switch( ( bindInfo >> ( GENTITYNUM_BITS + 1 ) ) & 3 ) {
  4199. case 1: {
  4200. BindToJoint( master, (jointHandle_t) bindPos, bindOrientated );
  4201. break;
  4202. }
  4203. case 2: {
  4204. BindToBody( master, bindPos, bindOrientated );
  4205. break;
  4206. }
  4207. default: {
  4208. Bind( master, bindOrientated );
  4209. break;
  4210. }
  4211. }
  4212. } else if ( bindMaster ) {
  4213. Unbind();
  4214. }
  4215. }
  4216. /*
  4217. ================
  4218. idEntity::WriteColorToSnapshot
  4219. ================
  4220. */
  4221. void idEntity::WriteColorToSnapshot( idBitMsg &msg ) const {
  4222. idVec4 color;
  4223. color[0] = renderEntity.shaderParms[ SHADERPARM_RED ];
  4224. color[1] = renderEntity.shaderParms[ SHADERPARM_GREEN ];
  4225. color[2] = renderEntity.shaderParms[ SHADERPARM_BLUE ];
  4226. color[3] = renderEntity.shaderParms[ SHADERPARM_ALPHA ];
  4227. msg.WriteLong( PackColor( color ) );
  4228. }
  4229. /*
  4230. ================
  4231. idEntity::ReadColorFromSnapshot
  4232. ================
  4233. */
  4234. void idEntity::ReadColorFromSnapshot( const idBitMsg &msg ) {
  4235. idVec4 color;
  4236. UnpackColor( msg.ReadLong(), color );
  4237. renderEntity.shaderParms[ SHADERPARM_RED ] = color[0];
  4238. renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[1];
  4239. renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[2];
  4240. renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[3];
  4241. }
  4242. /*
  4243. ================
  4244. idEntity::WriteGUIToSnapshot
  4245. ================
  4246. */
  4247. void idEntity::WriteGUIToSnapshot( idBitMsg &msg ) const {
  4248. // no need to loop over MAX_RENDERENTITY_GUI at this time
  4249. if ( renderEntity.gui[ 0 ] ) {
  4250. msg.WriteByte( renderEntity.gui[ 0 ]->State().GetInt( "networkState" ) );
  4251. } else {
  4252. msg.WriteByte( 0 );
  4253. }
  4254. }
  4255. /*
  4256. ================
  4257. idEntity::ReadGUIFromSnapshot
  4258. ================
  4259. */
  4260. void idEntity::ReadGUIFromSnapshot( const idBitMsg &msg ) {
  4261. int state;
  4262. idUserInterface *gui;
  4263. state = msg.ReadByte( );
  4264. gui = renderEntity.gui[ 0 ];
  4265. if ( gui && state != mpGUIState ) {
  4266. mpGUIState = state;
  4267. gui->SetStateInt( "networkState", state );
  4268. gui->HandleNamedEvent( "networkState" );
  4269. }
  4270. }
  4271. /*
  4272. ================
  4273. idEntity::WriteToSnapshot
  4274. ================
  4275. */
  4276. void idEntity::WriteToSnapshot( idBitMsg &msg ) const {
  4277. }
  4278. /*
  4279. ================
  4280. idEntity::ReadFromSnapshot
  4281. ================
  4282. */
  4283. void idEntity::ReadFromSnapshot( const idBitMsg &msg ) {
  4284. }
  4285. /*
  4286. ================
  4287. idEntity::ReadFromSnapshot_Ex
  4288. Increments the snapshot counter for the entity.
  4289. ================
  4290. */
  4291. void idEntity::ReadFromSnapshot_Ex( const idBitMsg &msg ) {
  4292. snapshotsReceived += 1;
  4293. ReadFromSnapshot( msg );
  4294. }
  4295. /*
  4296. ================
  4297. idEntity::FlagNewSnapshot
  4298. Updates the interpolationBehavior so that subclasses will know if it's safe to interpolate.
  4299. Only call this when a new snapshot has been received for this entity!
  4300. ================
  4301. */
  4302. void idEntity::FlagNewSnapshot() {
  4303. switch( interpolationBehavior ) {
  4304. case USE_NO_INTERPOLATION: {
  4305. interpolationBehavior = USE_LATEST_SNAP_ONLY;
  4306. break;
  4307. }
  4308. case USE_LATEST_SNAP_ONLY: {
  4309. interpolationBehavior = USE_INTERPOLATION;
  4310. break;
  4311. }
  4312. default: {
  4313. break;
  4314. }
  4315. }
  4316. }
  4317. /*
  4318. ================
  4319. idEntity::ServerSendEvent
  4320. Saved events are also sent to any client that connects late so all clients
  4321. always receive the events nomatter what time they join the game.
  4322. ================
  4323. */
  4324. void idEntity::ServerSendEvent( int eventId, const idBitMsg *msg, bool saveEvent, lobbyUserID_t excluding ) const {
  4325. idBitMsg outMsg;
  4326. byte msgBuf[MAX_GAME_MESSAGE_SIZE];
  4327. if ( !common->IsServer() ) {
  4328. return;
  4329. }
  4330. // prevent dupe events caused by frame re-runs
  4331. if ( !gameLocal.isNewFrame ) {
  4332. return;
  4333. }
  4334. outMsg.InitWrite( msgBuf, sizeof( msgBuf ) );
  4335. outMsg.BeginWriting();
  4336. outMsg.WriteBits( gameLocal.GetSpawnId( this ), 32 );
  4337. outMsg.WriteByte( eventId );
  4338. outMsg.WriteLong( gameLocal.time );
  4339. if ( msg ) {
  4340. outMsg.WriteBits( msg->GetSize(), idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
  4341. outMsg.WriteData( msg->GetReadData(), msg->GetSize() );
  4342. } else {
  4343. outMsg.WriteBits( 0, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
  4344. }
  4345. idLobbyBase & lobby = session->GetActingGameStateLobbyBase();
  4346. peerMask_t peerMask = MAX_UNSIGNED_TYPE( peerMask_t );
  4347. if ( excluding.IsValid() ) {
  4348. peerMask = ~(peerMask_t)lobby.PeerIndexFromLobbyUser( excluding );
  4349. }
  4350. lobby.SendReliable( GAME_RELIABLE_MESSAGE_EVENT, outMsg, false, peerMask );
  4351. if ( saveEvent ) {
  4352. gameLocal.SaveEntityNetworkEvent( this, eventId, msg );
  4353. }
  4354. }
  4355. /*
  4356. ================
  4357. idEntity::ClientSendEvent
  4358. ================
  4359. */
  4360. void idEntity::ClientSendEvent( int eventId, const idBitMsg *msg ) const {
  4361. idBitMsg outMsg;
  4362. byte msgBuf[MAX_GAME_MESSAGE_SIZE];
  4363. if ( !common->IsClient() ) {
  4364. return;
  4365. }
  4366. // prevent dupe events caused by frame re-runs
  4367. if ( !gameLocal.isNewFrame ) {
  4368. return;
  4369. }
  4370. outMsg.InitWrite( msgBuf, sizeof( msgBuf ) );
  4371. outMsg.BeginWriting();
  4372. outMsg.WriteBits( gameLocal.GetSpawnId( this ), 32 );
  4373. outMsg.WriteByte( eventId );
  4374. outMsg.WriteLong( gameLocal.serverTime );
  4375. if ( msg ) {
  4376. outMsg.WriteBits( msg->GetSize(), idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
  4377. outMsg.WriteData( msg->GetReadData(), msg->GetSize() );
  4378. } else {
  4379. outMsg.WriteBits( 0, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
  4380. }
  4381. session->GetActingGameStateLobbyBase().SendReliableToHost( GAME_RELIABLE_MESSAGE_EVENT, outMsg );
  4382. }
  4383. /*
  4384. ================
  4385. idEntity::ServerReceiveEvent
  4386. ================
  4387. */
  4388. bool idEntity::ServerReceiveEvent( int event, int time, const idBitMsg &msg ) {
  4389. switch( event ) {
  4390. case 0: {
  4391. }
  4392. default: {
  4393. return false;
  4394. }
  4395. }
  4396. }
  4397. /*
  4398. ================
  4399. idEntity::ClientReceiveEvent
  4400. ================
  4401. */
  4402. bool idEntity::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  4403. int index;
  4404. const idSoundShader *shader;
  4405. s_channelType channel;
  4406. switch( event ) {
  4407. case EVENT_STARTSOUNDSHADER: {
  4408. // the sound stuff would early out
  4409. assert( gameLocal.isNewFrame );
  4410. if ( time < gameLocal.realClientTime - 1000 ) {
  4411. // too old, skip it ( reliable messages don't need to be parsed in full )
  4412. common->DPrintf( "ent 0x%x: start sound shader too old (%d ms)\n", entityNumber, gameLocal.realClientTime - time );
  4413. return true;
  4414. }
  4415. index = gameLocal.ClientRemapDecl( DECL_SOUND, msg.ReadLong() );
  4416. if ( index >= 0 && index < declManager->GetNumDecls( DECL_SOUND ) ) {
  4417. shader = declManager->SoundByIndex( index, false );
  4418. channel = (s_channelType)msg.ReadByte();
  4419. StartSoundShader( shader, channel, 0, false, NULL );
  4420. }
  4421. return true;
  4422. }
  4423. case EVENT_STOPSOUNDSHADER: {
  4424. // the sound stuff would early out
  4425. assert( gameLocal.isNewFrame );
  4426. channel = (s_channelType)msg.ReadByte();
  4427. StopSound( channel, false );
  4428. return true;
  4429. }
  4430. default: {
  4431. return false;
  4432. }
  4433. }
  4434. }
  4435. /*
  4436. ================
  4437. idEntity::DetermineTimeGroup
  4438. ================
  4439. */
  4440. void idEntity::DetermineTimeGroup( bool slowmo ) {
  4441. if ( slowmo || common->IsMultiplayer() ) {
  4442. timeGroup = TIME_GROUP1;
  4443. }
  4444. else {
  4445. timeGroup = TIME_GROUP2;
  4446. }
  4447. }
  4448. /*
  4449. ================
  4450. idEntity::SetGrabbedState
  4451. ================
  4452. */
  4453. void idEntity::SetGrabbedState( bool grabbed ) {
  4454. fl.grabbed = grabbed;
  4455. }
  4456. /*
  4457. ================
  4458. idEntity::IsGrabbed
  4459. ================
  4460. */
  4461. bool idEntity::IsGrabbed() {
  4462. return fl.grabbed;
  4463. }
  4464. /*
  4465. ========================
  4466. idEntity::DecayOriginAndAxisDelta
  4467. ========================
  4468. */
  4469. void idEntity::DecayOriginAndAxisDelta() {
  4470. idVec3 delta = vec3_zero - originDelta;
  4471. float length = delta.Length();
  4472. if ( length > 0.01f ) {
  4473. length *= net_errorSmoothingDecay.GetFloat();
  4474. if ( length > net_errorSmoothingMaxDecay.GetFloat() ) {
  4475. length = net_errorSmoothingMaxDecay.GetFloat();
  4476. }
  4477. delta.Normalize();
  4478. delta *= length;
  4479. originDelta += delta;
  4480. } else {
  4481. originDelta = vec3_zero;
  4482. }
  4483. idQuat q;
  4484. q.Slerp( axisDelta.ToQuat(), mat3_identity.ToQuat(), net_errorSmoothingDecay.GetFloat() );
  4485. axisDelta = q.ToMat3();
  4486. }
  4487. /*
  4488. ========================
  4489. idEntity::CreateDeltasFromOldOriginAndAxis
  4490. ========================
  4491. */
  4492. void idEntity::CreateDeltasFromOldOriginAndAxis( const idVec3 & oldOrigin, const idMat3 & oldAxis ) {
  4493. // Set smooth values so we transition from the old position/axis to what we are now (visual only)
  4494. if ( GetPhysics() ) {
  4495. originDelta = oldOrigin - GetPhysics()->GetOrigin();
  4496. axisDelta = oldAxis.Inverse() * GetPhysics()->GetAxis();
  4497. }
  4498. }
  4499. /*
  4500. ===============================================================================
  4501. idAnimatedEntity
  4502. ===============================================================================
  4503. */
  4504. const idEventDef EV_GetJointHandle( "getJointHandle", "s", 'd' );
  4505. const idEventDef EV_ClearAllJoints( "clearAllJoints" );
  4506. const idEventDef EV_ClearJoint( "clearJoint", "d" );
  4507. const idEventDef EV_SetJointPos( "setJointPos", "ddv" );
  4508. const idEventDef EV_SetJointAngle( "setJointAngle", "ddv" );
  4509. const idEventDef EV_GetJointPos( "getJointPos", "d", 'v' );
  4510. const idEventDef EV_GetJointAngle( "getJointAngle", "d", 'v' );
  4511. CLASS_DECLARATION( idEntity, idAnimatedEntity )
  4512. EVENT( EV_GetJointHandle, idAnimatedEntity::Event_GetJointHandle )
  4513. EVENT( EV_ClearAllJoints, idAnimatedEntity::Event_ClearAllJoints )
  4514. EVENT( EV_ClearJoint, idAnimatedEntity::Event_ClearJoint )
  4515. EVENT( EV_SetJointPos, idAnimatedEntity::Event_SetJointPos )
  4516. EVENT( EV_SetJointAngle, idAnimatedEntity::Event_SetJointAngle )
  4517. EVENT( EV_GetJointPos, idAnimatedEntity::Event_GetJointPos )
  4518. EVENT( EV_GetJointAngle, idAnimatedEntity::Event_GetJointAngle )
  4519. END_CLASS
  4520. /*
  4521. ================
  4522. idAnimatedEntity::idAnimatedEntity
  4523. ================
  4524. */
  4525. idAnimatedEntity::idAnimatedEntity() {
  4526. animator.SetEntity( this );
  4527. damageEffects = NULL;
  4528. }
  4529. /*
  4530. ================
  4531. idAnimatedEntity::~idAnimatedEntity
  4532. ================
  4533. */
  4534. idAnimatedEntity::~idAnimatedEntity() {
  4535. damageEffect_t *de;
  4536. for ( de = damageEffects; de; de = damageEffects ) {
  4537. damageEffects = de->next;
  4538. delete de;
  4539. }
  4540. }
  4541. /*
  4542. ================
  4543. idAnimatedEntity::Save
  4544. archives object for save game file
  4545. ================
  4546. */
  4547. void idAnimatedEntity::Save( idSaveGame *savefile ) const {
  4548. animator.Save( savefile );
  4549. // Wounds are very temporary, ignored at this time
  4550. //damageEffect_t *damageEffects;
  4551. }
  4552. /*
  4553. ================
  4554. idAnimatedEntity::Restore
  4555. unarchives object from save game file
  4556. ================
  4557. */
  4558. void idAnimatedEntity::Restore( idRestoreGame *savefile ) {
  4559. animator.Restore( savefile );
  4560. // check if the entity has an MD5 model
  4561. if ( animator.ModelHandle() ) {
  4562. // set the callback to update the joints
  4563. renderEntity.callback = idEntity::ModelCallback;
  4564. animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints );
  4565. animator.GetBounds( gameLocal.time, renderEntity.bounds );
  4566. if ( modelDefHandle != -1 ) {
  4567. gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
  4568. }
  4569. }
  4570. }
  4571. /*
  4572. ================
  4573. idAnimatedEntity::ClientPredictionThink
  4574. ================
  4575. */
  4576. void idAnimatedEntity::ClientPredictionThink() {
  4577. RunPhysics();
  4578. UpdateAnimation();
  4579. Present();
  4580. }
  4581. /*
  4582. ================
  4583. idAnimatedEntity::ClientThink
  4584. ================
  4585. */
  4586. void idAnimatedEntity::ClientThink( const int curTime, const float fraction, const bool predict ) {
  4587. InterpolatePhysics( fraction );
  4588. UpdateAnimation();
  4589. Present();
  4590. }
  4591. /*
  4592. ================
  4593. idAnimatedEntity::Think
  4594. ================
  4595. */
  4596. void idAnimatedEntity::Think() {
  4597. RunPhysics();
  4598. UpdateAnimation();
  4599. Present();
  4600. UpdateDamageEffects();
  4601. }
  4602. /*
  4603. ================
  4604. idAnimatedEntity::UpdateAnimation
  4605. ================
  4606. */
  4607. void idAnimatedEntity::UpdateAnimation() {
  4608. // don't do animations if they're not enabled
  4609. if ( !( thinkFlags & TH_ANIMATE ) ) {
  4610. return;
  4611. }
  4612. // is the model an MD5?
  4613. if ( !animator.ModelHandle() ) {
  4614. // no, so nothing to do
  4615. return;
  4616. }
  4617. // call any frame commands that have happened in the past frame
  4618. if ( !fl.hidden ) {
  4619. animator.ServiceAnims( gameLocal.previousTime, gameLocal.time );
  4620. }
  4621. // if the model is animating then we have to update it
  4622. if ( !animator.FrameHasChanged( gameLocal.time ) ) {
  4623. // still fine the way it was
  4624. return;
  4625. }
  4626. // get the latest frame bounds
  4627. animator.GetBounds( gameLocal.time, renderEntity.bounds );
  4628. if ( renderEntity.bounds.IsCleared() && !fl.hidden ) {
  4629. gameLocal.DPrintf( "%d: inside out bounds\n", gameLocal.time );
  4630. }
  4631. // update the renderEntity
  4632. UpdateVisuals();
  4633. // the animation is updated
  4634. animator.ClearForceUpdate();
  4635. }
  4636. /*
  4637. ================
  4638. idAnimatedEntity::GetAnimator
  4639. ================
  4640. */
  4641. idAnimator *idAnimatedEntity::GetAnimator() {
  4642. return &animator;
  4643. }
  4644. /*
  4645. ================
  4646. idAnimatedEntity::SetModel
  4647. ================
  4648. */
  4649. void idAnimatedEntity::SetModel( const char *modelname ) {
  4650. FreeModelDef();
  4651. renderEntity.hModel = animator.SetModel( modelname );
  4652. if ( !renderEntity.hModel ) {
  4653. idEntity::SetModel( modelname );
  4654. return;
  4655. }
  4656. if ( !renderEntity.customSkin ) {
  4657. renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin();
  4658. }
  4659. // set the callback to update the joints
  4660. renderEntity.callback = idEntity::ModelCallback;
  4661. animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints );
  4662. animator.GetBounds( gameLocal.time, renderEntity.bounds );
  4663. UpdateVisuals();
  4664. }
  4665. /*
  4666. =====================
  4667. idAnimatedEntity::GetJointWorldTransform
  4668. =====================
  4669. */
  4670. bool idAnimatedEntity::GetJointWorldTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) {
  4671. if ( !animator.GetJointTransform( jointHandle, currentTime, offset, axis ) ) {
  4672. return false;
  4673. }
  4674. ConvertLocalToWorldTransform( offset, axis );
  4675. return true;
  4676. }
  4677. /*
  4678. ==============
  4679. idAnimatedEntity::GetJointTransformForAnim
  4680. ==============
  4681. */
  4682. bool idAnimatedEntity::GetJointTransformForAnim( jointHandle_t jointHandle, int animNum, int frameTime, idVec3 &offset, idMat3 &axis ) const {
  4683. const idAnim *anim;
  4684. int numJoints;
  4685. idJointMat *frame;
  4686. anim = animator.GetAnim( animNum );
  4687. if ( !anim ) {
  4688. assert( 0 );
  4689. return false;
  4690. }
  4691. numJoints = animator.NumJoints();
  4692. if ( ( jointHandle < 0 ) || ( jointHandle >= numJoints ) ) {
  4693. assert( 0 );
  4694. return false;
  4695. }
  4696. frame = ( idJointMat * )_alloca16( numJoints * sizeof( idJointMat ) );
  4697. gameEdit->ANIM_CreateAnimFrame( animator.ModelHandle(), anim->MD5Anim( 0 ), renderEntity.numJoints, frame, frameTime, animator.ModelDef()->GetVisualOffset(), animator.RemoveOrigin() );
  4698. offset = frame[ jointHandle ].ToVec3();
  4699. axis = frame[ jointHandle ].ToMat3();
  4700. return true;
  4701. }
  4702. /*
  4703. ==============
  4704. idAnimatedEntity::AddDamageEffect
  4705. Dammage effects track the animating impact position, spitting out particles.
  4706. ==============
  4707. */
  4708. void idAnimatedEntity::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) {
  4709. jointHandle_t jointNum;
  4710. idVec3 origin, dir, localDir, localOrigin, localNormal;
  4711. idMat3 axis;
  4712. if ( !g_bloodEffects.GetBool() || renderEntity.joints == NULL ) {
  4713. return;
  4714. }
  4715. const idDeclEntityDef *def = gameLocal.FindEntityDef( damageDefName, false );
  4716. if ( def == NULL ) {
  4717. return;
  4718. }
  4719. jointNum = CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id );
  4720. if ( jointNum == INVALID_JOINT ) {
  4721. return;
  4722. }
  4723. dir = velocity;
  4724. dir.Normalize();
  4725. axis = renderEntity.joints[jointNum].ToMat3() * renderEntity.axis;
  4726. origin = renderEntity.origin + renderEntity.joints[jointNum].ToVec3() * renderEntity.axis;
  4727. localOrigin = ( collision.c.point - origin ) * axis.Transpose();
  4728. localNormal = collision.c.normal * axis.Transpose();
  4729. localDir = dir * axis.Transpose();
  4730. AddLocalDamageEffect( jointNum, localOrigin, localNormal, localDir, def, collision.c.material );
  4731. }
  4732. /*
  4733. ==============
  4734. idAnimatedEntity::GetDefaultSurfaceType
  4735. ==============
  4736. */
  4737. int idAnimatedEntity::GetDefaultSurfaceType() const {
  4738. return SURFTYPE_METAL;
  4739. }
  4740. /*
  4741. ==============
  4742. idAnimatedEntity::AddLocalDamageEffect
  4743. ==============
  4744. */
  4745. void idAnimatedEntity::AddLocalDamageEffect( jointHandle_t jointNum, const idVec3 &localOrigin, const idVec3 &localNormal, const idVec3 &localDir, const idDeclEntityDef *def, const idMaterial *collisionMaterial ) {
  4746. const char *sound, *splat, *decal, *bleed, *key;
  4747. damageEffect_t *de;
  4748. idVec3 origin, dir;
  4749. idMat3 axis;
  4750. SetTimeState ts( timeGroup );
  4751. axis = renderEntity.joints[jointNum].ToMat3() * renderEntity.axis;
  4752. origin = renderEntity.origin + renderEntity.joints[jointNum].ToVec3() * renderEntity.axis;
  4753. origin = origin + localOrigin * axis;
  4754. dir = localDir * axis;
  4755. int type = collisionMaterial->GetSurfaceType();
  4756. if ( type == SURFTYPE_NONE ) {
  4757. type = GetDefaultSurfaceType();
  4758. }
  4759. const char *materialType = gameLocal.sufaceTypeNames[ type ];
  4760. // start impact sound based on material type
  4761. key = va( "snd_%s", materialType );
  4762. sound = spawnArgs.GetString( key );
  4763. if ( *sound == '\0' ) {
  4764. sound = def->dict.GetString( key );
  4765. }
  4766. if ( *sound != '\0' ) {
  4767. StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL );
  4768. }
  4769. // blood splats are thrown onto nearby surfaces
  4770. key = va( "mtr_splat_%s", materialType );
  4771. splat = spawnArgs.RandomPrefix( key, gameLocal.random );
  4772. if ( *splat == '\0' ) {
  4773. splat = def->dict.RandomPrefix( key, gameLocal.random );
  4774. }
  4775. if ( *splat != '\0' ) {
  4776. gameLocal.BloodSplat( origin, dir, 64.0f, splat );
  4777. }
  4778. // can't see wounds on the player model in single player mode
  4779. if ( !( IsType( idPlayer::Type ) && !common->IsMultiplayer() ) ) {
  4780. // place a wound overlay on the model
  4781. key = va( "mtr_wound_%s", materialType );
  4782. decal = spawnArgs.RandomPrefix( key, gameLocal.random );
  4783. if ( *decal == '\0' ) {
  4784. decal = def->dict.RandomPrefix( key, gameLocal.random );
  4785. }
  4786. if ( *decal != '\0' ) {
  4787. ProjectOverlay( origin, dir, 20.0f, decal );
  4788. }
  4789. }
  4790. // a blood spurting wound is added
  4791. key = va( "smoke_wound_%s", materialType );
  4792. bleed = spawnArgs.GetString( key );
  4793. if ( *bleed == '\0' ) {
  4794. bleed = def->dict.GetString( key );
  4795. }
  4796. if ( *bleed != '\0' ) {
  4797. de = new (TAG_ENTITY) damageEffect_t;
  4798. de->next = this->damageEffects;
  4799. this->damageEffects = de;
  4800. de->jointNum = jointNum;
  4801. de->localOrigin = localOrigin;
  4802. de->localNormal = localNormal;
  4803. de->type = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, bleed ) );
  4804. de->time = gameLocal.time;
  4805. }
  4806. }
  4807. /*
  4808. ==============
  4809. idAnimatedEntity::UpdateDamageEffects
  4810. ==============
  4811. */
  4812. void idAnimatedEntity::UpdateDamageEffects() {
  4813. damageEffect_t *de, **prev;
  4814. // free any that have timed out
  4815. prev = &this->damageEffects;
  4816. while ( *prev ) {
  4817. de = *prev;
  4818. if ( de->time == 0 ) { // FIXME:SMOKE
  4819. *prev = de->next;
  4820. delete de;
  4821. } else {
  4822. prev = &de->next;
  4823. }
  4824. }
  4825. if ( !g_bloodEffects.GetBool() ) {
  4826. return;
  4827. }
  4828. // emit a particle for each bleeding wound
  4829. for ( de = this->damageEffects; de; de = de->next ) {
  4830. idVec3 origin, start;
  4831. idMat3 axis;
  4832. animator.GetJointTransform( de->jointNum, gameLocal.time, origin, axis );
  4833. axis *= renderEntity.axis;
  4834. origin = renderEntity.origin + origin * renderEntity.axis;
  4835. start = origin + de->localOrigin * axis;
  4836. if ( !gameLocal.smokeParticles->EmitSmoke( de->type, de->time, gameLocal.random.CRandomFloat(), start, axis, timeGroup /*_D3XP*/ ) ) {
  4837. de->time = 0;
  4838. }
  4839. }
  4840. }
  4841. /*
  4842. ================
  4843. idAnimatedEntity::ClientReceiveEvent
  4844. ================
  4845. */
  4846. bool idAnimatedEntity::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  4847. int damageDefIndex;
  4848. int materialIndex;
  4849. jointHandle_t jointNum;
  4850. idVec3 localOrigin, localNormal, localDir;
  4851. switch( event ) {
  4852. case EVENT_ADD_DAMAGE_EFFECT: {
  4853. jointNum = (jointHandle_t) msg.ReadShort();
  4854. localOrigin[0] = msg.ReadFloat();
  4855. localOrigin[1] = msg.ReadFloat();
  4856. localOrigin[2] = msg.ReadFloat();
  4857. localNormal = msg.ReadDir( 24 );
  4858. localDir = msg.ReadDir( 24 );
  4859. damageDefIndex = gameLocal.ClientRemapDecl( DECL_ENTITYDEF, msg.ReadLong() );
  4860. materialIndex = gameLocal.ClientRemapDecl( DECL_MATERIAL, msg.ReadLong() );
  4861. const idDeclEntityDef *damageDef = static_cast<const idDeclEntityDef *>( declManager->DeclByIndex( DECL_ENTITYDEF, damageDefIndex ) );
  4862. const idMaterial *collisionMaterial = static_cast<const idMaterial *>( declManager->DeclByIndex( DECL_MATERIAL, materialIndex ) );
  4863. AddLocalDamageEffect( jointNum, localOrigin, localNormal, localDir, damageDef, collisionMaterial );
  4864. return true;
  4865. }
  4866. default: {
  4867. return idEntity::ClientReceiveEvent( event, time, msg );
  4868. }
  4869. }
  4870. }
  4871. /*
  4872. ================
  4873. idAnimatedEntity::Event_GetJointHandle
  4874. looks up the number of the specified joint. returns INVALID_JOINT if the joint is not found.
  4875. ================
  4876. */
  4877. void idAnimatedEntity::Event_GetJointHandle( const char *jointname ) {
  4878. jointHandle_t joint;
  4879. joint = animator.GetJointHandle( jointname );
  4880. idThread::ReturnInt( joint );
  4881. }
  4882. /*
  4883. ================
  4884. idAnimatedEntity::Event_ClearAllJoints
  4885. removes any custom transforms on all joints
  4886. ================
  4887. */
  4888. void idAnimatedEntity::Event_ClearAllJoints() {
  4889. animator.ClearAllJoints();
  4890. }
  4891. /*
  4892. ================
  4893. idAnimatedEntity::Event_ClearJoint
  4894. removes any custom transforms on the specified joint
  4895. ================
  4896. */
  4897. void idAnimatedEntity::Event_ClearJoint( jointHandle_t jointnum ) {
  4898. animator.ClearJoint( jointnum );
  4899. }
  4900. /*
  4901. ================
  4902. idAnimatedEntity::Event_SetJointPos
  4903. modifies the position of the joint based on the transform type
  4904. ================
  4905. */
  4906. void idAnimatedEntity::Event_SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos ) {
  4907. animator.SetJointPos( jointnum, transform_type, pos );
  4908. }
  4909. /*
  4910. ================
  4911. idAnimatedEntity::Event_SetJointAngle
  4912. modifies the orientation of the joint based on the transform type
  4913. ================
  4914. */
  4915. void idAnimatedEntity::Event_SetJointAngle( jointHandle_t jointnum, jointModTransform_t transform_type, const idAngles &angles ) {
  4916. idMat3 mat;
  4917. mat = angles.ToMat3();
  4918. animator.SetJointAxis( jointnum, transform_type, mat );
  4919. }
  4920. /*
  4921. ================
  4922. idAnimatedEntity::Event_GetJointPos
  4923. returns the position of the joint in worldspace
  4924. ================
  4925. */
  4926. void idAnimatedEntity::Event_GetJointPos( jointHandle_t jointnum ) {
  4927. idVec3 offset;
  4928. idMat3 axis;
  4929. if ( !GetJointWorldTransform( jointnum, gameLocal.time, offset, axis ) ) {
  4930. gameLocal.Warning( "Joint # %d out of range on entity '%s'", jointnum, name.c_str() );
  4931. }
  4932. idThread::ReturnVector( offset );
  4933. }
  4934. /*
  4935. ================
  4936. idAnimatedEntity::Event_GetJointAngle
  4937. returns the orientation of the joint in worldspace
  4938. ================
  4939. */
  4940. void idAnimatedEntity::Event_GetJointAngle( jointHandle_t jointnum ) {
  4941. idVec3 offset;
  4942. idMat3 axis;
  4943. if ( !GetJointWorldTransform( jointnum, gameLocal.time, offset, axis ) ) {
  4944. gameLocal.Warning( "Joint # %d out of range on entity '%s'", jointnum, name.c_str() );
  4945. }
  4946. idAngles ang = axis.ToAngles();
  4947. idVec3 vec( ang[ 0 ], ang[ 1 ], ang[ 2 ] );
  4948. idThread::ReturnVector( vec );
  4949. }