AFEntity.cpp 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. /*
  24. ===============================================================================
  25. idMultiModelAF
  26. ===============================================================================
  27. */
  28. CLASS_DECLARATION( idEntity, idMultiModelAF )
  29. END_CLASS
  30. /*
  31. ================
  32. idMultiModelAF::Spawn
  33. ================
  34. */
  35. void idMultiModelAF::Spawn() {
  36. physicsObj.SetSelf( this );
  37. }
  38. /*
  39. ================
  40. idMultiModelAF::~idMultiModelAF
  41. ================
  42. */
  43. idMultiModelAF::~idMultiModelAF() {
  44. int i;
  45. for ( i = 0; i < modelDefHandles.Num(); i++ ) {
  46. if ( modelDefHandles[i] != -1 ) {
  47. gameRenderWorld->FreeEntityDef( modelDefHandles[i] );
  48. modelDefHandles[i] = -1;
  49. }
  50. }
  51. }
  52. /*
  53. ================
  54. idMultiModelAF::SetModelForId
  55. ================
  56. */
  57. void idMultiModelAF::SetModelForId( int id, const idStr &modelName ) {
  58. modelHandles.AssureSize( id+1, NULL );
  59. modelDefHandles.AssureSize( id+1, -1 );
  60. modelHandles[id] = renderModelManager->FindModel( modelName );
  61. }
  62. /*
  63. ================
  64. idMultiModelAF::Present
  65. ================
  66. */
  67. void idMultiModelAF::Present() {
  68. int i;
  69. // don't present to the renderer if the entity hasn't changed
  70. if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  71. return;
  72. }
  73. BecomeInactive( TH_UPDATEVISUALS );
  74. for ( i = 0; i < modelHandles.Num(); i++ ) {
  75. if ( !modelHandles[i] ) {
  76. continue;
  77. }
  78. renderEntity.origin = physicsObj.GetOrigin( i );
  79. renderEntity.axis = physicsObj.GetAxis( i );
  80. renderEntity.hModel = modelHandles[i];
  81. renderEntity.bodyId = i;
  82. // add to refresh list
  83. if ( modelDefHandles[i] == -1 ) {
  84. modelDefHandles[i] = gameRenderWorld->AddEntityDef( &renderEntity );
  85. } else {
  86. gameRenderWorld->UpdateEntityDef( modelDefHandles[i], &renderEntity );
  87. }
  88. }
  89. }
  90. /*
  91. ================
  92. idMultiModelAF::Think
  93. ================
  94. */
  95. void idMultiModelAF::Think() {
  96. RunPhysics();
  97. Present();
  98. }
  99. /*
  100. ===============================================================================
  101. idChain
  102. ===============================================================================
  103. */
  104. CLASS_DECLARATION( idMultiModelAF, idChain )
  105. END_CLASS
  106. /*
  107. ================
  108. idChain::BuildChain
  109. builds a chain hanging down from the ceiling
  110. the highest link is a child of the link below it etc.
  111. this allows an object to be attached to multiple chains while keeping a single tree structure
  112. ================
  113. */
  114. void idChain::BuildChain( const idStr &name, const idVec3 &origin, float linkLength, float linkWidth, float density, int numLinks, bool bindToWorld ) {
  115. int i;
  116. float halfLinkLength = linkLength * 0.5f;
  117. idTraceModel trm;
  118. idClipModel *clip;
  119. idAFBody *body, *lastBody;
  120. idAFConstraint_BallAndSocketJoint *bsj;
  121. idAFConstraint_UniversalJoint *uj;
  122. idVec3 org;
  123. // create a trace model
  124. trm = idTraceModel( linkLength, linkWidth );
  125. trm.Translate( -trm.offset );
  126. org = origin - idVec3( 0, 0, halfLinkLength );
  127. lastBody = NULL;
  128. for ( i = 0; i < numLinks; i++ ) {
  129. // add body
  130. clip = new (TAG_PHYSICS_CLIP_AF) idClipModel( trm );
  131. clip->SetContents( CONTENTS_SOLID );
  132. clip->Link( gameLocal.clip, this, 0, org, mat3_identity );
  133. body = new (TAG_PHYSICS_AF) idAFBody( name + idStr(i), clip, density );
  134. physicsObj.AddBody( body );
  135. // visual model for body
  136. SetModelForId( physicsObj.GetBodyId( body ), spawnArgs.GetString( "model" ) );
  137. // add constraint
  138. if ( bindToWorld ) {
  139. if ( !lastBody ) {
  140. uj = new (TAG_PHYSICS_AF) idAFConstraint_UniversalJoint( name + idStr(i), body, lastBody );
  141. uj->SetShafts( idVec3( 0, 0, -1 ), idVec3( 0, 0, 1 ) );
  142. //uj->SetConeLimit( idVec3( 0, 0, -1 ), 30.0f );
  143. //uj->SetPyramidLimit( idVec3( 0, 0, -1 ), idVec3( 1, 0, 0 ), 90.0f, 30.0f );
  144. }
  145. else {
  146. uj = new (TAG_PHYSICS_AF) idAFConstraint_UniversalJoint( name + idStr(i), lastBody, body );
  147. uj->SetShafts( idVec3( 0, 0, 1 ), idVec3( 0, 0, -1 ) );
  148. //uj->SetConeLimit( idVec3( 0, 0, 1 ), 30.0f );
  149. }
  150. uj->SetAnchor( org + idVec3( 0, 0, halfLinkLength ) );
  151. uj->SetFriction( 0.9f );
  152. physicsObj.AddConstraint( uj );
  153. }
  154. else {
  155. if ( lastBody ) {
  156. bsj = new (TAG_PHYSICS_AF) idAFConstraint_BallAndSocketJoint( "joint" + idStr(i), lastBody, body );
  157. bsj->SetAnchor( org + idVec3( 0, 0, halfLinkLength ) );
  158. bsj->SetConeLimit( idVec3( 0, 0, 1 ), 60.0f, idVec3( 0, 0, 1 ) );
  159. physicsObj.AddConstraint( bsj );
  160. }
  161. }
  162. org[2] -= linkLength;
  163. lastBody = body;
  164. }
  165. }
  166. /*
  167. ================
  168. idChain::Spawn
  169. ================
  170. */
  171. void idChain::Spawn() {
  172. int numLinks;
  173. float length, linkLength, linkWidth, density;
  174. bool drop;
  175. idVec3 origin;
  176. spawnArgs.GetBool( "drop", "0", drop );
  177. spawnArgs.GetInt( "links", "3", numLinks );
  178. spawnArgs.GetFloat( "length", idStr( numLinks * 32.0f ), length );
  179. spawnArgs.GetFloat( "width", "8", linkWidth );
  180. spawnArgs.GetFloat( "density", "0.2", density );
  181. linkLength = length / numLinks;
  182. origin = GetPhysics()->GetOrigin();
  183. // initialize physics
  184. physicsObj.SetSelf( this );
  185. physicsObj.SetGravity( gameLocal.GetGravity() );
  186. physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY );
  187. SetPhysics( &physicsObj );
  188. BuildChain( "link", origin, linkLength, linkWidth, density, numLinks, !drop );
  189. }
  190. /*
  191. ===============================================================================
  192. idAFAttachment
  193. ===============================================================================
  194. */
  195. CLASS_DECLARATION( idAnimatedEntity, idAFAttachment )
  196. END_CLASS
  197. /*
  198. =====================
  199. idAFAttachment::idAFAttachment
  200. =====================
  201. */
  202. idAFAttachment::idAFAttachment() {
  203. body = NULL;
  204. combatModel = NULL;
  205. idleAnim = 0;
  206. attachJoint = INVALID_JOINT;
  207. }
  208. /*
  209. =====================
  210. idAFAttachment::~idAFAttachment
  211. =====================
  212. */
  213. idAFAttachment::~idAFAttachment() {
  214. StopSound( SND_CHANNEL_ANY, false );
  215. delete combatModel;
  216. combatModel = NULL;
  217. }
  218. /*
  219. =====================
  220. idAFAttachment::Spawn
  221. =====================
  222. */
  223. void idAFAttachment::Spawn() {
  224. idleAnim = animator.GetAnim( "idle" );
  225. }
  226. /*
  227. =====================
  228. idAFAttachment::SetBody
  229. =====================
  230. */
  231. void idAFAttachment::SetBody( idEntity *bodyEnt, const char *model, jointHandle_t attachJoint ) {
  232. bool bleed;
  233. body = bodyEnt;
  234. this->attachJoint = attachJoint;
  235. SetModel( model );
  236. fl.takedamage = true;
  237. bleed = body->spawnArgs.GetBool( "bleed" );
  238. spawnArgs.SetBool( "bleed", bleed );
  239. }
  240. /*
  241. =====================
  242. idAFAttachment::ClearBody
  243. =====================
  244. */
  245. void idAFAttachment::ClearBody() {
  246. body = NULL;
  247. attachJoint = INVALID_JOINT;
  248. Hide();
  249. }
  250. /*
  251. =====================
  252. idAFAttachment::GetBody
  253. =====================
  254. */
  255. idEntity *idAFAttachment::GetBody() const {
  256. return body;
  257. }
  258. /*
  259. ================
  260. idAFAttachment::Save
  261. archive object for savegame file
  262. ================
  263. */
  264. void idAFAttachment::Save( idSaveGame *savefile ) const {
  265. savefile->WriteObject( body );
  266. savefile->WriteInt( idleAnim );
  267. savefile->WriteJoint( attachJoint );
  268. }
  269. /*
  270. ================
  271. idAFAttachment::Restore
  272. unarchives object from save game file
  273. ================
  274. */
  275. void idAFAttachment::Restore( idRestoreGame *savefile ) {
  276. savefile->ReadObject( reinterpret_cast<idClass *&>( body ) );
  277. savefile->ReadInt( idleAnim );
  278. savefile->ReadJoint( attachJoint );
  279. SetCombatModel();
  280. LinkCombat();
  281. }
  282. /*
  283. ================
  284. idAFAttachment::Hide
  285. ================
  286. */
  287. void idAFAttachment::Hide() {
  288. idEntity::Hide();
  289. UnlinkCombat();
  290. }
  291. /*
  292. ================
  293. idAFAttachment::Show
  294. ================
  295. */
  296. void idAFAttachment::Show() {
  297. idEntity::Show();
  298. LinkCombat();
  299. }
  300. /*
  301. ============
  302. idAFAttachment::Damage
  303. Pass damage to body at the bindjoint
  304. ============
  305. */
  306. void idAFAttachment::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir,
  307. const char *damageDefName, const float damageScale, const int location ) {
  308. if ( body ) {
  309. body->Damage( inflictor, attacker, dir, damageDefName, damageScale, attachJoint );
  310. }
  311. }
  312. /*
  313. ================
  314. idAFAttachment::AddDamageEffect
  315. ================
  316. */
  317. void idAFAttachment::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) {
  318. if ( body ) {
  319. trace_t c = collision;
  320. c.c.id = JOINT_HANDLE_TO_CLIPMODEL_ID( attachJoint );
  321. body->AddDamageEffect( c, velocity, damageDefName );
  322. }
  323. }
  324. /*
  325. ================
  326. idAFAttachment::GetImpactInfo
  327. ================
  328. */
  329. void idAFAttachment::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
  330. if ( body ) {
  331. body->GetImpactInfo( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( attachJoint ), point, info );
  332. } else {
  333. idEntity::GetImpactInfo( ent, id, point, info );
  334. }
  335. }
  336. /*
  337. ================
  338. idAFAttachment::ApplyImpulse
  339. ================
  340. */
  341. void idAFAttachment::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) {
  342. if ( body ) {
  343. body->ApplyImpulse( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( attachJoint ), point, impulse );
  344. } else {
  345. idEntity::ApplyImpulse( ent, id, point, impulse );
  346. }
  347. }
  348. /*
  349. ================
  350. idAFAttachment::AddForce
  351. ================
  352. */
  353. void idAFAttachment::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
  354. if ( body ) {
  355. body->AddForce( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( attachJoint ), point, force );
  356. } else {
  357. idEntity::AddForce( ent, id, point, force );
  358. }
  359. }
  360. /*
  361. ================
  362. idAFAttachment::PlayIdleAnim
  363. ================
  364. */
  365. void idAFAttachment::PlayIdleAnim( int blendTime ) {
  366. if ( idleAnim && ( idleAnim != animator.CurrentAnim( ANIMCHANNEL_ALL )->AnimNum() ) ) {
  367. animator.CycleAnim( ANIMCHANNEL_ALL, idleAnim, gameLocal.time, blendTime );
  368. }
  369. }
  370. /*
  371. ================
  372. idAfAttachment::Think
  373. ================
  374. */
  375. void idAFAttachment::Think() {
  376. idAnimatedEntity::Think();
  377. if ( thinkFlags & TH_UPDATEPARTICLES ) {
  378. UpdateDamageEffects();
  379. }
  380. }
  381. /*
  382. ================
  383. idAFAttachment::SetCombatModel
  384. ================
  385. */
  386. void idAFAttachment::SetCombatModel() {
  387. if ( combatModel ) {
  388. combatModel->Unlink();
  389. combatModel->LoadModel( modelDefHandle );
  390. } else {
  391. combatModel = new (TAG_PHYSICS_CLIP_AF) idClipModel( modelDefHandle );
  392. }
  393. combatModel->SetOwner( body );
  394. }
  395. /*
  396. ================
  397. idAFAttachment::GetCombatModel
  398. ================
  399. */
  400. idClipModel *idAFAttachment::GetCombatModel() const {
  401. return combatModel;
  402. }
  403. /*
  404. ================
  405. idAFAttachment::LinkCombat
  406. ================
  407. */
  408. void idAFAttachment::LinkCombat() {
  409. if ( fl.hidden ) {
  410. return;
  411. }
  412. if ( combatModel ) {
  413. combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  414. }
  415. }
  416. /*
  417. ================
  418. idAFAttachment::UnlinkCombat
  419. ================
  420. */
  421. void idAFAttachment::UnlinkCombat() {
  422. if ( combatModel ) {
  423. combatModel->Unlink();
  424. }
  425. }
  426. /*
  427. ===============================================================================
  428. idAFEntity_Base
  429. ===============================================================================
  430. */
  431. const idEventDef EV_SetConstraintPosition( "SetConstraintPosition", "sv" );
  432. CLASS_DECLARATION( idAnimatedEntity, idAFEntity_Base )
  433. EVENT( EV_SetConstraintPosition, idAFEntity_Base::Event_SetConstraintPosition )
  434. END_CLASS
  435. static const float BOUNCE_SOUND_MIN_VELOCITY = 80.0f;
  436. static const float BOUNCE_SOUND_MAX_VELOCITY = 200.0f;
  437. /*
  438. ================
  439. idAFEntity_Base::idAFEntity_Base
  440. ================
  441. */
  442. idAFEntity_Base::idAFEntity_Base() {
  443. combatModel = NULL;
  444. combatModelContents = 0;
  445. nextSoundTime = 0;
  446. spawnOrigin.Zero();
  447. spawnAxis.Identity();
  448. }
  449. /*
  450. ================
  451. idAFEntity_Base::~idAFEntity_Base
  452. ================
  453. */
  454. idAFEntity_Base::~idAFEntity_Base() {
  455. delete combatModel;
  456. combatModel = NULL;
  457. }
  458. /*
  459. ================
  460. idAFEntity_Base::Save
  461. ================
  462. */
  463. void idAFEntity_Base::Save( idSaveGame *savefile ) const {
  464. savefile->WriteInt( combatModelContents );
  465. savefile->WriteClipModel( combatModel );
  466. savefile->WriteVec3( spawnOrigin );
  467. savefile->WriteMat3( spawnAxis );
  468. savefile->WriteInt( nextSoundTime );
  469. af.Save( savefile );
  470. }
  471. /*
  472. ================
  473. idAFEntity_Base::Restore
  474. ================
  475. */
  476. void idAFEntity_Base::Restore( idRestoreGame *savefile ) {
  477. savefile->ReadInt( combatModelContents );
  478. savefile->ReadClipModel( combatModel );
  479. savefile->ReadVec3( spawnOrigin );
  480. savefile->ReadMat3( spawnAxis );
  481. savefile->ReadInt( nextSoundTime );
  482. LinkCombat();
  483. af.Restore( savefile );
  484. }
  485. /*
  486. ================
  487. idAFEntity_Base::Spawn
  488. ================
  489. */
  490. void idAFEntity_Base::Spawn() {
  491. spawnOrigin = GetPhysics()->GetOrigin();
  492. spawnAxis = GetPhysics()->GetAxis();
  493. nextSoundTime = 0;
  494. }
  495. /*
  496. ================
  497. idAFEntity_Base::LoadAF
  498. ================
  499. */
  500. bool idAFEntity_Base::LoadAF() {
  501. idStr fileName;
  502. if ( !spawnArgs.GetString( "articulatedFigure", "*unknown*", fileName ) ) {
  503. return false;
  504. }
  505. af.SetAnimator( GetAnimator() );
  506. if ( !af.Load( this, fileName ) ) {
  507. gameLocal.Error( "idAFEntity_Base::LoadAF: Couldn't load af file '%s' on entity '%s'", fileName.c_str(), name.c_str() );
  508. }
  509. float mass = spawnArgs.GetFloat( "mass", "-1" );
  510. if ( mass > 0.0f ) {
  511. af.GetPhysics()->SetMass( mass );
  512. }
  513. af.Start();
  514. af.GetPhysics()->Rotate( spawnAxis.ToRotation() );
  515. af.GetPhysics()->Translate( spawnOrigin );
  516. LoadState( spawnArgs );
  517. af.UpdateAnimation();
  518. animator.CreateFrame( gameLocal.time, true );
  519. UpdateVisuals();
  520. return true;
  521. }
  522. /*
  523. ================
  524. idAFEntity_Base::Think
  525. ================
  526. */
  527. void idAFEntity_Base::Think() {
  528. RunPhysics();
  529. UpdateAnimation();
  530. if ( thinkFlags & TH_UPDATEVISUALS ) {
  531. Present();
  532. LinkCombat();
  533. }
  534. }
  535. /*
  536. ================
  537. idAFEntity_Base::BodyForClipModelId
  538. ================
  539. */
  540. int idAFEntity_Base::BodyForClipModelId( int id ) const {
  541. return af.BodyForClipModelId( id );
  542. }
  543. /*
  544. ================
  545. idAFEntity_Base::SaveState
  546. ================
  547. */
  548. void idAFEntity_Base::SaveState( idDict &args ) const {
  549. const idKeyValue *kv;
  550. // save the ragdoll pose
  551. af.SaveState( args );
  552. // save all the bind constraints
  553. kv = spawnArgs.MatchPrefix( "bindConstraint ", NULL );
  554. while ( kv ) {
  555. args.Set( kv->GetKey(), kv->GetValue() );
  556. kv = spawnArgs.MatchPrefix( "bindConstraint ", kv );
  557. }
  558. // save the bind if it exists
  559. kv = spawnArgs.FindKey( "bind" );
  560. if ( kv ) {
  561. args.Set( kv->GetKey(), kv->GetValue() );
  562. }
  563. kv = spawnArgs.FindKey( "bindToJoint" );
  564. if ( kv ) {
  565. args.Set( kv->GetKey(), kv->GetValue() );
  566. }
  567. kv = spawnArgs.FindKey( "bindToBody" );
  568. if ( kv ) {
  569. args.Set( kv->GetKey(), kv->GetValue() );
  570. }
  571. }
  572. /*
  573. ================
  574. idAFEntity_Base::LoadState
  575. ================
  576. */
  577. void idAFEntity_Base::LoadState( const idDict &args ) {
  578. af.LoadState( args );
  579. }
  580. /*
  581. ================
  582. idAFEntity_Base::AddBindConstraints
  583. ================
  584. */
  585. void idAFEntity_Base::AddBindConstraints() {
  586. af.AddBindConstraints();
  587. }
  588. /*
  589. ================
  590. idAFEntity_Base::RemoveBindConstraints
  591. ================
  592. */
  593. void idAFEntity_Base::RemoveBindConstraints() {
  594. af.RemoveBindConstraints();
  595. }
  596. /*
  597. ================
  598. idAFEntity_Base::AddDamageEffect
  599. ================
  600. */
  601. void idAFEntity_Base::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) {
  602. idAnimatedEntity::AddDamageEffect( collision, velocity, damageDefName );
  603. }
  604. /*
  605. ================
  606. idAFEntity_Base::GetImpactInfo
  607. ================
  608. */
  609. void idAFEntity_Base::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
  610. if ( af.IsActive() ) {
  611. af.GetImpactInfo( ent, id, point, info );
  612. } else {
  613. idEntity::GetImpactInfo( ent, id, point, info );
  614. }
  615. }
  616. /*
  617. ================
  618. idAFEntity_Base::ApplyImpulse
  619. ================
  620. */
  621. void idAFEntity_Base::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) {
  622. if ( af.IsLoaded() ) {
  623. af.ApplyImpulse( ent, id, point, impulse );
  624. }
  625. if ( !af.IsActive() ) {
  626. idEntity::ApplyImpulse( ent, id, point, impulse );
  627. }
  628. }
  629. /*
  630. ================
  631. idAFEntity_Base::AddForce
  632. ================
  633. */
  634. void idAFEntity_Base::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
  635. if ( af.IsLoaded() ) {
  636. af.AddForce( ent, id, point, force );
  637. }
  638. if ( !af.IsActive() ) {
  639. idEntity::AddForce( ent, id, point, force );
  640. }
  641. }
  642. /*
  643. ================
  644. idAFEntity_Base::Collide
  645. ================
  646. */
  647. bool idAFEntity_Base::Collide( const trace_t &collision, const idVec3 &velocity ) {
  648. float v, f;
  649. if ( af.IsActive() ) {
  650. v = -( velocity * collision.c.normal );
  651. if ( v > BOUNCE_SOUND_MIN_VELOCITY && gameLocal.time > nextSoundTime ) {
  652. f = v > BOUNCE_SOUND_MAX_VELOCITY ? 1.0f : idMath::Sqrt( v - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / idMath::Sqrt( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) );
  653. if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) {
  654. // don't set the volume unless there is a bounce sound as it overrides the entire channel
  655. // which causes footsteps on ai's to not honor their shader parms
  656. SetSoundVolume( f );
  657. }
  658. nextSoundTime = gameLocal.time + 500;
  659. }
  660. }
  661. return false;
  662. }
  663. /*
  664. ================
  665. idAFEntity_Base::GetPhysicsToVisualTransform
  666. ================
  667. */
  668. bool idAFEntity_Base::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
  669. if ( af.IsActive() ) {
  670. af.GetPhysicsToVisualTransform( origin, axis );
  671. return true;
  672. }
  673. return idEntity::GetPhysicsToVisualTransform( origin, axis );
  674. }
  675. /*
  676. ================
  677. idAFEntity_Base::UpdateAnimationControllers
  678. ================
  679. */
  680. bool idAFEntity_Base::UpdateAnimationControllers() {
  681. if ( af.IsActive() ) {
  682. if ( af.UpdateAnimation() ) {
  683. return true;
  684. }
  685. }
  686. return false;
  687. }
  688. /*
  689. ================
  690. idAFEntity_Base::SetCombatModel
  691. ================
  692. */
  693. void idAFEntity_Base::SetCombatModel() {
  694. if ( combatModel ) {
  695. combatModel->Unlink();
  696. combatModel->LoadModel( modelDefHandle );
  697. } else {
  698. combatModel = new (TAG_PHYSICS_CLIP_AF) idClipModel( modelDefHandle );
  699. }
  700. }
  701. /*
  702. ================
  703. idAFEntity_Base::GetCombatModel
  704. ================
  705. */
  706. idClipModel *idAFEntity_Base::GetCombatModel() const {
  707. return combatModel;
  708. }
  709. /*
  710. ================
  711. idAFEntity_Base::SetCombatContents
  712. ================
  713. */
  714. void idAFEntity_Base::SetCombatContents( bool enable ) {
  715. assert( combatModel );
  716. if ( enable && combatModelContents ) {
  717. assert( !combatModel->GetContents() );
  718. combatModel->SetContents( combatModelContents );
  719. combatModelContents = 0;
  720. } else if ( !enable && combatModel->GetContents() ) {
  721. assert( !combatModelContents );
  722. combatModelContents = combatModel->GetContents();
  723. combatModel->SetContents( 0 );
  724. }
  725. }
  726. /*
  727. ================
  728. idAFEntity_Base::LinkCombat
  729. ================
  730. */
  731. void idAFEntity_Base::LinkCombat() {
  732. if ( fl.hidden ) {
  733. return;
  734. }
  735. if ( combatModel ) {
  736. combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  737. }
  738. }
  739. /*
  740. ================
  741. idAFEntity_Base::UnlinkCombat
  742. ================
  743. */
  744. void idAFEntity_Base::UnlinkCombat() {
  745. if ( combatModel ) {
  746. combatModel->Unlink();
  747. }
  748. }
  749. /*
  750. ================
  751. idAFEntity_Base::FreeModelDef
  752. ================
  753. */
  754. void idAFEntity_Base::FreeModelDef() {
  755. UnlinkCombat();
  756. idEntity::FreeModelDef();
  757. }
  758. /*
  759. ===============
  760. idAFEntity_Base::ShowEditingDialog
  761. ===============
  762. */
  763. void idAFEntity_Base::ShowEditingDialog() {
  764. }
  765. /*
  766. ================
  767. idAFEntity_Base::DropAFs
  768. The entity should have the following key/value pairs set:
  769. "def_drop<type>AF" "af def"
  770. "drop<type>Skin" "skin name"
  771. To drop multiple articulated figures the following key/value pairs can be used:
  772. "def_drop<type>AF*" "af def"
  773. where * is an aribtrary string.
  774. ================
  775. */
  776. void idAFEntity_Base::DropAFs( idEntity *ent, const char *type, idList<idEntity *> *list ) {
  777. const idKeyValue *kv;
  778. const char *skinName;
  779. idEntity *newEnt;
  780. idAFEntity_Base *af;
  781. idDict args;
  782. const idDeclSkin *skin;
  783. // drop the articulated figures
  784. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sAF", type ), NULL );
  785. while ( kv ) {
  786. args.Set( "classname", kv->GetValue() );
  787. gameLocal.SpawnEntityDef( args, &newEnt );
  788. if ( newEnt && newEnt->IsType( idAFEntity_Base::Type ) ) {
  789. af = static_cast<idAFEntity_Base *>(newEnt);
  790. af->GetPhysics()->SetOrigin( ent->GetPhysics()->GetOrigin() );
  791. af->GetPhysics()->SetAxis( ent->GetPhysics()->GetAxis() );
  792. af->af.SetupPose( ent, gameLocal.time );
  793. if ( list ) {
  794. list->Append( af );
  795. }
  796. }
  797. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sAF", type ), kv );
  798. }
  799. // change the skin to hide all the dropped articulated figures
  800. skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) );
  801. if ( skinName[0] ) {
  802. skin = declManager->FindSkin( skinName );
  803. ent->SetSkin( skin );
  804. }
  805. }
  806. /*
  807. ================
  808. idAFEntity_Base::Event_SetConstraintPosition
  809. ================
  810. */
  811. void idAFEntity_Base::Event_SetConstraintPosition( const char *name, const idVec3 &pos ) {
  812. af.SetConstraintPosition( name, pos );
  813. }
  814. /*
  815. ===============================================================================
  816. idAFEntity_Gibbable
  817. ===============================================================================
  818. */
  819. const idEventDef EV_Gib( "gib", "s" );
  820. const idEventDef EV_Gibbed( "<gibbed>" );
  821. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_Gibbable )
  822. EVENT( EV_Gib, idAFEntity_Gibbable::Event_Gib )
  823. EVENT( EV_Gibbed, idAFEntity_Base::Event_Remove )
  824. END_CLASS
  825. /*
  826. ================
  827. idAFEntity_Gibbable::idAFEntity_Gibbable
  828. ================
  829. */
  830. idAFEntity_Gibbable::idAFEntity_Gibbable() {
  831. skeletonModel = NULL;
  832. skeletonModelDefHandle = -1;
  833. gibbed = false;
  834. wasThrown = false;
  835. }
  836. /*
  837. ================
  838. idAFEntity_Gibbable::~idAFEntity_Gibbable
  839. ================
  840. */
  841. idAFEntity_Gibbable::~idAFEntity_Gibbable() {
  842. if ( skeletonModelDefHandle != -1 ) {
  843. gameRenderWorld->FreeEntityDef( skeletonModelDefHandle );
  844. skeletonModelDefHandle = -1;
  845. }
  846. }
  847. /*
  848. ================
  849. idAFEntity_Gibbable::Save
  850. ================
  851. */
  852. void idAFEntity_Gibbable::Save( idSaveGame *savefile ) const {
  853. savefile->WriteBool( gibbed );
  854. savefile->WriteBool( combatModel != NULL );
  855. savefile->WriteBool( wasThrown );
  856. }
  857. /*
  858. ================
  859. idAFEntity_Gibbable::Restore
  860. ================
  861. */
  862. void idAFEntity_Gibbable::Restore( idRestoreGame *savefile ) {
  863. bool hasCombatModel;
  864. savefile->ReadBool( gibbed );
  865. savefile->ReadBool( hasCombatModel );
  866. savefile->ReadBool( wasThrown );
  867. InitSkeletonModel();
  868. if ( hasCombatModel ) {
  869. SetCombatModel();
  870. LinkCombat();
  871. }
  872. }
  873. /*
  874. ================
  875. idAFEntity_Gibbable::Spawn
  876. ================
  877. */
  878. void idAFEntity_Gibbable::Spawn() {
  879. InitSkeletonModel();
  880. gibbed = false;
  881. wasThrown = false;
  882. }
  883. /*
  884. ================
  885. idAFEntity_Gibbable::InitSkeletonModel
  886. ================
  887. */
  888. void idAFEntity_Gibbable::InitSkeletonModel() {
  889. const char *modelName;
  890. const idDeclModelDef *modelDef;
  891. skeletonModel = NULL;
  892. skeletonModelDefHandle = -1;
  893. modelName = spawnArgs.GetString( "model_gib" );
  894. modelDef = NULL;
  895. if ( modelName[0] != '\0' ) {
  896. modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) );
  897. if ( modelDef ) {
  898. skeletonModel = modelDef->ModelHandle();
  899. } else {
  900. skeletonModel = renderModelManager->FindModel( modelName );
  901. }
  902. if ( skeletonModel != NULL && renderEntity.hModel != NULL ) {
  903. if ( skeletonModel->NumJoints() != renderEntity.hModel->NumJoints() ) {
  904. gameLocal.Error( "gib model '%s' has different number of joints than model '%s'",
  905. skeletonModel->Name(), renderEntity.hModel->Name() );
  906. }
  907. }
  908. }
  909. }
  910. /*
  911. ================
  912. idAFEntity_Gibbable::Present
  913. ================
  914. */
  915. void idAFEntity_Gibbable::Present() {
  916. renderEntity_t skeleton;
  917. if ( !gameLocal.isNewFrame ) {
  918. return;
  919. }
  920. // don't present to the renderer if the entity hasn't changed
  921. if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  922. return;
  923. }
  924. // update skeleton model
  925. if ( gibbed && !IsHidden() && skeletonModel != NULL ) {
  926. skeleton = renderEntity;
  927. skeleton.hModel = skeletonModel;
  928. // add to refresh list
  929. if ( skeletonModelDefHandle == -1 ) {
  930. skeletonModelDefHandle = gameRenderWorld->AddEntityDef( &skeleton );
  931. } else {
  932. gameRenderWorld->UpdateEntityDef( skeletonModelDefHandle, &skeleton );
  933. }
  934. }
  935. idEntity::Present();
  936. }
  937. /*
  938. ================
  939. idAFEntity_Gibbable::Damage
  940. ================
  941. */
  942. void idAFEntity_Gibbable::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
  943. if ( !fl.takedamage ) {
  944. return;
  945. }
  946. idAFEntity_Base::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
  947. if ( health < -20 && spawnArgs.GetBool( "gib" ) ) {
  948. Gib( dir, damageDefName );
  949. }
  950. }
  951. /*
  952. =====================
  953. idAFEntity_Gibbable::SetThrown
  954. =====================
  955. */
  956. void idAFEntity_Gibbable::SetThrown( bool isThrown ) {
  957. if ( isThrown ) {
  958. int i, num = af.GetPhysics()->GetNumBodies();
  959. for ( i=0; i<num; i++ ) {
  960. idAFBody *body;
  961. body = af.GetPhysics()->GetBody( i );
  962. body->SetClipMask( MASK_MONSTERSOLID );
  963. }
  964. }
  965. wasThrown = isThrown;
  966. }
  967. /*
  968. =====================
  969. idAFEntity_Gibbable::Collide
  970. =====================
  971. */
  972. bool idAFEntity_Gibbable::Collide( const trace_t &collision, const idVec3 &velocity ) {
  973. if ( !gibbed && wasThrown ) {
  974. // Everything gibs (if possible)
  975. if ( spawnArgs.GetBool( "gib" ) ) {
  976. idEntity *ent;
  977. ent = gameLocal.entities[ collision.c.entityNum ];
  978. if ( ent->fl.takedamage ) {
  979. ent->Damage( this, gameLocal.GetLocalPlayer(), collision.c.normal, "damage_thrown_ragdoll", 1.f, CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ) );
  980. }
  981. idVec3 vel = velocity;
  982. vel.NormalizeFast();
  983. Gib( vel, "damage_gib" );
  984. }
  985. }
  986. return idAFEntity_Base::Collide( collision, velocity );
  987. }
  988. /*
  989. =====================
  990. idAFEntity_Gibbable::SpawnGibs
  991. =====================
  992. */
  993. void idAFEntity_Gibbable::SpawnGibs( const idVec3 &dir, const char *damageDefName ) {
  994. int i;
  995. bool gibNonSolid;
  996. idVec3 entityCenter, velocity;
  997. idList<idEntity *> list;
  998. assert( !common->IsClient() );
  999. const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
  1000. if ( damageDef == NULL ) {
  1001. gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
  1002. return;
  1003. }
  1004. // spawn gib articulated figures
  1005. idAFEntity_Base::DropAFs( this, "gib", &list );
  1006. // spawn gib items
  1007. idMoveableItem::DropItems( this, "gib", &list );
  1008. // blow out the gibs in the given direction away from the center of the entity
  1009. entityCenter = GetPhysics()->GetAbsBounds().GetCenter();
  1010. gibNonSolid = damageDef->GetBool( "gibNonSolid" );
  1011. for ( i = 0; i < list.Num(); i++ ) {
  1012. if ( gibNonSolid ) {
  1013. list[i]->GetPhysics()->SetContents( 0 );
  1014. list[i]->GetPhysics()->SetClipMask( 0 );
  1015. list[i]->GetPhysics()->UnlinkClip();
  1016. list[i]->GetPhysics()->PutToRest();
  1017. } else {
  1018. list[i]->GetPhysics()->SetContents( 0 );
  1019. list[i]->GetPhysics()->SetClipMask( CONTENTS_SOLID );
  1020. velocity = list[i]->GetPhysics()->GetAbsBounds().GetCenter() - entityCenter;
  1021. velocity.NormalizeFast();
  1022. velocity += ( i & 1 ) ? dir : -dir;
  1023. list[i]->GetPhysics()->SetLinearVelocity( velocity * 75.0f );
  1024. }
  1025. // Don't allow grabber to pick up temporary gibs
  1026. list[i]->noGrab = true;
  1027. list[i]->GetRenderEntity()->noShadow = true;
  1028. list[i]->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  1029. list[i]->PostEventSec( &EV_Remove, 4.0f );
  1030. }
  1031. }
  1032. /*
  1033. ============
  1034. idAFEntity_Gibbable::Gib
  1035. ============
  1036. */
  1037. void idAFEntity_Gibbable::Gib( const idVec3 &dir, const char *damageDefName ) {
  1038. // only gib once
  1039. if ( gibbed ) {
  1040. return;
  1041. }
  1042. // Don't grab this ent after it's been gibbed (and now invisible!)
  1043. noGrab = true;
  1044. const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
  1045. if ( damageDef == NULL ) {
  1046. gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
  1047. return;
  1048. }
  1049. if ( damageDef->GetBool( "gibNonSolid" ) ) {
  1050. GetAFPhysics()->SetContents( 0 );
  1051. GetAFPhysics()->SetClipMask( 0 );
  1052. GetAFPhysics()->UnlinkClip();
  1053. GetAFPhysics()->PutToRest();
  1054. } else {
  1055. GetAFPhysics()->SetContents( CONTENTS_CORPSE );
  1056. GetAFPhysics()->SetClipMask( CONTENTS_SOLID );
  1057. }
  1058. UnlinkCombat();
  1059. if ( g_bloodEffects.GetBool() ) {
  1060. if ( gameLocal.time > gameLocal.GetGibTime() ) {
  1061. gameLocal.SetGibTime( gameLocal.time + GIB_DELAY );
  1062. SpawnGibs( dir, damageDefName );
  1063. renderEntity.noShadow = true;
  1064. renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  1065. StartSound( "snd_gibbed", SND_CHANNEL_ANY, 0, false, NULL );
  1066. gibbed = true;
  1067. }
  1068. } else {
  1069. gibbed = true;
  1070. }
  1071. PostEventSec( &EV_Gibbed, 4.0f );
  1072. }
  1073. /*
  1074. ============
  1075. idAFEntity_Gibbable::Event_Gib
  1076. ============
  1077. */
  1078. void idAFEntity_Gibbable::Event_Gib( const char *damageDefName ) {
  1079. Gib( idVec3( 0, 0, 1 ), damageDefName );
  1080. }
  1081. /*
  1082. ===============================================================================
  1083. idAFEntity_Generic
  1084. ===============================================================================
  1085. */
  1086. CLASS_DECLARATION( idAFEntity_Gibbable, idAFEntity_Generic )
  1087. EVENT( EV_Activate, idAFEntity_Generic::Event_Activate )
  1088. END_CLASS
  1089. /*
  1090. ================
  1091. idAFEntity_Generic::idAFEntity_Generic
  1092. ================
  1093. */
  1094. idAFEntity_Generic::idAFEntity_Generic() {
  1095. keepRunningPhysics = false;
  1096. }
  1097. /*
  1098. ================
  1099. idAFEntity_Generic::~idAFEntity_Generic
  1100. ================
  1101. */
  1102. idAFEntity_Generic::~idAFEntity_Generic() {
  1103. }
  1104. /*
  1105. ================
  1106. idAFEntity_Generic::Save
  1107. ================
  1108. */
  1109. void idAFEntity_Generic::Save( idSaveGame *savefile ) const {
  1110. savefile->WriteBool( keepRunningPhysics );
  1111. }
  1112. /*
  1113. ================
  1114. idAFEntity_Generic::Restore
  1115. ================
  1116. */
  1117. void idAFEntity_Generic::Restore( idRestoreGame *savefile ) {
  1118. savefile->ReadBool( keepRunningPhysics );
  1119. }
  1120. /*
  1121. ================
  1122. idAFEntity_Generic::Think
  1123. ================
  1124. */
  1125. void idAFEntity_Generic::Think() {
  1126. idAFEntity_Base::Think();
  1127. if ( keepRunningPhysics ) {
  1128. BecomeActive( TH_PHYSICS );
  1129. }
  1130. }
  1131. /*
  1132. ================
  1133. idAFEntity_Generic::Spawn
  1134. ================
  1135. */
  1136. void idAFEntity_Generic::Spawn() {
  1137. if ( !LoadAF() ) {
  1138. gameLocal.Error( "Couldn't load af file on entity '%s'", name.c_str() );
  1139. }
  1140. SetCombatModel();
  1141. SetPhysics( af.GetPhysics() );
  1142. af.GetPhysics()->PutToRest();
  1143. if ( !spawnArgs.GetBool( "nodrop", "0" ) ) {
  1144. af.GetPhysics()->Activate();
  1145. }
  1146. fl.takedamage = true;
  1147. }
  1148. /*
  1149. ================
  1150. idAFEntity_Generic::Event_Activate
  1151. ================
  1152. */
  1153. void idAFEntity_Generic::Event_Activate( idEntity *activator ) {
  1154. float delay;
  1155. idVec3 init_velocity, init_avelocity;
  1156. Show();
  1157. af.GetPhysics()->EnableImpact();
  1158. af.GetPhysics()->Activate();
  1159. spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity );
  1160. spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity );
  1161. delay = spawnArgs.GetFloat( "init_velocityDelay", "0" );
  1162. if ( delay == 0.0f ) {
  1163. af.GetPhysics()->SetLinearVelocity( init_velocity );
  1164. } else {
  1165. PostEventSec( &EV_SetLinearVelocity, delay, init_velocity );
  1166. }
  1167. delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" );
  1168. if ( delay == 0.0f ) {
  1169. af.GetPhysics()->SetAngularVelocity( init_avelocity );
  1170. } else {
  1171. PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity );
  1172. }
  1173. }
  1174. /*
  1175. ===============================================================================
  1176. idAFEntity_WithAttachedHead
  1177. ===============================================================================
  1178. */
  1179. CLASS_DECLARATION( idAFEntity_Gibbable, idAFEntity_WithAttachedHead )
  1180. EVENT( EV_Gib, idAFEntity_WithAttachedHead::Event_Gib )
  1181. EVENT( EV_Activate, idAFEntity_WithAttachedHead::Event_Activate )
  1182. END_CLASS
  1183. /*
  1184. ================
  1185. idAFEntity_WithAttachedHead::idAFEntity_WithAttachedHead
  1186. ================
  1187. */
  1188. idAFEntity_WithAttachedHead::idAFEntity_WithAttachedHead() {
  1189. head = NULL;
  1190. }
  1191. /*
  1192. ================
  1193. idAFEntity_WithAttachedHead::~idAFEntity_WithAttachedHead
  1194. ================
  1195. */
  1196. idAFEntity_WithAttachedHead::~idAFEntity_WithAttachedHead() {
  1197. if ( head.GetEntity() ) {
  1198. head.GetEntity()->ClearBody();
  1199. head.GetEntity()->PostEventMS( &EV_Remove, 0 );
  1200. }
  1201. }
  1202. /*
  1203. ================
  1204. idAFEntity_WithAttachedHead::Spawn
  1205. ================
  1206. */
  1207. void idAFEntity_WithAttachedHead::Spawn() {
  1208. SetupHead();
  1209. LoadAF();
  1210. SetCombatModel();
  1211. SetPhysics( af.GetPhysics() );
  1212. af.GetPhysics()->PutToRest();
  1213. if ( !spawnArgs.GetBool( "nodrop", "0" ) ) {
  1214. af.GetPhysics()->Activate();
  1215. }
  1216. fl.takedamage = true;
  1217. if ( head.GetEntity() ) {
  1218. int anim = head.GetEntity()->GetAnimator()->GetAnim( "dead" );
  1219. if ( anim ) {
  1220. head.GetEntity()->GetAnimator()->SetFrame( ANIMCHANNEL_ALL, anim, 0, gameLocal.time, 0 );
  1221. }
  1222. }
  1223. }
  1224. /*
  1225. ================
  1226. idAFEntity_WithAttachedHead::Save
  1227. ================
  1228. */
  1229. void idAFEntity_WithAttachedHead::Save( idSaveGame *savefile ) const {
  1230. head.Save( savefile );
  1231. }
  1232. /*
  1233. ================
  1234. idAFEntity_WithAttachedHead::Restore
  1235. ================
  1236. */
  1237. void idAFEntity_WithAttachedHead::Restore( idRestoreGame *savefile ) {
  1238. head.Restore( savefile );
  1239. }
  1240. /*
  1241. ================
  1242. idAFEntity_WithAttachedHead::SetupHead
  1243. ================
  1244. */
  1245. void idAFEntity_WithAttachedHead::SetupHead() {
  1246. idAFAttachment *headEnt;
  1247. idStr jointName;
  1248. const char *headModel;
  1249. jointHandle_t joint;
  1250. idVec3 origin;
  1251. idMat3 axis;
  1252. headModel = spawnArgs.GetString( "def_head", "" );
  1253. if ( headModel[ 0 ] ) {
  1254. jointName = spawnArgs.GetString( "head_joint" );
  1255. joint = animator.GetJointHandle( jointName );
  1256. if ( joint == INVALID_JOINT ) {
  1257. gameLocal.Error( "Joint '%s' not found for 'head_joint' on '%s'", jointName.c_str(), name.c_str() );
  1258. }
  1259. headEnt = static_cast<idAFAttachment *>( gameLocal.SpawnEntityType( idAFAttachment::Type, NULL ) );
  1260. headEnt->SetName( va( "%s_head", name.c_str() ) );
  1261. headEnt->SetBody( this, headModel, joint );
  1262. headEnt->SetCombatModel();
  1263. head = headEnt;
  1264. idStr xSkin;
  1265. if ( spawnArgs.GetString( "skin_head_xray", "", xSkin ) ) {
  1266. headEnt->xraySkin = declManager->FindSkin( xSkin.c_str() );
  1267. headEnt->UpdateModel();
  1268. }
  1269. animator.GetJointTransform( joint, gameLocal.time, origin, axis );
  1270. origin = renderEntity.origin + origin * renderEntity.axis;
  1271. headEnt->SetOrigin( origin );
  1272. headEnt->SetAxis( renderEntity.axis );
  1273. headEnt->BindToJoint( this, joint, true );
  1274. }
  1275. }
  1276. /*
  1277. ================
  1278. idAFEntity_WithAttachedHead::Think
  1279. ================
  1280. */
  1281. void idAFEntity_WithAttachedHead::Think() {
  1282. idAFEntity_Base::Think();
  1283. }
  1284. /*
  1285. ================
  1286. idAFEntity_WithAttachedHead::LinkCombat
  1287. ================
  1288. */
  1289. void idAFEntity_WithAttachedHead::LinkCombat() {
  1290. idAFAttachment *headEnt;
  1291. if ( fl.hidden ) {
  1292. return;
  1293. }
  1294. if ( combatModel ) {
  1295. combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  1296. }
  1297. headEnt = head.GetEntity();
  1298. if ( headEnt ) {
  1299. headEnt->LinkCombat();
  1300. }
  1301. }
  1302. /*
  1303. ================
  1304. idAFEntity_WithAttachedHead::UnlinkCombat
  1305. ================
  1306. */
  1307. void idAFEntity_WithAttachedHead::UnlinkCombat() {
  1308. idAFAttachment *headEnt;
  1309. if ( combatModel ) {
  1310. combatModel->Unlink();
  1311. }
  1312. headEnt = head.GetEntity();
  1313. if ( headEnt ) {
  1314. headEnt->UnlinkCombat();
  1315. }
  1316. }
  1317. /*
  1318. ================
  1319. idAFEntity_WithAttachedHead::Hide
  1320. ================
  1321. */
  1322. void idAFEntity_WithAttachedHead::Hide() {
  1323. idAFEntity_Base::Hide();
  1324. if ( head.GetEntity() ) {
  1325. head.GetEntity()->Hide();
  1326. }
  1327. UnlinkCombat();
  1328. }
  1329. /*
  1330. ================
  1331. idAFEntity_WithAttachedHead::Show
  1332. ================
  1333. */
  1334. void idAFEntity_WithAttachedHead::Show() {
  1335. idAFEntity_Base::Show();
  1336. if ( head.GetEntity() ) {
  1337. head.GetEntity()->Show();
  1338. }
  1339. LinkCombat();
  1340. }
  1341. /*
  1342. ================
  1343. idAFEntity_WithAttachedHead::ProjectOverlay
  1344. ================
  1345. */
  1346. void idAFEntity_WithAttachedHead::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
  1347. idEntity::ProjectOverlay( origin, dir, size, material );
  1348. if ( head.GetEntity() ) {
  1349. head.GetEntity()->ProjectOverlay( origin, dir, size, material );
  1350. }
  1351. }
  1352. /*
  1353. ============
  1354. idAFEntity_WithAttachedHead::Gib
  1355. ============
  1356. */
  1357. void idAFEntity_WithAttachedHead::Gib( const idVec3 &dir, const char *damageDefName ) {
  1358. // only gib once
  1359. if ( gibbed ) {
  1360. return;
  1361. }
  1362. idAFEntity_Gibbable::Gib( dir, damageDefName );
  1363. if ( head.GetEntity() ) {
  1364. head.GetEntity()->Hide();
  1365. }
  1366. }
  1367. /*
  1368. ============
  1369. idAFEntity_WithAttachedHead::Event_Gib
  1370. ============
  1371. */
  1372. void idAFEntity_WithAttachedHead::Event_Gib( const char *damageDefName ) {
  1373. Gib( idVec3( 0, 0, 1 ), damageDefName );
  1374. }
  1375. /*
  1376. ================
  1377. idAFEntity_WithAttachedHead::Event_Activate
  1378. ================
  1379. */
  1380. void idAFEntity_WithAttachedHead::Event_Activate( idEntity *activator ) {
  1381. float delay;
  1382. idVec3 init_velocity, init_avelocity;
  1383. Show();
  1384. af.GetPhysics()->EnableImpact();
  1385. af.GetPhysics()->Activate();
  1386. spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity );
  1387. spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity );
  1388. delay = spawnArgs.GetFloat( "init_velocityDelay", "0" );
  1389. if ( delay == 0.0f ) {
  1390. af.GetPhysics()->SetLinearVelocity( init_velocity );
  1391. } else {
  1392. PostEventSec( &EV_SetLinearVelocity, delay, init_velocity );
  1393. }
  1394. delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" );
  1395. if ( delay == 0.0f ) {
  1396. af.GetPhysics()->SetAngularVelocity( init_avelocity );
  1397. } else {
  1398. PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity );
  1399. }
  1400. }
  1401. /*
  1402. ===============================================================================
  1403. idAFEntity_Vehicle
  1404. ===============================================================================
  1405. */
  1406. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_Vehicle )
  1407. END_CLASS
  1408. /*
  1409. ================
  1410. idAFEntity_Vehicle::idAFEntity_Vehicle
  1411. ================
  1412. */
  1413. idAFEntity_Vehicle::idAFEntity_Vehicle() {
  1414. player = NULL;
  1415. eyesJoint = INVALID_JOINT;
  1416. steeringWheelJoint = INVALID_JOINT;
  1417. wheelRadius = 0.0f;
  1418. steerAngle = 0.0f;
  1419. steerSpeed = 0.0f;
  1420. dustSmoke = NULL;
  1421. }
  1422. /*
  1423. ================
  1424. idAFEntity_Vehicle::Spawn
  1425. ================
  1426. */
  1427. void idAFEntity_Vehicle::Spawn() {
  1428. const char *eyesJointName = spawnArgs.GetString( "eyesJoint", "eyes" );
  1429. const char *steeringWheelJointName = spawnArgs.GetString( "steeringWheelJoint", "steeringWheel" );
  1430. LoadAF();
  1431. SetCombatModel();
  1432. SetPhysics( af.GetPhysics() );
  1433. fl.takedamage = true;
  1434. if ( !eyesJointName[0] ) {
  1435. gameLocal.Error( "idAFEntity_Vehicle '%s' no eyes joint specified", name.c_str() );
  1436. }
  1437. eyesJoint = animator.GetJointHandle( eyesJointName );
  1438. if ( !steeringWheelJointName[0] ) {
  1439. gameLocal.Error( "idAFEntity_Vehicle '%s' no steering wheel joint specified", name.c_str() );
  1440. }
  1441. steeringWheelJoint = animator.GetJointHandle( steeringWheelJointName );
  1442. spawnArgs.GetFloat( "wheelRadius", "20", wheelRadius );
  1443. spawnArgs.GetFloat( "steerSpeed", "5", steerSpeed );
  1444. player = NULL;
  1445. steerAngle = 0.0f;
  1446. const char *smokeName = spawnArgs.GetString( "smoke_vehicle_dust", "muzzlesmoke" );
  1447. if ( *smokeName != '\0' ) {
  1448. dustSmoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1449. }
  1450. }
  1451. /*
  1452. ================
  1453. idAFEntity_Vehicle::Use
  1454. ================
  1455. */
  1456. void idAFEntity_Vehicle::Use( idPlayer *other ) {
  1457. idVec3 origin;
  1458. idMat3 axis;
  1459. if ( player ) {
  1460. if ( player == other ) {
  1461. other->Unbind();
  1462. player = NULL;
  1463. af.GetPhysics()->SetComeToRest( true );
  1464. }
  1465. }
  1466. else {
  1467. player = other;
  1468. animator.GetJointTransform( eyesJoint, gameLocal.time, origin, axis );
  1469. origin = renderEntity.origin + origin * renderEntity.axis;
  1470. player->GetPhysics()->SetOrigin( origin );
  1471. player->BindToBody( this, 0, true );
  1472. af.GetPhysics()->SetComeToRest( false );
  1473. af.GetPhysics()->Activate();
  1474. }
  1475. }
  1476. /*
  1477. ================
  1478. idAFEntity_Vehicle::GetSteerAngle
  1479. ================
  1480. */
  1481. float idAFEntity_Vehicle::GetSteerAngle() {
  1482. float idealSteerAngle, angleDelta;
  1483. idealSteerAngle = player->usercmd.rightmove * ( 30.0f / 128.0f );
  1484. angleDelta = idealSteerAngle - steerAngle;
  1485. if ( angleDelta > steerSpeed ) {
  1486. steerAngle += steerSpeed;
  1487. } else if ( angleDelta < -steerSpeed ) {
  1488. steerAngle -= steerSpeed;
  1489. } else {
  1490. steerAngle = idealSteerAngle;
  1491. }
  1492. return steerAngle;
  1493. }
  1494. /*
  1495. ===============================================================================
  1496. idAFEntity_VehicleSimple
  1497. ===============================================================================
  1498. */
  1499. CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleSimple )
  1500. END_CLASS
  1501. /*
  1502. ================
  1503. idAFEntity_VehicleSimple::idAFEntity_VehicleSimple
  1504. ================
  1505. */
  1506. idAFEntity_VehicleSimple::idAFEntity_VehicleSimple() {
  1507. int i;
  1508. for ( i = 0; i < 4; i++ ) {
  1509. suspension[i] = NULL;
  1510. }
  1511. }
  1512. /*
  1513. ================
  1514. idAFEntity_VehicleSimple::~idAFEntity_VehicleSimple
  1515. ================
  1516. */
  1517. idAFEntity_VehicleSimple::~idAFEntity_VehicleSimple() {
  1518. delete wheelModel;
  1519. wheelModel = NULL;
  1520. }
  1521. /*
  1522. ================
  1523. idAFEntity_VehicleSimple::Spawn
  1524. ================
  1525. */
  1526. void idAFEntity_VehicleSimple::Spawn() {
  1527. static const char *wheelJointKeys[] = {
  1528. "wheelJointFrontLeft",
  1529. "wheelJointFrontRight",
  1530. "wheelJointRearLeft",
  1531. "wheelJointRearRight"
  1532. };
  1533. static idVec3 wheelPoly[4] = { idVec3( 2, 2, 0 ), idVec3( 2, -2, 0 ), idVec3( -2, -2, 0 ), idVec3( -2, 2, 0 ) };
  1534. int i;
  1535. idVec3 origin;
  1536. idMat3 axis;
  1537. idTraceModel trm;
  1538. trm.SetupPolygon( wheelPoly, 4 );
  1539. trm.Translate( idVec3( 0, 0, -wheelRadius ) );
  1540. wheelModel = new (TAG_PHYSICS_CLIP_AF) idClipModel( trm );
  1541. for ( i = 0; i < 4; i++ ) {
  1542. const char *wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" );
  1543. if ( !wheelJointName[0] ) {
  1544. gameLocal.Error( "idAFEntity_VehicleSimple '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] );
  1545. }
  1546. wheelJoints[i] = animator.GetJointHandle( wheelJointName );
  1547. if ( wheelJoints[i] == INVALID_JOINT ) {
  1548. gameLocal.Error( "idAFEntity_VehicleSimple '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName );
  1549. }
  1550. GetAnimator()->GetJointTransform( wheelJoints[i], 0, origin, axis );
  1551. origin = renderEntity.origin + origin * renderEntity.axis;
  1552. suspension[i] = new (TAG_PHYSICS_AF) idAFConstraint_Suspension();
  1553. suspension[i]->Setup( va( "suspension%d", i ), af.GetPhysics()->GetBody( 0 ), origin, af.GetPhysics()->GetAxis( 0 ), wheelModel );
  1554. suspension[i]->SetSuspension( g_vehicleSuspensionUp.GetFloat(),
  1555. g_vehicleSuspensionDown.GetFloat(),
  1556. g_vehicleSuspensionKCompress.GetFloat(),
  1557. g_vehicleSuspensionDamping.GetFloat(),
  1558. g_vehicleTireFriction.GetFloat() );
  1559. af.GetPhysics()->AddConstraint( suspension[i] );
  1560. }
  1561. memset( wheelAngles, 0, sizeof( wheelAngles ) );
  1562. BecomeActive( TH_THINK );
  1563. }
  1564. /*
  1565. ================
  1566. idAFEntity_VehicleSimple::Think
  1567. ================
  1568. */
  1569. void idAFEntity_VehicleSimple::Think() {
  1570. int i;
  1571. float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f;
  1572. idVec3 origin;
  1573. idMat3 axis;
  1574. idRotation wheelRotation, steerRotation;
  1575. if ( thinkFlags & TH_THINK ) {
  1576. if ( player ) {
  1577. // capture the input from a player
  1578. velocity = g_vehicleVelocity.GetFloat();
  1579. if ( player->usercmd.forwardmove < 0 ) {
  1580. velocity = -velocity;
  1581. }
  1582. force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f);
  1583. steerAngle = GetSteerAngle();
  1584. }
  1585. // update the wheel motor force and steering
  1586. for ( i = 0; i < 2; i++ ) {
  1587. // front wheel drive
  1588. if ( velocity != 0.0f ) {
  1589. suspension[i]->EnableMotor( true );
  1590. } else {
  1591. suspension[i]->EnableMotor( false );
  1592. }
  1593. suspension[i]->SetMotorVelocity( velocity );
  1594. suspension[i]->SetMotorForce( force );
  1595. // update the wheel steering
  1596. suspension[i]->SetSteerAngle( steerAngle );
  1597. }
  1598. // adjust wheel velocity for better steering because there are no differentials between the wheels
  1599. if ( steerAngle < 0.0f ) {
  1600. suspension[0]->SetMotorVelocity( velocity * 0.5f );
  1601. } else if ( steerAngle > 0.0f ) {
  1602. suspension[1]->SetMotorVelocity( velocity * 0.5f );
  1603. }
  1604. // update suspension with latest cvar settings
  1605. for ( i = 0; i < 4; i++ ) {
  1606. suspension[i]->SetSuspension( g_vehicleSuspensionUp.GetFloat(),
  1607. g_vehicleSuspensionDown.GetFloat(),
  1608. g_vehicleSuspensionKCompress.GetFloat(),
  1609. g_vehicleSuspensionDamping.GetFloat(),
  1610. g_vehicleTireFriction.GetFloat() );
  1611. }
  1612. // run the physics
  1613. RunPhysics();
  1614. // move and rotate the wheels visually
  1615. for ( i = 0; i < 4; i++ ) {
  1616. idAFBody *body = af.GetPhysics()->GetBody( 0 );
  1617. origin = suspension[i]->GetWheelOrigin();
  1618. velocity = body->GetPointVelocity( origin ) * body->GetWorldAxis()[0];
  1619. wheelAngles[i] += velocity * MS2SEC( gameLocal.time - gameLocal.previousTime ) / wheelRadius;
  1620. // additional rotation about the wheel axis
  1621. wheelRotation.SetAngle( RAD2DEG( wheelAngles[i] ) );
  1622. wheelRotation.SetVec( 0, -1, 0 );
  1623. if ( i < 2 ) {
  1624. // rotate the wheel for steering
  1625. steerRotation.SetAngle( steerAngle );
  1626. steerRotation.SetVec( 0, 0, 1 );
  1627. // set wheel rotation
  1628. animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, wheelRotation.ToMat3() * steerRotation.ToMat3() );
  1629. } else {
  1630. // set wheel rotation
  1631. animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, wheelRotation.ToMat3() );
  1632. }
  1633. // set wheel position for suspension
  1634. origin = ( origin - renderEntity.origin ) * renderEntity.axis.Transpose();
  1635. GetAnimator()->SetJointPos( wheelJoints[i], JOINTMOD_WORLD_OVERRIDE, origin );
  1636. }
  1637. /*
  1638. // spawn dust particle effects
  1639. if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) {
  1640. int numContacts;
  1641. idAFConstraint_Contact *contacts[2];
  1642. for ( i = 0; i < 4; i++ ) {
  1643. numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 );
  1644. for ( int j = 0; j < numContacts; j++ ) {
  1645. gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() );
  1646. }
  1647. }
  1648. }
  1649. */
  1650. }
  1651. UpdateAnimation();
  1652. if ( thinkFlags & TH_UPDATEVISUALS ) {
  1653. Present();
  1654. LinkCombat();
  1655. }
  1656. }
  1657. /*
  1658. ===============================================================================
  1659. idAFEntity_VehicleFourWheels
  1660. ===============================================================================
  1661. */
  1662. CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleFourWheels )
  1663. END_CLASS
  1664. /*
  1665. ================
  1666. idAFEntity_VehicleFourWheels::idAFEntity_VehicleFourWheels
  1667. ================
  1668. */
  1669. idAFEntity_VehicleFourWheels::idAFEntity_VehicleFourWheels() {
  1670. int i;
  1671. for ( i = 0; i < 4; i++ ) {
  1672. wheels[i] = NULL;
  1673. wheelJoints[i] = INVALID_JOINT;
  1674. wheelAngles[i] = 0.0f;
  1675. }
  1676. steering[0] = NULL;
  1677. steering[1] = NULL;
  1678. }
  1679. /*
  1680. ================
  1681. idAFEntity_VehicleFourWheels::Spawn
  1682. ================
  1683. */
  1684. void idAFEntity_VehicleFourWheels::Spawn() {
  1685. int i;
  1686. static const char *wheelBodyKeys[] = {
  1687. "wheelBodyFrontLeft",
  1688. "wheelBodyFrontRight",
  1689. "wheelBodyRearLeft",
  1690. "wheelBodyRearRight"
  1691. };
  1692. static const char *wheelJointKeys[] = {
  1693. "wheelJointFrontLeft",
  1694. "wheelJointFrontRight",
  1695. "wheelJointRearLeft",
  1696. "wheelJointRearRight"
  1697. };
  1698. static const char *steeringHingeKeys[] = {
  1699. "steeringHingeFrontLeft",
  1700. "steeringHingeFrontRight",
  1701. };
  1702. const char *wheelBodyName, *wheelJointName, *steeringHingeName;
  1703. for ( i = 0; i < 4; i++ ) {
  1704. wheelBodyName = spawnArgs.GetString( wheelBodyKeys[i], "" );
  1705. if ( !wheelBodyName[0] ) {
  1706. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), wheelBodyKeys[i] );
  1707. }
  1708. wheels[i] = af.GetPhysics()->GetBody( wheelBodyName );
  1709. if ( !wheels[i] ) {
  1710. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' can't find wheel body '%s'", name.c_str(), wheelBodyName );
  1711. }
  1712. wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" );
  1713. if ( !wheelJointName[0] ) {
  1714. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] );
  1715. }
  1716. wheelJoints[i] = animator.GetJointHandle( wheelJointName );
  1717. if ( wheelJoints[i] == INVALID_JOINT ) {
  1718. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName );
  1719. }
  1720. }
  1721. for ( i = 0; i < 2; i++ ) {
  1722. steeringHingeName = spawnArgs.GetString( steeringHingeKeys[i], "" );
  1723. if ( !steeringHingeName[0] ) {
  1724. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), steeringHingeKeys[i] );
  1725. }
  1726. steering[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( steeringHingeName ));
  1727. if ( !steering[i] ) {
  1728. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s': can't find steering hinge '%s'", name.c_str(), steeringHingeName );
  1729. }
  1730. }
  1731. memset( wheelAngles, 0, sizeof( wheelAngles ) );
  1732. BecomeActive( TH_THINK );
  1733. }
  1734. /*
  1735. ================
  1736. idAFEntity_VehicleFourWheels::Think
  1737. ================
  1738. */
  1739. void idAFEntity_VehicleFourWheels::Think() {
  1740. int i;
  1741. float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f;
  1742. idVec3 origin;
  1743. idMat3 axis;
  1744. idRotation rotation;
  1745. if ( thinkFlags & TH_THINK ) {
  1746. if ( player ) {
  1747. // capture the input from a player
  1748. velocity = g_vehicleVelocity.GetFloat();
  1749. if ( player->usercmd.forwardmove < 0 ) {
  1750. velocity = -velocity;
  1751. }
  1752. force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f);
  1753. steerAngle = GetSteerAngle();
  1754. }
  1755. // update the wheel motor force
  1756. for ( i = 0; i < 2; i++ ) {
  1757. wheels[2+i]->SetContactMotorVelocity( velocity );
  1758. wheels[2+i]->SetContactMotorForce( force );
  1759. }
  1760. // adjust wheel velocity for better steering because there are no differentials between the wheels
  1761. if ( steerAngle < 0.0f ) {
  1762. wheels[2]->SetContactMotorVelocity( velocity * 0.5f );
  1763. }
  1764. else if ( steerAngle > 0.0f ) {
  1765. wheels[3]->SetContactMotorVelocity( velocity * 0.5f );
  1766. }
  1767. // update the wheel steering
  1768. steering[0]->SetSteerAngle( steerAngle );
  1769. steering[1]->SetSteerAngle( steerAngle );
  1770. for ( i = 0; i < 2; i++ ) {
  1771. steering[i]->SetSteerSpeed( 3.0f );
  1772. }
  1773. // update the steering wheel
  1774. animator.GetJointTransform( steeringWheelJoint, gameLocal.time, origin, axis );
  1775. rotation.SetVec( axis[2] );
  1776. rotation.SetAngle( -steerAngle );
  1777. animator.SetJointAxis( steeringWheelJoint, JOINTMOD_WORLD, rotation.ToMat3() );
  1778. // run the physics
  1779. RunPhysics();
  1780. // rotate the wheels visually
  1781. for ( i = 0; i < 4; i++ ) {
  1782. if ( force == 0.0f ) {
  1783. velocity = wheels[i]->GetLinearVelocity() * wheels[i]->GetWorldAxis()[0];
  1784. }
  1785. wheelAngles[i] += velocity * MS2SEC( gameLocal.time - gameLocal.previousTime ) / wheelRadius;
  1786. // give the wheel joint an additional rotation about the wheel axis
  1787. rotation.SetAngle( RAD2DEG( wheelAngles[i] ) );
  1788. axis = af.GetPhysics()->GetAxis( 0 );
  1789. rotation.SetVec( (wheels[i]->GetWorldAxis() * axis.Transpose())[2] );
  1790. animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, rotation.ToMat3() );
  1791. }
  1792. // spawn dust particle effects
  1793. if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) {
  1794. int numContacts;
  1795. idAFConstraint_Contact *contacts[2];
  1796. for ( i = 0; i < 4; i++ ) {
  1797. numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 );
  1798. for ( int j = 0; j < numContacts; j++ ) {
  1799. gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3(), timeGroup /* D3XP */ );
  1800. }
  1801. }
  1802. }
  1803. }
  1804. UpdateAnimation();
  1805. if ( thinkFlags & TH_UPDATEVISUALS ) {
  1806. Present();
  1807. LinkCombat();
  1808. }
  1809. }
  1810. /*
  1811. ===============================================================================
  1812. idAFEntity_VehicleSixWheels
  1813. ===============================================================================
  1814. */
  1815. CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleSixWheels )
  1816. END_CLASS
  1817. /*
  1818. ================
  1819. idAFEntity_VehicleSixWheels::idAFEntity_VehicleSixWheels
  1820. ================
  1821. */
  1822. idAFEntity_VehicleSixWheels::idAFEntity_VehicleSixWheels() {
  1823. int i;
  1824. for ( i = 0; i < 6; i++ ) {
  1825. wheels[i] = NULL;
  1826. wheelJoints[i] = INVALID_JOINT;
  1827. wheelAngles[i] = 0.0f;
  1828. }
  1829. steering[0] = NULL;
  1830. steering[1] = NULL;
  1831. steering[2] = NULL;
  1832. steering[3] = NULL;
  1833. }
  1834. /*
  1835. ================
  1836. idAFEntity_VehicleSixWheels::Spawn
  1837. ================
  1838. */
  1839. void idAFEntity_VehicleSixWheels::Spawn() {
  1840. int i;
  1841. static const char *wheelBodyKeys[] = {
  1842. "wheelBodyFrontLeft",
  1843. "wheelBodyFrontRight",
  1844. "wheelBodyMiddleLeft",
  1845. "wheelBodyMiddleRight",
  1846. "wheelBodyRearLeft",
  1847. "wheelBodyRearRight"
  1848. };
  1849. static const char *wheelJointKeys[] = {
  1850. "wheelJointFrontLeft",
  1851. "wheelJointFrontRight",
  1852. "wheelJointMiddleLeft",
  1853. "wheelJointMiddleRight",
  1854. "wheelJointRearLeft",
  1855. "wheelJointRearRight"
  1856. };
  1857. static const char *steeringHingeKeys[] = {
  1858. "steeringHingeFrontLeft",
  1859. "steeringHingeFrontRight",
  1860. "steeringHingeRearLeft",
  1861. "steeringHingeRearRight"
  1862. };
  1863. const char *wheelBodyName, *wheelJointName, *steeringHingeName;
  1864. for ( i = 0; i < 6; i++ ) {
  1865. wheelBodyName = spawnArgs.GetString( wheelBodyKeys[i], "" );
  1866. if ( !wheelBodyName[0] ) {
  1867. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), wheelBodyKeys[i] );
  1868. }
  1869. wheels[i] = af.GetPhysics()->GetBody( wheelBodyName );
  1870. if ( !wheels[i] ) {
  1871. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' can't find wheel body '%s'", name.c_str(), wheelBodyName );
  1872. }
  1873. wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" );
  1874. if ( !wheelJointName[0] ) {
  1875. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] );
  1876. }
  1877. wheelJoints[i] = animator.GetJointHandle( wheelJointName );
  1878. if ( wheelJoints[i] == INVALID_JOINT ) {
  1879. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName );
  1880. }
  1881. }
  1882. for ( i = 0; i < 4; i++ ) {
  1883. steeringHingeName = spawnArgs.GetString( steeringHingeKeys[i], "" );
  1884. if ( !steeringHingeName[0] ) {
  1885. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), steeringHingeKeys[i] );
  1886. }
  1887. steering[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( steeringHingeName ));
  1888. if ( !steering[i] ) {
  1889. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s': can't find steering hinge '%s'", name.c_str(), steeringHingeName );
  1890. }
  1891. }
  1892. memset( wheelAngles, 0, sizeof( wheelAngles ) );
  1893. BecomeActive( TH_THINK );
  1894. }
  1895. /*
  1896. ================
  1897. idAFEntity_VehicleSixWheels::Think
  1898. ================
  1899. */
  1900. void idAFEntity_VehicleSixWheels::Think() {
  1901. int i;
  1902. idVec3 origin;
  1903. idMat3 axis;
  1904. idRotation rotation;
  1905. if ( thinkFlags & TH_THINK ) {
  1906. if ( player ) {
  1907. // capture the input from a player
  1908. velocity = g_vehicleVelocity.GetFloat();
  1909. if ( player->usercmd.forwardmove < 0 ) {
  1910. velocity = -velocity;
  1911. }
  1912. force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f);
  1913. steerAngle = GetSteerAngle();
  1914. }
  1915. // update the wheel motor force
  1916. for ( i = 0; i < 6; i++ ) {
  1917. wheels[i]->SetContactMotorVelocity( velocity );
  1918. wheels[i]->SetContactMotorForce( force );
  1919. }
  1920. // adjust wheel velocity for better steering because there are no differentials between the wheels
  1921. if ( steerAngle < 0.0f ) {
  1922. for ( i = 0; i < 3; i++ ) {
  1923. wheels[(i<<1)]->SetContactMotorVelocity( velocity * 0.5f );
  1924. }
  1925. }
  1926. else if ( steerAngle > 0.0f ) {
  1927. for ( i = 0; i < 3; i++ ) {
  1928. wheels[1+(i<<1)]->SetContactMotorVelocity( velocity * 0.5f );
  1929. }
  1930. }
  1931. // update the wheel steering
  1932. steering[0]->SetSteerAngle( steerAngle );
  1933. steering[1]->SetSteerAngle( steerAngle );
  1934. steering[2]->SetSteerAngle( -steerAngle );
  1935. steering[3]->SetSteerAngle( -steerAngle );
  1936. for ( i = 0; i < 4; i++ ) {
  1937. steering[i]->SetSteerSpeed( 3.0f );
  1938. }
  1939. // update the steering wheel
  1940. animator.GetJointTransform( steeringWheelJoint, gameLocal.time, origin, axis );
  1941. rotation.SetVec( axis[2] );
  1942. rotation.SetAngle( -steerAngle );
  1943. animator.SetJointAxis( steeringWheelJoint, JOINTMOD_WORLD, rotation.ToMat3() );
  1944. // run the physics
  1945. RunPhysics();
  1946. // rotate the wheels visually
  1947. for ( i = 0; i < 6; i++ ) {
  1948. if ( force == 0.0f ) {
  1949. velocity = wheels[i]->GetLinearVelocity() * wheels[i]->GetWorldAxis()[0];
  1950. }
  1951. wheelAngles[i] += velocity * MS2SEC( gameLocal.time - gameLocal.previousTime ) / wheelRadius;
  1952. // give the wheel joint an additional rotation about the wheel axis
  1953. rotation.SetAngle( RAD2DEG( wheelAngles[i] ) );
  1954. axis = af.GetPhysics()->GetAxis( 0 );
  1955. rotation.SetVec( (wheels[i]->GetWorldAxis() * axis.Transpose())[2] );
  1956. animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, rotation.ToMat3() );
  1957. }
  1958. // spawn dust particle effects
  1959. if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) {
  1960. int numContacts;
  1961. idAFConstraint_Contact *contacts[2];
  1962. for ( i = 0; i < 6; i++ ) {
  1963. numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 );
  1964. for ( int j = 0; j < numContacts; j++ ) {
  1965. gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3(), timeGroup /* D3XP */ );
  1966. }
  1967. }
  1968. }
  1969. }
  1970. UpdateAnimation();
  1971. if ( thinkFlags & TH_UPDATEVISUALS ) {
  1972. Present();
  1973. LinkCombat();
  1974. }
  1975. }
  1976. /*
  1977. ===============================================================================
  1978. idAFEntity_VehicleAutomated
  1979. ===============================================================================
  1980. */
  1981. const idEventDef EV_Vehicle_setVelocity( "setVelocity", "f" );
  1982. const idEventDef EV_Vehicle_setTorque( "setTorque", "f" );
  1983. const idEventDef EV_Vehicle_setSteeringSpeed( "setSteeringSpeed", "f" );
  1984. const idEventDef EV_Vehicle_setWaypoint( "setWaypoint", "e" );
  1985. CLASS_DECLARATION( idAFEntity_VehicleSixWheels, idAFEntity_VehicleAutomated )
  1986. EVENT( EV_PostSpawn, idAFEntity_VehicleAutomated::PostSpawn )
  1987. EVENT( EV_Vehicle_setVelocity, idAFEntity_VehicleAutomated::Event_SetVelocity )
  1988. EVENT( EV_Vehicle_setTorque, idAFEntity_VehicleAutomated::Event_SetTorque )
  1989. EVENT( EV_Vehicle_setSteeringSpeed, idAFEntity_VehicleAutomated::Event_SetSteeringSpeed )
  1990. EVENT( EV_Vehicle_setWaypoint, idAFEntity_VehicleAutomated::Event_SetWayPoint )
  1991. END_CLASS
  1992. /*
  1993. ================
  1994. idAFEntity_VehicleAutomated::Spawn
  1995. ================
  1996. */
  1997. void idAFEntity_VehicleAutomated::Spawn() {
  1998. velocity = force = steerAngle = 0.f;
  1999. currentSteering = steeringSpeed = 0.f;
  2000. originHeight = 0.f;
  2001. waypoint = NULL;
  2002. spawnArgs.GetFloat( "velocity", "150", velocity );
  2003. spawnArgs.GetFloat( "torque", "200000", force );
  2004. spawnArgs.GetFloat( "steeringSpeed", "1", steeringSpeed );
  2005. spawnArgs.GetFloat( "originHeight", "0", originHeight );
  2006. PostEventMS( &EV_PostSpawn, 0 );
  2007. }
  2008. /*
  2009. ================
  2010. idAFEntity_VehicleAutomated::PostSpawn
  2011. ================
  2012. */
  2013. void idAFEntity_VehicleAutomated::PostSpawn() {
  2014. if ( targets.Num() ) {
  2015. waypoint = targets[0].GetEntity();
  2016. }
  2017. }
  2018. /*
  2019. ================
  2020. idAFEntity_VehicleAutomated::Event_SetVelocity
  2021. ================
  2022. */
  2023. void idAFEntity_VehicleAutomated::Event_SetVelocity( float _velocity ) {
  2024. velocity = _velocity;
  2025. }
  2026. /*
  2027. ================
  2028. idAFEntity_VehicleAutomated::Event_SetTorque
  2029. ================
  2030. */
  2031. void idAFEntity_VehicleAutomated::Event_SetTorque( float _torque ) {
  2032. force = _torque;
  2033. }
  2034. /*
  2035. ================
  2036. idAFEntity_VehicleAutomated::Event_SetSteeringSpeed
  2037. ================
  2038. */
  2039. void idAFEntity_VehicleAutomated::Event_SetSteeringSpeed( float _steeringSpeed ) {
  2040. steeringSpeed = _steeringSpeed;
  2041. }
  2042. /*
  2043. ================
  2044. idAFEntity_VehicleAutomated::Event_SetWayPoint
  2045. ================
  2046. */
  2047. void idAFEntity_VehicleAutomated::Event_SetWayPoint( idEntity *_waypoint ) {
  2048. waypoint = _waypoint;
  2049. }
  2050. /*
  2051. ================
  2052. idAFEntity_VehicleAutomated::Think
  2053. ================
  2054. */
  2055. #define HIT_WAYPOINT_THRESHOLD 80.f
  2056. void idAFEntity_VehicleAutomated::Think() {
  2057. // If we don't have a waypoint, coast to a stop
  2058. if ( !waypoint ) {
  2059. velocity = force = steerAngle = 0.f;
  2060. idAFEntity_VehicleSixWheels::Think();
  2061. return;
  2062. }
  2063. idVec3 waypoint_origin, vehicle_origin;
  2064. idVec3 travel_vector;
  2065. float distance_from_waypoint;
  2066. // Set up the vector from the vehicle origin, to the waypoint
  2067. vehicle_origin = GetPhysics()->GetOrigin();
  2068. vehicle_origin.z -= originHeight;
  2069. waypoint_origin = waypoint->GetPhysics()->GetOrigin();
  2070. travel_vector = waypoint_origin - vehicle_origin;
  2071. distance_from_waypoint = travel_vector.Length();
  2072. // Check if we've hit the waypoint (within a certain threshold)
  2073. if ( distance_from_waypoint < HIT_WAYPOINT_THRESHOLD ) {
  2074. idStr callfunc;
  2075. const function_t *func;
  2076. idThread *thread;
  2077. // Waypoints can call script functions
  2078. waypoint->spawnArgs.GetString( "call", "", callfunc );
  2079. if ( callfunc.Length() ) {
  2080. func = gameLocal.program.FindFunction( callfunc );
  2081. if ( func != NULL ) {
  2082. thread = new idThread( func );
  2083. thread->DelayedStart( 0 );
  2084. }
  2085. }
  2086. // Get next waypoint
  2087. if ( waypoint->targets.Num() ) {
  2088. waypoint = waypoint->targets[0].GetEntity();
  2089. } else {
  2090. waypoint = NULL;
  2091. }
  2092. // We are switching waypoints, adjust steering next frame
  2093. idAFEntity_VehicleSixWheels::Think();
  2094. return;
  2095. }
  2096. idAngles vehicle_angles, travel_angles;
  2097. // Get the angles we need to steer towards
  2098. travel_angles = travel_vector.ToAngles().Normalize360();
  2099. vehicle_angles = this->GetPhysics()->GetAxis().ToAngles().Normalize360();
  2100. float delta_yaw;
  2101. // Get the shortest steering angle towards the travel angles
  2102. delta_yaw = vehicle_angles.yaw - travel_angles.yaw;
  2103. if ( idMath::Fabs( delta_yaw ) > 180.f ) {
  2104. if ( delta_yaw > 0 ) {
  2105. delta_yaw = delta_yaw - 360;
  2106. } else {
  2107. delta_yaw = delta_yaw + 360;
  2108. }
  2109. }
  2110. // Maximum steering angle is 35 degrees
  2111. delta_yaw = idMath::ClampFloat( -35.f, 35.f, delta_yaw );
  2112. idealSteering = delta_yaw;
  2113. // Adjust steering incrementally so it doesn't snap to the ideal angle
  2114. if ( idMath::Fabs( (idealSteering - currentSteering) ) > steeringSpeed ) {
  2115. if ( idealSteering > currentSteering ) {
  2116. currentSteering += steeringSpeed;
  2117. } else {
  2118. currentSteering -= steeringSpeed;
  2119. }
  2120. } else {
  2121. currentSteering = idealSteering;
  2122. }
  2123. // DEBUG
  2124. if ( g_vehicleDebug.GetBool() ) {
  2125. gameRenderWorld->DebugBounds( colorRed, idBounds(idVec3(-4,-4,-4),idVec3(4,4,4)), vehicle_origin );
  2126. gameRenderWorld->DebugBounds( colorRed, idBounds(idVec3(-4,-4,-4),idVec3(4,4,4)), waypoint_origin );
  2127. gameRenderWorld->DrawText( waypoint->name.c_str(), waypoint_origin + idVec3(0,0,16), 0.25f, colorYellow, gameLocal.GetLocalPlayer()->viewAxis );
  2128. gameRenderWorld->DebugArrow( colorWhite, vehicle_origin, waypoint_origin, 12.f );
  2129. }
  2130. // Set the final steerAngle for the vehicle
  2131. steerAngle = currentSteering;
  2132. idAFEntity_VehicleSixWheels::Think();
  2133. }
  2134. /*
  2135. ===============================================================================
  2136. idAFEntity_SteamPipe
  2137. ===============================================================================
  2138. */
  2139. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_SteamPipe )
  2140. END_CLASS
  2141. /*
  2142. ================
  2143. idAFEntity_SteamPipe::idAFEntity_SteamPipe
  2144. ================
  2145. */
  2146. idAFEntity_SteamPipe::idAFEntity_SteamPipe() {
  2147. steamBody = 0;
  2148. steamForce = 0.0f;
  2149. steamUpForce = 0.0f;
  2150. steamModelDefHandle = -1;
  2151. memset( &steamRenderEntity, 0, sizeof( steamRenderEntity ) );
  2152. }
  2153. /*
  2154. ================
  2155. idAFEntity_SteamPipe::~idAFEntity_SteamPipe
  2156. ================
  2157. */
  2158. idAFEntity_SteamPipe::~idAFEntity_SteamPipe() {
  2159. if ( steamModelDefHandle >= 0 ){
  2160. gameRenderWorld->FreeEntityDef( steamModelDefHandle );
  2161. }
  2162. }
  2163. /*
  2164. ================
  2165. idAFEntity_SteamPipe::Save
  2166. ================
  2167. */
  2168. void idAFEntity_SteamPipe::Save( idSaveGame *savefile ) const {
  2169. }
  2170. /*
  2171. ================
  2172. idAFEntity_SteamPipe::Restore
  2173. ================
  2174. */
  2175. void idAFEntity_SteamPipe::Restore( idRestoreGame *savefile ) {
  2176. Spawn();
  2177. }
  2178. /*
  2179. ================
  2180. idAFEntity_SteamPipe::Spawn
  2181. ================
  2182. */
  2183. void idAFEntity_SteamPipe::Spawn() {
  2184. idVec3 steamDir;
  2185. const char *steamBodyName;
  2186. LoadAF();
  2187. SetCombatModel();
  2188. SetPhysics( af.GetPhysics() );
  2189. fl.takedamage = true;
  2190. steamBodyName = spawnArgs.GetString( "steamBody", "" );
  2191. steamForce = spawnArgs.GetFloat( "steamForce", "2000" );
  2192. steamUpForce = spawnArgs.GetFloat( "steamUpForce", "10" );
  2193. steamDir = af.GetPhysics()->GetAxis( steamBody )[2];
  2194. steamBody = af.GetPhysics()->GetBodyId( steamBodyName );
  2195. force.SetPosition( af.GetPhysics(), steamBody, af.GetPhysics()->GetOrigin( steamBody ) );
  2196. force.SetForce( steamDir * -steamForce );
  2197. InitSteamRenderEntity();
  2198. BecomeActive( TH_THINK );
  2199. }
  2200. /*
  2201. ================
  2202. idAFEntity_SteamPipe::InitSteamRenderEntity
  2203. ================
  2204. */
  2205. void idAFEntity_SteamPipe::InitSteamRenderEntity() {
  2206. const char *temp;
  2207. const idDeclModelDef *modelDef;
  2208. memset( &steamRenderEntity, 0, sizeof( steamRenderEntity ) );
  2209. steamRenderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f;
  2210. steamRenderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
  2211. steamRenderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
  2212. modelDef = NULL;
  2213. temp = spawnArgs.GetString ( "model_steam" );
  2214. if ( *temp != '\0' ) {
  2215. if ( !strstr( temp, "." ) ) {
  2216. modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, temp, false ) );
  2217. if ( modelDef ) {
  2218. steamRenderEntity.hModel = modelDef->ModelHandle();
  2219. }
  2220. }
  2221. if ( !steamRenderEntity.hModel ) {
  2222. steamRenderEntity.hModel = renderModelManager->FindModel( temp );
  2223. }
  2224. if ( steamRenderEntity.hModel ) {
  2225. steamRenderEntity.bounds = steamRenderEntity.hModel->Bounds( &steamRenderEntity );
  2226. } else {
  2227. steamRenderEntity.bounds.Zero();
  2228. }
  2229. steamRenderEntity.origin = af.GetPhysics()->GetOrigin( steamBody );
  2230. steamRenderEntity.axis = af.GetPhysics()->GetAxis( steamBody );
  2231. steamModelDefHandle = gameRenderWorld->AddEntityDef( &steamRenderEntity );
  2232. }
  2233. }
  2234. /*
  2235. ================
  2236. idAFEntity_SteamPipe::Think
  2237. ================
  2238. */
  2239. void idAFEntity_SteamPipe::Think() {
  2240. idVec3 steamDir;
  2241. if ( thinkFlags & TH_THINK ) {
  2242. steamDir.x = gameLocal.random.CRandomFloat() * steamForce;
  2243. steamDir.y = gameLocal.random.CRandomFloat() * steamForce;
  2244. steamDir.z = steamUpForce;
  2245. force.SetForce( steamDir );
  2246. force.Evaluate( gameLocal.time );
  2247. //gameRenderWorld->DebugArrow( colorWhite, af.GetPhysics()->GetOrigin( steamBody ), af.GetPhysics()->GetOrigin( steamBody ) - 10.0f * steamDir, 4 );
  2248. }
  2249. if ( steamModelDefHandle >= 0 ){
  2250. steamRenderEntity.origin = af.GetPhysics()->GetOrigin( steamBody );
  2251. steamRenderEntity.axis = af.GetPhysics()->GetAxis( steamBody );
  2252. gameRenderWorld->UpdateEntityDef( steamModelDefHandle, &steamRenderEntity );
  2253. }
  2254. idAFEntity_Base::Think();
  2255. }
  2256. /*
  2257. ===============================================================================
  2258. idAFEntity_ClawFourFingers
  2259. ===============================================================================
  2260. */
  2261. const idEventDef EV_SetFingerAngle( "setFingerAngle", "f" );
  2262. const idEventDef EV_StopFingers( "stopFingers" );
  2263. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_ClawFourFingers )
  2264. EVENT( EV_SetFingerAngle, idAFEntity_ClawFourFingers::Event_SetFingerAngle )
  2265. EVENT( EV_StopFingers, idAFEntity_ClawFourFingers::Event_StopFingers )
  2266. END_CLASS
  2267. static const char *clawConstraintNames[] = {
  2268. "claw1", "claw2", "claw3", "claw4"
  2269. };
  2270. /*
  2271. ================
  2272. idAFEntity_ClawFourFingers::idAFEntity_ClawFourFingers
  2273. ================
  2274. */
  2275. idAFEntity_ClawFourFingers::idAFEntity_ClawFourFingers() {
  2276. fingers[0] = NULL;
  2277. fingers[1] = NULL;
  2278. fingers[2] = NULL;
  2279. fingers[3] = NULL;
  2280. }
  2281. /*
  2282. ================
  2283. idAFEntity_ClawFourFingers::Save
  2284. ================
  2285. */
  2286. void idAFEntity_ClawFourFingers::Save( idSaveGame *savefile ) const {
  2287. int i;
  2288. for ( i = 0; i < 4; i++ ) {
  2289. fingers[i]->Save( savefile );
  2290. }
  2291. }
  2292. /*
  2293. ================
  2294. idAFEntity_ClawFourFingers::Restore
  2295. ================
  2296. */
  2297. void idAFEntity_ClawFourFingers::Restore( idRestoreGame *savefile ) {
  2298. int i;
  2299. for ( i = 0; i < 4; i++ ) {
  2300. fingers[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( clawConstraintNames[i] ));
  2301. fingers[i]->Restore( savefile );
  2302. }
  2303. SetCombatModel();
  2304. LinkCombat();
  2305. }
  2306. /*
  2307. ================
  2308. idAFEntity_ClawFourFingers::Spawn
  2309. ================
  2310. */
  2311. void idAFEntity_ClawFourFingers::Spawn() {
  2312. int i;
  2313. LoadAF();
  2314. SetCombatModel();
  2315. af.GetPhysics()->LockWorldConstraints( true );
  2316. af.GetPhysics()->SetForcePushable( true );
  2317. SetPhysics( af.GetPhysics() );
  2318. fl.takedamage = true;
  2319. for ( i = 0; i < 4; i++ ) {
  2320. fingers[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( clawConstraintNames[i] ));
  2321. if ( !fingers[i] ) {
  2322. gameLocal.Error( "idClaw_FourFingers '%s': can't find claw constraint '%s'", name.c_str(), clawConstraintNames[i] );
  2323. }
  2324. }
  2325. }
  2326. /*
  2327. ================
  2328. idAFEntity_ClawFourFingers::Event_SetFingerAngle
  2329. ================
  2330. */
  2331. void idAFEntity_ClawFourFingers::Event_SetFingerAngle( float angle ) {
  2332. int i;
  2333. for ( i = 0; i < 4; i++ ) {
  2334. fingers[i]->SetSteerAngle( angle );
  2335. fingers[i]->SetSteerSpeed( 0.5f );
  2336. }
  2337. af.GetPhysics()->Activate();
  2338. }
  2339. /*
  2340. ================
  2341. idAFEntity_ClawFourFingers::Event_StopFingers
  2342. ================
  2343. */
  2344. void idAFEntity_ClawFourFingers::Event_StopFingers() {
  2345. int i;
  2346. for ( i = 0; i < 4; i++ ) {
  2347. fingers[i]->SetSteerAngle( fingers[i]->GetAngle() );
  2348. }
  2349. }
  2350. /*
  2351. ===============================================================================
  2352. editor support routines
  2353. ===============================================================================
  2354. */
  2355. /*
  2356. ================
  2357. idGameEdit::AF_SpawnEntity
  2358. ================
  2359. */
  2360. bool idGameEdit::AF_SpawnEntity( const char *fileName ) {
  2361. idDict args;
  2362. idPlayer *player;
  2363. idAFEntity_Generic *ent;
  2364. const idDeclAF *af;
  2365. idVec3 org;
  2366. float yaw;
  2367. player = gameLocal.GetLocalPlayer();
  2368. if ( !player || !gameLocal.CheatsOk( false ) ) {
  2369. return false;
  2370. }
  2371. af = static_cast<const idDeclAF *>( declManager->FindType( DECL_AF, fileName ) );
  2372. if ( !af ) {
  2373. return false;
  2374. }
  2375. yaw = player->viewAngles.yaw;
  2376. args.Set( "angle", va( "%f", yaw + 180 ) );
  2377. org = player->GetPhysics()->GetOrigin() + idAngles( 0, yaw, 0 ).ToForward() * 80 + idVec3( 0, 0, 1 );
  2378. args.Set( "origin", org.ToString() );
  2379. args.Set( "spawnclass", "idAFEntity_Generic" );
  2380. if ( af->model[0] ) {
  2381. args.Set( "model", af->model.c_str() );
  2382. } else {
  2383. args.Set( "model", fileName );
  2384. }
  2385. if ( af->skin[0] ) {
  2386. args.Set( "skin", af->skin.c_str() );
  2387. }
  2388. args.Set( "articulatedFigure", fileName );
  2389. args.Set( "nodrop", "1" );
  2390. ent = static_cast<idAFEntity_Generic *>(gameLocal.SpawnEntityType( idAFEntity_Generic::Type, &args));
  2391. // always update this entity
  2392. ent->BecomeActive( TH_THINK );
  2393. ent->KeepRunningPhysics();
  2394. ent->fl.forcePhysicsUpdate = true;
  2395. player->dragEntity.SetSelected( ent );
  2396. return true;
  2397. }
  2398. /*
  2399. ================
  2400. idGameEdit::AF_UpdateEntities
  2401. ================
  2402. */
  2403. void idGameEdit::AF_UpdateEntities( const char *fileName ) {
  2404. idEntity *ent;
  2405. idAFEntity_Base *af;
  2406. idStr name;
  2407. name = fileName;
  2408. name.StripFileExtension();
  2409. // reload any idAFEntity_Generic which uses the given articulated figure file
  2410. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  2411. if ( ent->IsType( idAFEntity_Base::Type ) ) {
  2412. af = static_cast<idAFEntity_Base *>(ent);
  2413. if ( name.Icmp( af->GetAFName() ) == 0 ) {
  2414. af->LoadAF();
  2415. af->GetAFPhysics()->PutToRest();
  2416. }
  2417. }
  2418. }
  2419. }
  2420. /*
  2421. ================
  2422. idGameEdit::AF_UndoChanges
  2423. ================
  2424. */
  2425. void idGameEdit::AF_UndoChanges() {
  2426. int i, c;
  2427. idEntity *ent;
  2428. idAFEntity_Base *af;
  2429. idDeclAF *decl;
  2430. c = declManager->GetNumDecls( DECL_AF );
  2431. for ( i = 0; i < c; i++ ) {
  2432. decl = static_cast<idDeclAF *>( const_cast<idDecl *>( declManager->DeclByIndex( DECL_AF, i, false ) ) );
  2433. if ( !decl->modified ) {
  2434. continue;
  2435. }
  2436. decl->Invalidate();
  2437. declManager->FindType( DECL_AF, decl->GetName() );
  2438. // reload all AF entities using the file
  2439. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  2440. if ( ent->IsType( idAFEntity_Base::Type ) ) {
  2441. af = static_cast<idAFEntity_Base *>(ent);
  2442. if ( idStr::Icmp( decl->GetName(), af->GetAFName() ) == 0 ) {
  2443. af->LoadAF();
  2444. }
  2445. }
  2446. }
  2447. }
  2448. }
  2449. /*
  2450. ================
  2451. GetJointTransform
  2452. ================
  2453. */
  2454. typedef struct {
  2455. renderEntity_t *ent;
  2456. const idMD5Joint *joints;
  2457. } jointTransformData_t;
  2458. static bool GetJointTransform( void *model, const idJointMat *frame, const char *jointName, idVec3 &origin, idMat3 &axis ) {
  2459. int i;
  2460. jointTransformData_t *data = reinterpret_cast<jointTransformData_t *>(model);
  2461. for ( i = 0; i < data->ent->numJoints; i++ ) {
  2462. if ( data->joints[i].name.Icmp( jointName ) == 0 ) {
  2463. break;
  2464. }
  2465. }
  2466. if ( i >= data->ent->numJoints ) {
  2467. return false;
  2468. }
  2469. origin = frame[i].ToVec3();
  2470. axis = frame[i].ToMat3();
  2471. return true;
  2472. }
  2473. /*
  2474. ================
  2475. GetArgString
  2476. ================
  2477. */
  2478. static const char *GetArgString( const idDict &args, const idDict *defArgs, const char *key ) {
  2479. const char *s;
  2480. s = args.GetString( key );
  2481. if ( !s[0] && defArgs ) {
  2482. s = defArgs->GetString( key );
  2483. }
  2484. return s;
  2485. }
  2486. /*
  2487. ================
  2488. idGameEdit::AF_CreateMesh
  2489. ================
  2490. */
  2491. idRenderModel *idGameEdit::AF_CreateMesh( const idDict &args, idVec3 &meshOrigin, idMat3 &meshAxis, bool &poseIsSet ) {
  2492. int i, jointNum;
  2493. const idDeclAF *af = NULL;
  2494. const idDeclAF_Body *fb = NULL;
  2495. renderEntity_t ent;
  2496. idVec3 origin, *bodyOrigin = NULL, *newBodyOrigin = NULL, *modifiedOrigin = NULL;
  2497. idMat3 axis, *bodyAxis = NULL, *newBodyAxis = NULL, *modifiedAxis = NULL;
  2498. declAFJointMod_t *jointMod = NULL;
  2499. idAngles angles;
  2500. const idDict *defArgs = NULL;
  2501. const idKeyValue *arg = NULL;
  2502. idStr name;
  2503. jointTransformData_t data;
  2504. const char *classname = NULL, *afName = NULL, *modelName = NULL;
  2505. idRenderModel *md5 = NULL;
  2506. const idDeclModelDef *modelDef = NULL;
  2507. const idMD5Anim *MD5anim = NULL;
  2508. const idMD5Joint *MD5joint = NULL;
  2509. const idMD5Joint *MD5joints = NULL;
  2510. int numMD5joints;
  2511. idJointMat *originalJoints = NULL;
  2512. int parentNum;
  2513. poseIsSet = false;
  2514. meshOrigin.Zero();
  2515. meshAxis.Identity();
  2516. classname = args.GetString( "classname" );
  2517. defArgs = gameLocal.FindEntityDefDict( classname );
  2518. // get the articulated figure
  2519. afName = GetArgString( args, defArgs, "articulatedFigure" );
  2520. af = static_cast<const idDeclAF *>( declManager->FindType( DECL_AF, afName ) );
  2521. if ( !af ) {
  2522. return NULL;
  2523. }
  2524. // get the md5 model
  2525. modelName = GetArgString( args, defArgs, "model" );
  2526. modelDef = static_cast< const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) );
  2527. if ( !modelDef ) {
  2528. return NULL;
  2529. }
  2530. // make sure model hasn't been purged
  2531. if ( modelDef->ModelHandle() && !modelDef->ModelHandle()->IsLoaded() ) {
  2532. modelDef->ModelHandle()->LoadModel();
  2533. }
  2534. // get the md5
  2535. md5 = modelDef->ModelHandle();
  2536. if ( !md5 || md5->IsDefaultModel() ) {
  2537. return NULL;
  2538. }
  2539. // get the articulated figure pose anim
  2540. int animNum = modelDef->GetAnim( "af_pose" );
  2541. if ( !animNum ) {
  2542. return NULL;
  2543. }
  2544. const idAnim *anim = modelDef->GetAnim( animNum );
  2545. if ( !anim ) {
  2546. return NULL;
  2547. }
  2548. MD5anim = anim->MD5Anim( 0 );
  2549. MD5joints = md5->GetJoints();
  2550. numMD5joints = md5->NumJoints();
  2551. // setup a render entity
  2552. memset( &ent, 0, sizeof( ent ) );
  2553. ent.customSkin = modelDef->GetSkin();
  2554. ent.bounds.Clear();
  2555. ent.numJoints = numMD5joints;
  2556. ent.joints = ( idJointMat * )_alloca16( ent.numJoints * sizeof( *ent.joints ) );
  2557. // create animation from of the af_pose
  2558. ANIM_CreateAnimFrame( md5, MD5anim, ent.numJoints, ent.joints, 1, modelDef->GetVisualOffset(), false );
  2559. // buffers to store the initial origin and axis for each body
  2560. bodyOrigin = (idVec3 *) _alloca16( af->bodies.Num() * sizeof( idVec3 ) );
  2561. bodyAxis = (idMat3 *) _alloca16( af->bodies.Num() * sizeof( idMat3 ) );
  2562. newBodyOrigin = (idVec3 *) _alloca16( af->bodies.Num() * sizeof( idVec3 ) );
  2563. newBodyAxis = (idMat3 *) _alloca16( af->bodies.Num() * sizeof( idMat3 ) );
  2564. // finish the AF positions
  2565. data.ent = &ent;
  2566. data.joints = MD5joints;
  2567. af->Finish( GetJointTransform, ent.joints, &data );
  2568. // get the initial origin and axis for each AF body
  2569. for ( i = 0; i < af->bodies.Num(); i++ ) {
  2570. fb = af->bodies[i];
  2571. if ( fb->modelType == TRM_BONE ) {
  2572. // axis of bone trace model
  2573. axis[2] = fb->v2.ToVec3() - fb->v1.ToVec3();
  2574. axis[2].Normalize();
  2575. axis[2].NormalVectors( axis[0], axis[1] );
  2576. axis[1] = -axis[1];
  2577. } else {
  2578. axis = fb->angles.ToMat3();
  2579. }
  2580. newBodyOrigin[i] = bodyOrigin[i] = fb->origin.ToVec3();
  2581. newBodyAxis[i] = bodyAxis[i] = axis;
  2582. }
  2583. // get any new body transforms stored in the key/value pairs
  2584. for ( arg = args.MatchPrefix( "body ", NULL ); arg; arg = args.MatchPrefix( "body ", arg ) ) {
  2585. name = arg->GetKey();
  2586. name.Strip( "body " );
  2587. for ( i = 0; i < af->bodies.Num(); i++ ) {
  2588. fb = af->bodies[i];
  2589. if ( fb->name.Icmp( name ) == 0 ) {
  2590. break;
  2591. }
  2592. }
  2593. if ( i >= af->bodies.Num() ) {
  2594. continue;
  2595. }
  2596. sscanf( arg->GetValue(), "%f %f %f %f %f %f", &origin.x, &origin.y, &origin.z, &angles.pitch, &angles.yaw, &angles.roll );
  2597. if ( fb != NULL && fb->jointName.Icmp( "origin" ) == 0 ) {
  2598. meshAxis = bodyAxis[i].Transpose() * angles.ToMat3();
  2599. meshOrigin = origin - bodyOrigin[i] * meshAxis;
  2600. poseIsSet = true;
  2601. } else {
  2602. newBodyOrigin[i] = origin;
  2603. newBodyAxis[i] = angles.ToMat3();
  2604. }
  2605. }
  2606. // save the original joints
  2607. originalJoints = ( idJointMat * )_alloca16( numMD5joints * sizeof( originalJoints[0] ) );
  2608. memcpy( originalJoints, ent.joints, numMD5joints * sizeof( originalJoints[0] ) );
  2609. // buffer to store the joint mods
  2610. jointMod = (declAFJointMod_t *) _alloca16( numMD5joints * sizeof( declAFJointMod_t ) );
  2611. memset( jointMod, -1, numMD5joints * sizeof( declAFJointMod_t ) );
  2612. modifiedOrigin = (idVec3 *) _alloca16( numMD5joints * sizeof( idVec3 ) );
  2613. memset( modifiedOrigin, 0, numMD5joints * sizeof( idVec3 ) );
  2614. modifiedAxis = (idMat3 *) _alloca16( numMD5joints * sizeof( idMat3 ) );
  2615. memset( modifiedAxis, 0, numMD5joints * sizeof( idMat3 ) );
  2616. // get all the joint modifications
  2617. for ( i = 0; i < af->bodies.Num(); i++ ) {
  2618. fb = af->bodies[i];
  2619. if ( fb->jointName.Icmp( "origin" ) == 0 ) {
  2620. continue;
  2621. }
  2622. for ( jointNum = 0; jointNum < numMD5joints; jointNum++ ) {
  2623. if ( MD5joints[jointNum].name.Icmp( fb->jointName ) == 0 ) {
  2624. break;
  2625. }
  2626. }
  2627. if ( jointNum >= 0 && jointNum < ent.numJoints ) {
  2628. jointMod[ jointNum ] = fb->jointMod;
  2629. modifiedAxis[ jointNum ] = ( bodyAxis[i] * originalJoints[jointNum].ToMat3().Transpose() ).Transpose() * ( newBodyAxis[i] * meshAxis.Transpose() );
  2630. // FIXME: calculate correct modifiedOrigin
  2631. modifiedOrigin[ jointNum ] = originalJoints[ jointNum ].ToVec3();
  2632. }
  2633. }
  2634. // apply joint modifications to the skeleton
  2635. MD5joint = MD5joints + 1;
  2636. for( i = 1; i < numMD5joints; i++, MD5joint++ ) {
  2637. parentNum = MD5joint->parent - MD5joints;
  2638. idMat3 parentAxis = originalJoints[ parentNum ].ToMat3();
  2639. idMat3 localm = originalJoints[i].ToMat3() * parentAxis.Transpose();
  2640. idVec3 localt = ( originalJoints[i].ToVec3() - originalJoints[ parentNum ].ToVec3() ) * parentAxis.Transpose();
  2641. switch( jointMod[i] ) {
  2642. case DECLAF_JOINTMOD_ORIGIN: {
  2643. ent.joints[ i ].SetRotation( localm * ent.joints[ parentNum ].ToMat3() );
  2644. ent.joints[ i ].SetTranslation( modifiedOrigin[ i ] );
  2645. break;
  2646. }
  2647. case DECLAF_JOINTMOD_AXIS: {
  2648. ent.joints[ i ].SetRotation( modifiedAxis[ i ] );
  2649. ent.joints[ i ].SetTranslation( ent.joints[ parentNum ].ToVec3() + localt * ent.joints[ parentNum ].ToMat3() );
  2650. break;
  2651. }
  2652. case DECLAF_JOINTMOD_BOTH: {
  2653. ent.joints[ i ].SetRotation( modifiedAxis[ i ] );
  2654. ent.joints[ i ].SetTranslation( modifiedOrigin[ i ] );
  2655. break;
  2656. }
  2657. default: {
  2658. ent.joints[ i ].SetRotation( localm * ent.joints[ parentNum ].ToMat3() );
  2659. ent.joints[ i ].SetTranslation( ent.joints[ parentNum ].ToVec3() + localt * ent.joints[ parentNum ].ToMat3() );
  2660. break;
  2661. }
  2662. }
  2663. }
  2664. // instantiate a mesh using the joint information from the render entity
  2665. return md5->InstantiateDynamicModel( &ent, NULL, NULL );
  2666. }
  2667. /*
  2668. ===============================================================================
  2669. idHarvestable
  2670. ===============================================================================
  2671. */
  2672. const idEventDef EV_Harvest_SpawnHarvestTrigger( "<spawnHarvestTrigger>", NULL );
  2673. CLASS_DECLARATION( idEntity, idHarvestable )
  2674. EVENT( EV_Harvest_SpawnHarvestTrigger, idHarvestable::Event_SpawnHarvestTrigger )
  2675. EVENT( EV_Touch, idHarvestable::Event_Touch )
  2676. END_CLASS
  2677. idHarvestable::idHarvestable() {
  2678. trigger = NULL;
  2679. parentEnt = NULL;
  2680. }
  2681. idHarvestable::~idHarvestable() {
  2682. if ( trigger ) {
  2683. delete trigger;
  2684. trigger = NULL;
  2685. }
  2686. }
  2687. void idHarvestable::Spawn() {
  2688. startTime = 0;
  2689. spawnArgs.GetFloat( "triggersize", "120", triggersize );
  2690. spawnArgs.GetFloat( "give_delay", "3", giveDelay);
  2691. giveDelay *= 1000;
  2692. given = false;
  2693. removeDelay = spawnArgs.GetFloat( "remove_delay") * 1000.0f;
  2694. fxFollowPlayer = spawnArgs.GetBool("fx_follow_player", "1");
  2695. fxOrient = spawnArgs.GetString("fx_orient");
  2696. }
  2697. void idHarvestable::Init(idEntity* parent) {
  2698. assert(parent);
  2699. parentEnt = parent;
  2700. GetPhysics()->SetOrigin( parent->GetPhysics()->GetOrigin() );
  2701. this->Bind(parent, true);
  2702. //Set the skin of the entity to the harvest skin
  2703. idStr skin = parent->spawnArgs.GetString("skin_harvest", "");
  2704. if(skin.Length()) {
  2705. parent->SetSkin(declManager->FindSkin(skin.c_str()));
  2706. }
  2707. idEntity* head = NULL;
  2708. if(parent->IsType(idActor::Type)) {
  2709. idActor* withHead = (idActor*)parent;
  2710. head = withHead->GetHeadEntity();
  2711. }
  2712. if(parent->IsType(idAFEntity_WithAttachedHead::Type)) {
  2713. idAFEntity_WithAttachedHead* withHead = (idAFEntity_WithAttachedHead*)parent;
  2714. head = withHead->head.GetEntity();
  2715. }
  2716. if(head) {
  2717. idStr headskin = parent->spawnArgs.GetString("skin_harvest_head", "");
  2718. if(headskin.Length()) {
  2719. head->SetSkin(declManager->FindSkin(headskin.c_str()));
  2720. }
  2721. }
  2722. idStr sound = parent->spawnArgs.GetString("harvest_sound");
  2723. if(sound.Length() > 0) {
  2724. parent->StartSound( sound.c_str(), SND_CHANNEL_ANY, 0, false, NULL);
  2725. }
  2726. PostEventMS( &EV_Harvest_SpawnHarvestTrigger, 0 );
  2727. }
  2728. void idHarvestable::Save( idSaveGame *savefile ) const {
  2729. savefile->WriteFloat( triggersize );
  2730. savefile->WriteClipModel( trigger );
  2731. savefile->WriteFloat( giveDelay );
  2732. savefile->WriteFloat( removeDelay );
  2733. savefile->WriteBool( given );
  2734. player.Save( savefile );
  2735. savefile->WriteInt( startTime );
  2736. savefile->WriteBool( fxFollowPlayer );
  2737. fx.Save( savefile );
  2738. savefile->WriteString( fxOrient );
  2739. parentEnt.Save(savefile);
  2740. }
  2741. void idHarvestable::Restore( idRestoreGame *savefile ) {
  2742. savefile->ReadFloat( triggersize );
  2743. savefile->ReadClipModel( trigger );
  2744. savefile->ReadFloat( giveDelay );
  2745. savefile->ReadFloat( removeDelay );
  2746. savefile->ReadBool( given );
  2747. player.Restore( savefile );
  2748. savefile->ReadInt( startTime );
  2749. savefile->ReadBool( fxFollowPlayer );
  2750. fx.Restore( savefile );
  2751. savefile->ReadString( fxOrient );
  2752. parentEnt.Restore(savefile);
  2753. }
  2754. void idHarvestable::SetParent(idEntity* parent) {
  2755. parentEnt = parent;
  2756. }
  2757. void idHarvestable::Think() {
  2758. idEntity* parent = parentEnt.GetEntity();
  2759. if(!parent) {
  2760. return;
  2761. }
  2762. //Update the orientation of the box
  2763. if(trigger && parent && !parent->GetPhysics()->IsAtRest()) {
  2764. trigger->Link( gameLocal.clip, this, 0, parent->GetPhysics()->GetOrigin(), parent->GetPhysics()->GetAxis());
  2765. }
  2766. if(startTime && gameLocal.slow.time - startTime > giveDelay && ! given) {
  2767. idPlayer *thePlayer = player.GetEntity();
  2768. thePlayer->Give(spawnArgs.GetString("give_item"), spawnArgs.GetString("give_value"), ITEM_GIVE_FEEDBACK | ITEM_GIVE_UPDATE_STATE );
  2769. thePlayer->harvest_lock = false;
  2770. given = true;
  2771. }
  2772. if(startTime && gameLocal.slow.time - startTime > removeDelay) {
  2773. parent->PostEventMS( &EV_Remove, 0 );
  2774. PostEventMS( &EV_Remove, 0 );
  2775. }
  2776. if(fxFollowPlayer) {
  2777. idEntityFx* fxEnt = fx.GetEntity();
  2778. if(fxEnt) {
  2779. idMat3 orientAxisLocal;
  2780. if(GetFxOrientationAxis(orientAxisLocal)) {
  2781. //gameRenderWorld->DebugAxis(fxEnt->GetPhysics()->GetOrigin(), orientAxisLocal);
  2782. fxEnt->GetPhysics()->SetAxis(orientAxisLocal);
  2783. }
  2784. }
  2785. }
  2786. }
  2787. /*
  2788. ================
  2789. idAFEntity_Harvest::Gib
  2790. Called when the parent object has been gibbed.
  2791. ================
  2792. */
  2793. void idHarvestable::Gib() {
  2794. //Stop any looping sound that was playing
  2795. idEntity* parent = parentEnt.GetEntity();
  2796. if(parent) {
  2797. idStr sound = parent->spawnArgs.GetString("harvest_sound");
  2798. if(sound.Length() > 0) {
  2799. parent->StopSound(SND_CHANNEL_ANY, false);
  2800. }
  2801. }
  2802. }
  2803. /*
  2804. ================
  2805. idAFEntity_Harvest::BeginBurn
  2806. ================
  2807. */
  2808. void idHarvestable::BeginBurn() {
  2809. idEntity* parent = parentEnt.GetEntity();
  2810. if(!parent) {
  2811. return;
  2812. }
  2813. if(!spawnArgs.GetBool("burn")) {
  2814. return;
  2815. }
  2816. //Switch Skins if the parent would like us to.
  2817. idStr skin = parent->spawnArgs.GetString("skin_harvest_burn", "");
  2818. if(skin.Length()) {
  2819. parent->SetSkin(declManager->FindSkin(skin.c_str()));
  2820. }
  2821. parent->GetRenderEntity()->noShadow = true;
  2822. parent->SetShaderParm( SHADERPARM_TIME_OF_DEATH, gameLocal.slow.time * 0.001f );
  2823. idEntity* head = NULL;
  2824. if(parent->IsType(idActor::Type)) {
  2825. idActor* withHead = (idActor*)parent;
  2826. head = withHead->GetHeadEntity();
  2827. }
  2828. if(parent->IsType(idAFEntity_WithAttachedHead::Type)) {
  2829. idAFEntity_WithAttachedHead* withHead = (idAFEntity_WithAttachedHead*)parent;
  2830. head = withHead->head.GetEntity();
  2831. }
  2832. if(head) {
  2833. idStr headskin = parent->spawnArgs.GetString("skin_harvest_burn_head", "");
  2834. if(headskin.Length()) {
  2835. head->SetSkin(declManager->FindSkin(headskin.c_str()));
  2836. }
  2837. head->GetRenderEntity()->noShadow = true;
  2838. head->SetShaderParm( SHADERPARM_TIME_OF_DEATH, gameLocal.slow.time * 0.001f );
  2839. }
  2840. }
  2841. /*
  2842. ================
  2843. idAFEntity_Harvest::BeginFX
  2844. ================
  2845. */
  2846. void idHarvestable::BeginFX() {
  2847. if(strlen(spawnArgs.GetString("fx")) <= 0) {
  2848. return;
  2849. }
  2850. idMat3* orientAxis = NULL;
  2851. idMat3 orientAxisLocal;
  2852. if(GetFxOrientationAxis(orientAxisLocal)) {
  2853. orientAxis = &orientAxisLocal;
  2854. }
  2855. fx = idEntityFx::StartFx( spawnArgs.GetString("fx"), NULL, orientAxis, this, spawnArgs.GetBool("fx_bind") );
  2856. }
  2857. /*
  2858. ================
  2859. idAFEntity_Harvest::CalcTriggerBounds
  2860. ================
  2861. */
  2862. void idHarvestable::CalcTriggerBounds( float size, idBounds &bounds ) {
  2863. idEntity* parent = parentEnt.GetEntity();
  2864. if(!parent) {
  2865. return;
  2866. }
  2867. //Simple trigger bounds is the absolute bounds of the AF plus a defined size
  2868. bounds = parent->GetPhysics()->GetAbsBounds();
  2869. bounds.ExpandSelf(size);
  2870. bounds[0] -= parent->GetPhysics()->GetOrigin();
  2871. bounds[1] -= parent->GetPhysics()->GetOrigin();
  2872. }
  2873. bool idHarvestable::GetFxOrientationAxis(idMat3& mat) {
  2874. idEntity* parent = parentEnt.GetEntity();
  2875. if(!parent) {
  2876. return false;
  2877. }
  2878. idPlayer *thePlayer = player.GetEntity();
  2879. if(!fxOrient.Icmp("up")) {
  2880. //Orient up
  2881. idVec3 grav = parent->GetPhysics()->GetGravityNormal()*-1;
  2882. idVec3 left, up;
  2883. grav.OrthogonalBasis(left, up);
  2884. idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, grav.x, grav.y, grav.z);
  2885. mat = temp;
  2886. return true;
  2887. } else if(!fxOrient.Icmp("weapon")) {
  2888. //Orient the fx towards the muzzle of the weapon
  2889. jointHandle_t joint;
  2890. idVec3 joint_origin;
  2891. idMat3 joint_axis;
  2892. joint = thePlayer->weapon.GetEntity()->GetAnimator()->GetJointHandle( spawnArgs.GetString("fx_weapon_joint") );
  2893. if ( joint != INVALID_JOINT ) {
  2894. thePlayer->weapon.GetEntity()->GetJointWorldTransform( joint, gameLocal.slow.time, joint_origin, joint_axis );
  2895. } else {
  2896. joint_origin = thePlayer->GetPhysics()->GetOrigin();
  2897. }
  2898. idVec3 toPlayer = joint_origin-parent->GetPhysics()->GetOrigin();
  2899. toPlayer.NormalizeFast();
  2900. idVec3 left, up;
  2901. toPlayer.OrthogonalBasis(left, up);
  2902. idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, toPlayer.x, toPlayer.y, toPlayer.z);
  2903. mat = temp;
  2904. return true;
  2905. } else if(!fxOrient.Icmp("player")) {
  2906. //Orient the fx towards the eye of the player
  2907. idVec3 eye = thePlayer->GetEyePosition();
  2908. idVec3 toPlayer = eye-parent->GetPhysics()->GetOrigin();
  2909. toPlayer.Normalize();
  2910. idVec3 left, up;
  2911. up.Set(0, 1, 0);
  2912. left = toPlayer.Cross(up);
  2913. up = left.Cross(toPlayer);
  2914. //common->Printf("%.2f %.2f %.2f - %.2f %.2f %.2f - %.2f %.2f %.2f\n", toPlayer.x, toPlayer.y, toPlayer.z, left.x, left.y, left.z, up.x, up.y, up.z );
  2915. idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, toPlayer.x, toPlayer.y, toPlayer.z);
  2916. mat = temp;
  2917. return true;
  2918. }
  2919. //Returning false indicates that the orientation is not used;
  2920. return false;
  2921. }
  2922. /*
  2923. ================
  2924. idAFEntity_Harvest::Event_SpawnHarvestTrigger
  2925. ================
  2926. */
  2927. void idHarvestable::Event_SpawnHarvestTrigger() {
  2928. idBounds bounds;
  2929. idEntity* parent = parentEnt.GetEntity();
  2930. if(!parent) {
  2931. return;
  2932. }
  2933. CalcTriggerBounds( triggersize, bounds );
  2934. // create a trigger clip model
  2935. trigger = new (TAG_PHYSICS_CLIP_AF) idClipModel( idTraceModel( bounds ) );
  2936. trigger->Link( gameLocal.clip, this, 255, parent->GetPhysics()->GetOrigin(), mat3_identity);
  2937. trigger->SetContents( CONTENTS_TRIGGER );
  2938. startTime = 0;
  2939. }
  2940. /*
  2941. ================
  2942. idAFEntity_Harvest::Event_Touch
  2943. ================
  2944. */
  2945. void idHarvestable::Event_Touch( idEntity *other, trace_t *trace ) {
  2946. idEntity* parent = parentEnt.GetEntity();
  2947. if(!parent) {
  2948. return;
  2949. }
  2950. if(parent->IsType(idAFEntity_Gibbable::Type)) {
  2951. idAFEntity_Gibbable* gibParent = (idAFEntity_Gibbable*)parent;
  2952. if(gibParent->IsGibbed())
  2953. return;
  2954. }
  2955. if(!startTime && other && other->IsType(idPlayer::Type)) {
  2956. idPlayer *thePlayer = static_cast<idPlayer *>(other);
  2957. if(thePlayer->harvest_lock) {
  2958. //Don't harvest if the player is in mid harvest
  2959. return;
  2960. }
  2961. player = thePlayer;
  2962. bool okToGive = true;
  2963. idStr requiredWeapons = spawnArgs.GetString("required_weapons");
  2964. if(requiredWeapons.Length() > 0) {
  2965. idStr playerWeap = thePlayer->GetCurrentWeapon();
  2966. if(playerWeap.Length() == 0 || requiredWeapons.Find(playerWeap, false) == -1) {
  2967. okToGive = false;
  2968. }
  2969. }
  2970. if(okToGive) {
  2971. if(thePlayer->CanGive(spawnArgs.GetString("give_item"), spawnArgs.GetString("give_value"))) {
  2972. startTime = gameLocal.slow.time;
  2973. //Lock the player from harvesting to prevent multiple harvests when only one is needed
  2974. thePlayer->harvest_lock = true;
  2975. idWeapon* weap = (idWeapon*)thePlayer->weapon.GetEntity();
  2976. if(weap) {
  2977. //weap->PostEventMS(&EV_Weapon_State, 0, "Charge", 8);
  2978. weap->ProcessEvent(&EV_Weapon_State, "Charge", 8);
  2979. }
  2980. BeginBurn();
  2981. BeginFX();
  2982. //Stop any looping sound that was playing
  2983. idStr sound = parent->spawnArgs.GetString("harvest_sound");
  2984. if(sound.Length() > 0) {
  2985. parent->StopSound(SND_CHANNEL_ANY, false);
  2986. }
  2987. //Make the parent object non-solid
  2988. parent->GetPhysics()->SetContents( 0 );
  2989. parent->GetPhysics()->GetClipModel()->Unlink();
  2990. //Turn of the trigger so it doesn't process twice
  2991. trigger->SetContents( 0 );
  2992. }
  2993. }
  2994. }
  2995. }
  2996. /*
  2997. ===============================================================================
  2998. idAFEntity_Harvest
  2999. ===============================================================================
  3000. */
  3001. const idEventDef EV_Harvest_SpawnHarvestEntity( "<spawnHarvestEntity>", NULL );
  3002. CLASS_DECLARATION( idAFEntity_WithAttachedHead, idAFEntity_Harvest )
  3003. EVENT( EV_Harvest_SpawnHarvestEntity, idAFEntity_Harvest::Event_SpawnHarvestEntity )
  3004. END_CLASS
  3005. /*
  3006. ================
  3007. idAFEntity_Harvest::idAFEntity_Harvest
  3008. ================
  3009. */
  3010. idAFEntity_Harvest::idAFEntity_Harvest() {
  3011. harvestEnt = NULL;
  3012. }
  3013. /*
  3014. ================
  3015. idAFEntity_Harvest::~idAFEntity_Harvest
  3016. ================
  3017. */
  3018. idAFEntity_Harvest::~idAFEntity_Harvest() {
  3019. if ( harvestEnt.GetEntity() ) {
  3020. harvestEnt.GetEntity()->PostEventMS( &EV_Remove, 0 );
  3021. }
  3022. }
  3023. /*
  3024. ================
  3025. idAFEntity_Harvest::Save
  3026. ================
  3027. */
  3028. void idAFEntity_Harvest::Save( idSaveGame *savefile ) const {
  3029. harvestEnt.Save(savefile);
  3030. }
  3031. /*
  3032. ================
  3033. idAFEntity_Harvest::Restore
  3034. ================
  3035. */
  3036. void idAFEntity_Harvest::Restore( idRestoreGame *savefile ) {
  3037. harvestEnt.Restore(savefile);
  3038. //if(harvestEnt.GetEntity()) {
  3039. // harvestEnt.GetEntity()->SetParent(this);
  3040. //}
  3041. }
  3042. /*
  3043. ================
  3044. idAFEntity_Harvest::Spawn
  3045. ================
  3046. */
  3047. void idAFEntity_Harvest::Spawn() {
  3048. PostEventMS( &EV_Harvest_SpawnHarvestEntity, 0 );
  3049. }
  3050. /*
  3051. ================
  3052. idAFEntity_Harvest::Think
  3053. ================
  3054. */
  3055. void idAFEntity_Harvest::Think() {
  3056. idAFEntity_WithAttachedHead::Think();
  3057. }
  3058. void idAFEntity_Harvest::Event_SpawnHarvestEntity() {
  3059. const idDict *harvestDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_harvest_type"), false );
  3060. if ( harvestDef ) {
  3061. idEntity *temp;
  3062. gameLocal.SpawnEntityDef( *harvestDef, &temp, false );
  3063. harvestEnt = static_cast<idHarvestable *>(temp);
  3064. }
  3065. if(harvestEnt.GetEntity()) {
  3066. //Let the harvest entity set itself up
  3067. harvestEnt.GetEntity()->Init(this);
  3068. harvestEnt.GetEntity()->BecomeActive( TH_THINK );
  3069. }
  3070. }
  3071. void idAFEntity_Harvest::Gib( const idVec3 &dir, const char *damageDefName ) {
  3072. if(harvestEnt.GetEntity()) {
  3073. //Let the harvest ent know that we gibbed
  3074. harvestEnt.GetEntity()->Gib();
  3075. }
  3076. idAFEntity_WithAttachedHead::Gib(dir, damageDefName);
  3077. }