AFEntity.cpp 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #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( void ) {
  36. physicsObj.SetSelf( this );
  37. }
  38. /*
  39. ================
  40. idMultiModelAF::~idMultiModelAF
  41. ================
  42. */
  43. idMultiModelAF::~idMultiModelAF( void ) {
  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( void ) {
  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( void ) {
  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 idClipModel( trm );
  131. clip->SetContents( CONTENTS_SOLID );
  132. clip->Link( gameLocal.clip, this, 0, org, mat3_identity );
  133. body = new 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 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 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 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( void ) {
  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( void ) {
  203. body = NULL;
  204. combatModel = NULL;
  205. idleAnim = 0;
  206. attachJoint = INVALID_JOINT;
  207. }
  208. /*
  209. =====================
  210. idAFAttachment::~idAFAttachment
  211. =====================
  212. */
  213. idAFAttachment::~idAFAttachment( void ) {
  214. StopSound( SND_CHANNEL_ANY, false );
  215. delete combatModel;
  216. combatModel = NULL;
  217. }
  218. /*
  219. =====================
  220. idAFAttachment::Spawn
  221. =====================
  222. */
  223. void idAFAttachment::Spawn( void ) {
  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( void ) {
  246. body = NULL;
  247. attachJoint = INVALID_JOINT;
  248. Hide();
  249. }
  250. /*
  251. =====================
  252. idAFAttachment::GetBody
  253. =====================
  254. */
  255. idEntity *idAFAttachment::GetBody( void ) 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( void ) {
  288. idEntity::Hide();
  289. UnlinkCombat();
  290. }
  291. /*
  292. ================
  293. idAFAttachment::Show
  294. ================
  295. */
  296. void idAFAttachment::Show( void ) {
  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( void ) {
  376. idAnimatedEntity::Think();
  377. if ( thinkFlags & TH_UPDATEPARTICLES ) {
  378. UpdateDamageEffects();
  379. }
  380. }
  381. /*
  382. ================
  383. idAFAttachment::SetCombatModel
  384. ================
  385. */
  386. void idAFAttachment::SetCombatModel( void ) {
  387. if ( combatModel ) {
  388. combatModel->Unlink();
  389. combatModel->LoadModel( modelDefHandle );
  390. } else {
  391. combatModel = new idClipModel( modelDefHandle );
  392. }
  393. combatModel->SetOwner( body );
  394. }
  395. /*
  396. ================
  397. idAFAttachment::GetCombatModel
  398. ================
  399. */
  400. idClipModel *idAFAttachment::GetCombatModel( void ) const {
  401. return combatModel;
  402. }
  403. /*
  404. ================
  405. idAFAttachment::LinkCombat
  406. ================
  407. */
  408. void idAFAttachment::LinkCombat( void ) {
  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( void ) {
  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( void ) {
  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( void ) {
  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( void ) {
  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( void ) {
  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. af.Start();
  510. af.GetPhysics()->Rotate( spawnAxis.ToRotation() );
  511. af.GetPhysics()->Translate( spawnOrigin );
  512. LoadState( spawnArgs );
  513. af.UpdateAnimation();
  514. animator.CreateFrame( gameLocal.time, true );
  515. UpdateVisuals();
  516. return true;
  517. }
  518. /*
  519. ================
  520. idAFEntity_Base::Think
  521. ================
  522. */
  523. void idAFEntity_Base::Think( void ) {
  524. RunPhysics();
  525. UpdateAnimation();
  526. if ( thinkFlags & TH_UPDATEVISUALS ) {
  527. Present();
  528. LinkCombat();
  529. }
  530. }
  531. /*
  532. ================
  533. idAFEntity_Base::BodyForClipModelId
  534. ================
  535. */
  536. int idAFEntity_Base::BodyForClipModelId( int id ) const {
  537. return af.BodyForClipModelId( id );
  538. }
  539. /*
  540. ================
  541. idAFEntity_Base::SaveState
  542. ================
  543. */
  544. void idAFEntity_Base::SaveState( idDict &args ) const {
  545. const idKeyValue *kv;
  546. // save the ragdoll pose
  547. af.SaveState( args );
  548. // save all the bind constraints
  549. kv = spawnArgs.MatchPrefix( "bindConstraint ", NULL );
  550. while ( kv ) {
  551. args.Set( kv->GetKey(), kv->GetValue() );
  552. kv = spawnArgs.MatchPrefix( "bindConstraint ", kv );
  553. }
  554. // save the bind if it exists
  555. kv = spawnArgs.FindKey( "bind" );
  556. if ( kv ) {
  557. args.Set( kv->GetKey(), kv->GetValue() );
  558. }
  559. kv = spawnArgs.FindKey( "bindToJoint" );
  560. if ( kv ) {
  561. args.Set( kv->GetKey(), kv->GetValue() );
  562. }
  563. kv = spawnArgs.FindKey( "bindToBody" );
  564. if ( kv ) {
  565. args.Set( kv->GetKey(), kv->GetValue() );
  566. }
  567. }
  568. /*
  569. ================
  570. idAFEntity_Base::LoadState
  571. ================
  572. */
  573. void idAFEntity_Base::LoadState( const idDict &args ) {
  574. af.LoadState( args );
  575. }
  576. /*
  577. ================
  578. idAFEntity_Base::AddBindConstraints
  579. ================
  580. */
  581. void idAFEntity_Base::AddBindConstraints( void ) {
  582. af.AddBindConstraints();
  583. }
  584. /*
  585. ================
  586. idAFEntity_Base::RemoveBindConstraints
  587. ================
  588. */
  589. void idAFEntity_Base::RemoveBindConstraints( void ) {
  590. af.RemoveBindConstraints();
  591. }
  592. /*
  593. ================
  594. idAFEntity_Base::GetImpactInfo
  595. ================
  596. */
  597. void idAFEntity_Base::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
  598. if ( af.IsActive() ) {
  599. af.GetImpactInfo( ent, id, point, info );
  600. } else {
  601. idEntity::GetImpactInfo( ent, id, point, info );
  602. }
  603. }
  604. /*
  605. ================
  606. idAFEntity_Base::ApplyImpulse
  607. ================
  608. */
  609. void idAFEntity_Base::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) {
  610. if ( af.IsLoaded() ) {
  611. af.ApplyImpulse( ent, id, point, impulse );
  612. }
  613. if ( !af.IsActive() ) {
  614. idEntity::ApplyImpulse( ent, id, point, impulse );
  615. }
  616. }
  617. /*
  618. ================
  619. idAFEntity_Base::AddForce
  620. ================
  621. */
  622. void idAFEntity_Base::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
  623. if ( af.IsLoaded() ) {
  624. af.AddForce( ent, id, point, force );
  625. }
  626. if ( !af.IsActive() ) {
  627. idEntity::AddForce( ent, id, point, force );
  628. }
  629. }
  630. /*
  631. ================
  632. idAFEntity_Base::Collide
  633. ================
  634. */
  635. bool idAFEntity_Base::Collide( const trace_t &collision, const idVec3 &velocity ) {
  636. float v, f;
  637. if ( af.IsActive() ) {
  638. v = -( velocity * collision.c.normal );
  639. if ( v > BOUNCE_SOUND_MIN_VELOCITY && gameLocal.time > nextSoundTime ) {
  640. 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 ) );
  641. if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) {
  642. // don't set the volume unless there is a bounce sound as it overrides the entire channel
  643. // which causes footsteps on ai's to not honor their shader parms
  644. SetSoundVolume( f );
  645. }
  646. nextSoundTime = gameLocal.time + 500;
  647. }
  648. }
  649. return false;
  650. }
  651. /*
  652. ================
  653. idAFEntity_Base::GetPhysicsToVisualTransform
  654. ================
  655. */
  656. bool idAFEntity_Base::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
  657. if ( af.IsActive() ) {
  658. af.GetPhysicsToVisualTransform( origin, axis );
  659. return true;
  660. }
  661. return idEntity::GetPhysicsToVisualTransform( origin, axis );
  662. }
  663. /*
  664. ================
  665. idAFEntity_Base::UpdateAnimationControllers
  666. ================
  667. */
  668. bool idAFEntity_Base::UpdateAnimationControllers( void ) {
  669. if ( af.IsActive() ) {
  670. if ( af.UpdateAnimation() ) {
  671. return true;
  672. }
  673. }
  674. return false;
  675. }
  676. /*
  677. ================
  678. idAFEntity_Base::SetCombatModel
  679. ================
  680. */
  681. void idAFEntity_Base::SetCombatModel( void ) {
  682. if ( combatModel ) {
  683. combatModel->Unlink();
  684. combatModel->LoadModel( modelDefHandle );
  685. } else {
  686. combatModel = new idClipModel( modelDefHandle );
  687. }
  688. }
  689. /*
  690. ================
  691. idAFEntity_Base::GetCombatModel
  692. ================
  693. */
  694. idClipModel *idAFEntity_Base::GetCombatModel( void ) const {
  695. return combatModel;
  696. }
  697. /*
  698. ================
  699. idAFEntity_Base::SetCombatContents
  700. ================
  701. */
  702. void idAFEntity_Base::SetCombatContents( bool enable ) {
  703. assert( combatModel );
  704. if ( enable && combatModelContents ) {
  705. assert( !combatModel->GetContents() );
  706. combatModel->SetContents( combatModelContents );
  707. combatModelContents = 0;
  708. } else if ( !enable && combatModel->GetContents() ) {
  709. assert( !combatModelContents );
  710. combatModelContents = combatModel->GetContents();
  711. combatModel->SetContents( 0 );
  712. }
  713. }
  714. /*
  715. ================
  716. idAFEntity_Base::LinkCombat
  717. ================
  718. */
  719. void idAFEntity_Base::LinkCombat( void ) {
  720. if ( fl.hidden ) {
  721. return;
  722. }
  723. if ( combatModel ) {
  724. combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  725. }
  726. }
  727. /*
  728. ================
  729. idAFEntity_Base::UnlinkCombat
  730. ================
  731. */
  732. void idAFEntity_Base::UnlinkCombat( void ) {
  733. if ( combatModel ) {
  734. combatModel->Unlink();
  735. }
  736. }
  737. /*
  738. ================
  739. idAFEntity_Base::FreeModelDef
  740. ================
  741. */
  742. void idAFEntity_Base::FreeModelDef( void ) {
  743. UnlinkCombat();
  744. idEntity::FreeModelDef();
  745. }
  746. /*
  747. ===============
  748. idAFEntity_Base::ShowEditingDialog
  749. ===============
  750. */
  751. void idAFEntity_Base::ShowEditingDialog( void ) {
  752. common->InitTool( EDITOR_AF, &spawnArgs );
  753. }
  754. /*
  755. ================
  756. idAFEntity_Base::DropAFs
  757. The entity should have the following key/value pairs set:
  758. "def_drop<type>AF" "af def"
  759. "drop<type>Skin" "skin name"
  760. To drop multiple articulated figures the following key/value pairs can be used:
  761. "def_drop<type>AF*" "af def"
  762. where * is an aribtrary string.
  763. ================
  764. */
  765. void idAFEntity_Base::DropAFs( idEntity *ent, const char *type, idList<idEntity *> *list ) {
  766. const idKeyValue *kv;
  767. const char *skinName;
  768. idEntity *newEnt;
  769. idAFEntity_Base *af;
  770. idDict args;
  771. const idDeclSkin *skin;
  772. // drop the articulated figures
  773. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sAF", type ), NULL );
  774. while ( kv ) {
  775. args.Set( "classname", kv->GetValue() );
  776. gameLocal.SpawnEntityDef( args, &newEnt );
  777. if ( newEnt && newEnt->IsType( idAFEntity_Base::Type ) ) {
  778. af = static_cast<idAFEntity_Base *>(newEnt);
  779. af->GetPhysics()->SetOrigin( ent->GetPhysics()->GetOrigin() );
  780. af->GetPhysics()->SetAxis( ent->GetPhysics()->GetAxis() );
  781. af->af.SetupPose( ent, gameLocal.time );
  782. if ( list ) {
  783. list->Append( af );
  784. }
  785. }
  786. kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sAF", type ), kv );
  787. }
  788. // change the skin to hide all the dropped articulated figures
  789. skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) );
  790. if ( skinName[0] ) {
  791. skin = declManager->FindSkin( skinName );
  792. ent->SetSkin( skin );
  793. }
  794. }
  795. /*
  796. ================
  797. idAFEntity_Base::Event_SetConstraintPosition
  798. ================
  799. */
  800. void idAFEntity_Base::Event_SetConstraintPosition( const char *name, const idVec3 &pos ) {
  801. af.SetConstraintPosition( name, pos );
  802. }
  803. /*
  804. ===============================================================================
  805. idAFEntity_Gibbable
  806. ===============================================================================
  807. */
  808. const idEventDef EV_Gib( "gib", "s" );
  809. const idEventDef EV_Gibbed( "<gibbed>" );
  810. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_Gibbable )
  811. EVENT( EV_Gib, idAFEntity_Gibbable::Event_Gib )
  812. EVENT( EV_Gibbed, idAFEntity_Base::Event_Remove )
  813. END_CLASS
  814. /*
  815. ================
  816. idAFEntity_Gibbable::idAFEntity_Gibbable
  817. ================
  818. */
  819. idAFEntity_Gibbable::idAFEntity_Gibbable( void ) {
  820. skeletonModel = NULL;
  821. skeletonModelDefHandle = -1;
  822. gibbed = false;
  823. }
  824. /*
  825. ================
  826. idAFEntity_Gibbable::~idAFEntity_Gibbable
  827. ================
  828. */
  829. idAFEntity_Gibbable::~idAFEntity_Gibbable() {
  830. if ( skeletonModelDefHandle != -1 ) {
  831. gameRenderWorld->FreeEntityDef( skeletonModelDefHandle );
  832. skeletonModelDefHandle = -1;
  833. }
  834. }
  835. /*
  836. ================
  837. idAFEntity_Gibbable::Save
  838. ================
  839. */
  840. void idAFEntity_Gibbable::Save( idSaveGame *savefile ) const {
  841. savefile->WriteBool( gibbed );
  842. savefile->WriteBool( combatModel != NULL );
  843. }
  844. /*
  845. ================
  846. idAFEntity_Gibbable::Restore
  847. ================
  848. */
  849. void idAFEntity_Gibbable::Restore( idRestoreGame *savefile ) {
  850. bool hasCombatModel;
  851. savefile->ReadBool( gibbed );
  852. savefile->ReadBool( hasCombatModel );
  853. InitSkeletonModel();
  854. if ( hasCombatModel ) {
  855. SetCombatModel();
  856. LinkCombat();
  857. }
  858. }
  859. /*
  860. ================
  861. idAFEntity_Gibbable::Spawn
  862. ================
  863. */
  864. void idAFEntity_Gibbable::Spawn( void ) {
  865. InitSkeletonModel();
  866. gibbed = false;
  867. }
  868. /*
  869. ================
  870. idAFEntity_Gibbable::InitSkeletonModel
  871. ================
  872. */
  873. void idAFEntity_Gibbable::InitSkeletonModel( void ) {
  874. const char *modelName;
  875. const idDeclModelDef *modelDef;
  876. skeletonModel = NULL;
  877. skeletonModelDefHandle = -1;
  878. modelName = spawnArgs.GetString( "model_gib" );
  879. modelDef = NULL;
  880. if ( modelName[0] != '\0' ) {
  881. modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) );
  882. if ( modelDef ) {
  883. skeletonModel = modelDef->ModelHandle();
  884. } else {
  885. skeletonModel = renderModelManager->FindModel( modelName );
  886. }
  887. if ( skeletonModel != NULL && renderEntity.hModel != NULL ) {
  888. if ( skeletonModel->NumJoints() != renderEntity.hModel->NumJoints() ) {
  889. gameLocal.Error( "gib model '%s' has different number of joints than model '%s'",
  890. skeletonModel->Name(), renderEntity.hModel->Name() );
  891. }
  892. }
  893. }
  894. }
  895. /*
  896. ================
  897. idAFEntity_Gibbable::Present
  898. ================
  899. */
  900. void idAFEntity_Gibbable::Present( void ) {
  901. renderEntity_t skeleton;
  902. if ( !gameLocal.isNewFrame ) {
  903. return;
  904. }
  905. // don't present to the renderer if the entity hasn't changed
  906. if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  907. return;
  908. }
  909. // update skeleton model
  910. if ( gibbed && !IsHidden() && skeletonModel != NULL ) {
  911. skeleton = renderEntity;
  912. skeleton.hModel = skeletonModel;
  913. // add to refresh list
  914. if ( skeletonModelDefHandle == -1 ) {
  915. skeletonModelDefHandle = gameRenderWorld->AddEntityDef( &skeleton );
  916. } else {
  917. gameRenderWorld->UpdateEntityDef( skeletonModelDefHandle, &skeleton );
  918. }
  919. }
  920. idEntity::Present();
  921. }
  922. /*
  923. ================
  924. idAFEntity_Gibbable::Damage
  925. ================
  926. */
  927. void idAFEntity_Gibbable::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
  928. if ( !fl.takedamage ) {
  929. return;
  930. }
  931. idAFEntity_Base::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
  932. if ( health < -20 && spawnArgs.GetBool( "gib" ) ) {
  933. Gib( dir, damageDefName );
  934. }
  935. }
  936. /*
  937. =====================
  938. idAFEntity_Gibbable::SpawnGibs
  939. =====================
  940. */
  941. void idAFEntity_Gibbable::SpawnGibs( const idVec3 &dir, const char *damageDefName ) {
  942. int i;
  943. bool gibNonSolid;
  944. idVec3 entityCenter, velocity;
  945. idList<idEntity *> list;
  946. assert( !gameLocal.isClient );
  947. const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
  948. if ( !damageDef ) {
  949. gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
  950. }
  951. // spawn gib articulated figures
  952. idAFEntity_Base::DropAFs( this, "gib", &list );
  953. // spawn gib items
  954. idMoveableItem::DropItems( this, "gib", &list );
  955. // blow out the gibs in the given direction away from the center of the entity
  956. entityCenter = GetPhysics()->GetAbsBounds().GetCenter();
  957. gibNonSolid = damageDef->GetBool( "gibNonSolid" );
  958. for ( i = 0; i < list.Num(); i++ ) {
  959. if ( gibNonSolid ) {
  960. list[i]->GetPhysics()->SetContents( 0 );
  961. list[i]->GetPhysics()->SetClipMask( 0 );
  962. list[i]->GetPhysics()->UnlinkClip();
  963. list[i]->GetPhysics()->PutToRest();
  964. } else {
  965. list[i]->GetPhysics()->SetContents( CONTENTS_CORPSE );
  966. list[i]->GetPhysics()->SetClipMask( CONTENTS_SOLID );
  967. velocity = list[i]->GetPhysics()->GetAbsBounds().GetCenter() - entityCenter;
  968. velocity.NormalizeFast();
  969. velocity += ( i & 1 ) ? dir : -dir;
  970. list[i]->GetPhysics()->SetLinearVelocity( velocity * 75.0f );
  971. }
  972. list[i]->GetRenderEntity()->noShadow = true;
  973. list[i]->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  974. list[i]->PostEventSec( &EV_Remove, 4.0f );
  975. }
  976. }
  977. /*
  978. ============
  979. idAFEntity_Gibbable::Gib
  980. ============
  981. */
  982. void idAFEntity_Gibbable::Gib( const idVec3 &dir, const char *damageDefName ) {
  983. // only gib once
  984. if ( gibbed ) {
  985. return;
  986. }
  987. const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
  988. if ( !damageDef ) {
  989. gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
  990. }
  991. if ( damageDef->GetBool( "gibNonSolid" ) ) {
  992. GetAFPhysics()->SetContents( 0 );
  993. GetAFPhysics()->SetClipMask( 0 );
  994. GetAFPhysics()->UnlinkClip();
  995. GetAFPhysics()->PutToRest();
  996. } else {
  997. GetAFPhysics()->SetContents( CONTENTS_CORPSE );
  998. GetAFPhysics()->SetClipMask( CONTENTS_SOLID );
  999. }
  1000. UnlinkCombat();
  1001. if ( g_bloodEffects.GetBool() ) {
  1002. if ( gameLocal.time > gameLocal.GetGibTime() ) {
  1003. gameLocal.SetGibTime( gameLocal.time + GIB_DELAY );
  1004. SpawnGibs( dir, damageDefName );
  1005. renderEntity.noShadow = true;
  1006. renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  1007. StartSound( "snd_gibbed", SND_CHANNEL_ANY, 0, false, NULL );
  1008. gibbed = true;
  1009. }
  1010. } else {
  1011. gibbed = true;
  1012. }
  1013. PostEventSec( &EV_Gibbed, 4.0f );
  1014. }
  1015. /*
  1016. ============
  1017. idAFEntity_Gibbable::Event_Gib
  1018. ============
  1019. */
  1020. void idAFEntity_Gibbable::Event_Gib( const char *damageDefName ) {
  1021. Gib( idVec3( 0, 0, 1 ), damageDefName );
  1022. }
  1023. /*
  1024. ===============================================================================
  1025. idAFEntity_Generic
  1026. ===============================================================================
  1027. */
  1028. CLASS_DECLARATION( idAFEntity_Gibbable, idAFEntity_Generic )
  1029. EVENT( EV_Activate, idAFEntity_Generic::Event_Activate )
  1030. END_CLASS
  1031. /*
  1032. ================
  1033. idAFEntity_Generic::idAFEntity_Generic
  1034. ================
  1035. */
  1036. idAFEntity_Generic::idAFEntity_Generic( void ) {
  1037. keepRunningPhysics = false;
  1038. }
  1039. /*
  1040. ================
  1041. idAFEntity_Generic::~idAFEntity_Generic
  1042. ================
  1043. */
  1044. idAFEntity_Generic::~idAFEntity_Generic( void ) {
  1045. }
  1046. /*
  1047. ================
  1048. idAFEntity_Generic::Save
  1049. ================
  1050. */
  1051. void idAFEntity_Generic::Save( idSaveGame *savefile ) const {
  1052. savefile->WriteBool( keepRunningPhysics );
  1053. }
  1054. /*
  1055. ================
  1056. idAFEntity_Generic::Restore
  1057. ================
  1058. */
  1059. void idAFEntity_Generic::Restore( idRestoreGame *savefile ) {
  1060. savefile->ReadBool( keepRunningPhysics );
  1061. }
  1062. /*
  1063. ================
  1064. idAFEntity_Generic::Think
  1065. ================
  1066. */
  1067. void idAFEntity_Generic::Think( void ) {
  1068. idAFEntity_Base::Think();
  1069. if ( keepRunningPhysics ) {
  1070. BecomeActive( TH_PHYSICS );
  1071. }
  1072. }
  1073. /*
  1074. ================
  1075. idAFEntity_Generic::Spawn
  1076. ================
  1077. */
  1078. void idAFEntity_Generic::Spawn( void ) {
  1079. if ( !LoadAF() ) {
  1080. gameLocal.Error( "Couldn't load af file on entity '%s'", name.c_str() );
  1081. }
  1082. SetCombatModel();
  1083. SetPhysics( af.GetPhysics() );
  1084. af.GetPhysics()->PutToRest();
  1085. if ( !spawnArgs.GetBool( "nodrop", "0" ) ) {
  1086. af.GetPhysics()->Activate();
  1087. }
  1088. fl.takedamage = true;
  1089. }
  1090. /*
  1091. ================
  1092. idAFEntity_Generic::Event_Activate
  1093. ================
  1094. */
  1095. void idAFEntity_Generic::Event_Activate( idEntity *activator ) {
  1096. float delay;
  1097. idVec3 init_velocity, init_avelocity;
  1098. Show();
  1099. af.GetPhysics()->EnableImpact();
  1100. af.GetPhysics()->Activate();
  1101. spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity );
  1102. spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity );
  1103. delay = spawnArgs.GetFloat( "init_velocityDelay", "0" );
  1104. if ( delay == 0.0f ) {
  1105. af.GetPhysics()->SetLinearVelocity( init_velocity );
  1106. } else {
  1107. PostEventSec( &EV_SetLinearVelocity, delay, init_velocity );
  1108. }
  1109. delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" );
  1110. if ( delay == 0.0f ) {
  1111. af.GetPhysics()->SetAngularVelocity( init_avelocity );
  1112. } else {
  1113. PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity );
  1114. }
  1115. }
  1116. /*
  1117. ===============================================================================
  1118. idAFEntity_WithAttachedHead
  1119. ===============================================================================
  1120. */
  1121. CLASS_DECLARATION( idAFEntity_Gibbable, idAFEntity_WithAttachedHead )
  1122. EVENT( EV_Gib, idAFEntity_WithAttachedHead::Event_Gib )
  1123. EVENT( EV_Activate, idAFEntity_WithAttachedHead::Event_Activate )
  1124. END_CLASS
  1125. /*
  1126. ================
  1127. idAFEntity_WithAttachedHead::idAFEntity_WithAttachedHead
  1128. ================
  1129. */
  1130. idAFEntity_WithAttachedHead::idAFEntity_WithAttachedHead() {
  1131. head = NULL;
  1132. }
  1133. /*
  1134. ================
  1135. idAFEntity_WithAttachedHead::~idAFEntity_WithAttachedHead
  1136. ================
  1137. */
  1138. idAFEntity_WithAttachedHead::~idAFEntity_WithAttachedHead() {
  1139. if ( head.GetEntity() ) {
  1140. head.GetEntity()->ClearBody();
  1141. head.GetEntity()->PostEventMS( &EV_Remove, 0 );
  1142. }
  1143. }
  1144. /*
  1145. ================
  1146. idAFEntity_WithAttachedHead::Spawn
  1147. ================
  1148. */
  1149. void idAFEntity_WithAttachedHead::Spawn( void ) {
  1150. SetupHead();
  1151. LoadAF();
  1152. SetCombatModel();
  1153. SetPhysics( af.GetPhysics() );
  1154. af.GetPhysics()->PutToRest();
  1155. if ( !spawnArgs.GetBool( "nodrop", "0" ) ) {
  1156. af.GetPhysics()->Activate();
  1157. }
  1158. fl.takedamage = true;
  1159. if ( head.GetEntity() ) {
  1160. int anim = head.GetEntity()->GetAnimator()->GetAnim( "dead" );
  1161. if ( anim ) {
  1162. head.GetEntity()->GetAnimator()->SetFrame( ANIMCHANNEL_ALL, anim, 0, gameLocal.time, 0 );
  1163. }
  1164. }
  1165. }
  1166. /*
  1167. ================
  1168. idAFEntity_WithAttachedHead::Save
  1169. ================
  1170. */
  1171. void idAFEntity_WithAttachedHead::Save( idSaveGame *savefile ) const {
  1172. head.Save( savefile );
  1173. }
  1174. /*
  1175. ================
  1176. idAFEntity_WithAttachedHead::Restore
  1177. ================
  1178. */
  1179. void idAFEntity_WithAttachedHead::Restore( idRestoreGame *savefile ) {
  1180. head.Restore( savefile );
  1181. }
  1182. /*
  1183. ================
  1184. idAFEntity_WithAttachedHead::SetupHead
  1185. ================
  1186. */
  1187. void idAFEntity_WithAttachedHead::SetupHead( void ) {
  1188. idAFAttachment *headEnt;
  1189. idStr jointName;
  1190. const char *headModel;
  1191. jointHandle_t joint;
  1192. idVec3 origin;
  1193. idMat3 axis;
  1194. headModel = spawnArgs.GetString( "def_head", "" );
  1195. if ( headModel[ 0 ] ) {
  1196. jointName = spawnArgs.GetString( "head_joint" );
  1197. joint = animator.GetJointHandle( jointName );
  1198. if ( joint == INVALID_JOINT ) {
  1199. gameLocal.Error( "Joint '%s' not found for 'head_joint' on '%s'", jointName.c_str(), name.c_str() );
  1200. }
  1201. headEnt = static_cast<idAFAttachment *>( gameLocal.SpawnEntityType( idAFAttachment::Type, NULL ) );
  1202. headEnt->SetName( va( "%s_head", name.c_str() ) );
  1203. headEnt->SetBody( this, headModel, joint );
  1204. headEnt->SetCombatModel();
  1205. head = headEnt;
  1206. animator.GetJointTransform( joint, gameLocal.time, origin, axis );
  1207. origin = renderEntity.origin + origin * renderEntity.axis;
  1208. headEnt->SetOrigin( origin );
  1209. headEnt->SetAxis( renderEntity.axis );
  1210. headEnt->BindToJoint( this, joint, true );
  1211. }
  1212. }
  1213. /*
  1214. ================
  1215. idAFEntity_WithAttachedHead::Think
  1216. ================
  1217. */
  1218. void idAFEntity_WithAttachedHead::Think( void ) {
  1219. idAFEntity_Base::Think();
  1220. }
  1221. /*
  1222. ================
  1223. idAFEntity_WithAttachedHead::LinkCombat
  1224. ================
  1225. */
  1226. void idAFEntity_WithAttachedHead::LinkCombat( void ) {
  1227. idAFAttachment *headEnt;
  1228. if ( fl.hidden ) {
  1229. return;
  1230. }
  1231. if ( combatModel ) {
  1232. combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  1233. }
  1234. headEnt = head.GetEntity();
  1235. if ( headEnt ) {
  1236. headEnt->LinkCombat();
  1237. }
  1238. }
  1239. /*
  1240. ================
  1241. idAFEntity_WithAttachedHead::UnlinkCombat
  1242. ================
  1243. */
  1244. void idAFEntity_WithAttachedHead::UnlinkCombat( void ) {
  1245. idAFAttachment *headEnt;
  1246. if ( combatModel ) {
  1247. combatModel->Unlink();
  1248. }
  1249. headEnt = head.GetEntity();
  1250. if ( headEnt ) {
  1251. headEnt->UnlinkCombat();
  1252. }
  1253. }
  1254. /*
  1255. ================
  1256. idAFEntity_WithAttachedHead::Hide
  1257. ================
  1258. */
  1259. void idAFEntity_WithAttachedHead::Hide( void ) {
  1260. idAFEntity_Base::Hide();
  1261. if ( head.GetEntity() ) {
  1262. head.GetEntity()->Hide();
  1263. }
  1264. UnlinkCombat();
  1265. }
  1266. /*
  1267. ================
  1268. idAFEntity_WithAttachedHead::Show
  1269. ================
  1270. */
  1271. void idAFEntity_WithAttachedHead::Show( void ) {
  1272. idAFEntity_Base::Show();
  1273. if ( head.GetEntity() ) {
  1274. head.GetEntity()->Show();
  1275. }
  1276. LinkCombat();
  1277. }
  1278. /*
  1279. ================
  1280. idAFEntity_WithAttachedHead::ProjectOverlay
  1281. ================
  1282. */
  1283. void idAFEntity_WithAttachedHead::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
  1284. idEntity::ProjectOverlay( origin, dir, size, material );
  1285. if ( head.GetEntity() ) {
  1286. head.GetEntity()->ProjectOverlay( origin, dir, size, material );
  1287. }
  1288. }
  1289. /*
  1290. ============
  1291. idAFEntity_WithAttachedHead::Gib
  1292. ============
  1293. */
  1294. void idAFEntity_WithAttachedHead::Gib( const idVec3 &dir, const char *damageDefName ) {
  1295. // only gib once
  1296. if ( gibbed ) {
  1297. return;
  1298. }
  1299. idAFEntity_Gibbable::Gib( dir, damageDefName );
  1300. if ( head.GetEntity() ) {
  1301. head.GetEntity()->Hide();
  1302. }
  1303. }
  1304. /*
  1305. ============
  1306. idAFEntity_WithAttachedHead::Event_Gib
  1307. ============
  1308. */
  1309. void idAFEntity_WithAttachedHead::Event_Gib( const char *damageDefName ) {
  1310. Gib( idVec3( 0, 0, 1 ), damageDefName );
  1311. }
  1312. /*
  1313. ================
  1314. idAFEntity_WithAttachedHead::Event_Activate
  1315. ================
  1316. */
  1317. void idAFEntity_WithAttachedHead::Event_Activate( idEntity *activator ) {
  1318. float delay;
  1319. idVec3 init_velocity, init_avelocity;
  1320. Show();
  1321. af.GetPhysics()->EnableImpact();
  1322. af.GetPhysics()->Activate();
  1323. spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity );
  1324. spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity );
  1325. delay = spawnArgs.GetFloat( "init_velocityDelay", "0" );
  1326. if ( delay == 0.0f ) {
  1327. af.GetPhysics()->SetLinearVelocity( init_velocity );
  1328. } else {
  1329. PostEventSec( &EV_SetLinearVelocity, delay, init_velocity );
  1330. }
  1331. delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" );
  1332. if ( delay == 0.0f ) {
  1333. af.GetPhysics()->SetAngularVelocity( init_avelocity );
  1334. } else {
  1335. PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity );
  1336. }
  1337. }
  1338. /*
  1339. ===============================================================================
  1340. idAFEntity_Vehicle
  1341. ===============================================================================
  1342. */
  1343. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_Vehicle )
  1344. END_CLASS
  1345. /*
  1346. ================
  1347. idAFEntity_Vehicle::idAFEntity_Vehicle
  1348. ================
  1349. */
  1350. idAFEntity_Vehicle::idAFEntity_Vehicle( void ) {
  1351. player = NULL;
  1352. eyesJoint = INVALID_JOINT;
  1353. steeringWheelJoint = INVALID_JOINT;
  1354. wheelRadius = 0.0f;
  1355. steerAngle = 0.0f;
  1356. steerSpeed = 0.0f;
  1357. dustSmoke = NULL;
  1358. }
  1359. /*
  1360. ================
  1361. idAFEntity_Vehicle::Spawn
  1362. ================
  1363. */
  1364. void idAFEntity_Vehicle::Spawn( void ) {
  1365. const char *eyesJointName = spawnArgs.GetString( "eyesJoint", "eyes" );
  1366. const char *steeringWheelJointName = spawnArgs.GetString( "steeringWheelJoint", "steeringWheel" );
  1367. LoadAF();
  1368. SetCombatModel();
  1369. SetPhysics( af.GetPhysics() );
  1370. fl.takedamage = true;
  1371. if ( !eyesJointName[0] ) {
  1372. gameLocal.Error( "idAFEntity_Vehicle '%s' no eyes joint specified", name.c_str() );
  1373. }
  1374. eyesJoint = animator.GetJointHandle( eyesJointName );
  1375. if ( !steeringWheelJointName[0] ) {
  1376. gameLocal.Error( "idAFEntity_Vehicle '%s' no steering wheel joint specified", name.c_str() );
  1377. }
  1378. steeringWheelJoint = animator.GetJointHandle( steeringWheelJointName );
  1379. spawnArgs.GetFloat( "wheelRadius", "20", wheelRadius );
  1380. spawnArgs.GetFloat( "steerSpeed", "5", steerSpeed );
  1381. player = NULL;
  1382. steerAngle = 0.0f;
  1383. const char *smokeName = spawnArgs.GetString( "smoke_vehicle_dust", "muzzlesmoke" );
  1384. if ( *smokeName != '\0' ) {
  1385. dustSmoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  1386. }
  1387. }
  1388. /*
  1389. ================
  1390. idAFEntity_Vehicle::Use
  1391. ================
  1392. */
  1393. void idAFEntity_Vehicle::Use( idPlayer *other ) {
  1394. idVec3 origin;
  1395. idMat3 axis;
  1396. if ( player ) {
  1397. if ( player == other ) {
  1398. other->Unbind();
  1399. player = NULL;
  1400. af.GetPhysics()->SetComeToRest( true );
  1401. }
  1402. }
  1403. else {
  1404. player = other;
  1405. animator.GetJointTransform( eyesJoint, gameLocal.time, origin, axis );
  1406. origin = renderEntity.origin + origin * renderEntity.axis;
  1407. player->GetPhysics()->SetOrigin( origin );
  1408. player->BindToBody( this, 0, true );
  1409. af.GetPhysics()->SetComeToRest( false );
  1410. af.GetPhysics()->Activate();
  1411. }
  1412. }
  1413. /*
  1414. ================
  1415. idAFEntity_Vehicle::GetSteerAngle
  1416. ================
  1417. */
  1418. float idAFEntity_Vehicle::GetSteerAngle( void ) {
  1419. float idealSteerAngle, angleDelta;
  1420. idealSteerAngle = player->usercmd.rightmove * ( 30.0f / 128.0f );
  1421. angleDelta = idealSteerAngle - steerAngle;
  1422. if ( angleDelta > steerSpeed ) {
  1423. steerAngle += steerSpeed;
  1424. } else if ( angleDelta < -steerSpeed ) {
  1425. steerAngle -= steerSpeed;
  1426. } else {
  1427. steerAngle = idealSteerAngle;
  1428. }
  1429. return steerAngle;
  1430. }
  1431. /*
  1432. ===============================================================================
  1433. idAFEntity_VehicleSimple
  1434. ===============================================================================
  1435. */
  1436. CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleSimple )
  1437. END_CLASS
  1438. /*
  1439. ================
  1440. idAFEntity_VehicleSimple::idAFEntity_VehicleSimple
  1441. ================
  1442. */
  1443. idAFEntity_VehicleSimple::idAFEntity_VehicleSimple( void ) {
  1444. int i;
  1445. for ( i = 0; i < 4; i++ ) {
  1446. suspension[i] = NULL;
  1447. }
  1448. }
  1449. /*
  1450. ================
  1451. idAFEntity_VehicleSimple::~idAFEntity_VehicleSimple
  1452. ================
  1453. */
  1454. idAFEntity_VehicleSimple::~idAFEntity_VehicleSimple( void ) {
  1455. delete wheelModel;
  1456. wheelModel = NULL;
  1457. }
  1458. /*
  1459. ================
  1460. idAFEntity_VehicleSimple::Spawn
  1461. ================
  1462. */
  1463. void idAFEntity_VehicleSimple::Spawn( void ) {
  1464. static const char *wheelJointKeys[] = {
  1465. "wheelJointFrontLeft",
  1466. "wheelJointFrontRight",
  1467. "wheelJointRearLeft",
  1468. "wheelJointRearRight"
  1469. };
  1470. static idVec3 wheelPoly[4] = { idVec3( 2, 2, 0 ), idVec3( 2, -2, 0 ), idVec3( -2, -2, 0 ), idVec3( -2, 2, 0 ) };
  1471. int i;
  1472. idVec3 origin;
  1473. idMat3 axis;
  1474. idTraceModel trm;
  1475. trm.SetupPolygon( wheelPoly, 4 );
  1476. trm.Translate( idVec3( 0, 0, -wheelRadius ) );
  1477. wheelModel = new idClipModel( trm );
  1478. for ( i = 0; i < 4; i++ ) {
  1479. const char *wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" );
  1480. if ( !wheelJointName[0] ) {
  1481. gameLocal.Error( "idAFEntity_VehicleSimple '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] );
  1482. }
  1483. wheelJoints[i] = animator.GetJointHandle( wheelJointName );
  1484. if ( wheelJoints[i] == INVALID_JOINT ) {
  1485. gameLocal.Error( "idAFEntity_VehicleSimple '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName );
  1486. }
  1487. GetAnimator()->GetJointTransform( wheelJoints[i], 0, origin, axis );
  1488. origin = renderEntity.origin + origin * renderEntity.axis;
  1489. suspension[i] = new idAFConstraint_Suspension();
  1490. suspension[i]->Setup( va( "suspension%d", i ), af.GetPhysics()->GetBody( 0 ), origin, af.GetPhysics()->GetAxis( 0 ), wheelModel );
  1491. suspension[i]->SetSuspension( g_vehicleSuspensionUp.GetFloat(),
  1492. g_vehicleSuspensionDown.GetFloat(),
  1493. g_vehicleSuspensionKCompress.GetFloat(),
  1494. g_vehicleSuspensionDamping.GetFloat(),
  1495. g_vehicleTireFriction.GetFloat() );
  1496. af.GetPhysics()->AddConstraint( suspension[i] );
  1497. }
  1498. memset( wheelAngles, 0, sizeof( wheelAngles ) );
  1499. BecomeActive( TH_THINK );
  1500. }
  1501. /*
  1502. ================
  1503. idAFEntity_VehicleSimple::Think
  1504. ================
  1505. */
  1506. void idAFEntity_VehicleSimple::Think( void ) {
  1507. int i;
  1508. float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f;
  1509. idVec3 origin;
  1510. idMat3 axis;
  1511. idRotation wheelRotation, steerRotation;
  1512. if ( thinkFlags & TH_THINK ) {
  1513. if ( player ) {
  1514. // capture the input from a player
  1515. velocity = g_vehicleVelocity.GetFloat();
  1516. if ( player->usercmd.forwardmove < 0 ) {
  1517. velocity = -velocity;
  1518. }
  1519. force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f);
  1520. steerAngle = GetSteerAngle();
  1521. }
  1522. // update the wheel motor force and steering
  1523. for ( i = 0; i < 2; i++ ) {
  1524. // front wheel drive
  1525. if ( velocity != 0.0f ) {
  1526. suspension[i]->EnableMotor( true );
  1527. } else {
  1528. suspension[i]->EnableMotor( false );
  1529. }
  1530. suspension[i]->SetMotorVelocity( velocity );
  1531. suspension[i]->SetMotorForce( force );
  1532. // update the wheel steering
  1533. suspension[i]->SetSteerAngle( steerAngle );
  1534. }
  1535. // adjust wheel velocity for better steering because there are no differentials between the wheels
  1536. if ( steerAngle < 0.0f ) {
  1537. suspension[0]->SetMotorVelocity( velocity * 0.5f );
  1538. } else if ( steerAngle > 0.0f ) {
  1539. suspension[1]->SetMotorVelocity( velocity * 0.5f );
  1540. }
  1541. // update suspension with latest cvar settings
  1542. for ( i = 0; i < 4; i++ ) {
  1543. suspension[i]->SetSuspension( g_vehicleSuspensionUp.GetFloat(),
  1544. g_vehicleSuspensionDown.GetFloat(),
  1545. g_vehicleSuspensionKCompress.GetFloat(),
  1546. g_vehicleSuspensionDamping.GetFloat(),
  1547. g_vehicleTireFriction.GetFloat() );
  1548. }
  1549. // run the physics
  1550. RunPhysics();
  1551. // move and rotate the wheels visually
  1552. for ( i = 0; i < 4; i++ ) {
  1553. idAFBody *body = af.GetPhysics()->GetBody( 0 );
  1554. origin = suspension[i]->GetWheelOrigin();
  1555. velocity = body->GetPointVelocity( origin ) * body->GetWorldAxis()[0];
  1556. wheelAngles[i] += velocity * MS2SEC( gameLocal.msec ) / wheelRadius;
  1557. // additional rotation about the wheel axis
  1558. wheelRotation.SetAngle( RAD2DEG( wheelAngles[i] ) );
  1559. wheelRotation.SetVec( 0, -1, 0 );
  1560. if ( i < 2 ) {
  1561. // rotate the wheel for steering
  1562. steerRotation.SetAngle( steerAngle );
  1563. steerRotation.SetVec( 0, 0, 1 );
  1564. // set wheel rotation
  1565. animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, wheelRotation.ToMat3() * steerRotation.ToMat3() );
  1566. } else {
  1567. // set wheel rotation
  1568. animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, wheelRotation.ToMat3() );
  1569. }
  1570. // set wheel position for suspension
  1571. origin = ( origin - renderEntity.origin ) * renderEntity.axis.Transpose();
  1572. GetAnimator()->SetJointPos( wheelJoints[i], JOINTMOD_WORLD_OVERRIDE, origin );
  1573. }
  1574. /*
  1575. // spawn dust particle effects
  1576. if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) {
  1577. int numContacts;
  1578. idAFConstraint_Contact *contacts[2];
  1579. for ( i = 0; i < 4; i++ ) {
  1580. numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 );
  1581. for ( int j = 0; j < numContacts; j++ ) {
  1582. gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() );
  1583. }
  1584. }
  1585. }
  1586. */
  1587. }
  1588. UpdateAnimation();
  1589. if ( thinkFlags & TH_UPDATEVISUALS ) {
  1590. Present();
  1591. LinkCombat();
  1592. }
  1593. }
  1594. /*
  1595. ===============================================================================
  1596. idAFEntity_VehicleFourWheels
  1597. ===============================================================================
  1598. */
  1599. CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleFourWheels )
  1600. END_CLASS
  1601. /*
  1602. ================
  1603. idAFEntity_VehicleFourWheels::idAFEntity_VehicleFourWheels
  1604. ================
  1605. */
  1606. idAFEntity_VehicleFourWheels::idAFEntity_VehicleFourWheels( void ) {
  1607. int i;
  1608. for ( i = 0; i < 4; i++ ) {
  1609. wheels[i] = NULL;
  1610. wheelJoints[i] = INVALID_JOINT;
  1611. wheelAngles[i] = 0.0f;
  1612. }
  1613. steering[0] = NULL;
  1614. steering[1] = NULL;
  1615. }
  1616. /*
  1617. ================
  1618. idAFEntity_VehicleFourWheels::Spawn
  1619. ================
  1620. */
  1621. void idAFEntity_VehicleFourWheels::Spawn( void ) {
  1622. int i;
  1623. static const char *wheelBodyKeys[] = {
  1624. "wheelBodyFrontLeft",
  1625. "wheelBodyFrontRight",
  1626. "wheelBodyRearLeft",
  1627. "wheelBodyRearRight"
  1628. };
  1629. static const char *wheelJointKeys[] = {
  1630. "wheelJointFrontLeft",
  1631. "wheelJointFrontRight",
  1632. "wheelJointRearLeft",
  1633. "wheelJointRearRight"
  1634. };
  1635. static const char *steeringHingeKeys[] = {
  1636. "steeringHingeFrontLeft",
  1637. "steeringHingeFrontRight",
  1638. };
  1639. const char *wheelBodyName, *wheelJointName, *steeringHingeName;
  1640. for ( i = 0; i < 4; i++ ) {
  1641. wheelBodyName = spawnArgs.GetString( wheelBodyKeys[i], "" );
  1642. if ( !wheelBodyName[0] ) {
  1643. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), wheelBodyKeys[i] );
  1644. }
  1645. wheels[i] = af.GetPhysics()->GetBody( wheelBodyName );
  1646. if ( !wheels[i] ) {
  1647. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' can't find wheel body '%s'", name.c_str(), wheelBodyName );
  1648. }
  1649. wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" );
  1650. if ( !wheelJointName[0] ) {
  1651. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] );
  1652. }
  1653. wheelJoints[i] = animator.GetJointHandle( wheelJointName );
  1654. if ( wheelJoints[i] == INVALID_JOINT ) {
  1655. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName );
  1656. }
  1657. }
  1658. for ( i = 0; i < 2; i++ ) {
  1659. steeringHingeName = spawnArgs.GetString( steeringHingeKeys[i], "" );
  1660. if ( !steeringHingeName[0] ) {
  1661. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), steeringHingeKeys[i] );
  1662. }
  1663. steering[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( steeringHingeName ));
  1664. if ( !steering[i] ) {
  1665. gameLocal.Error( "idAFEntity_VehicleFourWheels '%s': can't find steering hinge '%s'", name.c_str(), steeringHingeName );
  1666. }
  1667. }
  1668. memset( wheelAngles, 0, sizeof( wheelAngles ) );
  1669. BecomeActive( TH_THINK );
  1670. }
  1671. /*
  1672. ================
  1673. idAFEntity_VehicleFourWheels::Think
  1674. ================
  1675. */
  1676. void idAFEntity_VehicleFourWheels::Think( void ) {
  1677. int i;
  1678. float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f;
  1679. idVec3 origin;
  1680. idMat3 axis;
  1681. idRotation rotation;
  1682. if ( thinkFlags & TH_THINK ) {
  1683. if ( player ) {
  1684. // capture the input from a player
  1685. velocity = g_vehicleVelocity.GetFloat();
  1686. if ( player->usercmd.forwardmove < 0 ) {
  1687. velocity = -velocity;
  1688. }
  1689. force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f);
  1690. steerAngle = GetSteerAngle();
  1691. }
  1692. // update the wheel motor force
  1693. for ( i = 0; i < 2; i++ ) {
  1694. wheels[2+i]->SetContactMotorVelocity( velocity );
  1695. wheels[2+i]->SetContactMotorForce( force );
  1696. }
  1697. // adjust wheel velocity for better steering because there are no differentials between the wheels
  1698. if ( steerAngle < 0.0f ) {
  1699. wheels[2]->SetContactMotorVelocity( velocity * 0.5f );
  1700. }
  1701. else if ( steerAngle > 0.0f ) {
  1702. wheels[3]->SetContactMotorVelocity( velocity * 0.5f );
  1703. }
  1704. // update the wheel steering
  1705. steering[0]->SetSteerAngle( steerAngle );
  1706. steering[1]->SetSteerAngle( steerAngle );
  1707. for ( i = 0; i < 2; i++ ) {
  1708. steering[i]->SetSteerSpeed( 3.0f );
  1709. }
  1710. // update the steering wheel
  1711. animator.GetJointTransform( steeringWheelJoint, gameLocal.time, origin, axis );
  1712. rotation.SetVec( axis[2] );
  1713. rotation.SetAngle( -steerAngle );
  1714. animator.SetJointAxis( steeringWheelJoint, JOINTMOD_WORLD, rotation.ToMat3() );
  1715. // run the physics
  1716. RunPhysics();
  1717. // rotate the wheels visually
  1718. for ( i = 0; i < 4; i++ ) {
  1719. if ( force == 0.0f ) {
  1720. velocity = wheels[i]->GetLinearVelocity() * wheels[i]->GetWorldAxis()[0];
  1721. }
  1722. wheelAngles[i] += velocity * MS2SEC( gameLocal.msec ) / wheelRadius;
  1723. // give the wheel joint an additional rotation about the wheel axis
  1724. rotation.SetAngle( RAD2DEG( wheelAngles[i] ) );
  1725. axis = af.GetPhysics()->GetAxis( 0 );
  1726. rotation.SetVec( (wheels[i]->GetWorldAxis() * axis.Transpose())[2] );
  1727. animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, rotation.ToMat3() );
  1728. }
  1729. // spawn dust particle effects
  1730. if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) {
  1731. int numContacts;
  1732. idAFConstraint_Contact *contacts[2];
  1733. for ( i = 0; i < 4; i++ ) {
  1734. numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 );
  1735. for ( int j = 0; j < numContacts; j++ ) {
  1736. gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() );
  1737. }
  1738. }
  1739. }
  1740. }
  1741. UpdateAnimation();
  1742. if ( thinkFlags & TH_UPDATEVISUALS ) {
  1743. Present();
  1744. LinkCombat();
  1745. }
  1746. }
  1747. /*
  1748. ===============================================================================
  1749. idAFEntity_VehicleSixWheels
  1750. ===============================================================================
  1751. */
  1752. CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleSixWheels )
  1753. END_CLASS
  1754. /*
  1755. ================
  1756. idAFEntity_VehicleSixWheels::idAFEntity_VehicleSixWheels
  1757. ================
  1758. */
  1759. idAFEntity_VehicleSixWheels::idAFEntity_VehicleSixWheels( void ) {
  1760. int i;
  1761. for ( i = 0; i < 6; i++ ) {
  1762. wheels[i] = NULL;
  1763. wheelJoints[i] = INVALID_JOINT;
  1764. wheelAngles[i] = 0.0f;
  1765. }
  1766. steering[0] = NULL;
  1767. steering[1] = NULL;
  1768. steering[2] = NULL;
  1769. steering[3] = NULL;
  1770. }
  1771. /*
  1772. ================
  1773. idAFEntity_VehicleSixWheels::Spawn
  1774. ================
  1775. */
  1776. void idAFEntity_VehicleSixWheels::Spawn( void ) {
  1777. int i;
  1778. static const char *wheelBodyKeys[] = {
  1779. "wheelBodyFrontLeft",
  1780. "wheelBodyFrontRight",
  1781. "wheelBodyMiddleLeft",
  1782. "wheelBodyMiddleRight",
  1783. "wheelBodyRearLeft",
  1784. "wheelBodyRearRight"
  1785. };
  1786. static const char *wheelJointKeys[] = {
  1787. "wheelJointFrontLeft",
  1788. "wheelJointFrontRight",
  1789. "wheelJointMiddleLeft",
  1790. "wheelJointMiddleRight",
  1791. "wheelJointRearLeft",
  1792. "wheelJointRearRight"
  1793. };
  1794. static const char *steeringHingeKeys[] = {
  1795. "steeringHingeFrontLeft",
  1796. "steeringHingeFrontRight",
  1797. "steeringHingeRearLeft",
  1798. "steeringHingeRearRight"
  1799. };
  1800. const char *wheelBodyName, *wheelJointName, *steeringHingeName;
  1801. for ( i = 0; i < 6; i++ ) {
  1802. wheelBodyName = spawnArgs.GetString( wheelBodyKeys[i], "" );
  1803. if ( !wheelBodyName[0] ) {
  1804. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), wheelBodyKeys[i] );
  1805. }
  1806. wheels[i] = af.GetPhysics()->GetBody( wheelBodyName );
  1807. if ( !wheels[i] ) {
  1808. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' can't find wheel body '%s'", name.c_str(), wheelBodyName );
  1809. }
  1810. wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" );
  1811. if ( !wheelJointName[0] ) {
  1812. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] );
  1813. }
  1814. wheelJoints[i] = animator.GetJointHandle( wheelJointName );
  1815. if ( wheelJoints[i] == INVALID_JOINT ) {
  1816. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName );
  1817. }
  1818. }
  1819. for ( i = 0; i < 4; i++ ) {
  1820. steeringHingeName = spawnArgs.GetString( steeringHingeKeys[i], "" );
  1821. if ( !steeringHingeName[0] ) {
  1822. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), steeringHingeKeys[i] );
  1823. }
  1824. steering[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( steeringHingeName ));
  1825. if ( !steering[i] ) {
  1826. gameLocal.Error( "idAFEntity_VehicleSixWheels '%s': can't find steering hinge '%s'", name.c_str(), steeringHingeName );
  1827. }
  1828. }
  1829. memset( wheelAngles, 0, sizeof( wheelAngles ) );
  1830. BecomeActive( TH_THINK );
  1831. }
  1832. /*
  1833. ================
  1834. idAFEntity_VehicleSixWheels::Think
  1835. ================
  1836. */
  1837. void idAFEntity_VehicleSixWheels::Think( void ) {
  1838. int i;
  1839. float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f;
  1840. idVec3 origin;
  1841. idMat3 axis;
  1842. idRotation rotation;
  1843. if ( thinkFlags & TH_THINK ) {
  1844. if ( player ) {
  1845. // capture the input from a player
  1846. velocity = g_vehicleVelocity.GetFloat();
  1847. if ( player->usercmd.forwardmove < 0 ) {
  1848. velocity = -velocity;
  1849. }
  1850. force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f);
  1851. steerAngle = GetSteerAngle();
  1852. }
  1853. // update the wheel motor force
  1854. for ( i = 0; i < 6; i++ ) {
  1855. wheels[i]->SetContactMotorVelocity( velocity );
  1856. wheels[i]->SetContactMotorForce( force );
  1857. }
  1858. // adjust wheel velocity for better steering because there are no differentials between the wheels
  1859. if ( steerAngle < 0.0f ) {
  1860. for ( i = 0; i < 3; i++ ) {
  1861. wheels[(i<<1)]->SetContactMotorVelocity( velocity * 0.5f );
  1862. }
  1863. }
  1864. else if ( steerAngle > 0.0f ) {
  1865. for ( i = 0; i < 3; i++ ) {
  1866. wheels[1+(i<<1)]->SetContactMotorVelocity( velocity * 0.5f );
  1867. }
  1868. }
  1869. // update the wheel steering
  1870. steering[0]->SetSteerAngle( steerAngle );
  1871. steering[1]->SetSteerAngle( steerAngle );
  1872. steering[2]->SetSteerAngle( -steerAngle );
  1873. steering[3]->SetSteerAngle( -steerAngle );
  1874. for ( i = 0; i < 4; i++ ) {
  1875. steering[i]->SetSteerSpeed( 3.0f );
  1876. }
  1877. // update the steering wheel
  1878. animator.GetJointTransform( steeringWheelJoint, gameLocal.time, origin, axis );
  1879. rotation.SetVec( axis[2] );
  1880. rotation.SetAngle( -steerAngle );
  1881. animator.SetJointAxis( steeringWheelJoint, JOINTMOD_WORLD, rotation.ToMat3() );
  1882. // run the physics
  1883. RunPhysics();
  1884. // rotate the wheels visually
  1885. for ( i = 0; i < 6; i++ ) {
  1886. if ( force == 0.0f ) {
  1887. velocity = wheels[i]->GetLinearVelocity() * wheels[i]->GetWorldAxis()[0];
  1888. }
  1889. wheelAngles[i] += velocity * MS2SEC( gameLocal.msec ) / wheelRadius;
  1890. // give the wheel joint an additional rotation about the wheel axis
  1891. rotation.SetAngle( RAD2DEG( wheelAngles[i] ) );
  1892. axis = af.GetPhysics()->GetAxis( 0 );
  1893. rotation.SetVec( (wheels[i]->GetWorldAxis() * axis.Transpose())[2] );
  1894. animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, rotation.ToMat3() );
  1895. }
  1896. // spawn dust particle effects
  1897. if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) {
  1898. int numContacts;
  1899. idAFConstraint_Contact *contacts[2];
  1900. for ( i = 0; i < 6; i++ ) {
  1901. numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 );
  1902. for ( int j = 0; j < numContacts; j++ ) {
  1903. gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() );
  1904. }
  1905. }
  1906. }
  1907. }
  1908. UpdateAnimation();
  1909. if ( thinkFlags & TH_UPDATEVISUALS ) {
  1910. Present();
  1911. LinkCombat();
  1912. }
  1913. }
  1914. /*
  1915. ===============================================================================
  1916. idAFEntity_SteamPipe
  1917. ===============================================================================
  1918. */
  1919. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_SteamPipe )
  1920. END_CLASS
  1921. /*
  1922. ================
  1923. idAFEntity_SteamPipe::idAFEntity_SteamPipe
  1924. ================
  1925. */
  1926. idAFEntity_SteamPipe::idAFEntity_SteamPipe( void ) {
  1927. steamBody = 0;
  1928. steamForce = 0.0f;
  1929. steamUpForce = 0.0f;
  1930. steamModelDefHandle = -1;
  1931. memset( &steamRenderEntity, 0, sizeof( steamRenderEntity ) );
  1932. }
  1933. /*
  1934. ================
  1935. idAFEntity_SteamPipe::~idAFEntity_SteamPipe
  1936. ================
  1937. */
  1938. idAFEntity_SteamPipe::~idAFEntity_SteamPipe( void ) {
  1939. if ( steamModelDefHandle >= 0 ){
  1940. gameRenderWorld->FreeEntityDef( steamModelDefHandle );
  1941. }
  1942. }
  1943. /*
  1944. ================
  1945. idAFEntity_SteamPipe::Save
  1946. ================
  1947. */
  1948. void idAFEntity_SteamPipe::Save( idSaveGame *savefile ) const {
  1949. }
  1950. /*
  1951. ================
  1952. idAFEntity_SteamPipe::Restore
  1953. ================
  1954. */
  1955. void idAFEntity_SteamPipe::Restore( idRestoreGame *savefile ) {
  1956. Spawn();
  1957. }
  1958. /*
  1959. ================
  1960. idAFEntity_SteamPipe::Spawn
  1961. ================
  1962. */
  1963. void idAFEntity_SteamPipe::Spawn( void ) {
  1964. idVec3 steamDir;
  1965. const char *steamBodyName;
  1966. LoadAF();
  1967. SetCombatModel();
  1968. SetPhysics( af.GetPhysics() );
  1969. fl.takedamage = true;
  1970. steamBodyName = spawnArgs.GetString( "steamBody", "" );
  1971. steamForce = spawnArgs.GetFloat( "steamForce", "2000" );
  1972. steamUpForce = spawnArgs.GetFloat( "steamUpForce", "10" );
  1973. steamDir = af.GetPhysics()->GetAxis( steamBody )[2];
  1974. steamBody = af.GetPhysics()->GetBodyId( steamBodyName );
  1975. force.SetPosition( af.GetPhysics(), steamBody, af.GetPhysics()->GetOrigin( steamBody ) );
  1976. force.SetForce( steamDir * -steamForce );
  1977. InitSteamRenderEntity();
  1978. BecomeActive( TH_THINK );
  1979. }
  1980. /*
  1981. ================
  1982. idAFEntity_SteamPipe::InitSteamRenderEntity
  1983. ================
  1984. */
  1985. void idAFEntity_SteamPipe::InitSteamRenderEntity( void ) {
  1986. const char *temp;
  1987. const idDeclModelDef *modelDef;
  1988. memset( &steamRenderEntity, 0, sizeof( steamRenderEntity ) );
  1989. steamRenderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f;
  1990. steamRenderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
  1991. steamRenderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
  1992. modelDef = NULL;
  1993. temp = spawnArgs.GetString ( "model_steam" );
  1994. if ( *temp != '\0' ) {
  1995. if ( !strstr( temp, "." ) ) {
  1996. modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, temp, false ) );
  1997. if ( modelDef ) {
  1998. steamRenderEntity.hModel = modelDef->ModelHandle();
  1999. }
  2000. }
  2001. if ( !steamRenderEntity.hModel ) {
  2002. steamRenderEntity.hModel = renderModelManager->FindModel( temp );
  2003. }
  2004. if ( steamRenderEntity.hModel ) {
  2005. steamRenderEntity.bounds = steamRenderEntity.hModel->Bounds( &steamRenderEntity );
  2006. } else {
  2007. steamRenderEntity.bounds.Zero();
  2008. }
  2009. steamRenderEntity.origin = af.GetPhysics()->GetOrigin( steamBody );
  2010. steamRenderEntity.axis = af.GetPhysics()->GetAxis( steamBody );
  2011. steamModelDefHandle = gameRenderWorld->AddEntityDef( &steamRenderEntity );
  2012. }
  2013. }
  2014. /*
  2015. ================
  2016. idAFEntity_SteamPipe::Think
  2017. ================
  2018. */
  2019. void idAFEntity_SteamPipe::Think( void ) {
  2020. idVec3 steamDir;
  2021. if ( thinkFlags & TH_THINK ) {
  2022. steamDir.x = gameLocal.random.CRandomFloat() * steamForce;
  2023. steamDir.y = gameLocal.random.CRandomFloat() * steamForce;
  2024. steamDir.z = steamUpForce;
  2025. force.SetForce( steamDir );
  2026. force.Evaluate( gameLocal.time );
  2027. //gameRenderWorld->DebugArrow( colorWhite, af.GetPhysics()->GetOrigin( steamBody ), af.GetPhysics()->GetOrigin( steamBody ) - 10.0f * steamDir, 4 );
  2028. }
  2029. if ( steamModelDefHandle >= 0 ){
  2030. steamRenderEntity.origin = af.GetPhysics()->GetOrigin( steamBody );
  2031. steamRenderEntity.axis = af.GetPhysics()->GetAxis( steamBody );
  2032. gameRenderWorld->UpdateEntityDef( steamModelDefHandle, &steamRenderEntity );
  2033. }
  2034. idAFEntity_Base::Think();
  2035. }
  2036. /*
  2037. ===============================================================================
  2038. idAFEntity_ClawFourFingers
  2039. ===============================================================================
  2040. */
  2041. const idEventDef EV_SetFingerAngle( "setFingerAngle", "f" );
  2042. const idEventDef EV_StopFingers( "stopFingers" );
  2043. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_ClawFourFingers )
  2044. EVENT( EV_SetFingerAngle, idAFEntity_ClawFourFingers::Event_SetFingerAngle )
  2045. EVENT( EV_StopFingers, idAFEntity_ClawFourFingers::Event_StopFingers )
  2046. END_CLASS
  2047. static const char *clawConstraintNames[] = {
  2048. "claw1", "claw2", "claw3", "claw4"
  2049. };
  2050. /*
  2051. ================
  2052. idAFEntity_ClawFourFingers::idAFEntity_ClawFourFingers
  2053. ================
  2054. */
  2055. idAFEntity_ClawFourFingers::idAFEntity_ClawFourFingers( void ) {
  2056. fingers[0] = NULL;
  2057. fingers[1] = NULL;
  2058. fingers[2] = NULL;
  2059. fingers[3] = NULL;
  2060. }
  2061. /*
  2062. ================
  2063. idAFEntity_ClawFourFingers::Save
  2064. ================
  2065. */
  2066. void idAFEntity_ClawFourFingers::Save( idSaveGame *savefile ) const {
  2067. int i;
  2068. for ( i = 0; i < 4; i++ ) {
  2069. fingers[i]->Save( savefile );
  2070. }
  2071. }
  2072. /*
  2073. ================
  2074. idAFEntity_ClawFourFingers::Restore
  2075. ================
  2076. */
  2077. void idAFEntity_ClawFourFingers::Restore( idRestoreGame *savefile ) {
  2078. int i;
  2079. for ( i = 0; i < 4; i++ ) {
  2080. fingers[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( clawConstraintNames[i] ));
  2081. fingers[i]->Restore( savefile );
  2082. }
  2083. SetCombatModel();
  2084. LinkCombat();
  2085. }
  2086. /*
  2087. ================
  2088. idAFEntity_ClawFourFingers::Spawn
  2089. ================
  2090. */
  2091. void idAFEntity_ClawFourFingers::Spawn( void ) {
  2092. int i;
  2093. LoadAF();
  2094. SetCombatModel();
  2095. af.GetPhysics()->LockWorldConstraints( true );
  2096. af.GetPhysics()->SetForcePushable( true );
  2097. SetPhysics( af.GetPhysics() );
  2098. fl.takedamage = true;
  2099. for ( i = 0; i < 4; i++ ) {
  2100. fingers[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( clawConstraintNames[i] ));
  2101. if ( !fingers[i] ) {
  2102. gameLocal.Error( "idClaw_FourFingers '%s': can't find claw constraint '%s'", name.c_str(), clawConstraintNames[i] );
  2103. }
  2104. }
  2105. }
  2106. /*
  2107. ================
  2108. idAFEntity_ClawFourFingers::Event_SetFingerAngle
  2109. ================
  2110. */
  2111. void idAFEntity_ClawFourFingers::Event_SetFingerAngle( float angle ) {
  2112. int i;
  2113. for ( i = 0; i < 4; i++ ) {
  2114. fingers[i]->SetSteerAngle( angle );
  2115. fingers[i]->SetSteerSpeed( 0.5f );
  2116. }
  2117. af.GetPhysics()->Activate();
  2118. }
  2119. /*
  2120. ================
  2121. idAFEntity_ClawFourFingers::Event_StopFingers
  2122. ================
  2123. */
  2124. void idAFEntity_ClawFourFingers::Event_StopFingers( void ) {
  2125. int i;
  2126. for ( i = 0; i < 4; i++ ) {
  2127. fingers[i]->SetSteerAngle( fingers[i]->GetAngle() );
  2128. }
  2129. }
  2130. /*
  2131. ===============================================================================
  2132. editor support routines
  2133. ===============================================================================
  2134. */
  2135. /*
  2136. ================
  2137. idGameEdit::AF_SpawnEntity
  2138. ================
  2139. */
  2140. bool idGameEdit::AF_SpawnEntity( const char *fileName ) {
  2141. idDict args;
  2142. idPlayer *player;
  2143. idAFEntity_Generic *ent;
  2144. const idDeclAF *af;
  2145. idVec3 org;
  2146. float yaw;
  2147. player = gameLocal.GetLocalPlayer();
  2148. if ( !player || !gameLocal.CheatsOk( false ) ) {
  2149. return false;
  2150. }
  2151. af = static_cast<const idDeclAF *>( declManager->FindType( DECL_AF, fileName ) );
  2152. if ( !af ) {
  2153. return false;
  2154. }
  2155. yaw = player->viewAngles.yaw;
  2156. args.Set( "angle", va( "%f", yaw + 180 ) );
  2157. org = player->GetPhysics()->GetOrigin() + idAngles( 0, yaw, 0 ).ToForward() * 80 + idVec3( 0, 0, 1 );
  2158. args.Set( "origin", org.ToString() );
  2159. args.Set( "spawnclass", "idAFEntity_Generic" );
  2160. if ( af->model[0] ) {
  2161. args.Set( "model", af->model.c_str() );
  2162. } else {
  2163. args.Set( "model", fileName );
  2164. }
  2165. if ( af->skin[0] ) {
  2166. args.Set( "skin", af->skin.c_str() );
  2167. }
  2168. args.Set( "articulatedFigure", fileName );
  2169. args.Set( "nodrop", "1" );
  2170. ent = static_cast<idAFEntity_Generic *>(gameLocal.SpawnEntityType( idAFEntity_Generic::Type, &args));
  2171. // always update this entity
  2172. ent->BecomeActive( TH_THINK );
  2173. ent->KeepRunningPhysics();
  2174. ent->fl.forcePhysicsUpdate = true;
  2175. player->dragEntity.SetSelected( ent );
  2176. return true;
  2177. }
  2178. /*
  2179. ================
  2180. idGameEdit::AF_UpdateEntities
  2181. ================
  2182. */
  2183. void idGameEdit::AF_UpdateEntities( const char *fileName ) {
  2184. idEntity *ent;
  2185. idAFEntity_Base *af;
  2186. idStr name;
  2187. name = fileName;
  2188. name.StripFileExtension();
  2189. // reload any idAFEntity_Generic which uses the given articulated figure file
  2190. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  2191. if ( ent->IsType( idAFEntity_Base::Type ) ) {
  2192. af = static_cast<idAFEntity_Base *>(ent);
  2193. if ( name.Icmp( af->GetAFName() ) == 0 ) {
  2194. af->LoadAF();
  2195. af->GetAFPhysics()->PutToRest();
  2196. }
  2197. }
  2198. }
  2199. }
  2200. /*
  2201. ================
  2202. idGameEdit::AF_UndoChanges
  2203. ================
  2204. */
  2205. void idGameEdit::AF_UndoChanges( void ) {
  2206. int i, c;
  2207. idEntity *ent;
  2208. idAFEntity_Base *af;
  2209. idDeclAF *decl;
  2210. c = declManager->GetNumDecls( DECL_AF );
  2211. for ( i = 0; i < c; i++ ) {
  2212. decl = static_cast<idDeclAF *>( const_cast<idDecl *>( declManager->DeclByIndex( DECL_AF, i, false ) ) );
  2213. if ( !decl->modified ) {
  2214. continue;
  2215. }
  2216. decl->Invalidate();
  2217. declManager->FindType( DECL_AF, decl->GetName() );
  2218. // reload all AF entities using the file
  2219. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  2220. if ( ent->IsType( idAFEntity_Base::Type ) ) {
  2221. af = static_cast<idAFEntity_Base *>(ent);
  2222. if ( idStr::Icmp( decl->GetName(), af->GetAFName() ) == 0 ) {
  2223. af->LoadAF();
  2224. }
  2225. }
  2226. }
  2227. }
  2228. }
  2229. /*
  2230. ================
  2231. GetJointTransform
  2232. ================
  2233. */
  2234. typedef struct {
  2235. renderEntity_t *ent;
  2236. const idMD5Joint *joints;
  2237. } jointTransformData_t;
  2238. static bool GetJointTransform( void *model, const idJointMat *frame, const char *jointName, idVec3 &origin, idMat3 &axis ) {
  2239. int i;
  2240. jointTransformData_t *data = reinterpret_cast<jointTransformData_t *>(model);
  2241. for ( i = 0; i < data->ent->numJoints; i++ ) {
  2242. if ( data->joints[i].name.Icmp( jointName ) == 0 ) {
  2243. break;
  2244. }
  2245. }
  2246. if ( i >= data->ent->numJoints ) {
  2247. return false;
  2248. }
  2249. origin = frame[i].ToVec3();
  2250. axis = frame[i].ToMat3();
  2251. return true;
  2252. }
  2253. /*
  2254. ================
  2255. GetArgString
  2256. ================
  2257. */
  2258. static const char *GetArgString( const idDict &args, const idDict *defArgs, const char *key ) {
  2259. const char *s;
  2260. s = args.GetString( key );
  2261. if ( !s[0] && defArgs ) {
  2262. s = defArgs->GetString( key );
  2263. }
  2264. return s;
  2265. }
  2266. /*
  2267. ================
  2268. idGameEdit::AF_CreateMesh
  2269. ================
  2270. */
  2271. idRenderModel *idGameEdit::AF_CreateMesh( const idDict &args, idVec3 &meshOrigin, idMat3 &meshAxis, bool &poseIsSet ) {
  2272. int i, jointNum;
  2273. const idDeclAF *af;
  2274. const idDeclAF_Body *fb;
  2275. renderEntity_t ent;
  2276. idVec3 origin, *bodyOrigin, *newBodyOrigin, *modifiedOrigin;
  2277. idMat3 axis, *bodyAxis, *newBodyAxis, *modifiedAxis;
  2278. declAFJointMod_t *jointMod;
  2279. idAngles angles;
  2280. const idDict *defArgs;
  2281. const idKeyValue *arg;
  2282. idStr name;
  2283. jointTransformData_t data;
  2284. const char *classname, *afName, *modelName;
  2285. idRenderModel *md5;
  2286. const idDeclModelDef *modelDef;
  2287. const idMD5Anim *MD5anim;
  2288. const idMD5Joint *MD5joint;
  2289. const idMD5Joint *MD5joints;
  2290. int numMD5joints;
  2291. idJointMat *originalJoints;
  2292. int parentNum;
  2293. poseIsSet = false;
  2294. meshOrigin.Zero();
  2295. meshAxis.Identity();
  2296. classname = args.GetString( "classname" );
  2297. defArgs = gameLocal.FindEntityDefDict( classname );
  2298. // get the articulated figure
  2299. afName = GetArgString( args, defArgs, "articulatedFigure" );
  2300. af = static_cast<const idDeclAF *>( declManager->FindType( DECL_AF, afName ) );
  2301. if ( !af ) {
  2302. return NULL;
  2303. }
  2304. // get the md5 model
  2305. modelName = GetArgString( args, defArgs, "model" );
  2306. modelDef = static_cast< const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) );
  2307. if ( !modelDef ) {
  2308. return NULL;
  2309. }
  2310. // make sure model hasn't been purged
  2311. if ( modelDef->ModelHandle() && !modelDef->ModelHandle()->IsLoaded() ) {
  2312. modelDef->ModelHandle()->LoadModel();
  2313. }
  2314. // get the md5
  2315. md5 = modelDef->ModelHandle();
  2316. if ( !md5 || md5->IsDefaultModel() ) {
  2317. return NULL;
  2318. }
  2319. // get the articulated figure pose anim
  2320. int animNum = modelDef->GetAnim( "af_pose" );
  2321. if ( !animNum ) {
  2322. return NULL;
  2323. }
  2324. const idAnim *anim = modelDef->GetAnim( animNum );
  2325. if ( !anim ) {
  2326. return NULL;
  2327. }
  2328. MD5anim = anim->MD5Anim( 0 );
  2329. MD5joints = md5->GetJoints();
  2330. numMD5joints = md5->NumJoints();
  2331. // setup a render entity
  2332. memset( &ent, 0, sizeof( ent ) );
  2333. ent.customSkin = modelDef->GetSkin();
  2334. ent.bounds.Clear();
  2335. ent.numJoints = numMD5joints;
  2336. ent.joints = ( idJointMat * )_alloca16( ent.numJoints * sizeof( *ent.joints ) );
  2337. // create animation from of the af_pose
  2338. ANIM_CreateAnimFrame( md5, MD5anim, ent.numJoints, ent.joints, 1, modelDef->GetVisualOffset(), false );
  2339. // buffers to store the initial origin and axis for each body
  2340. bodyOrigin = (idVec3 *) _alloca16( af->bodies.Num() * sizeof( idVec3 ) );
  2341. bodyAxis = (idMat3 *) _alloca16( af->bodies.Num() * sizeof( idMat3 ) );
  2342. newBodyOrigin = (idVec3 *) _alloca16( af->bodies.Num() * sizeof( idVec3 ) );
  2343. newBodyAxis = (idMat3 *) _alloca16( af->bodies.Num() * sizeof( idMat3 ) );
  2344. // finish the AF positions
  2345. data.ent = &ent;
  2346. data.joints = MD5joints;
  2347. af->Finish( GetJointTransform, ent.joints, &data );
  2348. // get the initial origin and axis for each AF body
  2349. for ( i = 0; i < af->bodies.Num(); i++ ) {
  2350. fb = af->bodies[i];
  2351. if ( fb->modelType == TRM_BONE ) {
  2352. // axis of bone trace model
  2353. axis[2] = fb->v2.ToVec3() - fb->v1.ToVec3();
  2354. axis[2].Normalize();
  2355. axis[2].NormalVectors( axis[0], axis[1] );
  2356. axis[1] = -axis[1];
  2357. } else {
  2358. axis = fb->angles.ToMat3();
  2359. }
  2360. newBodyOrigin[i] = bodyOrigin[i] = fb->origin.ToVec3();
  2361. newBodyAxis[i] = bodyAxis[i] = axis;
  2362. }
  2363. // get any new body transforms stored in the key/value pairs
  2364. for ( arg = args.MatchPrefix( "body ", NULL ); arg; arg = args.MatchPrefix( "body ", arg ) ) {
  2365. name = arg->GetKey();
  2366. name.Strip( "body " );
  2367. for ( i = 0; i < af->bodies.Num(); i++ ) {
  2368. fb = af->bodies[i];
  2369. if ( fb->name.Icmp( name ) == 0 ) {
  2370. break;
  2371. }
  2372. }
  2373. if ( i >= af->bodies.Num() ) {
  2374. continue;
  2375. }
  2376. sscanf( arg->GetValue(), "%f %f %f %f %f %f", &origin.x, &origin.y, &origin.z, &angles.pitch, &angles.yaw, &angles.roll );
  2377. if ( fb->jointName.Icmp( "origin" ) == 0 ) {
  2378. meshAxis = bodyAxis[i].Transpose() * angles.ToMat3();
  2379. meshOrigin = origin - bodyOrigin[i] * meshAxis;
  2380. poseIsSet = true;
  2381. } else {
  2382. newBodyOrigin[i] = origin;
  2383. newBodyAxis[i] = angles.ToMat3();
  2384. }
  2385. }
  2386. // save the original joints
  2387. originalJoints = ( idJointMat * )_alloca16( numMD5joints * sizeof( originalJoints[0] ) );
  2388. memcpy( originalJoints, ent.joints, numMD5joints * sizeof( originalJoints[0] ) );
  2389. // buffer to store the joint mods
  2390. jointMod = (declAFJointMod_t *) _alloca16( numMD5joints * sizeof( declAFJointMod_t ) );
  2391. memset( jointMod, -1, numMD5joints * sizeof( declAFJointMod_t ) );
  2392. modifiedOrigin = (idVec3 *) _alloca16( numMD5joints * sizeof( idVec3 ) );
  2393. memset( modifiedOrigin, 0, numMD5joints * sizeof( idVec3 ) );
  2394. modifiedAxis = (idMat3 *) _alloca16( numMD5joints * sizeof( idMat3 ) );
  2395. memset( modifiedAxis, 0, numMD5joints * sizeof( idMat3 ) );
  2396. // get all the joint modifications
  2397. for ( i = 0; i < af->bodies.Num(); i++ ) {
  2398. fb = af->bodies[i];
  2399. if ( fb->jointName.Icmp( "origin" ) == 0 ) {
  2400. continue;
  2401. }
  2402. for ( jointNum = 0; jointNum < numMD5joints; jointNum++ ) {
  2403. if ( MD5joints[jointNum].name.Icmp( fb->jointName ) == 0 ) {
  2404. break;
  2405. }
  2406. }
  2407. if ( jointNum >= 0 && jointNum < ent.numJoints ) {
  2408. jointMod[ jointNum ] = fb->jointMod;
  2409. modifiedAxis[ jointNum ] = ( bodyAxis[i] * originalJoints[jointNum].ToMat3().Transpose() ).Transpose() * ( newBodyAxis[i] * meshAxis.Transpose() );
  2410. // FIXME: calculate correct modifiedOrigin
  2411. modifiedOrigin[ jointNum ] = originalJoints[ jointNum ].ToVec3();
  2412. }
  2413. }
  2414. // apply joint modifications to the skeleton
  2415. MD5joint = MD5joints + 1;
  2416. for( i = 1; i < numMD5joints; i++, MD5joint++ ) {
  2417. parentNum = MD5joint->parent - MD5joints;
  2418. idMat3 parentAxis = originalJoints[ parentNum ].ToMat3();
  2419. idMat3 localm = originalJoints[i].ToMat3() * parentAxis.Transpose();
  2420. idVec3 localt = ( originalJoints[i].ToVec3() - originalJoints[ parentNum ].ToVec3() ) * parentAxis.Transpose();
  2421. switch( jointMod[i] ) {
  2422. case DECLAF_JOINTMOD_ORIGIN: {
  2423. ent.joints[ i ].SetRotation( localm * ent.joints[ parentNum ].ToMat3() );
  2424. ent.joints[ i ].SetTranslation( modifiedOrigin[ i ] );
  2425. break;
  2426. }
  2427. case DECLAF_JOINTMOD_AXIS: {
  2428. ent.joints[ i ].SetRotation( modifiedAxis[ i ] );
  2429. ent.joints[ i ].SetTranslation( ent.joints[ parentNum ].ToVec3() + localt * ent.joints[ parentNum ].ToMat3() );
  2430. break;
  2431. }
  2432. case DECLAF_JOINTMOD_BOTH: {
  2433. ent.joints[ i ].SetRotation( modifiedAxis[ i ] );
  2434. ent.joints[ i ].SetTranslation( modifiedOrigin[ i ] );
  2435. break;
  2436. }
  2437. default: {
  2438. ent.joints[ i ].SetRotation( localm * ent.joints[ parentNum ].ToMat3() );
  2439. ent.joints[ i ].SetTranslation( ent.joints[ parentNum ].ToVec3() + localt * ent.joints[ parentNum ].ToMat3() );
  2440. break;
  2441. }
  2442. }
  2443. }
  2444. // instantiate a mesh using the joint information from the render entity
  2445. return md5->InstantiateDynamicModel( &ent, NULL, NULL );
  2446. }