123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "Game_local.h"
- /*
- ===============================================================================
- idEntity
- ===============================================================================
- */
- idCVar net_errorSmoothingMaxDecay( "net_errorSmoothingMaxDecay", "25.0", CVAR_FLOAT, "Max rate at which origin error smoothing decays (in units per game frame)" );
- idCVar net_errorSmoothingDecay( "net_errorSmoothingDecay", "0.06", CVAR_FLOAT, "Rate at which error smoothing decays (in percent per game frame)" );
- // overridable events
- const idEventDef EV_PostSpawn( "<postspawn>", NULL );
- const idEventDef EV_FindTargets( "<findTargets>", NULL );
- const idEventDef EV_Touch( "<touch>", "et" );
- const idEventDef EV_GetName( "getName", NULL, 's' );
- const idEventDef EV_SetName( "setName", "s" );
- const idEventDef EV_Activate( "activate", "e" );
- const idEventDef EV_ActivateTargets( "activateTargets", "e" );
- const idEventDef EV_NumTargets( "numTargets", NULL, 'f' );
- const idEventDef EV_GetTarget( "getTarget", "f", 'e' );
- const idEventDef EV_RandomTarget( "randomTarget", "s", 'e' );
- const idEventDef EV_Bind( "bind", "e" );
- const idEventDef EV_BindPosition( "bindPosition", "e" );
- const idEventDef EV_BindToJoint( "bindToJoint", "esf" );
- const idEventDef EV_Unbind( "unbind", NULL );
- const idEventDef EV_RemoveBinds( "removeBinds" );
- const idEventDef EV_SpawnBind( "<spawnbind>", NULL );
- const idEventDef EV_SetOwner( "setOwner", "e" );
- const idEventDef EV_SetModel( "setModel", "s" );
- const idEventDef EV_SetSkin( "setSkin", "s" );
- const idEventDef EV_GetWorldOrigin( "getWorldOrigin", NULL, 'v' );
- const idEventDef EV_SetWorldOrigin( "setWorldOrigin", "v" );
- const idEventDef EV_GetOrigin( "getOrigin", NULL, 'v' );
- const idEventDef EV_SetOrigin( "setOrigin", "v" );
- const idEventDef EV_GetAngles( "getAngles", NULL, 'v' );
- const idEventDef EV_SetAngles( "setAngles", "v" );
- const idEventDef EV_GetLinearVelocity( "getLinearVelocity", NULL, 'v' );
- const idEventDef EV_SetLinearVelocity( "setLinearVelocity", "v" );
- const idEventDef EV_GetAngularVelocity( "getAngularVelocity", NULL, 'v' );
- const idEventDef EV_SetAngularVelocity( "setAngularVelocity", "v" );
- const idEventDef EV_GetSize( "getSize", NULL, 'v' );
- const idEventDef EV_SetSize( "setSize", "vv" );
- const idEventDef EV_GetMins( "getMins", NULL, 'v' );
- const idEventDef EV_GetMaxs( "getMaxs", NULL, 'v' );
- const idEventDef EV_IsHidden( "isHidden", NULL, 'd' );
- const idEventDef EV_Hide( "hide", NULL );
- const idEventDef EV_Show( "show", NULL );
- const idEventDef EV_Touches( "touches", "E", 'd' );
- const idEventDef EV_ClearSignal( "clearSignal", "d" );
- const idEventDef EV_GetShaderParm( "getShaderParm", "d", 'f' );
- const idEventDef EV_SetShaderParm( "setShaderParm", "df" );
- const idEventDef EV_SetShaderParms( "setShaderParms", "ffff" );
- const idEventDef EV_SetColor( "setColor", "fff" );
- const idEventDef EV_GetColor( "getColor", NULL, 'v' );
- const idEventDef EV_CacheSoundShader( "cacheSoundShader", "s" );
- const idEventDef EV_StartSoundShader( "startSoundShader", "sd", 'f' );
- const idEventDef EV_StartSound( "startSound", "sdd", 'f' );
- const idEventDef EV_StopSound( "stopSound", "dd" );
- const idEventDef EV_FadeSound( "fadeSound", "dff" );
- const idEventDef EV_SetGuiParm( "setGuiParm", "ss" );
- const idEventDef EV_SetGuiFloat( "setGuiFloat", "sf" );
- const idEventDef EV_GetNextKey( "getNextKey", "ss", 's' );
- const idEventDef EV_SetKey( "setKey", "ss" );
- const idEventDef EV_GetKey( "getKey", "s", 's' );
- const idEventDef EV_GetIntKey( "getIntKey", "s", 'f' );
- const idEventDef EV_GetFloatKey( "getFloatKey", "s", 'f' );
- const idEventDef EV_GetVectorKey( "getVectorKey", "s", 'v' );
- const idEventDef EV_GetEntityKey( "getEntityKey", "s", 'e' );
- const idEventDef EV_RestorePosition( "restorePosition" );
- const idEventDef EV_UpdateCameraTarget( "<updateCameraTarget>", NULL );
- const idEventDef EV_DistanceTo( "distanceTo", "E", 'f' );
- const idEventDef EV_DistanceToPoint( "distanceToPoint", "v", 'f' );
- const idEventDef EV_StartFx( "startFx", "s" );
- const idEventDef EV_HasFunction( "hasFunction", "s", 'd' );
- const idEventDef EV_CallFunction( "callFunction", "s" );
- const idEventDef EV_SetNeverDormant( "setNeverDormant", "d" );
- const idEventDef EV_SetGui ( "setGui", "ds" );
- const idEventDef EV_PrecacheGui ( "precacheGui", "s" );
- const idEventDef EV_GetGuiParm ( "getGuiParm", "ds", 's' );
- const idEventDef EV_GetGuiParmFloat ( "getGuiParmFloat", "ds", 'f' );
- const idEventDef EV_MotionBlurOn( "motionBlurOn" );
- const idEventDef EV_MotionBlurOff( "motionBlurOff" );
- const idEventDef EV_GuiNamedEvent ( "guiNamedEvent", "ds" );
- ABSTRACT_DECLARATION( idClass, idEntity )
- EVENT( EV_GetName, idEntity::Event_GetName )
- EVENT( EV_SetName, idEntity::Event_SetName )
- EVENT( EV_FindTargets, idEntity::Event_FindTargets )
- EVENT( EV_ActivateTargets, idEntity::Event_ActivateTargets )
- EVENT( EV_NumTargets, idEntity::Event_NumTargets )
- EVENT( EV_GetTarget, idEntity::Event_GetTarget )
- EVENT( EV_RandomTarget, idEntity::Event_RandomTarget )
- EVENT( EV_BindToJoint, idEntity::Event_BindToJoint )
- EVENT( EV_RemoveBinds, idEntity::Event_RemoveBinds )
- EVENT( EV_Bind, idEntity::Event_Bind )
- EVENT( EV_BindPosition, idEntity::Event_BindPosition )
- EVENT( EV_Unbind, idEntity::Event_Unbind )
- EVENT( EV_SpawnBind, idEntity::Event_SpawnBind )
- EVENT( EV_SetOwner, idEntity::Event_SetOwner )
- EVENT( EV_SetModel, idEntity::Event_SetModel )
- EVENT( EV_SetSkin, idEntity::Event_SetSkin )
- EVENT( EV_GetShaderParm, idEntity::Event_GetShaderParm )
- EVENT( EV_SetShaderParm, idEntity::Event_SetShaderParm )
- EVENT( EV_SetShaderParms, idEntity::Event_SetShaderParms )
- EVENT( EV_SetColor, idEntity::Event_SetColor )
- EVENT( EV_GetColor, idEntity::Event_GetColor )
- EVENT( EV_IsHidden, idEntity::Event_IsHidden )
- EVENT( EV_Hide, idEntity::Event_Hide )
- EVENT( EV_Show, idEntity::Event_Show )
- EVENT( EV_CacheSoundShader, idEntity::Event_CacheSoundShader )
- EVENT( EV_StartSoundShader, idEntity::Event_StartSoundShader )
- EVENT( EV_StartSound, idEntity::Event_StartSound )
- EVENT( EV_StopSound, idEntity::Event_StopSound )
- EVENT( EV_FadeSound, idEntity::Event_FadeSound )
- EVENT( EV_GetWorldOrigin, idEntity::Event_GetWorldOrigin )
- EVENT( EV_SetWorldOrigin, idEntity::Event_SetWorldOrigin )
- EVENT( EV_GetOrigin, idEntity::Event_GetOrigin )
- EVENT( EV_SetOrigin, idEntity::Event_SetOrigin )
- EVENT( EV_GetAngles, idEntity::Event_GetAngles )
- EVENT( EV_SetAngles, idEntity::Event_SetAngles )
- EVENT( EV_GetLinearVelocity, idEntity::Event_GetLinearVelocity )
- EVENT( EV_SetLinearVelocity, idEntity::Event_SetLinearVelocity )
- EVENT( EV_GetAngularVelocity, idEntity::Event_GetAngularVelocity )
- EVENT( EV_SetAngularVelocity, idEntity::Event_SetAngularVelocity )
- EVENT( EV_GetSize, idEntity::Event_GetSize )
- EVENT( EV_SetSize, idEntity::Event_SetSize )
- EVENT( EV_GetMins, idEntity::Event_GetMins)
- EVENT( EV_GetMaxs, idEntity::Event_GetMaxs )
- EVENT( EV_Touches, idEntity::Event_Touches )
- EVENT( EV_SetGuiParm, idEntity::Event_SetGuiParm )
- EVENT( EV_SetGuiFloat, idEntity::Event_SetGuiFloat )
- EVENT( EV_GetNextKey, idEntity::Event_GetNextKey )
- EVENT( EV_SetKey, idEntity::Event_SetKey )
- EVENT( EV_GetKey, idEntity::Event_GetKey )
- EVENT( EV_GetIntKey, idEntity::Event_GetIntKey )
- EVENT( EV_GetFloatKey, idEntity::Event_GetFloatKey )
- EVENT( EV_GetVectorKey, idEntity::Event_GetVectorKey )
- EVENT( EV_GetEntityKey, idEntity::Event_GetEntityKey )
- EVENT( EV_RestorePosition, idEntity::Event_RestorePosition )
- EVENT( EV_UpdateCameraTarget, idEntity::Event_UpdateCameraTarget )
- EVENT( EV_DistanceTo, idEntity::Event_DistanceTo )
- EVENT( EV_DistanceToPoint, idEntity::Event_DistanceToPoint )
- EVENT( EV_StartFx, idEntity::Event_StartFx )
- EVENT( EV_Thread_WaitFrame, idEntity::Event_WaitFrame )
- EVENT( EV_Thread_Wait, idEntity::Event_Wait )
- EVENT( EV_HasFunction, idEntity::Event_HasFunction )
- EVENT( EV_CallFunction, idEntity::Event_CallFunction )
- EVENT( EV_SetNeverDormant, idEntity::Event_SetNeverDormant )
- EVENT( EV_SetGui, idEntity::Event_SetGui )
- EVENT( EV_PrecacheGui, idEntity::Event_PrecacheGui )
- EVENT( EV_GetGuiParm, idEntity::Event_GetGuiParm )
- EVENT( EV_GetGuiParmFloat, idEntity::Event_GetGuiParmFloat )
- EVENT( EV_GuiNamedEvent, idEntity::Event_GuiNamedEvent )
- END_CLASS
- /*
- ================
- UpdateGuiParms
- ================
- */
- void UpdateGuiParms( idUserInterface *gui, const idDict *args ) {
- if ( gui == NULL || args == NULL ) {
- return;
- }
- const idKeyValue *kv = args->MatchPrefix( "gui_parm", NULL );
- while( kv ) {
- gui->SetStateString( kv->GetKey(), kv->GetValue() );
- kv = args->MatchPrefix( "gui_parm", kv );
- }
- gui->SetStateBool( "noninteractive", args->GetBool( "gui_noninteractive" ) ) ;
- gui->StateChanged( gameLocal.time );
- }
- /*
- ================
- AddRenderGui
- ================
- */
- void AddRenderGui( const char *name, idUserInterface **gui, const idDict *args ) {
- const idKeyValue *kv = args->MatchPrefix( "gui_parm", NULL );
- *gui = uiManager->FindGui( name, true, ( kv != NULL ) );
- UpdateGuiParms( *gui, args );
- }
- /*
- ================
- idGameEdit::ParseSpawnArgsToRenderEntity
- parse the static model parameters
- this is the canonical renderEntity parm parsing,
- which should be used by dmap and the editor
- ================
- */
- void idGameEdit::ParseSpawnArgsToRenderEntity( const idDict *args, renderEntity_t *renderEntity ) {
- int i;
- const char *temp;
- idVec3 color;
- float angle;
- const idDeclModelDef *modelDef;
- memset( renderEntity, 0, sizeof( *renderEntity ) );
- temp = args->GetString( "model" );
- modelDef = NULL;
- if ( temp[0] != '\0' ) {
- modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, temp, false ) );
- if ( modelDef ) {
- renderEntity->hModel = modelDef->ModelHandle();
- }
- if ( !renderEntity->hModel ) {
- renderEntity->hModel = renderModelManager->FindModel( temp );
- }
- }
- if ( renderEntity->hModel ) {
- renderEntity->bounds = renderEntity->hModel->Bounds( renderEntity );
- } else {
- renderEntity->bounds.Zero();
- }
- temp = args->GetString( "skin" );
- if ( temp[0] != '\0' ) {
- renderEntity->customSkin = declManager->FindSkin( temp );
- } else if ( modelDef ) {
- renderEntity->customSkin = modelDef->GetDefaultSkin();
- }
- temp = args->GetString( "shader" );
- if ( temp[0] != '\0' ) {
- renderEntity->customShader = declManager->FindMaterial( temp );
- }
- args->GetVector( "origin", "0 0 0", renderEntity->origin );
- // get the rotation matrix in either full form, or single angle form
- if ( !args->GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", renderEntity->axis ) ) {
- angle = args->GetFloat( "angle" );
- if ( angle != 0.0f ) {
- renderEntity->axis = idAngles( 0.0f, angle, 0.0f ).ToMat3();
- } else {
- renderEntity->axis.Identity();
- }
- }
- renderEntity->referenceSound = NULL;
- // get shader parms
- args->GetVector( "_color", "1 1 1", color );
- renderEntity->shaderParms[ SHADERPARM_RED ] = color[0];
- renderEntity->shaderParms[ SHADERPARM_GREEN ] = color[1];
- renderEntity->shaderParms[ SHADERPARM_BLUE ] = color[2];
- renderEntity->shaderParms[ 3 ] = args->GetFloat( "shaderParm3", "1" );
- renderEntity->shaderParms[ 4 ] = args->GetFloat( "shaderParm4", "0" );
- renderEntity->shaderParms[ 5 ] = args->GetFloat( "shaderParm5", "0" );
- renderEntity->shaderParms[ 6 ] = args->GetFloat( "shaderParm6", "0" );
- renderEntity->shaderParms[ 7 ] = args->GetFloat( "shaderParm7", "0" );
- renderEntity->shaderParms[ 8 ] = args->GetFloat( "shaderParm8", "0" );
- renderEntity->shaderParms[ 9 ] = args->GetFloat( "shaderParm9", "0" );
- renderEntity->shaderParms[ 10 ] = args->GetFloat( "shaderParm10", "0" );
- renderEntity->shaderParms[ 11 ] = args->GetFloat( "shaderParm11", "0" );
- // check noDynamicInteractions flag
- renderEntity->noDynamicInteractions = args->GetBool( "noDynamicInteractions" );
- // check noshadows flag
- renderEntity->noShadow = args->GetBool( "noshadows" );
- // check noselfshadows flag
- renderEntity->noSelfShadow = args->GetBool( "noselfshadows" );
- // init any guis, including entity-specific states
- for( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
- temp = args->GetString( i == 0 ? "gui" : va( "gui%d", i + 1 ) );
- if ( temp[ 0 ] != '\0' ) {
- AddRenderGui( temp, &renderEntity->gui[ i ], args );
- }
- }
- }
- /*
- ================
- idGameEdit::ParseSpawnArgsToRefSound
- parse the sound parameters
- this is the canonical refSound parm parsing,
- which should be used by dmap and the editor
- ================
- */
- void idGameEdit::ParseSpawnArgsToRefSound( const idDict *args, refSound_t *refSound ) {
- const char *temp;
- memset( refSound, 0, sizeof( *refSound ) );
- refSound->parms.minDistance = args->GetFloat( "s_mindistance" );
- refSound->parms.maxDistance = args->GetFloat( "s_maxdistance" );
- refSound->parms.volume = args->GetFloat( "s_volume" );
- refSound->parms.shakes = args->GetFloat( "s_shakes" );
- args->GetVector( "origin", "0 0 0", refSound->origin );
- refSound->referenceSound = NULL;
- // if a diversity is not specified, every sound start will make
- // a random one. Specifying diversity is usefull to make multiple
- // lights all share the same buzz sound offset, for instance.
- refSound->diversity = args->GetFloat( "s_diversity", "-1" );
- refSound->waitfortrigger = args->GetBool( "s_waitfortrigger" );
- if ( args->GetBool( "s_omni" ) ) {
- refSound->parms.soundShaderFlags |= SSF_OMNIDIRECTIONAL;
- }
- if ( args->GetBool( "s_looping" ) ) {
- refSound->parms.soundShaderFlags |= SSF_LOOPING;
- }
- if ( args->GetBool( "s_occlusion" ) ) {
- refSound->parms.soundShaderFlags |= SSF_NO_OCCLUSION;
- }
- if ( args->GetBool( "s_global" ) ) {
- refSound->parms.soundShaderFlags |= SSF_GLOBAL;
- }
- if ( args->GetBool( "s_unclamped" ) ) {
- refSound->parms.soundShaderFlags |= SSF_UNCLAMPED;
- }
- refSound->parms.soundClass = args->GetInt( "s_soundClass" );
- temp = args->GetString( "s_shader" );
- if ( temp[0] != '\0' ) {
- refSound->shader = declManager->FindSound( temp );
- }
- }
- /*
- ===============
- idEntity::UpdateChangeableSpawnArgs
- Any key val pair that might change during the course of the game ( via a gui or whatever )
- should be initialize here so a gui or other trigger can change something and have it updated
- properly. An optional source may be provided if the values reside in an outside dictionary and
- first need copied over to spawnArgs
- ===============
- */
- void idEntity::UpdateChangeableSpawnArgs( const idDict *source ) {
- int i;
- const char *target;
- if ( !source ) {
- source = &spawnArgs;
- }
- cameraTarget = NULL;
- target = source->GetString( "cameraTarget" );
- if ( target != NULL && target[0] != NULL ) {
- // update the camera taget
- PostEventMS( &EV_UpdateCameraTarget, 0 );
- }
- for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
- UpdateGuiParms( renderEntity.gui[ i ], source );
- }
- }
- /*
- ================
- idEntity::idEntity
- ================
- */
- idEntity::idEntity():
- useClientInterpolation( true ),
- predictionKey( INVALID_PREDICTION_KEY ),
- originDelta( vec3_zero ),
- axisDelta( mat3_identity ),
- interpolationBehavior( USE_NO_INTERPOLATION ) {
- entityNumber = ENTITYNUM_NONE;
- entityDefNumber = -1;
- spawnNode.SetOwner( this );
- activeNode.SetOwner( this );
- snapshotNode.SetOwner( this );
- snapshotChanged = -1;
- snapshotStale = false;
- snapshotBits = 0;
- thinkFlags = 0;
- dormantStart = 0;
- cinematic = false;
- renderView = NULL;
- cameraTarget = NULL;
- health = 0;
- physics = NULL;
- bindMaster = NULL;
- bindJoint = INVALID_JOINT;
- bindBody = -1;
- teamMaster = NULL;
- teamChain = NULL;
- signals = NULL;
- snapshotsReceived = 0;
- memset( PVSAreas, 0, sizeof( PVSAreas ) );
- numPVSAreas = -1;
- memset( &fl, 0, sizeof( fl ) );
- fl.neverDormant = true; // most entities never go dormant
- memset( &renderEntity, 0, sizeof( renderEntity ) );
- modelDefHandle = -1;
- memset( &refSound, 0, sizeof( refSound ) );
- mpGUIState = -1;
- memset( &xrayEntity, 0, sizeof( xrayEntity ) );
- timeGroup = TIME_GROUP1;
- xrayEntityHandle = -1;
- xraySkin = NULL;
- noGrab = false;
- }
- /*
- ================
- idEntity::FixupLocalizedStrings
- ================
- */
- void idEntity::FixupLocalizedStrings() {
- for ( int i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
- const idKeyValue *kv = spawnArgs.GetKeyVal( i );
- if ( idStr::Cmpn( kv->GetValue(), STRTABLE_ID, STRTABLE_ID_LENGTH ) == 0 ){
- spawnArgs.Set( kv->GetKey(), idLocalization::GetString( kv->GetValue() ) );
- }
- }
- }
- /*
- ================
- idEntity::Spawn
- ================
- */
- void idEntity::Spawn() {
- int i;
- const char *temp;
- idVec3 origin;
- idMat3 axis;
- const idKeyValue *networkSync;
- const char *classname;
- const char *scriptObjectName;
- gameLocal.RegisterEntity( this, -1, gameLocal.GetSpawnArgs() );
- spawnArgs.GetString( "classname", NULL, &classname );
- const idDeclEntityDef *def = gameLocal.FindEntityDef( classname, false );
- if ( def ) {
- entityDefNumber = def->Index();
- }
- FixupLocalizedStrings();
- // parse static models the same way the editor display does
- gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &renderEntity );
- renderEntity.entityNum = entityNumber;
-
- noGrab = spawnArgs.GetBool( "noGrab", "0" );
- xraySkin = NULL;
- renderEntity.xrayIndex = 1;
- idStr str;
- if ( spawnArgs.GetString( "skin_xray", "", str ) ) {
- xraySkin = declManager->FindSkin( str.c_str() );
- }
- // go dormant within 100ms so that when the map starts most monsters are dormant
- dormantStart = gameLocal.time - DELAY_DORMANT_TIME + 100;
- origin = renderEntity.origin;
- axis = renderEntity.axis;
- // do the audio parsing the same way dmap and the editor do
- gameEdit->ParseSpawnArgsToRefSound( &spawnArgs, &refSound );
- // only play SCHANNEL_PRIVATE when sndworld->PlaceListener() is called with this listenerId
- // don't spatialize sounds from the same entity
- refSound.listenerId = entityNumber + 1;
- cameraTarget = NULL;
- temp = spawnArgs.GetString( "cameraTarget" );
- if ( temp != NULL && temp[0] != NULL ) {
- // update the camera taget
- PostEventMS( &EV_UpdateCameraTarget, 0 );
- }
- for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
- UpdateGuiParms( renderEntity.gui[ i ], &spawnArgs );
- }
- fl.solidForTeam = spawnArgs.GetBool( "solidForTeam", "0" );
- fl.neverDormant = spawnArgs.GetBool( "neverDormant", "0" );
- fl.hidden = spawnArgs.GetBool( "hide", "0" );
- if ( fl.hidden ) {
- // make sure we're hidden, since a spawn function might not set it up right
- PostEventMS( &EV_Hide, 0 );
- }
- cinematic = spawnArgs.GetBool( "cinematic", "0" );
- networkSync = spawnArgs.FindKey( "networkSync" );
- if ( networkSync ) {
- fl.networkSync = ( atoi( networkSync->GetValue() ) != 0 );
- }
- #if 0
- if ( !common->IsClient() ) {
- // common->DPrintf( "NET: DBG %s - %s is synced: %s\n", spawnArgs.GetString( "classname", "" ), GetType()->classname, fl.networkSync ? "true" : "false" );
- if ( spawnArgs.GetString( "classname", "" )[ 0 ] == '\0' && !fl.networkSync ) {
- common->DPrintf( "NET: WRN %s entity, no classname, and no networkSync?\n", GetType()->classname );
- }
- }
- #endif
- // every object will have a unique name
- temp = spawnArgs.GetString( "name", va( "%s_%s_%d", GetClassname(), spawnArgs.GetString( "classname" ), entityNumber ) );
- SetName( temp );
- // if we have targets, wait until all entities are spawned to get them
- if ( spawnArgs.MatchPrefix( "target" ) || spawnArgs.MatchPrefix( "guiTarget" ) ) {
- if ( gameLocal.GameState() == GAMESTATE_STARTUP ) {
- PostEventMS( &EV_FindTargets, 0 );
- } else {
- // not during spawn, so it's ok to get the targets
- FindTargets();
- }
- }
- health = spawnArgs.GetInt( "health" );
- InitDefaultPhysics( origin, axis );
- SetOrigin( origin );
- SetAxis( axis );
- temp = spawnArgs.GetString( "model" );
- if ( temp != NULL && *temp != NULL ) {
- SetModel( temp );
- }
- if ( spawnArgs.GetString( "bind", "", &temp ) ) {
- PostEventMS( &EV_SpawnBind, 0 );
- }
- // auto-start a sound on the entity
- if ( refSound.shader && !refSound.waitfortrigger ) {
- StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL );
- }
- // setup script object
- if ( ShouldConstructScriptObjectAtSpawn() && spawnArgs.GetString( "scriptobject", NULL, &scriptObjectName ) ) {
- if ( !scriptObject.SetType( scriptObjectName ) ) {
- gameLocal.Error( "Script object '%s' not found on entity '%s'.", scriptObjectName, name.c_str() );
- }
- ConstructScriptObject();
- }
- // determine time group
- DetermineTimeGroup( spawnArgs.GetBool( "slowmo", "1" ) );
- }
- /*
- ================
- idEntity::~idEntity
- ================
- */
- idEntity::~idEntity() {
- DeconstructScriptObject();
- scriptObject.Free();
- if ( thinkFlags ) {
- BecomeInactive( thinkFlags );
- }
- activeNode.Remove();
- Signal( SIG_REMOVED );
- // we have to set back the default physics object before unbinding because the entity
- // specific physics object might be an entity variable and as such could already be destroyed.
- SetPhysics( NULL );
- // remove any entities that are bound to me
- RemoveBinds();
- // unbind from master
- Unbind();
- QuitTeam();
- gameLocal.RemoveEntityFromHash( name.c_str(), this );
- delete renderView;
- renderView = NULL;
- delete signals;
- signals = NULL;
- FreeModelDef();
- FreeSoundEmitter( false );
- if ( xrayEntityHandle != -1) {
- gameRenderWorld->FreeEntityDef( xrayEntityHandle );
- xrayEntityHandle = -1;
- }
- gameLocal.UnregisterEntity( this );
- }
- /*
- ================
- idEntity::Save
- ================
- */
- void idEntity::Save( idSaveGame *savefile ) const {
- int i, j;
- savefile->WriteInt( entityNumber );
- savefile->WriteInt( entityDefNumber );
- // spawnNode and activeNode are restored by gameLocal
- savefile->WriteDict( &spawnArgs );
- savefile->WriteString( name );
- scriptObject.Save( savefile );
- savefile->WriteInt( thinkFlags );
- savefile->WriteInt( dormantStart );
- savefile->WriteBool( cinematic );
- savefile->WriteObject( cameraTarget );
- savefile->WriteInt( health );
- savefile->WriteInt( targets.Num() );
- for( i = 0; i < targets.Num(); i++ ) {
- targets[ i ].Save( savefile );
- }
- entityFlags_s flags = fl;
- LittleBitField( &flags, sizeof( flags ) );
- savefile->Write( &flags, sizeof( flags ) );
- savefile->WriteInt( timeGroup );
- savefile->WriteBool( noGrab );
- savefile->WriteRenderEntity( xrayEntity );
- savefile->WriteInt( xrayEntityHandle );
- savefile->WriteSkin( xraySkin );
- savefile->WriteRenderEntity( renderEntity );
- savefile->WriteInt( modelDefHandle );
- savefile->WriteRefSound( refSound );
- savefile->WriteObject( bindMaster );
- savefile->WriteJoint( bindJoint );
- savefile->WriteInt( bindBody );
- savefile->WriteObject( teamMaster );
- savefile->WriteObject( teamChain );
- savefile->WriteStaticObject( defaultPhysicsObj );
- savefile->WriteInt( numPVSAreas );
- for( i = 0; i < MAX_PVS_AREAS; i++ ) {
- savefile->WriteInt( PVSAreas[ i ] );
- }
- if ( !signals ) {
- savefile->WriteBool( false );
- } else {
- savefile->WriteBool( true );
- for( i = 0; i < NUM_SIGNALS; i++ ) {
- savefile->WriteInt( signals->signal[ i ].Num() );
- for( j = 0; j < signals->signal[ i ].Num(); j++ ) {
- savefile->WriteInt( signals->signal[ i ][ j ].threadnum );
- savefile->WriteString( signals->signal[ i ][ j ].function->Name() );
- }
- }
- }
- savefile->WriteInt( mpGUIState );
- }
- /*
- ================
- idEntity::Restore
- ================
- */
- void idEntity::Restore( idRestoreGame *savefile ) {
- int i, j;
- int num;
- idStr funcname;
- savefile->ReadInt( entityNumber );
- savefile->ReadInt( entityDefNumber );
- // spawnNode and activeNode are restored by gameLocal
- savefile->ReadDict( &spawnArgs );
- savefile->ReadString( name );
- SetName( name );
- scriptObject.Restore( savefile );
- savefile->ReadInt( thinkFlags );
- savefile->ReadInt( dormantStart );
- savefile->ReadBool( cinematic );
- savefile->ReadObject( reinterpret_cast<idClass *&>( cameraTarget ) );
- savefile->ReadInt( health );
- targets.Clear();
- savefile->ReadInt( num );
- targets.SetNum( num );
- for( i = 0; i < num; i++ ) {
- targets[ i ].Restore( savefile );
- }
- savefile->Read( &fl, sizeof( fl ) );
- LittleBitField( &fl, sizeof( fl ) );
-
- savefile->ReadInt( timeGroup );
- savefile->ReadBool( noGrab );
- savefile->ReadRenderEntity( xrayEntity );
- savefile->ReadInt( xrayEntityHandle );
- if ( xrayEntityHandle != -1 ) {
- xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity );
- }
- savefile->ReadSkin( xraySkin );
- savefile->ReadRenderEntity( renderEntity );
- savefile->ReadInt( modelDefHandle );
- savefile->ReadRefSound( refSound );
- savefile->ReadObject( reinterpret_cast<idClass *&>( bindMaster ) );
- savefile->ReadJoint( bindJoint );
- savefile->ReadInt( bindBody );
- savefile->ReadObject( reinterpret_cast<idClass *&>( teamMaster ) );
- savefile->ReadObject( reinterpret_cast<idClass *&>( teamChain ) );
- savefile->ReadStaticObject( defaultPhysicsObj );
- RestorePhysics( &defaultPhysicsObj );
- savefile->ReadInt( numPVSAreas );
- for( i = 0; i < MAX_PVS_AREAS; i++ ) {
- savefile->ReadInt( PVSAreas[ i ] );
- }
- bool readsignals;
- savefile->ReadBool( readsignals );
- if ( readsignals ) {
- signals = new (TAG_ENTITY) signalList_t;
- for( i = 0; i < NUM_SIGNALS; i++ ) {
- savefile->ReadInt( num );
- signals->signal[ i ].SetNum( num );
- for( j = 0; j < num; j++ ) {
- savefile->ReadInt( signals->signal[ i ][ j ].threadnum );
- savefile->ReadString( funcname );
- signals->signal[ i ][ j ].function = gameLocal.program.FindFunction( funcname );
- if ( !signals->signal[ i ][ j ].function ) {
- savefile->Error( "Function '%s' not found", funcname.c_str() );
- }
- }
- }
- }
- savefile->ReadInt( mpGUIState );
- // restore must retrieve modelDefHandle from the renderer
- if ( modelDefHandle != -1 ) {
- modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
- }
- }
- /*
- ================
- idEntity::GetEntityDefName
- ================
- */
- const char * idEntity::GetEntityDefName() const {
- if ( entityDefNumber < 0 ) {
- return "*unknown*";
- }
- return declManager->DeclByIndex( DECL_ENTITYDEF, entityDefNumber, false )->GetName();
- }
- /*
- ================
- idEntity::SetName
- ================
- */
- void idEntity::SetName( const char *newname ) {
- if ( name.Length() ) {
- gameLocal.RemoveEntityFromHash( name.c_str(), this );
- gameLocal.program.SetEntity( name, NULL );
- }
- name = newname;
- if ( name.Length() ) {
- if ( ( name == "NULL" ) || ( name == "null_entity" ) ) {
- gameLocal.Error( "Cannot name entity '%s'. '%s' is reserved for script.", name.c_str(), name.c_str() );
- }
- gameLocal.AddEntityToHash( name.c_str(), this );
- gameLocal.program.SetEntity( name, this );
- }
- }
- /*
- ================
- idEntity::GetName
- ================
- */
- const char * idEntity::GetName() const {
- return name.c_str();
- }
- /***********************************************************************
- Thinking
-
- ***********************************************************************/
- /*
- ================
- idEntity::Think
- ================
- */
- void idEntity::Think() {
- RunPhysics();
- Present();
- }
- /*
- ================
- idEntity::DoDormantTests
- Monsters and other expensive entities that are completely closed
- off from the player can skip all of their work
- ================
- */
- bool idEntity::DoDormantTests() {
- if ( fl.neverDormant ) {
- return false;
- }
- // if the monster area is not topologically connected to a player
- if ( !gameLocal.InPlayerConnectedArea( this ) ) {
- if ( dormantStart == 0 ) {
- dormantStart = gameLocal.time;
- }
- if ( gameLocal.time - dormantStart < DELAY_DORMANT_TIME ) {
- // just got closed off, don't go dormant yet
- return false;
- }
- return true;
- } else {
- // the monster area is topologically connected to a player, but if
- // the monster hasn't been woken up before, do the more precise PVS check
- if ( !fl.hasAwakened ) {
- if ( !gameLocal.InPlayerPVS( this ) ) {
- return true; // stay dormant
- }
- }
- // wake up
- dormantStart = 0;
- fl.hasAwakened = true; // only go dormant when area closed off now, not just out of PVS
- return false;
- }
- }
- /*
- ================
- idEntity::CheckDormant
- Monsters and other expensive entities that are completely closed
- off from the player can skip all of their work
- ================
- */
- bool idEntity::CheckDormant() {
- bool dormant;
-
- dormant = DoDormantTests();
- if ( dormant && !fl.isDormant ) {
- fl.isDormant = true;
- DormantBegin();
- } else if ( !dormant && fl.isDormant ) {
- fl.isDormant = false;
- DormantEnd();
- }
- return dormant;
- }
- /*
- ================
- idEntity::DormantBegin
- called when entity becomes dormant
- ================
- */
- void idEntity::DormantBegin() {
- }
- /*
- ================
- idEntity::DormantEnd
- called when entity wakes from being dormant
- ================
- */
- void idEntity::DormantEnd() {
- }
- /*
- ================
- idEntity::IsActive
- ================
- */
- bool idEntity::IsActive() const {
- return activeNode.InList();
- }
- /*
- ================
- idEntity::BecomeActive
- ================
- */
- void idEntity::BecomeActive( int flags ) {
- if ( ( flags & TH_PHYSICS ) ) {
- // enable the team master if this entity is part of a physics team
- if ( teamMaster && teamMaster != this ) {
- teamMaster->BecomeActive( TH_PHYSICS );
- } else if ( !( thinkFlags & TH_PHYSICS ) ) {
- // if this is a pusher
- if ( physics->IsType( idPhysics_Parametric::Type ) || physics->IsType( idPhysics_Actor::Type ) ) {
- gameLocal.sortPushers = true;
- }
- }
- }
- int oldFlags = thinkFlags;
- thinkFlags |= flags;
- if ( thinkFlags ) {
- if ( !IsActive() ) {
- activeNode.AddToEnd( gameLocal.activeEntities );
- } else if ( !oldFlags ) {
- // we became inactive this frame, so we have to decrease the count of entities to deactivate
- gameLocal.numEntitiesToDeactivate--;
- }
- }
- }
- /*
- ================
- idEntity::BecomeInactive
- ================
- */
- void idEntity::BecomeInactive( int flags ) {
- if ( ( flags & TH_PHYSICS ) ) {
- // may only disable physics on a team master if no team members are running physics or bound to a joints
- if ( teamMaster == this ) {
- for ( idEntity *ent = teamMaster->teamChain; ent; ent = ent->teamChain ) {
- if ( ( ent->thinkFlags & TH_PHYSICS ) || ( ( ent->bindMaster == this ) && ( ent->bindJoint != INVALID_JOINT ) ) ) {
- flags &= ~TH_PHYSICS;
- break;
- }
- }
- }
- }
- if ( thinkFlags ) {
- thinkFlags &= ~flags;
- if ( !thinkFlags && IsActive() ) {
- gameLocal.numEntitiesToDeactivate++;
- }
- }
- if ( ( flags & TH_PHYSICS ) ) {
- // if this entity has a team master
- if ( teamMaster && teamMaster != this ) {
- // if the team master is at rest
- if ( teamMaster->IsAtRest() ) {
- teamMaster->BecomeInactive( TH_PHYSICS );
- }
- }
- // Becoming inactive automagically turns on motion blur again
- renderEntity.skipMotionBlur = false;
- BecomeActive( TH_UPDATEVISUALS );
- }
- }
- /***********************************************************************
- Visuals
-
- ***********************************************************************/
- /*
- ================
- idEntity::SetShaderParm
- ================
- */
- void idEntity::SetShaderParm( int parmnum, float value ) {
- if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
- gameLocal.Warning( "shader parm index (%d) out of range", parmnum );
- return;
- }
- renderEntity.shaderParms[ parmnum ] = value;
- UpdateVisuals();
- }
- /*
- ================
- idEntity::SetColor
- ================
- */
- void idEntity::SetColor( float red, float green, float blue ) {
- renderEntity.shaderParms[ SHADERPARM_RED ] = red;
- renderEntity.shaderParms[ SHADERPARM_GREEN ] = green;
- renderEntity.shaderParms[ SHADERPARM_BLUE ] = blue;
- UpdateVisuals();
- }
- /*
- ================
- idEntity::SetColor
- ================
- */
- void idEntity::SetColor( const idVec3 &color ) {
- SetColor( color[ 0 ], color[ 1 ], color[ 2 ] );
- UpdateVisuals();
- }
- /*
- ================
- idEntity::GetColor
- ================
- */
- void idEntity::GetColor( idVec3 &out ) const {
- out[ 0 ] = renderEntity.shaderParms[ SHADERPARM_RED ];
- out[ 1 ] = renderEntity.shaderParms[ SHADERPARM_GREEN ];
- out[ 2 ] = renderEntity.shaderParms[ SHADERPARM_BLUE ];
- }
- /*
- ================
- idEntity::SetColor
- ================
- */
- void idEntity::SetColor( const idVec4 &color ) {
- renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ];
- renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ];
- renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ];
- renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ];
- UpdateVisuals();
- }
- /*
- ================
- idEntity::GetColor
- ================
- */
- void idEntity::GetColor( idVec4 &out ) const {
- out[ 0 ] = renderEntity.shaderParms[ SHADERPARM_RED ];
- out[ 1 ] = renderEntity.shaderParms[ SHADERPARM_GREEN ];
- out[ 2 ] = renderEntity.shaderParms[ SHADERPARM_BLUE ];
- out[ 3 ] = renderEntity.shaderParms[ SHADERPARM_ALPHA ];
- }
- /*
- ================
- idEntity::UpdateAnimationControllers
- ================
- */
- bool idEntity::UpdateAnimationControllers() {
- // any ragdoll and IK animation controllers should be updated here
- return false;
- }
- /*
- ================
- idEntity::SetModel
- ================
- */
- void idEntity::SetModel( const char *modelname ) {
- assert( modelname );
- FreeModelDef();
- renderEntity.hModel = renderModelManager->FindModel( modelname );
- if ( renderEntity.hModel ) {
- renderEntity.hModel->Reset();
- }
- renderEntity.callback = NULL;
- renderEntity.numJoints = 0;
- renderEntity.joints = NULL;
- if ( renderEntity.hModel ) {
- renderEntity.bounds = renderEntity.hModel->Bounds( &renderEntity );
- } else {
- renderEntity.bounds.Zero();
- }
- UpdateVisuals();
- }
- /*
- ================
- idEntity::SetSkin
- ================
- */
- void idEntity::SetSkin( const idDeclSkin *skin ) {
- renderEntity.customSkin = skin;
- UpdateVisuals();
- }
- /*
- ================
- idEntity::GetSkin
- ================
- */
- const idDeclSkin *idEntity::GetSkin() const {
- return renderEntity.customSkin;
- }
- /*
- ================
- idEntity::FreeModelDef
- ================
- */
- void idEntity::FreeModelDef() {
- if ( modelDefHandle != -1 ) {
- gameRenderWorld->FreeEntityDef( modelDefHandle );
- modelDefHandle = -1;
- }
- }
- /*
- ================
- idEntity::FreeLightDef
- ================
- */
- void idEntity::FreeLightDef() {
- }
- /*
- ================
- idEntity::IsHidden
- ================
- */
- bool idEntity::IsHidden() const {
- return fl.hidden;
- }
- /*
- ================
- idEntity::Hide
- ================
- */
- void idEntity::Hide() {
- if ( !IsHidden() ) {
- fl.hidden = true;
- FreeModelDef();
- UpdateVisuals();
- }
- }
- /*
- ================
- idEntity::Show
- ================
- */
- void idEntity::Show() {
- if ( IsHidden() ) {
- fl.hidden = false;
- UpdateVisuals();
- }
- }
- /*
- ================
- idEntity::UpdateModelTransform
- ================
- */
- void idEntity::UpdateModelTransform() {
- idVec3 origin;
- idMat3 axis;
- if ( GetPhysicsToVisualTransform( origin, axis ) ) {
- renderEntity.axis = axis * GetPhysics()->GetAxis();
- renderEntity.origin = GetPhysics()->GetOrigin() + origin * renderEntity.axis;
- } else {
- // Add the deltas here, used for projectiles in MP. These deltas should only affect the visuals.
- renderEntity.axis = GetPhysics()->GetAxis() * axisDelta;
- renderEntity.origin = GetPhysics()->GetOrigin() + originDelta;
- }
- }
- /*
- ================
- idEntity::UpdateModel
- ================
- */
- void idEntity::UpdateModel() {
- renderEntity.timeGroup = timeGroup;
- UpdateModelTransform();
- // check if the entity has an MD5 model
- idAnimator *animator = GetAnimator();
- if ( animator != NULL && animator->ModelHandle() != NULL ) {
- // set the callback to update the joints
- renderEntity.callback = idEntity::ModelCallback;
- }
- // set to invalid number to force an update the next time the PVS areas are retrieved
- ClearPVSAreas();
- // ensure that we call Present this frame
- BecomeActive( TH_UPDATEVISUALS );
- // If the entity has an xray skin, go ahead and add it
- if ( xraySkin != NULL ) {
- xrayEntity = renderEntity;
- xrayEntity.xrayIndex = 2;
- xrayEntity.customSkin = xraySkin;
- if ( xrayEntityHandle == -1 ) {
- xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity );
- } else {
- gameRenderWorld->UpdateEntityDef( xrayEntityHandle, &xrayEntity );
- }
- }
- }
- /*
- ================
- idEntity::UpdateVisuals
- ================
- */
- void idEntity::UpdateVisuals() {
- UpdateModel();
- UpdateSound();
- }
- /*
- ================
- idEntity::UpdatePVSAreas
- ================
- */
- void idEntity::UpdatePVSAreas() {
- int localNumPVSAreas, localPVSAreas[32];
- idBounds modelAbsBounds;
- int i;
- modelAbsBounds.FromTransformedBounds( renderEntity.bounds, renderEntity.origin, renderEntity.axis );
- localNumPVSAreas = gameLocal.pvs.GetPVSAreas( modelAbsBounds, localPVSAreas, sizeof( localPVSAreas ) / sizeof( localPVSAreas[0] ) );
- // FIXME: some particle systems may have huge bounds and end up in many PVS areas
- // 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
- if ( localNumPVSAreas > MAX_PVS_AREAS ) {
- localNumPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( renderEntity.origin ).Expand( 64.0f ), localPVSAreas, sizeof( localPVSAreas ) / sizeof( localPVSAreas[0] ) );
- }
- for ( numPVSAreas = 0; numPVSAreas < MAX_PVS_AREAS && numPVSAreas < localNumPVSAreas; numPVSAreas++ ) {
- PVSAreas[numPVSAreas] = localPVSAreas[numPVSAreas];
- }
- for( i = numPVSAreas; i < MAX_PVS_AREAS; i++ ) {
- PVSAreas[ i ] = 0;
- }
- }
- /*
- ================
- idEntity::UpdatePVSAreas
- ================
- */
- void idEntity::UpdatePVSAreas( const idVec3 &pos ) {
- int i;
- numPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( pos ), PVSAreas, MAX_PVS_AREAS );
- i = numPVSAreas;
- while ( i < MAX_PVS_AREAS ) {
- PVSAreas[ i++ ] = 0;
- }
- }
- /*
- ================
- idEntity::GetNumPVSAreas
- ================
- */
- int idEntity::GetNumPVSAreas() {
- if ( numPVSAreas < 0 ) {
- UpdatePVSAreas();
- }
- return numPVSAreas;
- }
- /*
- ================
- idEntity::GetPVSAreas
- ================
- */
- const int *idEntity::GetPVSAreas() {
- if ( numPVSAreas < 0 ) {
- UpdatePVSAreas();
- }
- return PVSAreas;
- }
- /*
- ================
- idEntity::ClearPVSAreas
- ================
- */
- void idEntity::ClearPVSAreas() {
- numPVSAreas = -1;
- }
- /*
- ================
- idEntity::PhysicsTeamInPVS
- FIXME: for networking also return true if any of the entity shadows is in the PVS
- ================
- */
- bool idEntity::PhysicsTeamInPVS( pvsHandle_t pvsHandle ) {
- idEntity *part;
- if ( teamMaster ) {
- for ( part = teamMaster; part; part = part->teamChain ) {
- if ( gameLocal.pvs.InCurrentPVS( pvsHandle, part->GetPVSAreas(), part->GetNumPVSAreas() ) ) {
- return true;
- }
- }
- } else {
- return gameLocal.pvs.InCurrentPVS( pvsHandle, GetPVSAreas(), GetNumPVSAreas() );
- }
- return false;
- }
- /*
- ==============
- idEntity::BecomeReplicated
- ==============
- */
- void idEntity::BecomeReplicated() {
- fl.skipReplication = false;
- if ( GetPhysics() ) {
- GetPhysics()->ResetInterpolationState( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
- }
- }
- /*
- ==============
- idEntity::ProjectOverlay
- ==============
- */
- void idEntity::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
- float s, c;
- idMat3 axis, axistemp;
- idVec3 localOrigin, localAxis[2];
- idPlane localPlane[2];
- // make sure the entity has a valid model handle
- if ( modelDefHandle < 0 ) {
- return;
- }
- // only do this on dynamic md5 models
- if ( renderEntity.hModel->IsDynamicModel() != DM_CACHED ) {
- return;
- }
- idMath::SinCos16( gameLocal.random.RandomFloat() * idMath::TWO_PI, s, c );
- axis[2] = -dir;
- axis[2].NormalVectors( axistemp[0], axistemp[1] );
- axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s;
- axis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c;
- renderEntity.axis.ProjectVector( origin - renderEntity.origin, localOrigin );
- renderEntity.axis.ProjectVector( axis[0], localAxis[0] );
- renderEntity.axis.ProjectVector( axis[1], localAxis[1] );
- size = 1.0f / size;
- localAxis[0] *= size;
- localAxis[1] *= size;
- localPlane[0] = localAxis[0];
- localPlane[0][3] = -( localOrigin * localAxis[0] ) + 0.5f;
- localPlane[1] = localAxis[1];
- localPlane[1][3] = -( localOrigin * localAxis[1] ) + 0.5f;
- const idMaterial *mtr = declManager->FindMaterial( material );
- // project an overlay onto the model
- gameRenderWorld->ProjectOverlay( modelDefHandle, localPlane, mtr, gameLocal.slow.time );
- // make sure non-animating models update their overlay
- UpdateVisuals();
- }
- /*
- ================
- idEntity::Present
- Present is called to allow entities to generate refEntities, lights, etc for the renderer.
- ================
- */
- void idEntity::Present() {
- if ( !gameLocal.isNewFrame ) {
- return;
- }
- // don't present to the renderer if the entity hasn't changed
- if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
- return;
- }
- BecomeInactive( TH_UPDATEVISUALS );
- // camera target for remote render views
- if ( cameraTarget && gameLocal.InPlayerPVS( this ) ) {
- renderEntity.remoteRenderView = cameraTarget->GetRenderView();
- }
- // if set to invisible, skip
- if ( !renderEntity.hModel || IsHidden() ) {
- return;
- }
- // add to refresh list
- if ( modelDefHandle == -1 ) {
- modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
- } else {
- gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
- }
- }
- /*
- ================
- idEntity::GetRenderEntity
- ================
- */
- renderEntity_t *idEntity::GetRenderEntity() {
- return &renderEntity;
- }
- /*
- ================
- idEntity::GetModelDefHandle
- ================
- */
- int idEntity::GetModelDefHandle() {
- return modelDefHandle;
- }
- /*
- ================
- idEntity::UpdateRenderEntity
- ================
- */
- bool idEntity::UpdateRenderEntity( renderEntity_s * renderEntity, const renderView_t * renderView ) {
- idAnimator * animator = GetAnimator();
- if ( animator != NULL ) {
- SetTimeState ts( timeGroup );
- int currentTime = gameLocal.time;
- if ( renderEntity != NULL ) {
- currentTime = gameLocal.GetTimeGroupTime( renderEntity->timeGroup );
- }
- return animator->CreateFrame( currentTime, false );
- }
- return false;
- }
- /*
- ================
- idEntity::ModelCallback
- NOTE: may not change the game state whatsoever!
- ================
- */
- bool idEntity::ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ) {
- idEntity *ent;
- ent = gameLocal.entities[ renderEntity->entityNum ];
- if ( ent == NULL ) {
- gameLocal.Error( "idEntity::ModelCallback: callback with NULL game entity" );
- return false;
- }
- return ent->UpdateRenderEntity( renderEntity, renderView );
- }
- /*
- ================
- idEntity::GetAnimator
- Subclasses will be responsible for allocating animator.
- ================
- */
- idAnimator *idEntity::GetAnimator() {
- return NULL;
- }
- /*
- =============
- idEntity::GetRenderView
- This is used by remote camera views to look from an entity
- =============
- */
- renderView_t *idEntity::GetRenderView() {
- if ( !renderView ) {
- renderView = new (TAG_ENTITY) renderView_t;
- }
- memset( renderView, 0, sizeof( *renderView ) );
- renderView->vieworg = GetPhysics()->GetOrigin();
- renderView->fov_x = 120;
- renderView->fov_y = 120;
- renderView->viewaxis = GetPhysics()->GetAxis();
- // copy global shader parms
- for( int i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
- renderView->shaderParms[ i ] = gameLocal.globalShaderParms[ i ];
- }
- renderView->globalMaterial = gameLocal.GetGlobalMaterial();
- renderView->time[0] = gameLocal.slow.time;
- renderView->time[1] = gameLocal.fast.time;
- return renderView;
- }
- /***********************************************************************
- Sound
-
- ***********************************************************************/
- /*
- ================
- idEntity::CanPlayChatterSounds
- Used for playing chatter sounds on monsters.
- ================
- */
- bool idEntity::CanPlayChatterSounds() const {
- return true;
- }
- /*
- ================
- idEntity::StartSound
- ================
- */
- bool idEntity::StartSound( const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ) {
- const idSoundShader *shader;
- const char *sound;
- if ( length ) {
- *length = 0;
- }
- // we should ALWAYS be playing sounds from the def.
- // hardcoded sounds MUST be avoided at all times because they won't get precached.
- assert( idStr::Icmpn( soundName, "snd_", 4 ) == 0 );
- if ( !spawnArgs.GetString( soundName, "", &sound ) ) {
- return false;
- }
- if ( sound[0] == '\0' ) {
- return false;
- }
- if ( !gameLocal.isNewFrame ) {
- // don't play the sound, but don't report an error
- return true;
- }
- shader = declManager->FindSound( sound );
- return StartSoundShader( shader, channel, soundShaderFlags, broadcast, length );
- }
- /*
- ================
- idEntity::StartSoundShader
- ================
- */
- bool idEntity::StartSoundShader( const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ) {
- float diversity;
- int len;
- if ( length ) {
- *length = 0;
- }
- if ( !shader ) {
- return false;
- }
- if ( !gameLocal.isNewFrame ) {
- return true;
- }
- if ( common->IsServer() && broadcast ) {
- idBitMsg msg;
- byte msgBuf[MAX_EVENT_PARAM_SIZE];
- msg.InitWrite( msgBuf, sizeof( msgBuf ) );
- msg.BeginWriting();
- msg.WriteLong( gameLocal.ServerRemapDecl( -1, DECL_SOUND, shader->Index() ) );
- msg.WriteByte( channel );
- ServerSendEvent( EVENT_STARTSOUNDSHADER, &msg, false );
- }
- // set a random value for diversity unless one was parsed from the entity
- if ( refSound.diversity < 0.0f ) {
- diversity = gameLocal.random.RandomFloat();
- } else {
- diversity = refSound.diversity;
- }
- // if we don't have a soundEmitter allocated yet, get one now
- if ( !refSound.referenceSound ) {
- refSound.referenceSound = gameSoundWorld->AllocSoundEmitter();
- }
- UpdateSound();
- len = refSound.referenceSound->StartSound( shader, channel, diversity, soundShaderFlags, !timeGroup /*_D3XP*/ );
- if ( length ) {
- *length = len;
- }
- // set reference to the sound for shader synced effects
- renderEntity.referenceSound = refSound.referenceSound;
- return true;
- }
- /*
- ================
- idEntity::StopSound
- ================
- */
- void idEntity::StopSound( const s_channelType channel, bool broadcast ) {
- if ( !gameLocal.isNewFrame ) {
- return;
- }
- if ( common->IsServer() && broadcast ) {
- idBitMsg msg;
- byte msgBuf[MAX_EVENT_PARAM_SIZE];
- msg.InitWrite( msgBuf, sizeof( msgBuf ) );
- msg.BeginWriting();
- msg.WriteByte( channel );
- ServerSendEvent( EVENT_STOPSOUNDSHADER, &msg, false );
- }
- if ( refSound.referenceSound ) {
- refSound.referenceSound->StopSound( channel );
- }
- }
- /*
- ================
- idEntity::SetSoundVolume
- Must be called before starting a new sound.
- ================
- */
- void idEntity::SetSoundVolume( float volume ) {
- refSound.parms.volume = volume;
- }
- /*
- ================
- idEntity::UpdateSound
- ================
- */
- void idEntity::UpdateSound() {
- if ( refSound.referenceSound ) {
- idVec3 origin;
- idMat3 axis;
- if ( GetPhysicsToSoundTransform( origin, axis ) ) {
- refSound.origin = GetPhysics()->GetOrigin() + origin * axis;
- } else {
- refSound.origin = GetPhysics()->GetOrigin();
- }
- refSound.referenceSound->UpdateEmitter( refSound.origin, refSound.listenerId, &refSound.parms );
- }
- }
- /*
- ================
- idEntity::GetListenerId
- ================
- */
- int idEntity::GetListenerId() const {
- return refSound.listenerId;
- }
- /*
- ================
- idEntity::GetSoundEmitter
- ================
- */
- idSoundEmitter *idEntity::GetSoundEmitter() const {
- return refSound.referenceSound;
- }
- /*
- ================
- idEntity::FreeSoundEmitter
- ================
- */
- void idEntity::FreeSoundEmitter( bool immediate ) {
- if ( refSound.referenceSound ) {
- refSound.referenceSound->Free( immediate );
- refSound.referenceSound = NULL;
- }
- }
- /***********************************************************************
- entity binding
-
- ***********************************************************************/
- /*
- ================
- idEntity::PreBind
- ================
- */
- void idEntity::PreBind() {
- }
- /*
- ================
- idEntity::PostBind
- ================
- */
- void idEntity::PostBind() {
- }
- /*
- ================
- idEntity::PreUnbind
- ================
- */
- void idEntity::PreUnbind() {
- }
- /*
- ================
- idEntity::PostUnbind
- ================
- */
- void idEntity::PostUnbind() {
- }
- /*
- ================
- idEntity::InitBind
- ================
- */
- bool idEntity::InitBind( idEntity *master ) {
- if ( master == this ) {
- gameLocal.Error( "Tried to bind an object to itself." );
- return false;
- }
- if ( this == gameLocal.world ) {
- gameLocal.Error( "Tried to bind world to another entity" );
- return false;
- }
- // unbind myself from my master
- Unbind();
- // add any bind constraints to an articulated figure
- if ( master && IsType( idAFEntity_Base::Type ) ) {
- static_cast<idAFEntity_Base *>(this)->AddBindConstraints();
- }
- if ( !master || master == gameLocal.world ) {
- // this can happen in scripts, so safely exit out.
- return false;
- }
- return true;
- }
- /*
- ================
- idEntity::FinishBind
- ================
- */
- void idEntity::FinishBind() {
- // set the master on the physics object
- physics->SetMaster( bindMaster, fl.bindOrientated );
- // We are now separated from our previous team and are either
- // an individual, or have a team of our own. Now we can join
- // the new bindMaster's team. Bindmaster must be set before
- // joining the team, or we will be placed in the wrong position
- // on the team.
- JoinTeam( bindMaster );
- // if our bindMaster is enabled during a cinematic, we must be, too
- cinematic = bindMaster->cinematic;
- // make sure the team master is active so that physics get run
- teamMaster->BecomeActive( TH_PHYSICS );
- }
- /*
- ================
- idEntity::Bind
- bind relative to the visual position of the master
- ================
- */
- void idEntity::Bind( idEntity *master, bool orientated ) {
- if ( !InitBind( master ) ) {
- return;
- }
- PreBind();
- bindJoint = INVALID_JOINT;
- bindBody = -1;
- bindMaster = master;
- fl.bindOrientated = orientated;
- FinishBind();
- PostBind( );
- }
- /*
- ================
- idEntity::BindToJoint
- bind relative to a joint of the md5 model used by the master
- ================
- */
- void idEntity::BindToJoint( idEntity *master, const char *jointname, bool orientated ) {
- jointHandle_t jointnum;
- idAnimator *masterAnimator;
- if ( !InitBind( master ) ) {
- return;
- }
- masterAnimator = master->GetAnimator();
- if ( !masterAnimator ) {
- gameLocal.Warning( "idEntity::BindToJoint: entity '%s' cannot support skeletal models.", master->GetName() );
- return;
- }
- jointnum = masterAnimator->GetJointHandle( jointname );
- if ( jointnum == INVALID_JOINT ) {
- gameLocal.Warning( "idEntity::BindToJoint: joint '%s' not found on entity '%s'.", jointname, master->GetName() );
- }
- PreBind();
- bindJoint = jointnum;
- bindBody = -1;
- bindMaster = master;
- fl.bindOrientated = orientated;
- FinishBind();
- PostBind();
- }
- /*
- ================
- idEntity::BindToJoint
- bind relative to a joint of the md5 model used by the master
- ================
- */
- void idEntity::BindToJoint( idEntity *master, jointHandle_t jointnum, bool orientated ) {
- if ( !InitBind( master ) ) {
- return;
- }
- PreBind();
- bindJoint = jointnum;
- bindBody = -1;
- bindMaster = master;
- fl.bindOrientated = orientated;
- FinishBind();
- PostBind();
- }
- /*
- ================
- idEntity::BindToBody
- bind relative to a collision model used by the physics of the master
- ================
- */
- void idEntity::BindToBody( idEntity *master, int bodyId, bool orientated ) {
- if ( !InitBind( master ) ) {
- return;
- }
- if ( bodyId < 0 ) {
- gameLocal.Warning( "idEntity::BindToBody: body '%d' not found.", bodyId );
- }
- PreBind();
- bindJoint = INVALID_JOINT;
- bindBody = bodyId;
- bindMaster = master;
- fl.bindOrientated = orientated;
- FinishBind();
- PostBind();
- }
- /*
- ================
- idEntity::Unbind
- ================
- */
- void idEntity::Unbind() {
- idEntity * prev;
- idEntity * next;
- idEntity * last;
- idEntity * ent;
- // remove any bind constraints from an articulated figure
- if ( IsType( idAFEntity_Base::Type ) ) {
- static_cast<idAFEntity_Base *>(this)->RemoveBindConstraints();
- }
- if ( !bindMaster ) {
- return;
- }
- if ( !teamMaster ) {
- // Teammaster already has been freed
- bindMaster = NULL;
- return;
- }
- PreUnbind();
- if ( physics ) {
- physics->SetMaster( NULL, fl.bindOrientated );
- }
- // We're still part of a team, so that means I have to extricate myself
- // and any entities that are bound to me from the old team.
- // Find the node previous to me in the team
- prev = teamMaster;
- for( ent = teamMaster->teamChain; ent && ( ent != this ); ent = ent->teamChain ) {
- prev = ent;
- }
- assert( ent == this ); // If ent is not pointing to this, then something is very wrong.
- // Find the last node in my team that is bound to me.
- // Also find the first node not bound to me, if one exists.
- last = this;
- for( next = teamChain; next != NULL; next = next->teamChain ) {
- if ( !next->IsBoundTo( this ) ) {
- break;
- }
- // Tell them I'm now the teamMaster
- next->teamMaster = this;
- last = next;
- }
- // disconnect the last member of our team from the old team
- last->teamChain = NULL;
- // connect up the previous member of the old team to the node that
- // follow the last node bound to me (if one exists).
- if ( teamMaster != this ) {
- prev->teamChain = next;
- if ( !next && ( teamMaster == prev ) ) {
- prev->teamMaster = NULL;
- }
- } else if ( next ) {
- // If we were the teamMaster, then the nodes that were not bound to me are now
- // a disconnected chain. Make them into their own team.
- for( ent = next; ent->teamChain != NULL; ent = ent->teamChain ) {
- ent->teamMaster = next;
- }
- next->teamMaster = next;
- }
- // If we don't have anyone on our team, then clear the team variables.
- if ( teamChain ) {
- // make myself my own team
- teamMaster = this;
- } else {
- // no longer a team
- teamMaster = NULL;
- }
- bindJoint = INVALID_JOINT;
- bindBody = -1;
- bindMaster = NULL;
- PostUnbind();
- }
- /*
- ================
- idEntity::RemoveBinds
- ================
- */
- void idEntity::RemoveBinds() {
- idEntity *ent;
- idEntity *next;
- for( ent = teamChain; ent != NULL; ent = next ) {
- next = ent->teamChain;
- if ( ent->bindMaster == this ) {
- ent->Unbind();
- ent->PostEventMS( &EV_Remove, 0 );
- next = teamChain;
- }
- }
- }
- /*
- ================
- idEntity::IsBound
- ================
- */
- bool idEntity::IsBound() const {
- if ( bindMaster ) {
- return true;
- }
- return false;
- }
- /*
- ================
- idEntity::IsBoundTo
- ================
- */
- bool idEntity::IsBoundTo( idEntity *master ) const {
- idEntity *ent;
- if ( !bindMaster ) {
- return false;
- }
- for ( ent = bindMaster; ent != NULL; ent = ent->bindMaster ) {
- if ( ent == master ) {
- return true;
- }
- }
- return false;
- }
- /*
- ================
- idEntity::GetBindMaster
- ================
- */
- idEntity *idEntity::GetBindMaster() const {
- return bindMaster;
- }
- /*
- ================
- idEntity::GetBindJoint
- ================
- */
- jointHandle_t idEntity::GetBindJoint() const {
- return bindJoint;
- }
- /*
- ================
- idEntity::GetBindBody
- ================
- */
- int idEntity::GetBindBody() const {
- return bindBody;
- }
- /*
- ================
- idEntity::GetTeamMaster
- ================
- */
- idEntity *idEntity::GetTeamMaster() const {
- return teamMaster;
- }
- /*
- ================
- idEntity::GetNextTeamEntity
- ================
- */
- idEntity *idEntity::GetNextTeamEntity() const {
- return teamChain;
- }
- /*
- =====================
- idEntity::ConvertLocalToWorldTransform
- =====================
- */
- void idEntity::ConvertLocalToWorldTransform( idVec3 &offset, idMat3 &axis ) {
- UpdateModelTransform();
- offset = renderEntity.origin + offset * renderEntity.axis;
- axis *= renderEntity.axis;
- }
- /*
- ================
- idEntity::GetLocalVector
- Takes a vector in worldspace and transforms it into the parent
- object's localspace.
- Note: Does not take origin into acount. Use getLocalCoordinate to
- convert coordinates.
- ================
- */
- idVec3 idEntity::GetLocalVector( const idVec3 &vec ) const {
- idVec3 pos;
- if ( !bindMaster ) {
- return vec;
- }
- idVec3 masterOrigin;
- idMat3 masterAxis;
- GetMasterPosition( masterOrigin, masterAxis );
- masterAxis.ProjectVector( vec, pos );
- return pos;
- }
- /*
- ================
- idEntity::GetLocalCoordinates
- Takes a vector in world coordinates and transforms it into the parent
- object's local coordinates.
- ================
- */
- idVec3 idEntity::GetLocalCoordinates( const idVec3 &vec ) const {
- idVec3 pos;
- if ( !bindMaster ) {
- return vec;
- }
- idVec3 masterOrigin;
- idMat3 masterAxis;
- GetMasterPosition( masterOrigin, masterAxis );
- masterAxis.ProjectVector( vec - masterOrigin, pos );
- return pos;
- }
- /*
- ================
- idEntity::GetWorldVector
- Takes a vector in the parent object's local coordinates and transforms
- it into world coordinates.
- Note: Does not take origin into acount. Use getWorldCoordinate to
- convert coordinates.
- ================
- */
- idVec3 idEntity::GetWorldVector( const idVec3 &vec ) const {
- idVec3 pos;
- if ( !bindMaster ) {
- return vec;
- }
- idVec3 masterOrigin;
- idMat3 masterAxis;
- GetMasterPosition( masterOrigin, masterAxis );
- masterAxis.UnprojectVector( vec, pos );
- return pos;
- }
- /*
- ================
- idEntity::GetWorldCoordinates
- Takes a vector in the parent object's local coordinates and transforms
- it into world coordinates.
- ================
- */
- idVec3 idEntity::GetWorldCoordinates( const idVec3 &vec ) const {
- idVec3 pos;
- if ( !bindMaster ) {
- return vec;
- }
- idVec3 masterOrigin;
- idMat3 masterAxis;
- GetMasterPosition( masterOrigin, masterAxis );
- masterAxis.UnprojectVector( vec, pos );
- pos += masterOrigin;
- return pos;
- }
- /*
- ================
- idEntity::GetMasterPosition
- ================
- */
- bool idEntity::GetMasterPosition( idVec3 &masterOrigin, idMat3 &masterAxis ) const {
- idVec3 localOrigin;
- idMat3 localAxis;
- idAnimator *masterAnimator;
- if ( bindMaster ) {
- // if bound to a joint of an animated model
- if ( bindJoint != INVALID_JOINT ) {
- masterAnimator = bindMaster->GetAnimator();
- if ( !masterAnimator ) {
- masterOrigin = vec3_origin;
- masterAxis = mat3_identity;
- return false;
- } else {
- masterAnimator->GetJointTransform( bindJoint, gameLocal.time, masterOrigin, masterAxis );
- masterAxis *= bindMaster->renderEntity.axis;
- masterOrigin = bindMaster->renderEntity.origin + masterOrigin * bindMaster->renderEntity.axis;
- }
- } else if ( bindBody >= 0 && bindMaster->GetPhysics() ) {
- masterOrigin = bindMaster->GetPhysics()->GetOrigin( bindBody );
- masterAxis = bindMaster->GetPhysics()->GetAxis( bindBody );
- } else {
- masterOrigin = bindMaster->renderEntity.origin;
- masterAxis = bindMaster->renderEntity.axis;
- }
- return true;
- } else {
- masterOrigin = vec3_origin;
- masterAxis = mat3_identity;
- return false;
- }
- }
- /*
- ================
- idEntity::GetWorldVelocities
- ================
- */
- void idEntity::GetWorldVelocities( idVec3 &linearVelocity, idVec3 &angularVelocity ) const {
- linearVelocity = physics->GetLinearVelocity();
- angularVelocity = physics->GetAngularVelocity();
- if ( bindMaster ) {
- idVec3 masterOrigin, masterLinearVelocity, masterAngularVelocity;
- idMat3 masterAxis;
- // get position of master
- GetMasterPosition( masterOrigin, masterAxis );
- // get master velocities
- bindMaster->GetWorldVelocities( masterLinearVelocity, masterAngularVelocity );
- // linear velocity relative to master plus master linear and angular velocity
- linearVelocity = linearVelocity * masterAxis + masterLinearVelocity +
- masterAngularVelocity.Cross( GetPhysics()->GetOrigin() - masterOrigin );
- }
- }
- /*
- ================
- idEntity::JoinTeam
- ================
- */
- void idEntity::JoinTeam( idEntity *teammember ) {
- idEntity *ent;
- idEntity *master;
- idEntity *prev;
- idEntity *next;
- // if we're already on a team, quit it so we can join this one
- if ( teamMaster && ( teamMaster != this ) ) {
- QuitTeam();
- }
- assert( teammember );
- if ( teammember == this ) {
- teamMaster = this;
- return;
- }
- // check if our new team mate is already on a team
- master = teammember->teamMaster;
- if ( !master ) {
- // he's not on a team, so he's the new teamMaster
- master = teammember;
- teammember->teamMaster = teammember;
- teammember->teamChain = this;
- // make anyone who's bound to me part of the new team
- for( ent = teamChain; ent != NULL; ent = ent->teamChain ) {
- ent->teamMaster = master;
- }
- } else {
- // skip past the chain members bound to the entity we're teaming up with
- prev = teammember;
- next = teammember->teamChain;
- if ( bindMaster ) {
- // if we have a bindMaster, join after any entities bound to the entity
- // we're joining
- while( next && next->IsBoundTo( teammember ) ) {
- prev = next;
- next = next->teamChain;
- }
- } else {
- // if we're not bound to someone, then put us at the end of the team
- while( next ) {
- prev = next;
- next = next->teamChain;
- }
- }
- // make anyone who's bound to me part of the new team and
- // also find the last member of my team
- for( ent = this; ent->teamChain != NULL; ent = ent->teamChain ) {
- ent->teamChain->teamMaster = master;
- }
- prev->teamChain = this;
- ent->teamChain = next;
- }
- teamMaster = master;
- // reorder the active entity list
- gameLocal.sortTeamMasters = true;
- }
- /*
- ================
- idEntity::QuitTeam
- ================
- */
- void idEntity::QuitTeam() {
- idEntity *ent;
- if ( !teamMaster ) {
- return;
- }
- // check if I'm the teamMaster
- if ( teamMaster == this ) {
- // do we have more than one teammate?
- if ( !teamChain->teamChain ) {
- // no, break up the team
- teamChain->teamMaster = NULL;
- } else {
- // yes, so make the first teammate the teamMaster
- for( ent = teamChain; ent; ent = ent->teamChain ) {
- ent->teamMaster = teamChain;
- }
- }
- } else {
- assert( teamMaster );
- assert( teamMaster->teamChain );
- // find the previous member of the teamChain
- ent = teamMaster;
- while( ent->teamChain != this ) {
- assert( ent->teamChain ); // this should never happen
- ent = ent->teamChain;
- }
- // remove this from the teamChain
- ent->teamChain = teamChain;
- // if no one is left on the team, break it up
- if ( !teamMaster->teamChain ) {
- teamMaster->teamMaster = NULL;
- }
- }
- teamMaster = NULL;
- teamChain = NULL;
- }
- /***********************************************************************
- Physics.
-
- ***********************************************************************/
- /*
- ================
- idEntity::InitDefaultPhysics
- ================
- */
- void idEntity::InitDefaultPhysics( const idVec3 &origin, const idMat3 &axis ) {
- const char *temp;
- idClipModel *clipModel = NULL;
- // check if a clipmodel key/value pair is set
- if ( spawnArgs.GetString( "clipmodel", "", &temp ) ) {
- if ( idClipModel::CheckModel( temp ) ) {
- clipModel = new (TAG_PHYSICS_CLIP_ENTITY) idClipModel( temp );
- }
- }
- if ( !spawnArgs.GetBool( "noclipmodel", "0" ) ) {
- // check if mins/maxs or size key/value pairs are set
- if ( !clipModel ) {
- idVec3 size;
- idBounds bounds;
- bool setClipModel = false;
- if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) &&
- spawnArgs.GetVector( "maxs", NULL, bounds[1] ) ) {
- setClipModel = true;
- if ( bounds[0][0] > bounds[1][0] || bounds[0][1] > bounds[1][1] || bounds[0][2] > bounds[1][2] ) {
- gameLocal.Error( "Invalid bounds '%s'-'%s' on entity '%s'", bounds[0].ToString(), bounds[1].ToString(), name.c_str() );
- }
- } else if ( spawnArgs.GetVector( "size", NULL, size ) ) {
- if ( ( size.x < 0.0f ) || ( size.y < 0.0f ) || ( size.z < 0.0f ) ) {
- gameLocal.Error( "Invalid size '%s' on entity '%s'", size.ToString(), name.c_str() );
- }
- bounds[0].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
- bounds[1].Set( size.x * 0.5f, size.y * 0.5f, size.z );
- setClipModel = true;
- }
- if ( setClipModel ) {
- int numSides;
- idTraceModel trm;
- if ( spawnArgs.GetInt( "cylinder", "0", numSides ) && numSides > 0 ) {
- trm.SetupCylinder( bounds, numSides < 3 ? 3 : numSides );
- } else if ( spawnArgs.GetInt( "cone", "0", numSides ) && numSides > 0 ) {
- trm.SetupCone( bounds, numSides < 3 ? 3 : numSides );
- } else {
- trm.SetupBox( bounds );
- }
- clipModel = new (TAG_PHYSICS_CLIP_ENTITY) idClipModel( trm );
- }
- }
- // check if the visual model can be used as collision model
- if ( !clipModel ) {
- temp = spawnArgs.GetString( "model" );
- if ( ( temp != NULL ) && ( *temp != 0 ) ) {
- if ( idClipModel::CheckModel( temp ) ) {
- clipModel = new (TAG_PHYSICS_CLIP_ENTITY) idClipModel( temp );
- }
- }
- }
- }
- defaultPhysicsObj.SetSelf( this );
- defaultPhysicsObj.SetClipModel( clipModel, 1.0f );
- defaultPhysicsObj.SetOrigin( origin );
- defaultPhysicsObj.SetAxis( axis );
- physics = &defaultPhysicsObj;
- }
- /*
- ================
- idEntity::SetPhysics
- ================
- */
- void idEntity::SetPhysics( idPhysics *phys ) {
- // clear any contacts the current physics object has
- if ( physics ) {
- physics->ClearContacts();
- }
- // set new physics object or set the default physics if NULL
- if ( phys != NULL ) {
- defaultPhysicsObj.SetClipModel( NULL, 1.0f );
- physics = phys;
- physics->Activate();
- } else {
- physics = &defaultPhysicsObj;
- }
- physics->UpdateTime( gameLocal.time );
- physics->SetMaster( bindMaster, fl.bindOrientated );
- }
- /*
- ================
- idEntity::RestorePhysics
- ================
- */
- void idEntity::RestorePhysics( idPhysics *phys ) {
- assert( phys != NULL );
- // restore physics pointer
- physics = phys;
- }
- /*
- ================
- idEntity::GetPhysics
- ================
- */
- idPhysics *idEntity::GetPhysics() const {
- return physics;
- }
- /*
- ================
- idEntity::RunPhysics
- ================
- */
- bool idEntity::RunPhysics() {
- int i, reachedTime;
- idEntity * part = NULL, *blockedPart = NULL, *blockingEntity = NULL;
- trace_t results;
- bool moved;
- // don't run physics if not enabled
- if ( !( thinkFlags & TH_PHYSICS ) ) {
- // however do update any animation controllers
- if ( UpdateAnimationControllers() ) {
- BecomeActive( TH_ANIMATE );
- }
- return false;
- }
- // if this entity is a team slave don't do anything because the team master will handle everything
- if ( teamMaster && teamMaster != this ) {
- return false;
- }
- const int startTime = gameLocal.previousTime;
- const int endTime = gameLocal.time;
- gameLocal.push.InitSavingPushedEntityPositions();
- blockedPart = NULL;
- // save the physics state of the whole team and disable the team for collision detection
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- if ( !part->fl.solidForTeam ) {
- part->physics->DisableClip();
- }
- part->physics->SaveState();
- }
- }
- // move the whole team
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- // run physics
- moved = part->physics->Evaluate( GetPhysicsTimeStep(), endTime );
- // check if the object is blocked
- blockingEntity = part->physics->GetBlockingEntity();
- if ( blockingEntity ) {
- blockedPart = part;
- break;
- }
- // if moved or forced to update the visual position and orientation from the physics
- if ( moved || part->fl.forcePhysicsUpdate ) {
- part->UpdateFromPhysics( false );
- }
- // update any animation controllers here so an entity bound
- // to a joint of this entity gets the correct position
- if ( part->UpdateAnimationControllers() ) {
- part->BecomeActive( TH_ANIMATE );
- }
- }
- }
- // enable the whole team for collision detection
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- if ( !part->fl.solidForTeam ) {
- part->physics->EnableClip();
- }
- }
- }
- // if one of the team entities is a pusher and blocked
- if ( blockedPart ) {
- // move the parts back to the previous position
- for ( part = this; part != blockedPart; part = part->teamChain ) {
- if ( part->physics ) {
- // restore the physics state
- part->physics->RestoreState();
- // move back the visual position and orientation
- part->UpdateFromPhysics( true );
- }
- }
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- // update the physics time without moving
- part->physics->UpdateTime( endTime );
- }
- }
- // restore the positions of any pushed entities
- gameLocal.push.RestorePushedEntityPositions();
- if ( common->IsClient() ) {
- return false;
- }
- // if the master pusher has a "blocked" function, call it
- Signal( SIG_BLOCKED );
- ProcessEvent( &EV_TeamBlocked, blockedPart, blockingEntity );
- // call the blocked function on the blocked part
- blockedPart->ProcessEvent( &EV_PartBlocked, blockingEntity );
- return false;
- }
- // This is to hack around an issue when reloading a game saved on certain movers would
- // eject the player randomly through the world due to the first couple of frames imparting
- // large pushVelocities.
- const bool useAbnormalVelocityHack = ( idStr::Cmp( name, "houndola" ) == 0 );
- // Disable motion blur if this object pushes the local player
- renderEntity.skipMotionBlur = false;
- // set pushed
- for ( i = 0; i < gameLocal.push.GetNumPushedEntities(); i++ ) {
- idEntity *ent = gameLocal.push.GetPushedEntity( i );
- if ( ent->physics->IsType( idPhysics_Player::Type ) ) {
- if ( gameLocal.GetLocalClientNum() == ent->entityNumber ) {
- renderEntity.skipMotionBlur = true;
- }
- if ( useAbnormalVelocityHack ) {
- idPhysics_Player * physics = static_cast< idPhysics_Player * >( ent->physics );
- physics->SetPushedWithAbnormalVelocityHack( GetPhysicsTimeStep() );
- } else {
- ent->physics->SetPushed( endTime - startTime );
- }
- } else {
- ent->physics->SetPushed( endTime - startTime );
- }
- }
- // Propogate skipMotionBlur to all team members
- for ( part = this; part != NULL; part = part->teamChain ) {
- part->renderEntity.skipMotionBlur = renderEntity.skipMotionBlur;
- }
- if ( common->IsClient() ) {
- return true;
- }
- // post reached event if the current time is at or past the end point of the motion
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- reachedTime = part->physics->GetLinearEndTime();
- if ( startTime < reachedTime && endTime >= reachedTime ) {
- part->ProcessEvent( &EV_ReachedPos );
- }
- reachedTime = part->physics->GetAngularEndTime();
- if ( startTime < reachedTime && endTime >= reachedTime ) {
- part->ProcessEvent( &EV_ReachedAng );
- }
- }
- }
- return true;
- }
- /*
- ================
- idEntity::InterpolatePhysics
- ================
- */
- void idEntity::InterpolatePhysics( const float fraction ) {
- int i, startTime, endTime;
- idEntity * part = NULL, *blockedPart = NULL, *blockingEntity = NULL;
- trace_t results;
- bool moved;
- // don't run physics if not enabled
- if ( !( thinkFlags & TH_PHYSICS ) ) {
- // however do update any animation controllers
- if ( UpdateAnimationControllers() ) {
- BecomeActive( TH_ANIMATE );
- }
- return;
- }
- // if this entity is a team slave, we still need to interpolate it's current position from the snapshot.
- // The team master probably depends on the current physics state, and may be unaware of prev/next or interpolation.
- if ( teamMaster && teamMaster != this ) {
- if ( physics != NULL && useClientInterpolation ) {
- if ( physics->Interpolate( fraction ) ) {
- UpdateFromPhysics( false );
- }
- }
- return;
- }
- startTime = gameLocal.previousTime;
- endTime = gameLocal.time;
- gameLocal.push.InitSavingPushedEntityPositions();
- blockedPart = NULL;
- // save the physics state of the whole team and disable the team for collision detection
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- if ( !part->fl.solidForTeam ) {
- part->physics->DisableClip();
- }
- part->physics->SaveState();
- }
- }
- // move the whole team
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- // run physics
- moved = part->physics->Evaluate( GetPhysicsTimeStep(), endTime );
- // check if the object is blocked
- blockingEntity = part->physics->GetBlockingEntity();
- if ( blockingEntity ) {
- blockedPart = part;
- break;
- }
- // if moved or forced to update the visual position and orientation from the physics
- if ( moved || part->fl.forcePhysicsUpdate ) {
- part->UpdateFromPhysics( false );
- }
- // update any animation controllers here so an entity bound
- // to a joint of this entity gets the correct position
- if ( part->UpdateAnimationControllers() ) {
- part->BecomeActive( TH_ANIMATE );
- }
- }
- }
- // enable the whole team for collision detection
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- if ( !part->fl.solidForTeam ) {
- part->physics->EnableClip();
- }
- }
- }
- // if one of the team entities is a pusher and blocked
- if ( blockedPart ) {
- // move the parts back to the previous position
- for ( part = this; part != blockedPart; part = part->teamChain ) {
- if ( part->physics ) {
- // restore the physics state
- part->physics->RestoreState();
- // move back the visual position and orientation
- part->UpdateFromPhysics( true );
- }
- }
- for ( part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics ) {
- // update the physics time without moving
- part->physics->UpdateTime( endTime );
- }
- }
- // restore the positions of any pushed entities
- gameLocal.push.RestorePushedEntityPositions();
- }
- // set pushed
- for ( i = 0; i < gameLocal.push.GetNumPushedEntities(); i++ ) {
- idEntity *ent = gameLocal.push.GetPushedEntity( i );
- ent->physics->SetPushed( GetPhysicsTimeStep() );
- }
- if ( physics && useClientInterpolation ) {
- if ( physics->Interpolate( fraction ) ) {
- UpdateFromPhysics( false );
- }
- }
- }
- /*
- ================
- idEntity::InterpolatePhysicsOnly
- ================
- */
- void idEntity::InterpolatePhysicsOnly( const float fraction, bool updateTeam ) {
- if ( physics && useClientInterpolation ) {
- if ( physics->Interpolate( fraction ) ) {
- UpdateFromPhysics( false );
- }
- }
- if( updateTeam ) {
- int endTime = gameLocal.time;
- // move the whole team
- for ( idEntity* part = this; part != NULL; part = part->teamChain ) {
- if ( part->physics && part != this ) {
- // run physics
- bool moved = part->physics->Evaluate( GetPhysicsTimeStep(), endTime );
- // if moved or forced to update the visual position and orientation from the physics
- if ( moved || part->fl.forcePhysicsUpdate ) {
- part->UpdateFromPhysics( false );
- }
- // update any animation controllers here so an entity bound
- // to a joint of this entity gets the correct position
- if ( part->UpdateAnimationControllers() ) {
- part->BecomeActive( TH_ANIMATE );
- }
- }
- }
- }
- }
- /*
- ================
- idEntity::UpdateFromPhysics
- ================
- */
- void idEntity::UpdateFromPhysics( bool moveBack ) {
- if ( IsType( idActor::Type ) ) {
- idActor *actor = static_cast<idActor *>( this );
- // set master delta angles for actors
- if ( GetBindMaster() ) {
- idAngles delta = actor->GetDeltaViewAngles();
- if ( moveBack ) {
- delta.yaw -= static_cast<idPhysics_Actor *>(physics)->GetMasterDeltaYaw();
- } else {
- delta.yaw += static_cast<idPhysics_Actor *>(physics)->GetMasterDeltaYaw();
- }
- actor->SetDeltaViewAngles( delta );
- }
- }
- UpdateVisuals();
- }
- /*
- ================
- idEntity::GetPhysicsTimeStep
- ================
- */
- int idEntity::GetPhysicsTimeStep() const {
- return gameLocal.time - gameLocal.previousTime;
- }
- /*
- ================
- idEntity::SetOrigin
- ================
- */
- void idEntity::SetOrigin( const idVec3 &org ) {
- GetPhysics()->SetOrigin( org );
- UpdateVisuals();
- }
- /*
- ================
- idEntity::SetAxis
- ================
- */
- void idEntity::SetAxis( const idMat3 &axis ) {
- if ( GetPhysics()->IsType( idPhysics_Actor::Type ) ) {
- static_cast<idActor *>(this)->viewAxis = axis;
- } else {
- GetPhysics()->SetAxis( axis );
- }
- UpdateVisuals();
- }
- /*
- ================
- idEntity::SetAngles
- ================
- */
- void idEntity::SetAngles( const idAngles &ang ) {
- SetAxis( ang.ToMat3() );
- }
- /*
- ================
- idEntity::GetFloorPos
- ================
- */
- bool idEntity::GetFloorPos( float max_dist, idVec3 &floorpos ) const {
- trace_t result;
- if ( !GetPhysics()->HasGroundContacts() ) {
- GetPhysics()->ClipTranslation( result, GetPhysics()->GetGravityNormal() * max_dist, NULL );
- if ( result.fraction < 1.0f ) {
- floorpos = result.endpos;
- return true;
- } else {
- floorpos = GetPhysics()->GetOrigin();
- return false;
- }
- } else {
- floorpos = GetPhysics()->GetOrigin();
- return true;
- }
- }
- /*
- ================
- idEntity::GetPhysicsToVisualTransform
- ================
- */
- bool idEntity::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
- return false;
- }
- /*
- ================
- idEntity::GetPhysicsToSoundTransform
- ================
- */
- bool idEntity::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
- // by default play the sound at the center of the bounding box of the first clip model
- if ( GetPhysics()->GetNumClipModels() > 0 ) {
- origin = GetPhysics()->GetBounds().GetCenter();
- axis.Identity();
- return true;
- }
- return false;
- }
- /*
- ================
- idEntity::Collide
- ================
- */
- bool idEntity::Collide( const trace_t &collision, const idVec3 &velocity ) {
- // this entity collides with collision.c.entityNum
- return false;
- }
- /*
- ================
- idEntity::GetImpactInfo
- ================
- */
- void idEntity::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
- GetPhysics()->GetImpactInfo( id, point, info );
- }
- /*
- ================
- idEntity::ApplyImpulse
- ================
- */
- void idEntity::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) {
- GetPhysics()->ApplyImpulse( id, point, impulse );
- }
- /*
- ================
- idEntity::AddForce
- ================
- */
- void idEntity::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
- GetPhysics()->AddForce( id, point, force );
- }
- /*
- ================
- idEntity::ActivatePhysics
- ================
- */
- void idEntity::ActivatePhysics( idEntity *ent ) {
- GetPhysics()->Activate();
- }
- /*
- ================
- idEntity::IsAtRest
- ================
- */
- bool idEntity::IsAtRest() const {
- return GetPhysics()->IsAtRest();
- }
- /*
- ================
- idEntity::GetRestStartTime
- ================
- */
- int idEntity::GetRestStartTime() const {
- return GetPhysics()->GetRestStartTime();
- }
- /*
- ================
- idEntity::AddContactEntity
- ================
- */
- void idEntity::AddContactEntity( idEntity *ent ) {
- GetPhysics()->AddContactEntity( ent );
- }
- /*
- ================
- idEntity::RemoveContactEntity
- ================
- */
- void idEntity::RemoveContactEntity( idEntity *ent ) {
- GetPhysics()->RemoveContactEntity( ent );
- }
- /***********************************************************************
- Damage
-
- ***********************************************************************/
- /*
- ============
- idEntity::CanDamage
- Returns true if the inflictor can directly damage the target. Used for
- explosions and melee attacks.
- ============
- */
- bool idEntity::CanDamage( const idVec3 &origin, idVec3 &damagePoint ) const {
- idVec3 dest;
- trace_t tr;
- idVec3 midpoint;
- // use the midpoint of the bounds instead of the origin, because
- // bmodels may have their origin at 0,0,0
- midpoint = ( GetPhysics()->GetAbsBounds()[0] + GetPhysics()->GetAbsBounds()[1] ) * 0.5;
- dest = midpoint;
- gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
- if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
- damagePoint = tr.endpos;
- return true;
- }
- // this should probably check in the plane of projection, rather than in world coordinate
- dest = midpoint;
- dest[0] += 15.0;
- dest[1] += 15.0;
- gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
- if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
- damagePoint = tr.endpos;
- return true;
- }
- dest = midpoint;
- dest[0] += 15.0;
- dest[1] -= 15.0;
- gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
- if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
- damagePoint = tr.endpos;
- return true;
- }
- dest = midpoint;
- dest[0] -= 15.0;
- dest[1] += 15.0;
- gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
- if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
- damagePoint = tr.endpos;
- return true;
- }
- dest = midpoint;
- dest[0] -= 15.0;
- dest[1] -= 15.0;
- gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
- if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
- damagePoint = tr.endpos;
- return true;
- }
- dest = midpoint;
- dest[2] += 15.0;
- gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
- if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
- damagePoint = tr.endpos;
- return true;
- }
- dest = midpoint;
- dest[2] -= 15.0;
- gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL );
- if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) {
- damagePoint = tr.endpos;
- return true;
- }
- return false;
- }
- /*
- ================
- idEntity::DamageFeedback
- callback function for when another entity received damage from this entity. damage can be adjusted and returned to the caller.
- ================
- */
- void idEntity::DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ) {
- // implemented in subclasses
- }
- /*
- ============
- Damage
- this entity that is being damaged
- inflictor entity that is causing the damage
- attacker entity that caused the inflictor to damage targ
- example: this=monster, inflictor=rocket, attacker=player
- dir direction of the attack for knockback in global space
- point point at which the damage is being inflicted, used for headshots
- damage amount of damage being inflicted
- inflictor, attacker, dir, and point can be NULL for environmental effects
- ============
- */
- void idEntity::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir,
- const char *damageDefName, const float damageScale, const int location ) {
- if ( !fl.takedamage ) {
- return;
- }
- SetTimeState ts( timeGroup );
- if ( !inflictor ) {
- inflictor = gameLocal.world;
- }
- if ( !attacker ) {
- attacker = gameLocal.world;
- }
- const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
- if ( damageDef == NULL ) {
- gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName );
- return;
- }
- int damage = damageDef->GetInt( "damage" );
- // inform the attacker that they hit someone
- attacker->DamageFeedback( this, inflictor, damage );
- if ( damage ) {
- // do the damage
- health -= damage;
- if ( health <= 0 ) {
- if ( health < -999 ) {
- health = -999;
- }
- Killed( inflictor, attacker, damage, dir, location );
- } else {
- Pain( inflictor, attacker, damage, dir, location );
- }
- }
- }
- /*
- ================
- idEntity::AddDamageEffect
- ================
- */
- void idEntity::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) {
- const char *sound, *decal, *key;
- const idDeclEntityDef *def = gameLocal.FindEntityDef( damageDefName, false );
- if ( def == NULL ) {
- return;
- }
- const char *materialType = gameLocal.sufaceTypeNames[ collision.c.material->GetSurfaceType() ];
- // start impact sound based on material type
- key = va( "snd_%s", materialType );
- sound = spawnArgs.GetString( key );
- if ( *sound == '\0' ) {
- sound = def->dict.GetString( key );
- }
- if ( *sound != '\0' ) {
- StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL );
- }
- if ( g_decals.GetBool() ) {
- // place a wound overlay on the model
- key = va( "mtr_wound_%s", materialType );
- decal = spawnArgs.RandomPrefix( key, gameLocal.random );
- if ( *decal == '\0' ) {
- decal = def->dict.RandomPrefix( key, gameLocal.random );
- }
- if ( *decal != '\0' ) {
- idVec3 dir = velocity;
- dir.Normalize();
- ProjectOverlay( collision.c.point, dir, 20.0f, decal );
- }
- }
- }
- /*
- ============
- idEntity::Pain
- Called whenever an entity recieves damage. Returns whether the entity responds to the pain.
- This is a virtual function that subclasses are expected to implement.
- ============
- */
- bool idEntity::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
- return false;
- }
- /*
- ============
- idEntity::Killed
- Called whenever an entity's health is reduced to 0 or less.
- This is a virtual function that subclasses are expected to implement.
- ============
- */
- void idEntity::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
- }
- /***********************************************************************
- Script functions
-
- ***********************************************************************/
- /*
- ================
- idEntity::ShouldConstructScriptObjectAtSpawn
- Called during idEntity::Spawn to see if it should construct the script object or not.
- Overridden by subclasses that need to spawn the script object themselves.
- ================
- */
- bool idEntity::ShouldConstructScriptObjectAtSpawn() const {
- return true;
- }
- /*
- ================
- idEntity::ConstructScriptObject
- Called during idEntity::Spawn. Calls the constructor on the script object.
- Can be overridden by subclasses when a thread doesn't need to be allocated.
- ================
- */
- idThread *idEntity::ConstructScriptObject() {
- idThread *thread;
- const function_t *constructor;
- // init the script object's data
- scriptObject.ClearObject();
- // call script object's constructor
- constructor = scriptObject.GetConstructor();
- if ( constructor ) {
- // start a thread that will initialize after Spawn is done being called
- thread = new idThread();
- thread->SetThreadName( name.c_str() );
- thread->CallFunction( this, constructor, true );
- thread->DelayedStart( 0 );
- } else {
- thread = NULL;
- }
- // clear out the object's memory
- scriptObject.ClearObject();
- return thread;
- }
- /*
- ================
- idEntity::DeconstructScriptObject
- Called during idEntity::~idEntity. Calls the destructor on the script object.
- Can be overridden by subclasses when a thread doesn't need to be allocated.
- Not called during idGameLocal::MapShutdown.
- ================
- */
- void idEntity::DeconstructScriptObject() {
- idThread *thread;
- const function_t *destructor;
- // don't bother calling the script object's destructor on map shutdown
- if ( gameLocal.GameState() == GAMESTATE_SHUTDOWN ) {
- return;
- }
- // call script object's destructor
- destructor = scriptObject.GetDestructor();
- if ( destructor ) {
- // start a thread that will run immediately and be destroyed
- thread = new idThread();
- thread->SetThreadName( name.c_str() );
- thread->CallFunction( this, destructor, true );
- thread->Execute();
- delete thread;
- }
- }
- /*
- ================
- idEntity::HasSignal
- ================
- */
- bool idEntity::HasSignal( signalNum_t signalnum ) const {
- if ( !signals ) {
- return false;
- }
- assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) );
- return ( signals->signal[ signalnum ].Num() > 0 );
- }
- /*
- ================
- idEntity::SetSignal
- ================
- */
- void idEntity::SetSignal( signalNum_t signalnum, idThread *thread, const function_t *function ) {
- int i;
- int num;
- signal_t sig;
- int threadnum;
- assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) );
- if ( !signals ) {
- signals = new (TAG_ENTITY) signalList_t;
- }
- assert( thread );
- threadnum = thread->GetThreadNum();
- num = signals->signal[ signalnum ].Num();
- for( i = 0; i < num; i++ ) {
- if ( signals->signal[ signalnum ][ i ].threadnum == threadnum ) {
- signals->signal[ signalnum ][ i ].function = function;
- return;
- }
- }
- if ( num >= MAX_SIGNAL_THREADS ) {
- thread->Error( "Exceeded maximum number of signals per object" );
- }
- sig.threadnum = threadnum;
- sig.function = function;
- signals->signal[ signalnum ].Append( sig );
- }
- /*
- ================
- idEntity::ClearSignal
- ================
- */
- void idEntity::ClearSignal( idThread *thread, signalNum_t signalnum ) {
- assert( thread );
- if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) {
- gameLocal.Error( "Signal out of range" );
- return;
- }
- if ( signals == NULL ) {
- return;
- }
- signals->signal[ signalnum ].Clear();
- }
- /*
- ================
- idEntity::ClearSignalThread
- ================
- */
- void idEntity::ClearSignalThread( signalNum_t signalnum, idThread *thread ) {
- int i;
- int num;
- int threadnum;
- assert( thread );
- if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) {
- gameLocal.Error( "Signal out of range" );
- return;
- }
- if ( signals == NULL ) {
- return;
- }
- threadnum = thread->GetThreadNum();
- num = signals->signal[ signalnum ].Num();
- for( i = 0; i < num; i++ ) {
- if ( signals->signal[ signalnum ][ i ].threadnum == threadnum ) {
- signals->signal[ signalnum ].RemoveIndex( i );
- return;
- }
- }
- }
- /*
- ================
- idEntity::Signal
- ================
- */
- void idEntity::Signal( signalNum_t signalnum ) {
- int i;
- int num;
- signal_t sigs[ MAX_SIGNAL_THREADS ];
- idThread *thread;
- assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) );
- if ( !signals ) {
- return;
- }
- // we copy the signal list since each thread has the potential
- // to end any of the threads in the list. By copying the list
- // we don't have to worry about the list changing as we're
- // processing it.
- num = signals->signal[ signalnum ].Num();
- for( i = 0; i < num; i++ ) {
- sigs[ i ] = signals->signal[ signalnum ][ i ];
- }
- // clear out the signal list so that we don't get into an infinite loop
- signals->signal[ signalnum ].Clear();
- for( i = 0; i < num; i++ ) {
- thread = idThread::GetThread( sigs[ i ].threadnum );
- if ( thread ) {
- thread->CallFunction( this, sigs[ i ].function, true );
- thread->Execute();
- }
- }
- }
- /*
- ================
- idEntity::SignalEvent
- ================
- */
- void idEntity::SignalEvent( idThread *thread, signalNum_t signalnum ) {
- if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) {
- gameLocal.Error( "Signal out of range" );
- }
- if ( !signals ) {
- return;
- }
- Signal( signalnum );
- }
- /***********************************************************************
- Guis.
-
- ***********************************************************************/
- /*
- ================
- idEntity::TriggerGuis
- ================
- */
- void idEntity::TriggerGuis() {
- int i;
- for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
- if ( renderEntity.gui[ i ] ) {
- renderEntity.gui[ i ]->Trigger( gameLocal.time );
- }
- }
- }
- /*
- ================
- idEntity::HandleGuiCommands
- ================
- */
- bool idEntity::HandleGuiCommands( idEntity *entityGui, const char *cmds ) {
- idEntity *targetEnt;
- bool ret = false;
- if ( entityGui && cmds && *cmds ) {
- idLexer src;
- idToken token, token2, token3, token4;
- src.LoadMemory( cmds, strlen( cmds ), "guiCommands" );
- while( 1 ) {
- if ( !src.ReadToken( &token ) ) {
- return ret;
- }
- if ( token == ";" ) {
- continue;
- }
- if ( token.Icmp( "activate" ) == 0 ) {
- bool targets = true;
- if ( src.ReadToken( &token2 ) ) {
- if ( token2 == ";" ) {
- src.UnreadToken( &token2 );
- } else {
- targets = false;
- }
- }
- if ( targets ) {
- entityGui->ActivateTargets( this );
- } else {
- idEntity *ent = gameLocal.FindEntity( token2 );
- if ( ent ) {
- ent->Signal( SIG_TRIGGER );
- ent->PostEventMS( &EV_Activate, 0, this );
- }
- }
- entityGui->renderEntity.shaderParms[ SHADERPARM_MODE ] = 1.0f;
- continue;
- }
- if ( token.Icmp( "runScript" ) == 0 ) {
- if ( src.ReadToken( &token2 ) ) {
- while( src.CheckTokenString( "::" ) ) {
- idToken token3;
- if ( !src.ReadToken( &token3 ) ) {
- gameLocal.Error( "Expecting function name following '::' in gui for entity '%s'", entityGui->name.c_str() );
- }
- token2 += "::" + token3;
- }
- const function_t *func = gameLocal.program.FindFunction( token2 );
- if ( !func ) {
- gameLocal.Error( "Can't find function '%s' for gui in entity '%s'", token2.c_str(), entityGui->name.c_str() );
- } else {
- idThread *thread = new idThread( func );
- thread->DelayedStart( 0 );
- }
- }
- continue;
- }
- if ( token.Icmp("play") == 0 ) {
- if ( src.ReadToken( &token2 ) ) {
- const idSoundShader *shader = declManager->FindSound(token2);
- entityGui->StartSoundShader( shader, SND_CHANNEL_ANY, 0, false, NULL );
- }
- continue;
- }
- if ( token.Icmp( "setkeyval" ) == 0 ) {
- if ( src.ReadToken( &token2 ) && src.ReadToken(&token3) && src.ReadToken( &token4 ) ) {
- idEntity *ent = gameLocal.FindEntity( token2 );
- if ( ent ) {
- ent->spawnArgs.Set( token3, token4 );
- ent->UpdateChangeableSpawnArgs( NULL );
- ent->UpdateVisuals();
- }
- }
- continue;
- }
- if ( token.Icmp( "setshaderparm" ) == 0 ) {
- if ( src.ReadToken( &token2 ) && src.ReadToken(&token3) ) {
- entityGui->SetShaderParm( atoi( token2 ), atof( token3 ) );
- entityGui->UpdateVisuals();
- }
- continue;
- }
- if ( token.Icmp("close") == 0 ) {
- ret = true;
- continue;
- }
- if ( !token.Icmp( "turkeyscore" ) ) {
- if ( src.ReadToken( &token2 ) && entityGui->renderEntity.gui[0] ) {
- int score = entityGui->renderEntity.gui[0]->State().GetInt( "score" );
- score += atoi( token2 );
- entityGui->renderEntity.gui[0]->SetStateInt( "score", score );
- if ( gameLocal.GetLocalPlayer() && score >= 25000 ) {
- gameLocal.GetLocalPlayer()->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_SCORE_25000_TURKEY_PUNCHER );
- gameLocal.GetLocalPlayer()->GiveEmail( static_cast<const idDeclEmail *>( declManager->FindType( DECL_EMAIL, "highScore", false ) ) );
- }
- }
- continue;
- }
- if ( !token.Icmp( "martianbuddycomplete" ) ) {
- gameLocal.GetLocalPlayer()->GiveEmail( static_cast<const idDeclEmail *>( declManager->FindType( DECL_EMAIL, "MartianBuddyGameComplete", false ) ) );
- continue;
- }
- // handy for debugging GUI stuff
- if ( !token.Icmp( "print" ) ) {
- idStr msg;
- while ( src.ReadToken( &token2 ) ) {
- if ( token2 == ";" ) {
- src.UnreadToken( &token2 );
- break;
- }
- msg += token2.c_str();
- }
- common->Printf( "ent gui 0x%x '%s': %s\n", entityNumber, name.c_str(), msg.c_str() );
- continue;
- }
- // if we get to this point we don't know how to handle it
- src.UnreadToken(&token);
- if ( !HandleSingleGuiCommand( entityGui, &src ) ) {
- // not handled there see if entity or any of its targets can handle it
- // this will only work for one target atm
- if ( entityGui->HandleSingleGuiCommand( entityGui, &src ) ) {
- continue;
- }
- int c = entityGui->targets.Num();
- int i;
- for ( i = 0; i < c; i++) {
- targetEnt = entityGui->targets[ i ].GetEntity();
- if ( targetEnt && targetEnt->HandleSingleGuiCommand( entityGui, &src ) ) {
- break;
- }
- }
- if ( i == c ) {
- // not handled
- common->DPrintf( "idEntity::HandleGuiCommands: '%s' not handled\n", token.c_str() );
- src.ReadToken( &token );
- }
- }
- }
- }
- return ret;
- }
- /*
- ================
- idEntity::HandleSingleGuiCommand
- ================
- */
- bool idEntity::HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ) {
- return false;
- }
- /***********************************************************************
- Targets
-
- ***********************************************************************/
- /*
- ===============
- idEntity::FindTargets
- We have to wait until all entities are spawned
- Used to build lists of targets after the entity is spawned. Since not all entities
- have been spawned when the entity is created at map load time, we have to wait
- ===============
- */
- void idEntity::FindTargets() {
- int i;
- // targets can be a list of multiple names
- gameLocal.GetTargets( spawnArgs, targets, "target" );
- // ensure that we don't target ourselves since that could cause an infinite loop when activating entities
- for( i = 0; i < targets.Num(); i++ ) {
- if ( targets[ i ].GetEntity() == this ) {
- gameLocal.Error( "Entity '%s' is targeting itself", name.c_str() );
- }
- }
- }
- /*
- ================
- idEntity::RemoveNullTargets
- ================
- */
- void idEntity::RemoveNullTargets() {
- int i;
- for( i = targets.Num() - 1; i >= 0; i-- ) {
- if ( !targets[ i ].GetEntity() ) {
- targets.RemoveIndex( i );
- }
- }
- }
- /*
- ==============================
- idEntity::ActivateTargets
- "activator" should be set to the entity that initiated the firing.
- ==============================
- */
- void idEntity::ActivateTargets( idEntity *activator ) const {
- idEntity *ent;
- int i, j;
-
- for( i = 0; i < targets.Num(); i++ ) {
- ent = targets[ i ].GetEntity();
- if ( !ent ) {
- continue;
- }
- if ( ent->RespondsTo( EV_Activate ) || ent->HasSignal( SIG_TRIGGER ) ) {
- ent->Signal( SIG_TRIGGER );
- ent->ProcessEvent( &EV_Activate, activator );
- }
- for ( j = 0; j < MAX_RENDERENTITY_GUI; j++ ) {
- if ( ent->renderEntity.gui[ j ] ) {
- ent->renderEntity.gui[ j ]->Trigger( gameLocal.time );
- }
- }
- }
- }
- /***********************************************************************
- Misc.
-
- ***********************************************************************/
- /*
- ================
- idEntity::Teleport
- ================
- */
- void idEntity::Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ) {
- GetPhysics()->SetOrigin( origin );
- GetPhysics()->SetAxis( angles.ToMat3() );
- UpdateVisuals();
- }
- /*
- ============
- idEntity::TouchTriggers
- Activate all trigger entities touched at the current position.
- ============
- */
- bool idEntity::TouchTriggers() const {
- int i, numClipModels, numEntities;
- idClipModel * cm;
- idClipModel * clipModels[ MAX_GENTITIES ];
- idEntity * ent;
- trace_t trace;
- memset( &trace, 0, sizeof( trace ) );
- trace.endpos = GetPhysics()->GetOrigin();
- trace.endAxis = GetPhysics()->GetAxis();
- numClipModels = gameLocal.clip.ClipModelsTouchingBounds( GetPhysics()->GetAbsBounds(), CONTENTS_TRIGGER, clipModels, MAX_GENTITIES );
- numEntities = 0;
- for ( i = 0; i < numClipModels; i++ ) {
- cm = clipModels[ i ];
- // don't touch it if we're the owner
- if ( cm->GetOwner() == this ) {
- continue;
- }
- ent = cm->GetEntity();
- if ( !ent->RespondsTo( EV_Touch ) && !ent->HasSignal( SIG_TOUCH ) ) {
- continue;
- }
- if ( !GetPhysics()->ClipContents( cm ) ) {
- continue;
- }
- SetTimeState ts( ent->timeGroup );
- numEntities++;
- trace.c.contents = cm->GetContents();
- trace.c.entityNum = cm->GetEntity()->entityNumber;
- trace.c.id = cm->GetId();
- ent->Signal( SIG_TOUCH );
- ent->ProcessEvent( &EV_Touch, this, &trace );
- if ( !gameLocal.entities[ entityNumber ] ) {
- gameLocal.Printf( "entity was removed while touching triggers\n" );
- return true;
- }
- }
- return ( numEntities != 0 );
- }
- /*
- ================
- idEntity::GetSpline
- ================
- */
- idCurve_Spline<idVec3> *idEntity::GetSpline() const {
- int i, numPoints, t;
- const idKeyValue *kv;
- idLexer lex;
- idVec3 v;
- idCurve_Spline<idVec3> *spline;
- const char *curveTag = "curve_";
- kv = spawnArgs.MatchPrefix( curveTag );
- if ( !kv ) {
- return NULL;
- }
- idStr str = kv->GetKey().Right( kv->GetKey().Length() - strlen( curveTag ) );
- if ( str.Icmp( "CatmullRomSpline" ) == 0 ) {
- spline = new (TAG_ENTITY) idCurve_CatmullRomSpline<idVec3>();
- } else if ( str.Icmp( "nubs" ) == 0 ) {
- spline = new (TAG_ENTITY) idCurve_NonUniformBSpline<idVec3>();
- } else if ( str.Icmp( "nurbs" ) == 0 ) {
- spline = new (TAG_ENTITY) idCurve_NURBS<idVec3>();
- } else {
- spline = new (TAG_ENTITY) idCurve_BSpline<idVec3>();
- }
- spline->SetBoundaryType( idCurve_Spline<idVec3>::BT_CLAMPED );
- lex.LoadMemory( kv->GetValue(), kv->GetValue().Length(), curveTag );
- numPoints = lex.ParseInt();
- lex.ExpectTokenString( "(" );
- for ( t = i = 0; i < numPoints; i++, t += 100 ) {
- v.x = lex.ParseFloat();
- v.y = lex.ParseFloat();
- v.z = lex.ParseFloat();
- spline->AddValue( t, v );
- }
- lex.ExpectTokenString( ")" );
- return spline;
- }
- /*
- ===============
- idEntity::ShowEditingDialog
- ===============
- */
- void idEntity::ShowEditingDialog() {
- }
- /***********************************************************************
- Events
-
- ***********************************************************************/
- /*
- ================
- idEntity::Event_GetName
- ================
- */
- void idEntity::Event_GetName() {
- idThread::ReturnString( name.c_str() );
- }
- /*
- ================
- idEntity::Event_SetName
- ================
- */
- void idEntity::Event_SetName( const char *newname ) {
- SetName( newname );
- }
- /*
- ===============
- idEntity::Event_FindTargets
- ===============
- */
- void idEntity::Event_FindTargets() {
- FindTargets();
- }
- /*
- ============
- idEntity::Event_ActivateTargets
- Activates any entities targeted by this entity. Mainly used as an
- event to delay activating targets.
- ============
- */
- void idEntity::Event_ActivateTargets( idEntity *activator ) {
- ActivateTargets( activator );
- }
- /*
- ================
- idEntity::Event_NumTargets
- ================
- */
- void idEntity::Event_NumTargets() {
- idThread::ReturnFloat( targets.Num() );
- }
- /*
- ================
- idEntity::Event_GetTarget
- ================
- */
- void idEntity::Event_GetTarget( float index ) {
- int i;
- i = ( int )index;
- if ( ( i < 0 ) || i >= targets.Num() ) {
- idThread::ReturnEntity( NULL );
- } else {
- idThread::ReturnEntity( targets[ i ].GetEntity() );
- }
- }
- /*
- ================
- idEntity::Event_RandomTarget
- ================
- */
- void idEntity::Event_RandomTarget( const char *ignore ) {
- int num;
- idEntity *ent;
- int i;
- int ignoreNum;
- RemoveNullTargets();
- if ( !targets.Num() ) {
- idThread::ReturnEntity( NULL );
- return;
- }
- ignoreNum = -1;
- if ( ignore && ( ignore[ 0 ] != 0 ) && ( targets.Num() > 1 ) ) {
- for( i = 0; i < targets.Num(); i++ ) {
- ent = targets[ i ].GetEntity();
- if ( ent && ( ent->name == ignore ) ) {
- ignoreNum = i;
- break;
- }
- }
- }
- if ( ignoreNum >= 0 ) {
- num = gameLocal.random.RandomInt( targets.Num() - 1 );
- if ( num >= ignoreNum ) {
- num++;
- }
- } else {
- num = gameLocal.random.RandomInt( targets.Num() );
- }
- ent = targets[ num ].GetEntity();
- idThread::ReturnEntity( ent );
- }
- /*
- ================
- idEntity::Event_BindToJoint
- ================
- */
- void idEntity::Event_BindToJoint( idEntity *master, const char *jointname, float orientated ) {
- BindToJoint( master, jointname, ( orientated != 0.0f ) );
- }
- /*
- ================
- idEntity::Event_RemoveBinds
- ================
- */
- void idEntity::Event_RemoveBinds() {
- RemoveBinds();
- }
- /*
- ================
- idEntity::Event_Bind
- ================
- */
- void idEntity::Event_Bind( idEntity *master ) {
- Bind( master, true );
- }
- /*
- ================
- idEntity::Event_BindPosition
- ================
- */
- void idEntity::Event_BindPosition( idEntity *master ) {
- Bind( master, false );
- }
- /*
- ================
- idEntity::Event_Unbind
- ================
- */
- void idEntity::Event_Unbind() {
- Unbind();
- }
- /*
- ================
- idEntity::Event_SpawnBind
- ================
- */
- void idEntity::Event_SpawnBind() {
- idEntity *parent;
- const char *bind, *joint, *bindanim;
- jointHandle_t bindJoint;
- bool bindOrientated;
- int id;
- const idAnim *anim;
- int animNum;
- idAnimator *parentAnimator;
-
- if ( spawnArgs.GetString( "bind", "", &bind ) ) {
- if ( idStr::Icmp( bind, "worldspawn" ) == 0 ) {
- //FIXME: Completely unneccessary since the worldspawn is called "world"
- parent = gameLocal.world;
- } else {
- parent = gameLocal.FindEntity( bind );
- }
- bindOrientated = spawnArgs.GetBool( "bindOrientated", "1" );
- if ( parent ) {
- // bind to a joint of the skeletal model of the parent
- if ( spawnArgs.GetString( "bindToJoint", "", &joint ) && *joint ) {
- parentAnimator = parent->GetAnimator();
- if ( parentAnimator == NULL ) {
- gameLocal.Error( "Cannot bind to joint '%s' on '%s'. Entity does not support skeletal models.", joint, name.c_str() );
- return;
- }
- bindJoint = parentAnimator->GetJointHandle( joint );
- if ( bindJoint == INVALID_JOINT ) {
- gameLocal.Error( "Joint '%s' not found for bind on '%s'", joint, name.c_str() );
- }
- // bind it relative to a specific anim
- if ( ( parent->spawnArgs.GetString( "bindanim", "", &bindanim ) || parent->spawnArgs.GetString( "anim", "", &bindanim ) ) && *bindanim ) {
- animNum = parentAnimator->GetAnim( bindanim );
- if ( !animNum ) {
- gameLocal.Error( "Anim '%s' not found for bind on '%s'", bindanim, name.c_str() );
- }
- anim = parentAnimator->GetAnim( animNum );
- if ( !anim ) {
- gameLocal.Error( "Anim '%s' not found for bind on '%s'", bindanim, name.c_str() );
- }
- // make sure parent's render origin has been set
- parent->UpdateModelTransform();
- //FIXME: need a BindToJoint that accepts a joint position
- parentAnimator->CreateFrame( gameLocal.time, true );
- idJointMat *frame = parent->renderEntity.joints;
- gameEdit->ANIM_CreateAnimFrame( parentAnimator->ModelHandle(), anim->MD5Anim( 0 ), parent->renderEntity.numJoints, frame, 0, parentAnimator->ModelDef()->GetVisualOffset(), parentAnimator->RemoveOrigin() );
- BindToJoint( parent, joint, bindOrientated );
- parentAnimator->ForceUpdate();
- } else {
- BindToJoint( parent, joint, bindOrientated );
- }
- }
- // bind to a body of the physics object of the parent
- else if ( spawnArgs.GetInt( "bindToBody", "0", id ) ) {
- BindToBody( parent, id, bindOrientated );
- }
- // bind to the parent
- else {
- Bind( parent, bindOrientated );
- }
- }
- }
- }
- /*
- ================
- idEntity::Event_SetOwner
- ================
- */
- void idEntity::Event_SetOwner( idEntity *owner ) {
- int i;
- for ( i = 0; i < GetPhysics()->GetNumClipModels(); i++ ) {
- GetPhysics()->GetClipModel( i )->SetOwner( owner );
- }
- }
- /*
- ================
- idEntity::Event_SetModel
- ================
- */
- void idEntity::Event_SetModel( const char *modelname ) {
- SetModel( modelname );
- }
- /*
- ================
- idEntity::Event_SetSkin
- ================
- */
- void idEntity::Event_SetSkin( const char *skinname ) {
- renderEntity.customSkin = declManager->FindSkin( skinname );
- UpdateVisuals();
- }
- /*
- ================
- idEntity::Event_GetShaderParm
- ================
- */
- void idEntity::Event_GetShaderParm( int parmnum ) {
- if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
- gameLocal.Error( "shader parm index (%d) out of range", parmnum );
- return;
- }
- idThread::ReturnFloat( renderEntity.shaderParms[ parmnum ] );
- }
- /*
- ================
- idEntity::Event_SetShaderParm
- ================
- */
- void idEntity::Event_SetShaderParm( int parmnum, float value ) {
- SetShaderParm( parmnum, value );
- }
- /*
- ================
- idEntity::Event_SetShaderParms
- ================
- */
- void idEntity::Event_SetShaderParms( float parm0, float parm1, float parm2, float parm3 ) {
- renderEntity.shaderParms[ SHADERPARM_RED ] = parm0;
- renderEntity.shaderParms[ SHADERPARM_GREEN ] = parm1;
- renderEntity.shaderParms[ SHADERPARM_BLUE ] = parm2;
- renderEntity.shaderParms[ SHADERPARM_ALPHA ] = parm3;
- UpdateVisuals();
- }
- /*
- ================
- idEntity::Event_SetColor
- ================
- */
- void idEntity::Event_SetColor( float red, float green, float blue ) {
- SetColor( red, green, blue );
- }
- /*
- ================
- idEntity::Event_GetColor
- ================
- */
- void idEntity::Event_GetColor() {
- idVec3 out;
- GetColor( out );
- idThread::ReturnVector( out );
- }
- /*
- ================
- idEntity::Event_IsHidden
- ================
- */
- void idEntity::Event_IsHidden() {
- idThread::ReturnInt( fl.hidden );
- }
- /*
- ================
- idEntity::Event_Hide
- ================
- */
- void idEntity::Event_Hide() {
- Hide();
- }
- /*
- ================
- idEntity::Event_Show
- ================
- */
- void idEntity::Event_Show() {
- Show();
- }
- /*
- ================
- idEntity::Event_CacheSoundShader
- ================
- */
- void idEntity::Event_CacheSoundShader( const char *soundName ) {
- declManager->FindSound( soundName );
- }
- /*
- ================
- idEntity::Event_StartSoundShader
- ================
- */
- void idEntity::Event_StartSoundShader( const char *soundName, int channel ) {
- int length = 0;
- if ( soundName == NULL || soundName[0] == 0 ) {
- StopSound( channel, false );
- } else {
- StartSoundShader( declManager->FindSound( soundName ), (s_channelType)channel, 0, false, &length );
- }
- idThread::ReturnFloat( MS2SEC( length ) );
- }
- /*
- ================
- idEntity::Event_StopSound
- ================
- */
- void idEntity::Event_StopSound( int channel, int netSync ) {
- StopSound( channel, ( netSync != 0 ) );
- }
- /*
- ================
- idEntity::Event_StartSound
- ================
- */
- void idEntity::Event_StartSound( const char *soundName, int channel, int netSync ) {
- int time;
-
- StartSound( soundName, ( s_channelType )channel, 0, ( netSync != 0 ), &time );
- idThread::ReturnFloat( MS2SEC( time ) );
- }
- /*
- ================
- idEntity::Event_FadeSound
- ================
- */
- void idEntity::Event_FadeSound( int channel, float to, float over ) {
- if ( refSound.referenceSound ) {
- refSound.referenceSound->FadeSound( channel, to, over );
- }
- }
- /*
- ================
- idEntity::Event_GetWorldOrigin
- ================
- */
- void idEntity::Event_GetWorldOrigin() {
- idThread::ReturnVector( GetPhysics()->GetOrigin() );
- }
- /*
- ================
- idEntity::Event_SetWorldOrigin
- ================
- */
- void idEntity::Event_SetWorldOrigin( idVec3 const &org ) {
- idVec3 neworg = GetLocalCoordinates( org );
- SetOrigin( neworg );
- }
- /*
- ================
- idEntity::Event_SetOrigin
- ================
- */
- void idEntity::Event_SetOrigin( idVec3 const &org ) {
- SetOrigin( org );
- }
- /*
- ================
- idEntity::Event_GetOrigin
- ================
- */
- void idEntity::Event_GetOrigin() {
- idThread::ReturnVector( GetLocalCoordinates( GetPhysics()->GetOrigin() ) );
- }
- /*
- ================
- idEntity::Event_SetAngles
- ================
- */
- void idEntity::Event_SetAngles( idAngles const &ang ) {
- SetAngles( ang );
- }
- /*
- ================
- idEntity::Event_GetAngles
- ================
- */
- void idEntity::Event_GetAngles() {
- idAngles ang = GetPhysics()->GetAxis().ToAngles();
- idThread::ReturnVector( idVec3( ang[0], ang[1], ang[2] ) );
- }
- /*
- ================
- idEntity::Event_SetLinearVelocity
- ================
- */
- void idEntity::Event_SetLinearVelocity( const idVec3 &velocity ) {
- GetPhysics()->SetLinearVelocity( velocity );
- }
- /*
- ================
- idEntity::Event_GetLinearVelocity
- ================
- */
- void idEntity::Event_GetLinearVelocity() {
- idThread::ReturnVector( GetPhysics()->GetLinearVelocity() );
- }
- /*
- ================
- idEntity::Event_SetAngularVelocity
- ================
- */
- void idEntity::Event_SetAngularVelocity( const idVec3 &velocity ) {
- GetPhysics()->SetAngularVelocity( velocity );
- }
- /*
- ================
- idEntity::Event_GetAngularVelocity
- ================
- */
- void idEntity::Event_GetAngularVelocity() {
- idThread::ReturnVector( GetPhysics()->GetAngularVelocity() );
- }
- /*
- ================
- idEntity::Event_SetSize
- ================
- */
- void idEntity::Event_SetSize( idVec3 const &mins, idVec3 const &maxs ) {
- GetPhysics()->SetClipBox( idBounds( mins, maxs ), 1.0f );
- }
- /*
- ================
- idEntity::Event_GetSize
- ================
- */
- void idEntity::Event_GetSize() {
- idBounds bounds;
- bounds = GetPhysics()->GetBounds();
- idThread::ReturnVector( bounds[1] - bounds[0] );
- }
- /*
- ================
- idEntity::Event_GetMins
- ================
- */
- void idEntity::Event_GetMins() {
- idThread::ReturnVector( GetPhysics()->GetBounds()[0] );
- }
- /*
- ================
- idEntity::Event_GetMaxs
- ================
- */
- void idEntity::Event_GetMaxs() {
- idThread::ReturnVector( GetPhysics()->GetBounds()[1] );
- }
- /*
- ================
- idEntity::Event_Touches
- ================
- */
- void idEntity::Event_Touches( idEntity *ent ) {
- if ( !ent ) {
- idThread::ReturnInt( false );
- return;
- }
- const idBounds &myBounds = GetPhysics()->GetAbsBounds();
- const idBounds &entBounds = ent->GetPhysics()->GetAbsBounds();
- idThread::ReturnInt( myBounds.IntersectsBounds( entBounds ) );
- }
- /*
- ================
- idEntity::Event_SetGuiParm
- ================
- */
- void idEntity::Event_SetGuiParm( const char *key, const char *val ) {
- for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
- if ( renderEntity.gui[ i ] ) {
- if ( idStr::Icmpn( key, "gui_", 4 ) == 0 ) {
- spawnArgs.Set( key, val );
- }
- renderEntity.gui[ i ]->SetStateString( key, val );
- renderEntity.gui[ i ]->StateChanged( gameLocal.time );
- }
- }
- }
- /*
- ================
- idEntity::Event_SetGuiParm
- ================
- */
- void idEntity::Event_SetGuiFloat( const char *key, float f ) {
- for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
- if ( renderEntity.gui[ i ] ) {
- renderEntity.gui[ i ]->SetStateString( key, va( "%f", f ) );
- renderEntity.gui[ i ]->StateChanged( gameLocal.time );
- }
- }
- }
- /*
- ================
- idEntity::Event_GetNextKey
- ================
- */
- void idEntity::Event_GetNextKey( const char *prefix, const char *lastMatch ) {
- const idKeyValue *kv;
- const idKeyValue *previous;
- if ( *lastMatch ) {
- previous = spawnArgs.FindKey( lastMatch );
- } else {
- previous = NULL;
- }
- kv = spawnArgs.MatchPrefix( prefix, previous );
- if ( !kv ) {
- idThread::ReturnString( "" );
- } else {
- idThread::ReturnString( kv->GetKey() );
- }
- }
- /*
- ================
- idEntity::Event_SetKey
- ================
- */
- void idEntity::Event_SetKey( const char *key, const char *value ) {
- spawnArgs.Set( key, value );
- UpdateChangeableSpawnArgs( NULL );
- }
- /*
- ================
- idEntity::Event_GetKey
- ================
- */
- void idEntity::Event_GetKey( const char *key ) {
- const char *value;
- spawnArgs.GetString( key, "", &value );
- idThread::ReturnString( value );
- }
- /*
- ================
- idEntity::Event_GetIntKey
- ================
- */
- void idEntity::Event_GetIntKey( const char *key ) {
- int value;
- spawnArgs.GetInt( key, "0", value );
- // scripts only support floats
- idThread::ReturnFloat( value );
- }
- /*
- ================
- idEntity::Event_GetFloatKey
- ================
- */
- void idEntity::Event_GetFloatKey( const char *key ) {
- float value;
- spawnArgs.GetFloat( key, "0", value );
- idThread::ReturnFloat( value );
- }
- /*
- ================
- idEntity::Event_GetVectorKey
- ================
- */
- void idEntity::Event_GetVectorKey( const char *key ) {
- idVec3 value;
- spawnArgs.GetVector( key, "0 0 0", value );
- idThread::ReturnVector( value );
- }
- /*
- ================
- idEntity::Event_GetEntityKey
- ================
- */
- void idEntity::Event_GetEntityKey( const char *key ) {
- idEntity *ent;
- const char *entname;
- if ( !spawnArgs.GetString( key, NULL, &entname ) ) {
- idThread::ReturnEntity( NULL );
- return;
- }
- ent = gameLocal.FindEntity( entname );
- if ( !ent ) {
- gameLocal.Warning( "Couldn't find entity '%s' specified in '%s' key in entity '%s'", entname, key, name.c_str() );
- }
- idThread::ReturnEntity( ent );
- }
- /*
- ================
- idEntity::Event_RestorePosition
- ================
- */
- void idEntity::Event_RestorePosition() {
- idVec3 org;
- idAngles angles;
- idMat3 axis;
- idEntity * part;
- spawnArgs.GetVector( "origin", "0 0 0", org );
- // get the rotation matrix in either full form, or single angle form
- if ( spawnArgs.GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", axis ) ) {
- angles = axis.ToAngles();
- } else {
- angles[ 0 ] = 0;
- angles[ 1 ] = spawnArgs.GetFloat( "angle" );
- angles[ 2 ] = 0;
- }
- Teleport( org, angles, NULL );
- for ( part = teamChain; part != NULL; part = part->teamChain ) {
- if ( part->bindMaster != this ) {
- continue;
- }
- if ( part->GetPhysics()->IsType( idPhysics_Parametric::Type ) ) {
- if ( static_cast<idPhysics_Parametric *>(part->GetPhysics())->IsPusher() ) {
- gameLocal.Warning( "teleported '%s' which has the pushing mover '%s' bound to it\n", GetName(), part->GetName() );
- }
- } else if ( part->GetPhysics()->IsType( idPhysics_AF::Type ) ) {
- gameLocal.Warning( "teleported '%s' which has the articulated figure '%s' bound to it\n", GetName(), part->GetName() );
- }
- }
- }
- /*
- ================
- idEntity::Event_UpdateCameraTarget
- ================
- */
- void idEntity::Event_UpdateCameraTarget() {
- const char *target;
- const idKeyValue *kv;
- idVec3 dir;
- target = spawnArgs.GetString( "cameraTarget" );
- cameraTarget = gameLocal.FindEntity( target );
- if ( cameraTarget != NULL ) {
- kv = cameraTarget->spawnArgs.MatchPrefix( "target", NULL );
- while( kv ) {
- idEntity *ent = gameLocal.FindEntity( kv->GetValue() );
- if ( ent != NULL && idStr::Icmp( ent->GetEntityDefName(), "target_null" ) == 0) {
- dir = ent->GetPhysics()->GetOrigin() - cameraTarget->GetPhysics()->GetOrigin();
- dir.Normalize();
- cameraTarget->SetAxis( dir.ToMat3() );
- SetAxis(dir.ToMat3());
- break;
- }
- kv = cameraTarget->spawnArgs.MatchPrefix( "target", kv );
- }
- }
- UpdateVisuals();
- }
- /*
- ================
- idEntity::Event_DistanceTo
- ================
- */
- void idEntity::Event_DistanceTo( idEntity *ent ) {
- if ( !ent ) {
- // just say it's really far away
- idThread::ReturnFloat( MAX_WORLD_SIZE );
- } else {
- float dist = ( GetPhysics()->GetOrigin() - ent->GetPhysics()->GetOrigin() ).LengthFast();
- idThread::ReturnFloat( dist );
- }
- }
- /*
- ================
- idEntity::Event_DistanceToPoint
- ================
- */
- void idEntity::Event_DistanceToPoint( const idVec3 &point ) {
- float dist = ( GetPhysics()->GetOrigin() - point ).LengthFast();
- idThread::ReturnFloat( dist );
- }
- /*
- ================
- idEntity::Event_StartFx
- ================
- */
- void idEntity::Event_StartFx( const char *fx ) {
- idEntityFx::StartFx( fx, NULL, NULL, this, true );
- }
- /*
- ================
- idEntity::Event_WaitFrame
- ================
- */
- void idEntity::Event_WaitFrame() {
- idThread *thread;
-
- thread = idThread::CurrentThread();
- if ( thread ) {
- thread->WaitFrame();
- }
- }
- /*
- =====================
- idEntity::Event_Wait
- =====================
- */
- void idEntity::Event_Wait( float time ) {
- idThread *thread = idThread::CurrentThread();
- if ( thread == NULL ) {
- gameLocal.Error( "Event 'wait' called from outside thread" );
- return;
- }
- thread->WaitSec( time );
- }
- /*
- =====================
- idEntity::Event_HasFunction
- =====================
- */
- void idEntity::Event_HasFunction( const char *name ) {
- const function_t *func;
- func = scriptObject.GetFunction( name );
- if ( func ) {
- idThread::ReturnInt( true );
- } else {
- idThread::ReturnInt( false );
- }
- }
- /*
- =====================
- idEntity::Event_CallFunction
- =====================
- */
- void idEntity::Event_CallFunction( const char *funcname ) {
- const function_t *func;
- idThread *thread;
- thread = idThread::CurrentThread();
- if ( thread == NULL ) {
- gameLocal.Error( "Event 'callFunction' called from outside thread" );
- return;
- }
- func = scriptObject.GetFunction( funcname );
- if ( func == NULL ) {
- gameLocal.Error( "Unknown function '%s' in '%s'", funcname, scriptObject.GetTypeName() );
- return;
- }
- if ( func->type->NumParameters() != 1 ) {
- gameLocal.Error( "Function '%s' has the wrong number of parameters for 'callFunction'", funcname );
- return;
- }
- if ( !scriptObject.GetTypeDef()->Inherits( func->type->GetParmType( 0 ) ) ) {
- gameLocal.Error( "Function '%s' is the wrong type for 'callFunction'", funcname );
- return;
- }
- // function args will be invalid after this call
- thread->CallFunction( this, func, false );
- }
- /*
- ================
- idEntity::Event_SetNeverDormant
- ================
- */
- void idEntity::Event_SetNeverDormant( int enable ) {
- fl.neverDormant = ( enable != 0 );
- dormantStart = 0;
- }
- /*
- ================
- idEntity::Event_SetGui
- ================
- * BSM Nerve: Allows guis to be changed at runtime. Guis that are
- * loaded after the level loads should be precahced using PrecacheGui.
- */
- void idEntity::Event_SetGui( int guiNum, const char *guiName) {
- idUserInterface** gui = NULL;
- if ( guiNum >= 1 && guiNum <= MAX_RENDERENTITY_GUI ) {
- gui = &renderEntity.gui[ guiNum-1 ];
- }
- if( gui ) {
- *gui = uiManager->FindGui( guiName, true, false );
- UpdateGuiParms( *gui, &spawnArgs );
- UpdateChangeableSpawnArgs( NULL );
- gameRenderWorld->UpdateEntityDef(modelDefHandle, &renderEntity);
- } else {
- gameLocal.Error( "Entity '%s' doesn't have a GUI %d", name.c_str(), guiNum );
- }
- }
- /*
- ================
- idEntity::Event_PrecacheGui
- ================
- * BSM Nerve: Forces the engine to initialize a gui even if it is not specified as used in a level.
- * This is useful for preventing load hitches when switching guis during the game using "setGui"
- */
- void idEntity::Event_PrecacheGui( const char *guiName ) {
- uiManager->FindGui( guiName, true, true );
- }
- void idEntity::Event_GetGuiParm(int guiNum, const char *key) {
- if(renderEntity.gui[guiNum-1]) {
- idThread::ReturnString(renderEntity.gui[guiNum-1]->GetStateString(key));
- return;
- }
- idThread::ReturnString("");
- }
- void idEntity::Event_GetGuiParmFloat(int guiNum, const char *key) {
- if(renderEntity.gui[guiNum-1]) {
- idThread::ReturnFloat(renderEntity.gui[guiNum-1]->GetStateFloat(key));
- return;
- }
- idThread::ReturnFloat(0.0f);
- }
- void idEntity::Event_GuiNamedEvent(int guiNum, const char *event) {
- if(renderEntity.gui[guiNum-1]) {
- renderEntity.gui[guiNum-1]->HandleNamedEvent(event);
- }
- }
- /***********************************************************************
- Network
-
- ***********************************************************************/
- /*
- ================
- idEntity::ClientThink
- ================
- */
- void idEntity::ClientThink( const int curTime, const float fraction, const bool predict ) {
- InterpolatePhysics( fraction );
- Present();
- }
- /*
- ================
- idEntity::ClientPredictionThink
- ================
- */
- void idEntity::ClientPredictionThink() {
- RunPhysics();
- Present();
- }
- /*
- ================
- idEntity::WriteBindToSnapshot
- ================
- */
- void idEntity::WriteBindToSnapshot( idBitMsg &msg ) const {
- int bindInfo;
- if ( bindMaster ) {
- bindInfo = bindMaster->entityNumber;
- bindInfo |= ( fl.bindOrientated & 1 ) << GENTITYNUM_BITS;
- if ( bindJoint != INVALID_JOINT ) {
- bindInfo |= 1 << ( GENTITYNUM_BITS + 1 );
- bindInfo |= bindJoint << ( 3 + GENTITYNUM_BITS );
- } else if ( bindBody != -1 ) {
- bindInfo |= 2 << ( GENTITYNUM_BITS + 1 );
- bindInfo |= bindBody << ( 3 + GENTITYNUM_BITS );
- }
- } else {
- bindInfo = ENTITYNUM_NONE;
- }
- msg.WriteBits( bindInfo, GENTITYNUM_BITS + 3 + 9 );
- }
- /*
- ================
- idEntity::ReadBindFromSnapshot
- ================
- */
- void idEntity::ReadBindFromSnapshot( const idBitMsg &msg ) {
- int bindInfo, bindEntityNum, bindPos;
- bool bindOrientated;
- idEntity *master;
- bindInfo = msg.ReadBits( GENTITYNUM_BITS + 3 + 9 );
- bindEntityNum = bindInfo & ( ( 1 << GENTITYNUM_BITS ) - 1 );
- if ( ( bindEntityNum != ENTITYNUM_NONE ) && ( bindEntityNum < MAX_GENTITIES ) ) {
- master = gameLocal.entities[ bindEntityNum ];
- bindOrientated = ( bindInfo >> GENTITYNUM_BITS ) & 1;
- bindPos = ( bindInfo >> ( GENTITYNUM_BITS + 3 ) );
- switch( ( bindInfo >> ( GENTITYNUM_BITS + 1 ) ) & 3 ) {
- case 1: {
- BindToJoint( master, (jointHandle_t) bindPos, bindOrientated );
- break;
- }
- case 2: {
- BindToBody( master, bindPos, bindOrientated );
- break;
- }
- default: {
- Bind( master, bindOrientated );
- break;
- }
- }
- } else if ( bindMaster ) {
- Unbind();
- }
- }
- /*
- ================
- idEntity::WriteColorToSnapshot
- ================
- */
- void idEntity::WriteColorToSnapshot( idBitMsg &msg ) const {
- idVec4 color;
- color[0] = renderEntity.shaderParms[ SHADERPARM_RED ];
- color[1] = renderEntity.shaderParms[ SHADERPARM_GREEN ];
- color[2] = renderEntity.shaderParms[ SHADERPARM_BLUE ];
- color[3] = renderEntity.shaderParms[ SHADERPARM_ALPHA ];
- msg.WriteLong( PackColor( color ) );
- }
- /*
- ================
- idEntity::ReadColorFromSnapshot
- ================
- */
- void idEntity::ReadColorFromSnapshot( const idBitMsg &msg ) {
- idVec4 color;
- UnpackColor( msg.ReadLong(), color );
- renderEntity.shaderParms[ SHADERPARM_RED ] = color[0];
- renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[1];
- renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[2];
- renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[3];
- }
- /*
- ================
- idEntity::WriteGUIToSnapshot
- ================
- */
- void idEntity::WriteGUIToSnapshot( idBitMsg &msg ) const {
- // no need to loop over MAX_RENDERENTITY_GUI at this time
- if ( renderEntity.gui[ 0 ] ) {
- msg.WriteByte( renderEntity.gui[ 0 ]->State().GetInt( "networkState" ) );
- } else {
- msg.WriteByte( 0 );
- }
- }
- /*
- ================
- idEntity::ReadGUIFromSnapshot
- ================
- */
- void idEntity::ReadGUIFromSnapshot( const idBitMsg &msg ) {
- int state;
- idUserInterface *gui;
- state = msg.ReadByte( );
- gui = renderEntity.gui[ 0 ];
- if ( gui && state != mpGUIState ) {
- mpGUIState = state;
- gui->SetStateInt( "networkState", state );
- gui->HandleNamedEvent( "networkState" );
- }
- }
- /*
- ================
- idEntity::WriteToSnapshot
- ================
- */
- void idEntity::WriteToSnapshot( idBitMsg &msg ) const {
- }
- /*
- ================
- idEntity::ReadFromSnapshot
- ================
- */
- void idEntity::ReadFromSnapshot( const idBitMsg &msg ) {
- }
- /*
- ================
- idEntity::ReadFromSnapshot_Ex
- Increments the snapshot counter for the entity.
- ================
- */
- void idEntity::ReadFromSnapshot_Ex( const idBitMsg &msg ) {
- snapshotsReceived += 1;
- ReadFromSnapshot( msg );
- }
- /*
- ================
- idEntity::FlagNewSnapshot
- Updates the interpolationBehavior so that subclasses will know if it's safe to interpolate.
- Only call this when a new snapshot has been received for this entity!
- ================
- */
- void idEntity::FlagNewSnapshot() {
- switch( interpolationBehavior ) {
- case USE_NO_INTERPOLATION: {
- interpolationBehavior = USE_LATEST_SNAP_ONLY;
- break;
- }
- case USE_LATEST_SNAP_ONLY: {
- interpolationBehavior = USE_INTERPOLATION;
- break;
- }
- default: {
- break;
- }
- }
- }
- /*
- ================
- idEntity::ServerSendEvent
- Saved events are also sent to any client that connects late so all clients
- always receive the events nomatter what time they join the game.
- ================
- */
- void idEntity::ServerSendEvent( int eventId, const idBitMsg *msg, bool saveEvent, lobbyUserID_t excluding ) const {
- idBitMsg outMsg;
- byte msgBuf[MAX_GAME_MESSAGE_SIZE];
- if ( !common->IsServer() ) {
- return;
- }
- // prevent dupe events caused by frame re-runs
- if ( !gameLocal.isNewFrame ) {
- return;
- }
- outMsg.InitWrite( msgBuf, sizeof( msgBuf ) );
- outMsg.BeginWriting();
- outMsg.WriteBits( gameLocal.GetSpawnId( this ), 32 );
- outMsg.WriteByte( eventId );
- outMsg.WriteLong( gameLocal.time );
- if ( msg ) {
- outMsg.WriteBits( msg->GetSize(), idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
- outMsg.WriteData( msg->GetReadData(), msg->GetSize() );
- } else {
- outMsg.WriteBits( 0, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
- }
- idLobbyBase & lobby = session->GetActingGameStateLobbyBase();
- peerMask_t peerMask = MAX_UNSIGNED_TYPE( peerMask_t );
- if ( excluding.IsValid() ) {
- peerMask = ~(peerMask_t)lobby.PeerIndexFromLobbyUser( excluding );
- }
- lobby.SendReliable( GAME_RELIABLE_MESSAGE_EVENT, outMsg, false, peerMask );
- if ( saveEvent ) {
- gameLocal.SaveEntityNetworkEvent( this, eventId, msg );
- }
- }
- /*
- ================
- idEntity::ClientSendEvent
- ================
- */
- void idEntity::ClientSendEvent( int eventId, const idBitMsg *msg ) const {
- idBitMsg outMsg;
- byte msgBuf[MAX_GAME_MESSAGE_SIZE];
- if ( !common->IsClient() ) {
- return;
- }
- // prevent dupe events caused by frame re-runs
- if ( !gameLocal.isNewFrame ) {
- return;
- }
- outMsg.InitWrite( msgBuf, sizeof( msgBuf ) );
- outMsg.BeginWriting();
- outMsg.WriteBits( gameLocal.GetSpawnId( this ), 32 );
- outMsg.WriteByte( eventId );
- outMsg.WriteLong( gameLocal.serverTime );
- if ( msg ) {
- outMsg.WriteBits( msg->GetSize(), idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
- outMsg.WriteData( msg->GetReadData(), msg->GetSize() );
- } else {
- outMsg.WriteBits( 0, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
- }
- session->GetActingGameStateLobbyBase().SendReliableToHost( GAME_RELIABLE_MESSAGE_EVENT, outMsg );
- }
- /*
- ================
- idEntity::ServerReceiveEvent
- ================
- */
- bool idEntity::ServerReceiveEvent( int event, int time, const idBitMsg &msg ) {
- switch( event ) {
- case 0: {
- }
- default: {
- return false;
- }
- }
- }
- /*
- ================
- idEntity::ClientReceiveEvent
- ================
- */
- bool idEntity::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
- int index;
- const idSoundShader *shader;
- s_channelType channel;
- switch( event ) {
- case EVENT_STARTSOUNDSHADER: {
- // the sound stuff would early out
- assert( gameLocal.isNewFrame );
- if ( time < gameLocal.realClientTime - 1000 ) {
- // too old, skip it ( reliable messages don't need to be parsed in full )
- common->DPrintf( "ent 0x%x: start sound shader too old (%d ms)\n", entityNumber, gameLocal.realClientTime - time );
- return true;
- }
- index = gameLocal.ClientRemapDecl( DECL_SOUND, msg.ReadLong() );
- if ( index >= 0 && index < declManager->GetNumDecls( DECL_SOUND ) ) {
- shader = declManager->SoundByIndex( index, false );
- channel = (s_channelType)msg.ReadByte();
- StartSoundShader( shader, channel, 0, false, NULL );
- }
- return true;
- }
- case EVENT_STOPSOUNDSHADER: {
- // the sound stuff would early out
- assert( gameLocal.isNewFrame );
- channel = (s_channelType)msg.ReadByte();
- StopSound( channel, false );
- return true;
- }
- default: {
- return false;
- }
- }
- }
- /*
- ================
- idEntity::DetermineTimeGroup
- ================
- */
- void idEntity::DetermineTimeGroup( bool slowmo ) {
- if ( slowmo || common->IsMultiplayer() ) {
- timeGroup = TIME_GROUP1;
- }
- else {
- timeGroup = TIME_GROUP2;
- }
- }
- /*
- ================
- idEntity::SetGrabbedState
- ================
- */
- void idEntity::SetGrabbedState( bool grabbed ) {
- fl.grabbed = grabbed;
- }
- /*
- ================
- idEntity::IsGrabbed
- ================
- */
- bool idEntity::IsGrabbed() {
- return fl.grabbed;
- }
- /*
- ========================
- idEntity::DecayOriginAndAxisDelta
- ========================
- */
- void idEntity::DecayOriginAndAxisDelta() {
- idVec3 delta = vec3_zero - originDelta;
- float length = delta.Length();
- if ( length > 0.01f ) {
- length *= net_errorSmoothingDecay.GetFloat();
- if ( length > net_errorSmoothingMaxDecay.GetFloat() ) {
- length = net_errorSmoothingMaxDecay.GetFloat();
- }
- delta.Normalize();
- delta *= length;
-
- originDelta += delta;
- } else {
- originDelta = vec3_zero;
- }
- idQuat q;
- q.Slerp( axisDelta.ToQuat(), mat3_identity.ToQuat(), net_errorSmoothingDecay.GetFloat() );
- axisDelta = q.ToMat3();
- }
- /*
- ========================
- idEntity::CreateDeltasFromOldOriginAndAxis
- ========================
- */
- void idEntity::CreateDeltasFromOldOriginAndAxis( const idVec3 & oldOrigin, const idMat3 & oldAxis ) {
- // Set smooth values so we transition from the old position/axis to what we are now (visual only)
- if ( GetPhysics() ) {
- originDelta = oldOrigin - GetPhysics()->GetOrigin();
- axisDelta = oldAxis.Inverse() * GetPhysics()->GetAxis();
- }
- }
- /*
- ===============================================================================
- idAnimatedEntity
- ===============================================================================
- */
- const idEventDef EV_GetJointHandle( "getJointHandle", "s", 'd' );
- const idEventDef EV_ClearAllJoints( "clearAllJoints" );
- const idEventDef EV_ClearJoint( "clearJoint", "d" );
- const idEventDef EV_SetJointPos( "setJointPos", "ddv" );
- const idEventDef EV_SetJointAngle( "setJointAngle", "ddv" );
- const idEventDef EV_GetJointPos( "getJointPos", "d", 'v' );
- const idEventDef EV_GetJointAngle( "getJointAngle", "d", 'v' );
- CLASS_DECLARATION( idEntity, idAnimatedEntity )
- EVENT( EV_GetJointHandle, idAnimatedEntity::Event_GetJointHandle )
- EVENT( EV_ClearAllJoints, idAnimatedEntity::Event_ClearAllJoints )
- EVENT( EV_ClearJoint, idAnimatedEntity::Event_ClearJoint )
- EVENT( EV_SetJointPos, idAnimatedEntity::Event_SetJointPos )
- EVENT( EV_SetJointAngle, idAnimatedEntity::Event_SetJointAngle )
- EVENT( EV_GetJointPos, idAnimatedEntity::Event_GetJointPos )
- EVENT( EV_GetJointAngle, idAnimatedEntity::Event_GetJointAngle )
- END_CLASS
- /*
- ================
- idAnimatedEntity::idAnimatedEntity
- ================
- */
- idAnimatedEntity::idAnimatedEntity() {
- animator.SetEntity( this );
- damageEffects = NULL;
- }
- /*
- ================
- idAnimatedEntity::~idAnimatedEntity
- ================
- */
- idAnimatedEntity::~idAnimatedEntity() {
- damageEffect_t *de;
- for ( de = damageEffects; de; de = damageEffects ) {
- damageEffects = de->next;
- delete de;
- }
- }
- /*
- ================
- idAnimatedEntity::Save
- archives object for save game file
- ================
- */
- void idAnimatedEntity::Save( idSaveGame *savefile ) const {
- animator.Save( savefile );
- // Wounds are very temporary, ignored at this time
- //damageEffect_t *damageEffects;
- }
- /*
- ================
- idAnimatedEntity::Restore
- unarchives object from save game file
- ================
- */
- void idAnimatedEntity::Restore( idRestoreGame *savefile ) {
- animator.Restore( savefile );
- // check if the entity has an MD5 model
- if ( animator.ModelHandle() ) {
- // set the callback to update the joints
- renderEntity.callback = idEntity::ModelCallback;
- animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints );
- animator.GetBounds( gameLocal.time, renderEntity.bounds );
- if ( modelDefHandle != -1 ) {
- gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
- }
- }
- }
- /*
- ================
- idAnimatedEntity::ClientPredictionThink
- ================
- */
- void idAnimatedEntity::ClientPredictionThink() {
- RunPhysics();
- UpdateAnimation();
- Present();
- }
- /*
- ================
- idAnimatedEntity::ClientThink
- ================
- */
- void idAnimatedEntity::ClientThink( const int curTime, const float fraction, const bool predict ) {
- InterpolatePhysics( fraction );
- UpdateAnimation();
- Present();
- }
- /*
- ================
- idAnimatedEntity::Think
- ================
- */
- void idAnimatedEntity::Think() {
- RunPhysics();
- UpdateAnimation();
- Present();
- UpdateDamageEffects();
- }
- /*
- ================
- idAnimatedEntity::UpdateAnimation
- ================
- */
- void idAnimatedEntity::UpdateAnimation() {
- // don't do animations if they're not enabled
- if ( !( thinkFlags & TH_ANIMATE ) ) {
- return;
- }
- // is the model an MD5?
- if ( !animator.ModelHandle() ) {
- // no, so nothing to do
- return;
- }
- // call any frame commands that have happened in the past frame
- if ( !fl.hidden ) {
- animator.ServiceAnims( gameLocal.previousTime, gameLocal.time );
- }
- // if the model is animating then we have to update it
- if ( !animator.FrameHasChanged( gameLocal.time ) ) {
- // still fine the way it was
- return;
- }
- // get the latest frame bounds
- animator.GetBounds( gameLocal.time, renderEntity.bounds );
- if ( renderEntity.bounds.IsCleared() && !fl.hidden ) {
- gameLocal.DPrintf( "%d: inside out bounds\n", gameLocal.time );
- }
- // update the renderEntity
- UpdateVisuals();
- // the animation is updated
- animator.ClearForceUpdate();
- }
- /*
- ================
- idAnimatedEntity::GetAnimator
- ================
- */
- idAnimator *idAnimatedEntity::GetAnimator() {
- return &animator;
- }
- /*
- ================
- idAnimatedEntity::SetModel
- ================
- */
- void idAnimatedEntity::SetModel( const char *modelname ) {
- FreeModelDef();
- renderEntity.hModel = animator.SetModel( modelname );
- if ( !renderEntity.hModel ) {
- idEntity::SetModel( modelname );
- return;
- }
- if ( !renderEntity.customSkin ) {
- renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin();
- }
- // set the callback to update the joints
- renderEntity.callback = idEntity::ModelCallback;
- animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints );
- animator.GetBounds( gameLocal.time, renderEntity.bounds );
- UpdateVisuals();
- }
- /*
- =====================
- idAnimatedEntity::GetJointWorldTransform
- =====================
- */
- bool idAnimatedEntity::GetJointWorldTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) {
- if ( !animator.GetJointTransform( jointHandle, currentTime, offset, axis ) ) {
- return false;
- }
- ConvertLocalToWorldTransform( offset, axis );
- return true;
- }
- /*
- ==============
- idAnimatedEntity::GetJointTransformForAnim
- ==============
- */
- bool idAnimatedEntity::GetJointTransformForAnim( jointHandle_t jointHandle, int animNum, int frameTime, idVec3 &offset, idMat3 &axis ) const {
- const idAnim *anim;
- int numJoints;
- idJointMat *frame;
- anim = animator.GetAnim( animNum );
- if ( !anim ) {
- assert( 0 );
- return false;
- }
- numJoints = animator.NumJoints();
- if ( ( jointHandle < 0 ) || ( jointHandle >= numJoints ) ) {
- assert( 0 );
- return false;
- }
- frame = ( idJointMat * )_alloca16( numJoints * sizeof( idJointMat ) );
- gameEdit->ANIM_CreateAnimFrame( animator.ModelHandle(), anim->MD5Anim( 0 ), renderEntity.numJoints, frame, frameTime, animator.ModelDef()->GetVisualOffset(), animator.RemoveOrigin() );
- offset = frame[ jointHandle ].ToVec3();
- axis = frame[ jointHandle ].ToMat3();
-
- return true;
- }
- /*
- ==============
- idAnimatedEntity::AddDamageEffect
- Dammage effects track the animating impact position, spitting out particles.
- ==============
- */
- void idAnimatedEntity::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) {
- jointHandle_t jointNum;
- idVec3 origin, dir, localDir, localOrigin, localNormal;
- idMat3 axis;
- if ( !g_bloodEffects.GetBool() || renderEntity.joints == NULL ) {
- return;
- }
- const idDeclEntityDef *def = gameLocal.FindEntityDef( damageDefName, false );
- if ( def == NULL ) {
- return;
- }
- jointNum = CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id );
- if ( jointNum == INVALID_JOINT ) {
- return;
- }
- dir = velocity;
- dir.Normalize();
- axis = renderEntity.joints[jointNum].ToMat3() * renderEntity.axis;
- origin = renderEntity.origin + renderEntity.joints[jointNum].ToVec3() * renderEntity.axis;
- localOrigin = ( collision.c.point - origin ) * axis.Transpose();
- localNormal = collision.c.normal * axis.Transpose();
- localDir = dir * axis.Transpose();
- AddLocalDamageEffect( jointNum, localOrigin, localNormal, localDir, def, collision.c.material );
- }
- /*
- ==============
- idAnimatedEntity::GetDefaultSurfaceType
- ==============
- */
- int idAnimatedEntity::GetDefaultSurfaceType() const {
- return SURFTYPE_METAL;
- }
- /*
- ==============
- idAnimatedEntity::AddLocalDamageEffect
- ==============
- */
- void idAnimatedEntity::AddLocalDamageEffect( jointHandle_t jointNum, const idVec3 &localOrigin, const idVec3 &localNormal, const idVec3 &localDir, const idDeclEntityDef *def, const idMaterial *collisionMaterial ) {
- const char *sound, *splat, *decal, *bleed, *key;
- damageEffect_t *de;
- idVec3 origin, dir;
- idMat3 axis;
- SetTimeState ts( timeGroup );
- axis = renderEntity.joints[jointNum].ToMat3() * renderEntity.axis;
- origin = renderEntity.origin + renderEntity.joints[jointNum].ToVec3() * renderEntity.axis;
- origin = origin + localOrigin * axis;
- dir = localDir * axis;
- int type = collisionMaterial->GetSurfaceType();
- if ( type == SURFTYPE_NONE ) {
- type = GetDefaultSurfaceType();
- }
- const char *materialType = gameLocal.sufaceTypeNames[ type ];
- // start impact sound based on material type
- key = va( "snd_%s", materialType );
- sound = spawnArgs.GetString( key );
- if ( *sound == '\0' ) {
- sound = def->dict.GetString( key );
- }
- if ( *sound != '\0' ) {
- StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL );
- }
- // blood splats are thrown onto nearby surfaces
- key = va( "mtr_splat_%s", materialType );
- splat = spawnArgs.RandomPrefix( key, gameLocal.random );
- if ( *splat == '\0' ) {
- splat = def->dict.RandomPrefix( key, gameLocal.random );
- }
- if ( *splat != '\0' ) {
- gameLocal.BloodSplat( origin, dir, 64.0f, splat );
- }
- // can't see wounds on the player model in single player mode
- if ( !( IsType( idPlayer::Type ) && !common->IsMultiplayer() ) ) {
- // place a wound overlay on the model
- key = va( "mtr_wound_%s", materialType );
- decal = spawnArgs.RandomPrefix( key, gameLocal.random );
- if ( *decal == '\0' ) {
- decal = def->dict.RandomPrefix( key, gameLocal.random );
- }
- if ( *decal != '\0' ) {
- ProjectOverlay( origin, dir, 20.0f, decal );
- }
- }
- // a blood spurting wound is added
- key = va( "smoke_wound_%s", materialType );
- bleed = spawnArgs.GetString( key );
- if ( *bleed == '\0' ) {
- bleed = def->dict.GetString( key );
- }
- if ( *bleed != '\0' ) {
- de = new (TAG_ENTITY) damageEffect_t;
- de->next = this->damageEffects;
- this->damageEffects = de;
- de->jointNum = jointNum;
- de->localOrigin = localOrigin;
- de->localNormal = localNormal;
- de->type = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, bleed ) );
- de->time = gameLocal.time;
- }
- }
- /*
- ==============
- idAnimatedEntity::UpdateDamageEffects
- ==============
- */
- void idAnimatedEntity::UpdateDamageEffects() {
- damageEffect_t *de, **prev;
- // free any that have timed out
- prev = &this->damageEffects;
- while ( *prev ) {
- de = *prev;
- if ( de->time == 0 ) { // FIXME:SMOKE
- *prev = de->next;
- delete de;
- } else {
- prev = &de->next;
- }
- }
- if ( !g_bloodEffects.GetBool() ) {
- return;
- }
- // emit a particle for each bleeding wound
- for ( de = this->damageEffects; de; de = de->next ) {
- idVec3 origin, start;
- idMat3 axis;
- animator.GetJointTransform( de->jointNum, gameLocal.time, origin, axis );
- axis *= renderEntity.axis;
- origin = renderEntity.origin + origin * renderEntity.axis;
- start = origin + de->localOrigin * axis;
- if ( !gameLocal.smokeParticles->EmitSmoke( de->type, de->time, gameLocal.random.CRandomFloat(), start, axis, timeGroup /*_D3XP*/ ) ) {
- de->time = 0;
- }
- }
- }
- /*
- ================
- idAnimatedEntity::ClientReceiveEvent
- ================
- */
- bool idAnimatedEntity::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
- int damageDefIndex;
- int materialIndex;
- jointHandle_t jointNum;
- idVec3 localOrigin, localNormal, localDir;
- switch( event ) {
- case EVENT_ADD_DAMAGE_EFFECT: {
- jointNum = (jointHandle_t) msg.ReadShort();
- localOrigin[0] = msg.ReadFloat();
- localOrigin[1] = msg.ReadFloat();
- localOrigin[2] = msg.ReadFloat();
- localNormal = msg.ReadDir( 24 );
- localDir = msg.ReadDir( 24 );
- damageDefIndex = gameLocal.ClientRemapDecl( DECL_ENTITYDEF, msg.ReadLong() );
- materialIndex = gameLocal.ClientRemapDecl( DECL_MATERIAL, msg.ReadLong() );
- const idDeclEntityDef *damageDef = static_cast<const idDeclEntityDef *>( declManager->DeclByIndex( DECL_ENTITYDEF, damageDefIndex ) );
- const idMaterial *collisionMaterial = static_cast<const idMaterial *>( declManager->DeclByIndex( DECL_MATERIAL, materialIndex ) );
- AddLocalDamageEffect( jointNum, localOrigin, localNormal, localDir, damageDef, collisionMaterial );
- return true;
- }
- default: {
- return idEntity::ClientReceiveEvent( event, time, msg );
- }
- }
- }
- /*
- ================
- idAnimatedEntity::Event_GetJointHandle
- looks up the number of the specified joint. returns INVALID_JOINT if the joint is not found.
- ================
- */
- void idAnimatedEntity::Event_GetJointHandle( const char *jointname ) {
- jointHandle_t joint;
- joint = animator.GetJointHandle( jointname );
- idThread::ReturnInt( joint );
- }
- /*
- ================
- idAnimatedEntity::Event_ClearAllJoints
- removes any custom transforms on all joints
- ================
- */
- void idAnimatedEntity::Event_ClearAllJoints() {
- animator.ClearAllJoints();
- }
- /*
- ================
- idAnimatedEntity::Event_ClearJoint
- removes any custom transforms on the specified joint
- ================
- */
- void idAnimatedEntity::Event_ClearJoint( jointHandle_t jointnum ) {
- animator.ClearJoint( jointnum );
- }
- /*
- ================
- idAnimatedEntity::Event_SetJointPos
- modifies the position of the joint based on the transform type
- ================
- */
- void idAnimatedEntity::Event_SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos ) {
- animator.SetJointPos( jointnum, transform_type, pos );
- }
- /*
- ================
- idAnimatedEntity::Event_SetJointAngle
- modifies the orientation of the joint based on the transform type
- ================
- */
- void idAnimatedEntity::Event_SetJointAngle( jointHandle_t jointnum, jointModTransform_t transform_type, const idAngles &angles ) {
- idMat3 mat;
- mat = angles.ToMat3();
- animator.SetJointAxis( jointnum, transform_type, mat );
- }
- /*
- ================
- idAnimatedEntity::Event_GetJointPos
- returns the position of the joint in worldspace
- ================
- */
- void idAnimatedEntity::Event_GetJointPos( jointHandle_t jointnum ) {
- idVec3 offset;
- idMat3 axis;
- if ( !GetJointWorldTransform( jointnum, gameLocal.time, offset, axis ) ) {
- gameLocal.Warning( "Joint # %d out of range on entity '%s'", jointnum, name.c_str() );
- }
- idThread::ReturnVector( offset );
- }
- /*
- ================
- idAnimatedEntity::Event_GetJointAngle
- returns the orientation of the joint in worldspace
- ================
- */
- void idAnimatedEntity::Event_GetJointAngle( jointHandle_t jointnum ) {
- idVec3 offset;
- idMat3 axis;
- if ( !GetJointWorldTransform( jointnum, gameLocal.time, offset, axis ) ) {
- gameLocal.Warning( "Joint # %d out of range on entity '%s'", jointnum, name.c_str() );
- }
- idAngles ang = axis.ToAngles();
- idVec3 vec( ang[ 0 ], ang[ 1 ], ang[ 2 ] );
- idThread::ReturnVector( vec );
- }
|