12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- 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
- ===============================================================================
- */
- // 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" );
- #ifdef _D3XP
- 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" );
- #endif
- 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 )
- #ifdef _D3XP
- 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 )
- #endif
- 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 && target[0] ) {
- // 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() {
- entityNumber = ENTITYNUM_NONE;
- entityDefNumber = -1;
- spawnNode.SetOwner( this );
- activeNode.SetOwner( this );
- snapshotNode.SetOwner( this );
- snapshotSequence = -1;
- 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;
- 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;
- #ifdef _D3XP
- memset( &xrayEntity, 0, sizeof( xrayEntity ) );
- timeGroup = TIME_GROUP1;
- xrayEntityHandle = -1;
- xraySkin = NULL;
- noGrab = false;
- #endif
- }
- /*
- ================
- 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(), common->GetLanguageDict()->GetString( kv->GetValue() ) );
- }
- }
- }
- /*
- ================
- idEntity::Spawn
- ================
- */
- void idEntity::Spawn( void ) {
- int i;
- const char *temp;
- idVec3 origin;
- idMat3 axis;
- const idKeyValue *networkSync;
- const char *classname;
- const char *scriptObjectName;
- gameLocal.RegisterEntity( this );
- 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;
-
- #ifdef _D3XP
- noGrab = spawnArgs.GetBool( "noGrab", "0" );
- xraySkin = NULL;
- renderEntity.xrayIndex = 1;
- idStr str;
- if ( spawnArgs.GetString( "skin_xray", "", str ) ) {
- xraySkin = declManager->FindSkin( str.c_str() );
- }
- #endif
- // go dormant within 5 frames so that when the map starts most monsters are dormant
- dormantStart = gameLocal.time - DELAY_DORMANT_TIME + gameLocal.msec * 5;
- 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 && temp[0] ) {
- // 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 ( !gameLocal.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 && *temp ) {
- 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();
- }
- #ifdef _D3XP
- // determine time group
- DetermineTimeGroup( spawnArgs.GetBool( "slowmo", "1" ) );
- #endif
- }
- /*
- ================
- idEntity::~idEntity
- ================
- */
- idEntity::~idEntity( void ) {
- if ( gameLocal.GameState() != GAMESTATE_SHUTDOWN && !gameLocal.isClient && fl.networkSync && entityNumber >= MAX_CLIENTS ) {
- idBitMsg msg;
- byte msgBuf[ MAX_GAME_MESSAGE_SIZE ];
- msg.Init( msgBuf, sizeof( msgBuf ) );
- msg.WriteByte( GAME_RELIABLE_MESSAGE_DELETE_ENT );
- msg.WriteBits( gameLocal.GetSpawnId( this ), 32 );
- networkSystem->ServerSendReliableMessage( -1, msg );
- }
- 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 );
- #ifdef _D3XP
- if ( xrayEntityHandle != -1) {
- gameRenderWorld->FreeEntityDef( xrayEntityHandle );
- xrayEntityHandle = -1;
- }
- #endif
- 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->WriteInt( snapshotSequence );
- savefile->WriteInt( snapshotBits );
- 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 ) );
- #ifdef _D3XP
- savefile->WriteInt( timeGroup );
- savefile->WriteBool( noGrab );
- savefile->WriteRenderEntity( xrayEntity );
- savefile->WriteInt( xrayEntityHandle );
- savefile->WriteSkin( xraySkin );
- #endif
- 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->ReadInt( snapshotSequence );
- savefile->ReadInt( snapshotBits );
- 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 ) );
-
- #ifdef _D3XP
- savefile->ReadInt( timeGroup );
- savefile->ReadBool( noGrab );
- savefile->ReadRenderEntity( xrayEntity );
- savefile->ReadInt( xrayEntityHandle );
- if ( xrayEntityHandle != -1 ) {
- xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity );
- }
- savefile->ReadSkin( xraySkin );
- #endif
- 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 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( void ) 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( void ) const {
- return name.c_str();
- }
- /***********************************************************************
- Thinking
-
- ***********************************************************************/
- /*
- ================
- idEntity::Think
- ================
- */
- void idEntity::Think( void ) {
- 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( void ) {
- 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;
- }
- 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( void ) {
- 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( void ) {
- }
- /*
- ================
- idEntity::DormantEnd
- called when entity wakes from being dormant
- ================
- */
- void idEntity::DormantEnd( void ) {
- }
- /*
- ================
- idEntity::IsActive
- ================
- */
- bool idEntity::IsActive( void ) 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 );
- }
- }
- }
- }
- /***********************************************************************
- 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( void ) {
- // 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( void ) const {
- return renderEntity.customSkin;
- }
- /*
- ================
- idEntity::FreeModelDef
- ================
- */
- void idEntity::FreeModelDef( void ) {
- if ( modelDefHandle != -1 ) {
- gameRenderWorld->FreeEntityDef( modelDefHandle );
- modelDefHandle = -1;
- }
- }
- /*
- ================
- idEntity::FreeLightDef
- ================
- */
- void idEntity::FreeLightDef( void ) {
- }
- /*
- ================
- idEntity::IsHidden
- ================
- */
- bool idEntity::IsHidden( void ) const {
- return fl.hidden;
- }
- /*
- ================
- idEntity::Hide
- ================
- */
- void idEntity::Hide( void ) {
- if ( !IsHidden() ) {
- fl.hidden = true;
- FreeModelDef();
- UpdateVisuals();
- }
- }
- /*
- ================
- idEntity::Show
- ================
- */
- void idEntity::Show( void ) {
- if ( IsHidden() ) {
- fl.hidden = false;
- UpdateVisuals();
- }
- }
- /*
- ================
- idEntity::UpdateModelTransform
- ================
- */
- void idEntity::UpdateModelTransform( void ) {
- idVec3 origin;
- idMat3 axis;
- if ( GetPhysicsToVisualTransform( origin, axis ) ) {
- renderEntity.axis = axis * GetPhysics()->GetAxis();
- renderEntity.origin = GetPhysics()->GetOrigin() + origin * renderEntity.axis;
- } else {
- renderEntity.axis = GetPhysics()->GetAxis();
- renderEntity.origin = GetPhysics()->GetOrigin();
- }
- }
- /*
- ================
- idEntity::UpdateModel
- ================
- */
- void idEntity::UpdateModel( void ) {
- #ifdef _D3XP
- renderEntity.timeGroup = timeGroup;
- #endif
- UpdateModelTransform();
- // check if the entity has an MD5 model
- idAnimator *animator = GetAnimator();
- if ( animator && animator->ModelHandle() ) {
- // 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 );
- #ifdef _D3XP
- // 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 );
- }
- }
- #endif
- }
- /*
- ================
- idEntity::UpdateVisuals
- ================
- */
- void idEntity::UpdateVisuals( void ) {
- UpdateModel();
- UpdateSound();
- }
- /*
- ================
- idEntity::UpdatePVSAreas
- ================
- */
- void idEntity::UpdatePVSAreas( void ) {
- 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( void ) {
- if ( numPVSAreas < 0 ) {
- UpdatePVSAreas();
- }
- return numPVSAreas;
- }
- /*
- ================
- idEntity::GetPVSAreas
- ================
- */
- const int *idEntity::GetPVSAreas( void ) {
- if ( numPVSAreas < 0 ) {
- UpdatePVSAreas();
- }
- return PVSAreas;
- }
- /*
- ================
- idEntity::ClearPVSAreas
- ================
- */
- void idEntity::ClearPVSAreas( void ) {
- 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::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 );
- // 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( void ) {
- 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( void ) {
- return &renderEntity;
- }
- /*
- ================
- idEntity::GetModelDefHandle
- ================
- */
- int idEntity::GetModelDefHandle( void ) {
- return modelDefHandle;
- }
- /*
- ================
- idEntity::UpdateRenderEntity
- ================
- */
- bool idEntity::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) {
- if ( gameLocal.inCinematic && gameLocal.skipCinematic ) {
- return false;
- }
- idAnimator *animator = GetAnimator();
- if ( animator ) {
- #ifdef _D3XP
- SetTimeState ts( timeGroup );
- #endif
- return animator->CreateFrame( gameLocal.time, 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 ) {
- gameLocal.Error( "idEntity::ModelCallback: callback with NULL game entity" );
- }
- return ent->UpdateRenderEntity( renderEntity, renderView );
- }
- /*
- ================
- idEntity::GetAnimator
- Subclasses will be responsible for allocating animator.
- ================
- */
- idAnimator *idEntity::GetAnimator( void ) {
- return NULL;
- }
- /*
- =============
- idEntity::GetRenderView
- This is used by remote camera views to look from an entity
- =============
- */
- renderView_t *idEntity::GetRenderView( void ) {
- if ( !renderView ) {
- renderView = new 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 = gameLocal.time;
- return renderView;
- }
- /***********************************************************************
- Sound
-
- ***********************************************************************/
- /*
- ================
- idEntity::CanPlayChatterSounds
- Used for playing chatter sounds on monsters.
- ================
- */
- bool idEntity::CanPlayChatterSounds( void ) 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 ( gameLocal.isServer && broadcast ) {
- idBitMsg msg;
- byte msgBuf[MAX_EVENT_PARAM_SIZE];
- msg.Init( msgBuf, sizeof( msgBuf ) );
- msg.BeginWriting();
- msg.WriteLong( gameLocal.ServerRemapDecl( -1, DECL_SOUND, shader->Index() ) );
- msg.WriteByte( channel );
- ServerSendEvent( EVENT_STARTSOUNDSHADER, &msg, false, -1 );
- }
- // 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 ( gameLocal.isServer && broadcast ) {
- idBitMsg msg;
- byte msgBuf[MAX_EVENT_PARAM_SIZE];
- msg.Init( msgBuf, sizeof( msgBuf ) );
- msg.BeginWriting();
- msg.WriteByte( channel );
- ServerSendEvent( EVENT_STOPSOUNDSHADER, &msg, false, -1 );
- }
- 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( void ) {
- 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( void ) const {
- return refSound.listenerId;
- }
- /*
- ================
- idEntity::GetSoundEmitter
- ================
- */
- idSoundEmitter *idEntity::GetSoundEmitter( void ) 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( void ) {
- }
- /*
- ================
- idEntity::PostBind
- ================
- */
- void idEntity::PostBind( void ) {
- }
- /*
- ================
- idEntity::PreUnbind
- ================
- */
- void idEntity::PreUnbind( void ) {
- }
- /*
- ================
- idEntity::PostUnbind
- ================
- */
- void idEntity::PostUnbind( void ) {
- }
- /*
- ================
- 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( void ) {
- // 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( void ) {
- 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( void ) {
- 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( void ) 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( void ) const {
- return bindMaster;
- }
- /*
- ================
- idEntity::GetBindJoint
- ================
- */
- jointHandle_t idEntity::GetBindJoint( void ) const {
- return bindJoint;
- }
- /*
- ================
- idEntity::GetBindBody
- ================
- */
- int idEntity::GetBindBody( void ) const {
- return bindBody;
- }
- /*
- ================
- idEntity::GetTeamMaster
- ================
- */
- idEntity *idEntity::GetTeamMaster( void ) const {
- return teamMaster;
- }
- /*
- ================
- idEntity::GetNextTeamEntity
- ================
- */
- idEntity *idEntity::GetNextTeamEntity( void ) 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( void ) {
- 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 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 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 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( void ) const {
- return physics;
- }
- /*
- ================
- idEntity::RunPhysics
- ================
- */
- bool idEntity::RunPhysics( void ) {
- int i, reachedTime, startTime, endTime;
- idEntity * part, *blockedPart, *blockingEntity;
- 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;
- }
- 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( endTime - startTime, 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 ( gameLocal.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;
- }
- // set pushed
- for ( i = 0; i < gameLocal.push.GetNumPushedEntities(); i++ ) {
- idEntity *ent = gameLocal.push.GetPushedEntity( i );
- ent->physics->SetPushed( endTime - startTime );
- }
- if ( gameLocal.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::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::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( void ) const {
- return GetPhysics()->IsAtRest();
- }
- /*
- ================
- idEntity::GetRestStartTime
- ================
- */
- int idEntity::GetRestStartTime( void ) 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;
- }
- #ifdef _D3XP
- SetTimeState ts( timeGroup );
- #endif
- if ( !inflictor ) {
- inflictor = gameLocal.world;
- }
- if ( !attacker ) {
- attacker = gameLocal.world;
- }
- const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
- if ( !damageDef ) {
- gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName );
- }
- 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( void ) 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( void ) {
- 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( void ) {
- 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 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" );
- }
- if ( !signals ) {
- 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" );
- }
- if ( !signals ) {
- 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( void ) {
- 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()->inventory.turkeyScore ) {
- gameLocal.GetLocalPlayer()->GiveEmail( "highScore" );
- gameLocal.GetLocalPlayer()->inventory.turkeyScore = true;
- }
- }
- continue;
- }
- #ifdef _D3XP
- if ( !token.Icmp( "martianbuddycomplete" ) ) {
- gameLocal.GetLocalPlayer()->GiveEmail( "MartianBuddyGameComplete" );
- continue;
- }
- #endif
- // 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( void ) {
- 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( void ) {
- 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( void ) 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;
- }
- #ifdef _D3XP
- SetTimeState ts( ent->timeGroup );
- #endif
- 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( void ) 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 idCurve_CatmullRomSpline<idVec3>();
- } else if ( str.Icmp( "nubs" ) == 0 ) {
- spline = new idCurve_NonUniformBSpline<idVec3>();
- } else if ( str.Icmp( "nurbs" ) == 0 ) {
- spline = new idCurve_NURBS<idVec3>();
- } else {
- spline = new 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( void ) {
- }
- /***********************************************************************
- Events
-
- ***********************************************************************/
- /*
- ================
- idEntity::Event_GetName
- ================
- */
- void idEntity::Event_GetName( void ) {
- idThread::ReturnString( name.c_str() );
- }
- /*
- ================
- idEntity::Event_SetName
- ================
- */
- void idEntity::Event_SetName( const char *newname ) {
- SetName( newname );
- }
- /*
- ===============
- idEntity::Event_FindTargets
- ===============
- */
- void idEntity::Event_FindTargets( void ) {
- 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( void ) {
- 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( void ) {
- 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( void ) {
- Unbind();
- }
- /*
- ================
- idEntity::Event_SpawnBind
- ================
- */
- void idEntity::Event_SpawnBind( void ) {
- 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 ) {
- gameLocal.Error( "Cannot bind to joint '%s' on '%s'. Entity does not support skeletal models.", joint, name.c_str() );
- }
- 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 );
- }
- 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( void ) {
- idVec3 out;
- GetColor( out );
- idThread::ReturnVector( out );
- }
- /*
- ================
- idEntity::Event_IsHidden
- ================
- */
- void idEntity::Event_IsHidden( void ) {
- idThread::ReturnInt( fl.hidden );
- }
- /*
- ================
- idEntity::Event_Hide
- ================
- */
- void idEntity::Event_Hide( void ) {
- Hide();
- }
- /*
- ================
- idEntity::Event_Show
- ================
- */
- void idEntity::Event_Show( void ) {
- 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;
- 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( void ) {
- 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( void ) {
- idThread::ReturnVector( GetLocalCoordinates( GetPhysics()->GetOrigin() ) );
- }
- /*
- ================
- idEntity::Event_SetAngles
- ================
- */
- void idEntity::Event_SetAngles( idAngles const &ang ) {
- SetAngles( ang );
- }
- /*
- ================
- idEntity::Event_GetAngles
- ================
- */
- void idEntity::Event_GetAngles( void ) {
- 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( void ) {
- idThread::ReturnVector( GetPhysics()->GetLinearVelocity() );
- }
- /*
- ================
- idEntity::Event_SetAngularVelocity
- ================
- */
- void idEntity::Event_SetAngularVelocity( const idVec3 &velocity ) {
- GetPhysics()->SetAngularVelocity( velocity );
- }
- /*
- ================
- idEntity::Event_GetAngularVelocity
- ================
- */
- void idEntity::Event_GetAngularVelocity( void ) {
- 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( void ) {
- idBounds bounds;
- bounds = GetPhysics()->GetBounds();
- idThread::ReturnVector( bounds[1] - bounds[0] );
- }
- /*
- ================
- idEntity::Event_GetMins
- ================
- */
- void idEntity::Event_GetMins( void ) {
- idThread::ReturnVector( GetPhysics()->GetBounds()[0] );
- }
- /*
- ================
- idEntity::Event_GetMaxs
- ================
- */
- void idEntity::Event_GetMaxs( void ) {
- 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 );
- #ifdef _D3XP
- UpdateChangeableSpawnArgs( NULL );
- #endif
- }
- /*
- ================
- 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( void ) {
- 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( void ) {
- const char *target;
- const idKeyValue *kv;
- idVec3 dir;
- target = spawnArgs.GetString( "cameraTarget" );
- cameraTarget = gameLocal.FindEntity( target );
- if ( cameraTarget ) {
- kv = cameraTarget->spawnArgs.MatchPrefix( "target", NULL );
- while( kv ) {
- idEntity *ent = gameLocal.FindEntity( kv->GetValue() );
- if ( ent && 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( void ) {
- idThread *thread;
-
- thread = idThread::CurrentThread();
- if ( thread ) {
- thread->WaitFrame();
- }
- }
- /*
- =====================
- idEntity::Event_Wait
- =====================
- */
- void idEntity::Event_Wait( float time ) {
- idThread *thread = idThread::CurrentThread();
- if ( !thread ) {
- gameLocal.Error( "Event 'wait' called from outside thread" );
- }
- 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 ) {
- gameLocal.Error( "Event 'callFunction' called from outside thread" );
- }
- func = scriptObject.GetFunction( funcname );
- if ( !func ) {
- gameLocal.Error( "Unknown function '%s' in '%s'", funcname, scriptObject.GetTypeName() );
- }
- if ( func->type->NumParameters() != 1 ) {
- gameLocal.Error( "Function '%s' has the wrong number of parameters for 'callFunction'", funcname );
- }
- if ( !scriptObject.GetTypeDef()->Inherits( func->type->GetParmType( 0 ) ) ) {
- gameLocal.Error( "Function '%s' is the wrong type for 'callFunction'", funcname );
- }
- // 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;
- }
- #ifdef _D3XP
- /*
- ================
- 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);
- }
- }
- #endif
- /***********************************************************************
- Network
-
- ***********************************************************************/
- /*
- ================
- idEntity::ClientPredictionThink
- ================
- */
- void idEntity::ClientPredictionThink( void ) {
- RunPhysics();
- Present();
- }
- /*
- ================
- idEntity::WriteBindToSnapshot
- ================
- */
- void idEntity::WriteBindToSnapshot( idBitMsgDelta &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 idBitMsgDelta &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 ) {
- 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( idBitMsgDelta &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 idBitMsgDelta &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( idBitMsgDelta &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 idBitMsgDelta &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( idBitMsgDelta &msg ) const {
- }
- /*
- ================
- idEntity::ReadFromSnapshot
- ================
- */
- void idEntity::ReadFromSnapshot( const idBitMsgDelta &msg ) {
- }
- /*
- ================
- 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, int excludeClient ) const {
- idBitMsg outMsg;
- byte msgBuf[MAX_GAME_MESSAGE_SIZE];
- if ( !gameLocal.isServer ) {
- return;
- }
- // prevent dupe events caused by frame re-runs
- if ( !gameLocal.isNewFrame ) {
- return;
- }
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.BeginWriting();
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_EVENT );
- 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->GetData(), msg->GetSize() );
- } else {
- outMsg.WriteBits( 0, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
- }
- if ( excludeClient != -1 ) {
- networkSystem->ServerSendReliableMessageExcluding( excludeClient, outMsg );
- } else {
- networkSystem->ServerSendReliableMessage( -1, outMsg );
- }
- 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 ( !gameLocal.isClient ) {
- return;
- }
- // prevent dupe events caused by frame re-runs
- if ( !gameLocal.isNewFrame ) {
- return;
- }
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.BeginWriting();
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_EVENT );
- 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->GetData(), msg->GetSize() );
- } else {
- outMsg.WriteBits( 0, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
- }
- networkSystem->ClientSendReliableMessage( 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;
- }
- }
- return false;
- }
- #ifdef _D3XP
- /*
- ================
- idEntity::DetermineTimeGroup
- ================
- */
- void idEntity::DetermineTimeGroup( bool slowmo ) {
- if ( slowmo || gameLocal.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;
- }
- #endif
- /*
- ===============================================================================
- 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( void ) {
- RunPhysics();
- UpdateAnimation();
- Present();
- }
- /*
- ================
- idAnimatedEntity::Think
- ================
- */
- void idAnimatedEntity::Think( void ) {
- RunPhysics();
- UpdateAnimation();
- Present();
- UpdateDamageEffects();
- }
- /*
- ================
- idAnimatedEntity::UpdateAnimation
- ================
- */
- void idAnimatedEntity::UpdateAnimation( void ) {
- // 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( void ) {
- 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 );
- if ( gameLocal.isServer ) {
- idBitMsg msg;
- byte msgBuf[MAX_EVENT_PARAM_SIZE];
- msg.Init( msgBuf, sizeof( msgBuf ) );
- msg.BeginWriting();
- msg.WriteShort( (int)jointNum );
- msg.WriteFloat( localOrigin[0] );
- msg.WriteFloat( localOrigin[1] );
- msg.WriteFloat( localOrigin[2] );
- msg.WriteDir( localNormal, 24 );
- msg.WriteDir( localDir, 24 );
- msg.WriteLong( gameLocal.ServerRemapDecl( -1, DECL_ENTITYDEF, def->Index() ) );
- msg.WriteLong( gameLocal.ServerRemapDecl( -1, DECL_MATERIAL, collision.c.material->Index() ) );
- ServerSendEvent( EVENT_ADD_DAMAGE_EFFECT, &msg, false, -1 );
- }
- }
- /*
- ==============
- idAnimatedEntity::GetDefaultSurfaceType
- ==============
- */
- int idAnimatedEntity::GetDefaultSurfaceType( void ) 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;
- #ifdef _D3XP
- SetTimeState ts( timeGroup );
- #endif
- 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 ) && !gameLocal.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 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( void ) {
- 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 );
- }
- }
- return false;
- }
- /*
- ================
- 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( void ) {
- 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 );
- }
|