AFEntity.cpp 104 KB

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