Actor.cpp 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. /***********************************************************************
  24. idAnimState
  25. ***********************************************************************/
  26. /*
  27. =====================
  28. idAnimState::idAnimState
  29. =====================
  30. */
  31. idAnimState::idAnimState() {
  32. self = NULL;
  33. animator = NULL;
  34. thread = NULL;
  35. idleAnim = true;
  36. disabled = true;
  37. channel = ANIMCHANNEL_ALL;
  38. animBlendFrames = 0;
  39. lastAnimBlendFrames = 0;
  40. }
  41. /*
  42. =====================
  43. idAnimState::~idAnimState
  44. =====================
  45. */
  46. idAnimState::~idAnimState() {
  47. delete thread;
  48. }
  49. /*
  50. =====================
  51. idAnimState::Save
  52. =====================
  53. */
  54. void idAnimState::Save( idSaveGame *savefile ) const {
  55. savefile->WriteObject( self );
  56. // Save the entity owner of the animator
  57. savefile->WriteObject( animator->GetEntity() );
  58. savefile->WriteObject( thread );
  59. savefile->WriteString( state );
  60. savefile->WriteInt( animBlendFrames );
  61. savefile->WriteInt( lastAnimBlendFrames );
  62. savefile->WriteInt( channel );
  63. savefile->WriteBool( idleAnim );
  64. savefile->WriteBool( disabled );
  65. }
  66. /*
  67. =====================
  68. idAnimState::Restore
  69. =====================
  70. */
  71. void idAnimState::Restore( idRestoreGame *savefile ) {
  72. savefile->ReadObject( reinterpret_cast<idClass *&>( self ) );
  73. idEntity *animowner;
  74. savefile->ReadObject( reinterpret_cast<idClass *&>( animowner ) );
  75. if ( animowner ) {
  76. animator = animowner->GetAnimator();
  77. }
  78. savefile->ReadObject( reinterpret_cast<idClass *&>( thread ) );
  79. savefile->ReadString( state );
  80. savefile->ReadInt( animBlendFrames );
  81. savefile->ReadInt( lastAnimBlendFrames );
  82. savefile->ReadInt( channel );
  83. savefile->ReadBool( idleAnim );
  84. savefile->ReadBool( disabled );
  85. }
  86. /*
  87. =====================
  88. idAnimState::Init
  89. =====================
  90. */
  91. void idAnimState::Init( idActor *owner, idAnimator *_animator, int animchannel ) {
  92. assert( owner );
  93. assert( _animator );
  94. self = owner;
  95. animator = _animator;
  96. channel = animchannel;
  97. if ( !thread ) {
  98. thread = new idThread();
  99. thread->ManualDelete();
  100. }
  101. thread->EndThread();
  102. thread->ManualControl();
  103. }
  104. /*
  105. =====================
  106. idAnimState::Shutdown
  107. =====================
  108. */
  109. void idAnimState::Shutdown() {
  110. delete thread;
  111. thread = NULL;
  112. }
  113. /*
  114. =====================
  115. idAnimState::SetState
  116. =====================
  117. */
  118. void idAnimState::SetState( const char *statename, int blendFrames ) {
  119. const function_t *func;
  120. func = self->scriptObject.GetFunction( statename );
  121. if ( !func ) {
  122. assert( 0 );
  123. gameLocal.Error( "Can't find function '%s' in object '%s'", statename, self->scriptObject.GetTypeName() );
  124. }
  125. state = statename;
  126. disabled = false;
  127. animBlendFrames = blendFrames;
  128. lastAnimBlendFrames = blendFrames;
  129. thread->CallFunction( self, func, true );
  130. animBlendFrames = blendFrames;
  131. lastAnimBlendFrames = blendFrames;
  132. disabled = false;
  133. idleAnim = false;
  134. if ( ai_debugScript.GetInteger() == self->entityNumber ) {
  135. gameLocal.Printf( "%d: %s: Animstate: %s\n", gameLocal.time, self->name.c_str(), state.c_str() );
  136. }
  137. }
  138. /*
  139. =====================
  140. idAnimState::StopAnim
  141. =====================
  142. */
  143. void idAnimState::StopAnim( int frames ) {
  144. animBlendFrames = 0;
  145. animator->Clear( channel, gameLocal.time, FRAME2MS( frames ) );
  146. }
  147. /*
  148. =====================
  149. idAnimState::PlayAnim
  150. =====================
  151. */
  152. void idAnimState::PlayAnim( int anim ) {
  153. if ( anim ) {
  154. animator->PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
  155. }
  156. animBlendFrames = 0;
  157. }
  158. /*
  159. =====================
  160. idAnimState::CycleAnim
  161. =====================
  162. */
  163. void idAnimState::CycleAnim( int anim ) {
  164. if ( anim ) {
  165. animator->CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
  166. }
  167. animBlendFrames = 0;
  168. }
  169. /*
  170. =====================
  171. idAnimState::BecomeIdle
  172. =====================
  173. */
  174. void idAnimState::BecomeIdle() {
  175. idleAnim = true;
  176. }
  177. /*
  178. =====================
  179. idAnimState::Disabled
  180. =====================
  181. */
  182. bool idAnimState::Disabled() const {
  183. return disabled;
  184. }
  185. /*
  186. =====================
  187. idAnimState::AnimDone
  188. =====================
  189. */
  190. bool idAnimState::AnimDone( int blendFrames ) const {
  191. int animDoneTime;
  192. animDoneTime = animator->CurrentAnim( channel )->GetEndTime();
  193. if ( animDoneTime < 0 ) {
  194. // playing a cycle
  195. return false;
  196. } else if ( animDoneTime - FRAME2MS( blendFrames ) <= gameLocal.time ) {
  197. return true;
  198. } else {
  199. return false;
  200. }
  201. }
  202. /*
  203. =====================
  204. idAnimState::IsIdle
  205. =====================
  206. */
  207. bool idAnimState::IsIdle() const {
  208. return disabled || idleAnim;
  209. }
  210. /*
  211. =====================
  212. idAnimState::GetAnimFlags
  213. =====================
  214. */
  215. animFlags_t idAnimState::GetAnimFlags() const {
  216. animFlags_t flags;
  217. memset( &flags, 0, sizeof( flags ) );
  218. if ( !disabled && !AnimDone( 0 ) ) {
  219. flags = animator->GetAnimFlags( animator->CurrentAnim( channel )->AnimNum() );
  220. }
  221. return flags;
  222. }
  223. /*
  224. =====================
  225. idAnimState::Enable
  226. =====================
  227. */
  228. void idAnimState::Enable( int blendFrames ) {
  229. if ( disabled ) {
  230. disabled = false;
  231. animBlendFrames = blendFrames;
  232. lastAnimBlendFrames = blendFrames;
  233. if ( state.Length() ) {
  234. SetState( state.c_str(), blendFrames );
  235. }
  236. }
  237. }
  238. /*
  239. =====================
  240. idAnimState::Disable
  241. =====================
  242. */
  243. void idAnimState::Disable() {
  244. disabled = true;
  245. idleAnim = false;
  246. }
  247. /*
  248. =====================
  249. idAnimState::UpdateState
  250. =====================
  251. */
  252. bool idAnimState::UpdateState() {
  253. if ( disabled ) {
  254. return false;
  255. }
  256. if ( ai_debugScript.GetInteger() == self->entityNumber ) {
  257. thread->EnableDebugInfo();
  258. } else {
  259. thread->DisableDebugInfo();
  260. }
  261. thread->Execute();
  262. return true;
  263. }
  264. /***********************************************************************
  265. idActor
  266. ***********************************************************************/
  267. const idEventDef AI_EnableEyeFocus( "enableEyeFocus" );
  268. const idEventDef AI_DisableEyeFocus( "disableEyeFocus" );
  269. const idEventDef EV_Footstep( "footstep" );
  270. const idEventDef EV_FootstepLeft( "leftFoot" );
  271. const idEventDef EV_FootstepRight( "rightFoot" );
  272. const idEventDef EV_EnableWalkIK( "EnableWalkIK" );
  273. const idEventDef EV_DisableWalkIK( "DisableWalkIK" );
  274. const idEventDef EV_EnableLegIK( "EnableLegIK", "d" );
  275. const idEventDef EV_DisableLegIK( "DisableLegIK", "d" );
  276. const idEventDef AI_StopAnim( "stopAnim", "dd" );
  277. const idEventDef AI_PlayAnim( "playAnim", "ds", 'd' );
  278. const idEventDef AI_PlayCycle( "playCycle", "ds", 'd' );
  279. const idEventDef AI_IdleAnim( "idleAnim", "ds", 'd' );
  280. const idEventDef AI_SetSyncedAnimWeight( "setSyncedAnimWeight", "ddf" );
  281. const idEventDef AI_SetBlendFrames( "setBlendFrames", "dd" );
  282. const idEventDef AI_GetBlendFrames( "getBlendFrames", "d", 'd' );
  283. const idEventDef AI_AnimState( "animState", "dsd" );
  284. const idEventDef AI_GetAnimState( "getAnimState", "d", 's' );
  285. const idEventDef AI_InAnimState( "inAnimState", "ds", 'd' );
  286. const idEventDef AI_FinishAction( "finishAction", "s" );
  287. const idEventDef AI_AnimDone( "animDone", "dd", 'd' );
  288. const idEventDef AI_OverrideAnim( "overrideAnim", "d" );
  289. const idEventDef AI_EnableAnim( "enableAnim", "dd" );
  290. const idEventDef AI_PreventPain( "preventPain", "f" );
  291. const idEventDef AI_DisablePain( "disablePain" );
  292. const idEventDef AI_EnablePain( "enablePain" );
  293. const idEventDef AI_GetPainAnim( "getPainAnim", NULL, 's' );
  294. const idEventDef AI_SetAnimPrefix( "setAnimPrefix", "s" );
  295. const idEventDef AI_HasAnim( "hasAnim", "ds", 'f' );
  296. const idEventDef AI_CheckAnim( "checkAnim", "ds" );
  297. const idEventDef AI_ChooseAnim( "chooseAnim", "ds", 's' );
  298. const idEventDef AI_AnimLength( "animLength", "ds", 'f' );
  299. const idEventDef AI_AnimDistance( "animDistance", "ds", 'f' );
  300. const idEventDef AI_HasEnemies( "hasEnemies", NULL, 'd' );
  301. const idEventDef AI_NextEnemy( "nextEnemy", "E", 'e' );
  302. const idEventDef AI_ClosestEnemyToPoint( "closestEnemyToPoint", "v", 'e' );
  303. const idEventDef AI_SetNextState( "setNextState", "s" );
  304. const idEventDef AI_SetState( "setState", "s" );
  305. const idEventDef AI_GetState( "getState", NULL, 's' );
  306. const idEventDef AI_GetHead( "getHead", NULL, 'e' );
  307. const idEventDef EV_SetDamageGroupScale( "setDamageGroupScale", "sf" );
  308. const idEventDef EV_SetDamageGroupScaleAll( "setDamageGroupScaleAll", "f" );
  309. const idEventDef EV_GetDamageGroupScale( "getDamageGroupScale", "s", 'f' );
  310. const idEventDef EV_SetDamageCap( "setDamageCap", "f" );
  311. const idEventDef EV_SetWaitState( "setWaitState" , "s" );
  312. const idEventDef EV_GetWaitState( "getWaitState", NULL, 's' );
  313. CLASS_DECLARATION( idAFEntity_Gibbable, idActor )
  314. EVENT( AI_EnableEyeFocus, idActor::Event_EnableEyeFocus )
  315. EVENT( AI_DisableEyeFocus, idActor::Event_DisableEyeFocus )
  316. EVENT( EV_Footstep, idActor::Event_Footstep )
  317. EVENT( EV_FootstepLeft, idActor::Event_Footstep )
  318. EVENT( EV_FootstepRight, idActor::Event_Footstep )
  319. EVENT( EV_EnableWalkIK, idActor::Event_EnableWalkIK )
  320. EVENT( EV_DisableWalkIK, idActor::Event_DisableWalkIK )
  321. EVENT( EV_EnableLegIK, idActor::Event_EnableLegIK )
  322. EVENT( EV_DisableLegIK, idActor::Event_DisableLegIK )
  323. EVENT( AI_PreventPain, idActor::Event_PreventPain )
  324. EVENT( AI_DisablePain, idActor::Event_DisablePain )
  325. EVENT( AI_EnablePain, idActor::Event_EnablePain )
  326. EVENT( AI_GetPainAnim, idActor::Event_GetPainAnim )
  327. EVENT( AI_SetAnimPrefix, idActor::Event_SetAnimPrefix )
  328. EVENT( AI_StopAnim, idActor::Event_StopAnim )
  329. EVENT( AI_PlayAnim, idActor::Event_PlayAnim )
  330. EVENT( AI_PlayCycle, idActor::Event_PlayCycle )
  331. EVENT( AI_IdleAnim, idActor::Event_IdleAnim )
  332. EVENT( AI_SetSyncedAnimWeight, idActor::Event_SetSyncedAnimWeight )
  333. EVENT( AI_SetBlendFrames, idActor::Event_SetBlendFrames )
  334. EVENT( AI_GetBlendFrames, idActor::Event_GetBlendFrames )
  335. EVENT( AI_AnimState, idActor::Event_AnimState )
  336. EVENT( AI_GetAnimState, idActor::Event_GetAnimState )
  337. EVENT( AI_InAnimState, idActor::Event_InAnimState )
  338. EVENT( AI_FinishAction, idActor::Event_FinishAction )
  339. EVENT( AI_AnimDone, idActor::Event_AnimDone )
  340. EVENT( AI_OverrideAnim, idActor::Event_OverrideAnim )
  341. EVENT( AI_EnableAnim, idActor::Event_EnableAnim )
  342. EVENT( AI_HasAnim, idActor::Event_HasAnim )
  343. EVENT( AI_CheckAnim, idActor::Event_CheckAnim )
  344. EVENT( AI_ChooseAnim, idActor::Event_ChooseAnim )
  345. EVENT( AI_AnimLength, idActor::Event_AnimLength )
  346. EVENT( AI_AnimDistance, idActor::Event_AnimDistance )
  347. EVENT( AI_HasEnemies, idActor::Event_HasEnemies )
  348. EVENT( AI_NextEnemy, idActor::Event_NextEnemy )
  349. EVENT( AI_ClosestEnemyToPoint, idActor::Event_ClosestEnemyToPoint )
  350. EVENT( EV_StopSound, idActor::Event_StopSound )
  351. EVENT( AI_SetNextState, idActor::Event_SetNextState )
  352. EVENT( AI_SetState, idActor::Event_SetState )
  353. EVENT( AI_GetState, idActor::Event_GetState )
  354. EVENT( AI_GetHead, idActor::Event_GetHead )
  355. EVENT( EV_SetDamageGroupScale, idActor::Event_SetDamageGroupScale )
  356. EVENT( EV_SetDamageGroupScaleAll, idActor::Event_SetDamageGroupScaleAll )
  357. EVENT( EV_GetDamageGroupScale, idActor::Event_GetDamageGroupScale )
  358. EVENT( EV_SetDamageCap, idActor::Event_SetDamageCap )
  359. EVENT( EV_SetWaitState, idActor::Event_SetWaitState )
  360. EVENT( EV_GetWaitState, idActor::Event_GetWaitState )
  361. END_CLASS
  362. /*
  363. =====================
  364. idActor::idActor
  365. =====================
  366. */
  367. idActor::idActor() {
  368. viewAxis.Identity();
  369. scriptThread = NULL; // initialized by ConstructScriptObject, which is called by idEntity::Spawn
  370. use_combat_bbox = false;
  371. head = NULL;
  372. team = 0;
  373. rank = 0;
  374. fovDot = 0.0f;
  375. eyeOffset.Zero();
  376. pain_debounce_time = 0;
  377. pain_delay = 0;
  378. pain_threshold = 0;
  379. state = NULL;
  380. idealState = NULL;
  381. leftEyeJoint = INVALID_JOINT;
  382. rightEyeJoint = INVALID_JOINT;
  383. soundJoint = INVALID_JOINT;
  384. modelOffset.Zero();
  385. deltaViewAngles.Zero();
  386. painTime = 0;
  387. allowPain = false;
  388. allowEyeFocus = false;
  389. waitState = "";
  390. blink_anim = NULL;
  391. blink_time = 0;
  392. blink_min = 0;
  393. blink_max = 0;
  394. finalBoss = false;
  395. damageNotByFists = false; // for killed by fists achievement
  396. attachments.SetGranularity( 1 );
  397. enemyNode.SetOwner( this );
  398. enemyList.SetOwner( this );
  399. aimAssistNode.SetOwner( this );
  400. aimAssistNode.AddToEnd( gameLocal.aimAssistEntities );
  401. damageCap = -1;
  402. }
  403. /*
  404. =====================
  405. idActor::~idActor
  406. =====================
  407. */
  408. idActor::~idActor() {
  409. int i;
  410. idEntity *ent;
  411. DeconstructScriptObject();
  412. scriptObject.Free();
  413. StopSound( SND_CHANNEL_ANY, false );
  414. delete combatModel;
  415. combatModel = NULL;
  416. if ( head.GetEntity() ) {
  417. head.GetEntity()->ClearBody();
  418. head.GetEntity()->PostEventMS( &EV_Remove, 0 );
  419. }
  420. // remove any attached entities
  421. for( i = 0; i < attachments.Num(); i++ ) {
  422. ent = attachments[ i ].ent.GetEntity();
  423. if ( ent ) {
  424. ent->PostEventMS( &EV_Remove, 0 );
  425. }
  426. }
  427. aimAssistNode.Remove();
  428. ShutdownThreads();
  429. }
  430. /*
  431. =====================
  432. idActor::Spawn
  433. =====================
  434. */
  435. void idActor::Spawn() {
  436. idEntity *ent;
  437. idStr jointName;
  438. float fovDegrees;
  439. copyJoints_t copyJoint;
  440. animPrefix = "";
  441. state = NULL;
  442. idealState = NULL;
  443. spawnArgs.GetInt( "rank", "0", rank );
  444. spawnArgs.GetInt( "team", "0", team );
  445. spawnArgs.GetVector( "offsetModel", "0 0 0", modelOffset );
  446. spawnArgs.GetBool( "use_combat_bbox", "0", use_combat_bbox );
  447. viewAxis = GetPhysics()->GetAxis();
  448. spawnArgs.GetFloat( "fov", "90", fovDegrees );
  449. SetFOV( fovDegrees );
  450. pain_debounce_time = 0;
  451. pain_delay = SEC2MS( spawnArgs.GetFloat( "pain_delay" ) );
  452. pain_threshold = spawnArgs.GetInt( "pain_threshold" );
  453. LoadAF();
  454. walkIK.Init( this, IK_ANIM, modelOffset );
  455. // the animation used to be set to the IK_ANIM at this point, but that was fixed, resulting in
  456. // attachments not binding correctly, so we're stuck setting the IK_ANIM before attaching things.
  457. animator.ClearAllAnims( gameLocal.time, 0 );
  458. animator.SetFrame( ANIMCHANNEL_ALL, animator.GetAnim( IK_ANIM ), 0, 0, 0 );
  459. // spawn any attachments we might have
  460. const idKeyValue *kv = spawnArgs.MatchPrefix( "def_attach", NULL );
  461. while ( kv ) {
  462. idDict args;
  463. args.Set( "classname", kv->GetValue().c_str() );
  464. // make items non-touchable so the player can't take them out of the character's hands
  465. args.Set( "no_touch", "1" );
  466. // don't let them drop to the floor
  467. args.Set( "dropToFloor", "0" );
  468. gameLocal.SpawnEntityDef( args, &ent );
  469. if ( !ent ) {
  470. gameLocal.Error( "Couldn't spawn '%s' to attach to entity '%s'", kv->GetValue().c_str(), name.c_str() );
  471. } else {
  472. Attach( ent );
  473. }
  474. kv = spawnArgs.MatchPrefix( "def_attach", kv );
  475. }
  476. SetupDamageGroups();
  477. SetupHead();
  478. // clear the bind anim
  479. animator.ClearAllAnims( gameLocal.time, 0 );
  480. idEntity *headEnt = head.GetEntity();
  481. idAnimator *headAnimator;
  482. if ( headEnt ) {
  483. headAnimator = headEnt->GetAnimator();
  484. } else {
  485. headAnimator = &animator;
  486. }
  487. if ( headEnt ) {
  488. // set up the list of joints to copy to the head
  489. for( kv = spawnArgs.MatchPrefix( "copy_joint", NULL ); kv != NULL; kv = spawnArgs.MatchPrefix( "copy_joint", kv ) ) {
  490. if ( kv->GetValue() == "" ) {
  491. // probably clearing out inherited key, so skip it
  492. continue;
  493. }
  494. jointName = kv->GetKey();
  495. if ( jointName.StripLeadingOnce( "copy_joint_world " ) ) {
  496. copyJoint.mod = JOINTMOD_WORLD_OVERRIDE;
  497. } else {
  498. jointName.StripLeadingOnce( "copy_joint " );
  499. copyJoint.mod = JOINTMOD_LOCAL_OVERRIDE;
  500. }
  501. copyJoint.from = animator.GetJointHandle( jointName );
  502. if ( copyJoint.from == INVALID_JOINT ) {
  503. gameLocal.Warning( "Unknown copy_joint '%s' on entity %s", jointName.c_str(), name.c_str() );
  504. continue;
  505. }
  506. jointName = kv->GetValue();
  507. copyJoint.to = headAnimator->GetJointHandle( jointName );
  508. if ( copyJoint.to == INVALID_JOINT ) {
  509. gameLocal.Warning( "Unknown copy_joint '%s' on head of entity %s", jointName.c_str(), name.c_str() );
  510. continue;
  511. }
  512. copyJoints.Append( copyJoint );
  513. }
  514. }
  515. // set up blinking
  516. blink_anim = headAnimator->GetAnim( "blink" );
  517. blink_time = 0; // it's ok to blink right away
  518. blink_min = SEC2MS( spawnArgs.GetFloat( "blink_min", "0.5" ) );
  519. blink_max = SEC2MS( spawnArgs.GetFloat( "blink_max", "8" ) );
  520. // set up the head anim if necessary
  521. int headAnim = headAnimator->GetAnim( "def_head" );
  522. if ( headAnim ) {
  523. if ( headEnt ) {
  524. headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, 0 );
  525. } else {
  526. headAnimator->CycleAnim( ANIMCHANNEL_HEAD, headAnim, gameLocal.time, 0 );
  527. }
  528. }
  529. if ( spawnArgs.GetString( "sound_bone", "", jointName ) ) {
  530. soundJoint = animator.GetJointHandle( jointName );
  531. if ( soundJoint == INVALID_JOINT ) {
  532. gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString(0), jointName.c_str() );
  533. }
  534. }
  535. finalBoss = spawnArgs.GetBool( "finalBoss" );
  536. FinishSetup();
  537. }
  538. /*
  539. ================
  540. idActor::FinishSetup
  541. ================
  542. */
  543. void idActor::FinishSetup() {
  544. const char *scriptObjectName;
  545. // setup script object
  546. if ( spawnArgs.GetString( "scriptobject", NULL, &scriptObjectName ) ) {
  547. if ( !scriptObject.SetType( scriptObjectName ) ) {
  548. gameLocal.Error( "Script object '%s' not found on entity '%s'.", scriptObjectName, name.c_str() );
  549. }
  550. ConstructScriptObject();
  551. }
  552. SetupBody();
  553. }
  554. /*
  555. ================
  556. idActor::SetupHead
  557. ================
  558. */
  559. void idActor::SetupHead() {
  560. idAFAttachment *headEnt;
  561. idStr jointName;
  562. const char *headModel;
  563. jointHandle_t joint;
  564. jointHandle_t damageJoint;
  565. int i;
  566. const idKeyValue *sndKV;
  567. if ( common->IsClient() ) {
  568. return;
  569. }
  570. headModel = spawnArgs.GetString( "def_head", "" );
  571. if ( headModel[ 0 ] ) {
  572. jointName = spawnArgs.GetString( "head_joint" );
  573. joint = animator.GetJointHandle( jointName );
  574. if ( joint == INVALID_JOINT ) {
  575. gameLocal.Error( "Joint '%s' not found for 'head_joint' on '%s'", jointName.c_str(), name.c_str() );
  576. }
  577. // set the damage joint to be part of the head damage group
  578. damageJoint = joint;
  579. for( i = 0; i < damageGroups.Num(); i++ ) {
  580. if ( damageGroups[ i ] == "head" ) {
  581. damageJoint = static_cast<jointHandle_t>( i );
  582. break;
  583. }
  584. }
  585. // copy any sounds in case we have frame commands on the head
  586. idDict args;
  587. sndKV = spawnArgs.MatchPrefix( "snd_", NULL );
  588. while( sndKV ) {
  589. args.Set( sndKV->GetKey(), sndKV->GetValue() );
  590. sndKV = spawnArgs.MatchPrefix( "snd_", sndKV );
  591. }
  592. // copy slowmo param to the head
  593. args.SetBool( "slowmo", spawnArgs.GetBool("slowmo", "1") );
  594. headEnt = static_cast<idAFAttachment *>( gameLocal.SpawnEntityType( idAFAttachment::Type, &args ) );
  595. headEnt->SetName( va( "%s_head", name.c_str() ) );
  596. headEnt->SetBody( this, headModel, damageJoint );
  597. head = headEnt;
  598. idStr xSkin;
  599. if ( spawnArgs.GetString( "skin_head_xray", "", xSkin ) ) {
  600. headEnt->xraySkin = declManager->FindSkin( xSkin.c_str() );
  601. headEnt->UpdateModel();
  602. }
  603. idVec3 origin;
  604. idMat3 axis;
  605. idAttachInfo &attach = attachments.Alloc();
  606. attach.channel = animator.GetChannelForJoint( joint );
  607. animator.GetJointTransform( joint, gameLocal.time, origin, axis );
  608. origin = renderEntity.origin + ( origin + modelOffset ) * renderEntity.axis;
  609. attach.ent = headEnt;
  610. headEnt->SetOrigin( origin );
  611. headEnt->SetAxis( renderEntity.axis );
  612. headEnt->BindToJoint( this, joint, true );
  613. }
  614. }
  615. /*
  616. ================
  617. idActor::CopyJointsFromBodyToHead
  618. ================
  619. */
  620. void idActor::CopyJointsFromBodyToHead() {
  621. idEntity *headEnt = head.GetEntity();
  622. idAnimator *headAnimator;
  623. int i;
  624. idMat3 mat;
  625. idMat3 axis;
  626. idVec3 pos;
  627. if ( !headEnt ) {
  628. return;
  629. }
  630. headAnimator = headEnt->GetAnimator();
  631. // copy the animation from the body to the head
  632. for( i = 0; i < copyJoints.Num(); i++ ) {
  633. if ( copyJoints[ i ].mod == JOINTMOD_WORLD_OVERRIDE ) {
  634. mat = headEnt->GetPhysics()->GetAxis().Transpose();
  635. GetJointWorldTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
  636. pos -= headEnt->GetPhysics()->GetOrigin();
  637. headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos * mat );
  638. headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis * mat );
  639. } else {
  640. animator.GetJointLocalTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
  641. headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos );
  642. headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis );
  643. }
  644. }
  645. }
  646. /*
  647. ================
  648. idActor::Restart
  649. ================
  650. */
  651. void idActor::Restart() {
  652. assert( !head.GetEntity() );
  653. SetupHead();
  654. FinishSetup();
  655. }
  656. /*
  657. ================
  658. idActor::Save
  659. archive object for savegame file
  660. ================
  661. */
  662. void idActor::Save( idSaveGame *savefile ) const {
  663. idActor *ent;
  664. int i;
  665. savefile->WriteInt( team );
  666. savefile->WriteInt( rank );
  667. savefile->WriteMat3( viewAxis );
  668. savefile->WriteInt( enemyList.Num() );
  669. for ( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  670. savefile->WriteObject( ent );
  671. }
  672. savefile->WriteFloat( fovDot );
  673. savefile->WriteVec3( eyeOffset );
  674. savefile->WriteVec3( modelOffset );
  675. savefile->WriteAngles( deltaViewAngles );
  676. savefile->WriteInt( pain_debounce_time );
  677. savefile->WriteInt( pain_delay );
  678. savefile->WriteInt( pain_threshold );
  679. savefile->WriteInt( damageGroups.Num() );
  680. for( i = 0; i < damageGroups.Num(); i++ ) {
  681. savefile->WriteString( damageGroups[ i ] );
  682. }
  683. savefile->WriteInt( damageScale.Num() );
  684. for( i = 0; i < damageScale.Num(); i++ ) {
  685. savefile->WriteFloat( damageScale[ i ] );
  686. }
  687. savefile->WriteBool( use_combat_bbox );
  688. head.Save( savefile );
  689. savefile->WriteInt( copyJoints.Num() );
  690. for( i = 0; i < copyJoints.Num(); i++ ) {
  691. savefile->WriteInt( copyJoints[i].mod );
  692. savefile->WriteJoint( copyJoints[i].from );
  693. savefile->WriteJoint( copyJoints[i].to );
  694. }
  695. savefile->WriteJoint( leftEyeJoint );
  696. savefile->WriteJoint( rightEyeJoint );
  697. savefile->WriteJoint( soundJoint );
  698. walkIK.Save( savefile );
  699. savefile->WriteString( animPrefix );
  700. savefile->WriteString( painAnim );
  701. savefile->WriteInt( blink_anim );
  702. savefile->WriteInt( blink_time );
  703. savefile->WriteInt( blink_min );
  704. savefile->WriteInt( blink_max );
  705. // script variables
  706. savefile->WriteObject( scriptThread );
  707. savefile->WriteString( waitState );
  708. headAnim.Save( savefile );
  709. torsoAnim.Save( savefile );
  710. legsAnim.Save( savefile );
  711. savefile->WriteBool( allowPain );
  712. savefile->WriteBool( allowEyeFocus );
  713. savefile->WriteInt( painTime );
  714. savefile->WriteInt( attachments.Num() );
  715. for ( i = 0; i < attachments.Num(); i++ ) {
  716. attachments[i].ent.Save( savefile );
  717. savefile->WriteInt( attachments[i].channel );
  718. }
  719. savefile->WriteBool( finalBoss );
  720. idToken token;
  721. //FIXME: this is unneccesary
  722. if ( state ) {
  723. idLexer src( state->Name(), idStr::Length( state->Name() ), "idAI::Save" );
  724. src.ReadTokenOnLine( &token );
  725. src.ExpectTokenString( "::" );
  726. src.ReadTokenOnLine( &token );
  727. savefile->WriteString( token );
  728. } else {
  729. savefile->WriteString( "" );
  730. }
  731. if ( idealState ) {
  732. idLexer src( idealState->Name(), idStr::Length( idealState->Name() ), "idAI::Save" );
  733. src.ReadTokenOnLine( &token );
  734. src.ExpectTokenString( "::" );
  735. src.ReadTokenOnLine( &token );
  736. savefile->WriteString( token );
  737. } else {
  738. savefile->WriteString( "" );
  739. }
  740. savefile->WriteInt(damageCap);
  741. }
  742. /*
  743. ================
  744. idActor::Restore
  745. unarchives object from save game file
  746. ================
  747. */
  748. void idActor::Restore( idRestoreGame *savefile ) {
  749. int i, num;
  750. idActor *ent;
  751. savefile->ReadInt( team );
  752. savefile->ReadInt( rank );
  753. savefile->ReadMat3( viewAxis );
  754. savefile->ReadInt( num );
  755. for ( i = 0; i < num; i++ ) {
  756. savefile->ReadObject( reinterpret_cast<idClass *&>( ent ) );
  757. assert( ent );
  758. if ( ent ) {
  759. ent->enemyNode.AddToEnd( enemyList );
  760. }
  761. }
  762. savefile->ReadFloat( fovDot );
  763. savefile->ReadVec3( eyeOffset );
  764. savefile->ReadVec3( modelOffset );
  765. savefile->ReadAngles( deltaViewAngles );
  766. savefile->ReadInt( pain_debounce_time );
  767. savefile->ReadInt( pain_delay );
  768. savefile->ReadInt( pain_threshold );
  769. savefile->ReadInt( num );
  770. damageGroups.SetGranularity( 1 );
  771. damageGroups.SetNum( num );
  772. for( i = 0; i < num; i++ ) {
  773. savefile->ReadString( damageGroups[ i ] );
  774. }
  775. savefile->ReadInt( num );
  776. damageScale.SetNum( num );
  777. for( i = 0; i < num; i++ ) {
  778. savefile->ReadFloat( damageScale[ i ] );
  779. }
  780. savefile->ReadBool( use_combat_bbox );
  781. head.Restore( savefile );
  782. savefile->ReadInt( num );
  783. copyJoints.SetNum( num );
  784. for( i = 0; i < num; i++ ) {
  785. int val;
  786. savefile->ReadInt( val );
  787. copyJoints[i].mod = static_cast<jointModTransform_t>( val );
  788. savefile->ReadJoint( copyJoints[i].from );
  789. savefile->ReadJoint( copyJoints[i].to );
  790. }
  791. savefile->ReadJoint( leftEyeJoint );
  792. savefile->ReadJoint( rightEyeJoint );
  793. savefile->ReadJoint( soundJoint );
  794. walkIK.Restore( savefile );
  795. savefile->ReadString( animPrefix );
  796. savefile->ReadString( painAnim );
  797. savefile->ReadInt( blink_anim );
  798. savefile->ReadInt( blink_time );
  799. savefile->ReadInt( blink_min );
  800. savefile->ReadInt( blink_max );
  801. savefile->ReadObject( reinterpret_cast<idClass *&>( scriptThread ) );
  802. savefile->ReadString( waitState );
  803. headAnim.Restore( savefile );
  804. torsoAnim.Restore( savefile );
  805. legsAnim.Restore( savefile );
  806. savefile->ReadBool( allowPain );
  807. savefile->ReadBool( allowEyeFocus );
  808. savefile->ReadInt( painTime );
  809. savefile->ReadInt( num );
  810. for ( i = 0; i < num; i++ ) {
  811. idAttachInfo &attach = attachments.Alloc();
  812. attach.ent.Restore( savefile );
  813. savefile->ReadInt( attach.channel );
  814. }
  815. savefile->ReadBool( finalBoss );
  816. idStr statename;
  817. savefile->ReadString( statename );
  818. if ( statename.Length() > 0 ) {
  819. state = GetScriptFunction( statename );
  820. }
  821. savefile->ReadString( statename );
  822. if ( statename.Length() > 0 ) {
  823. idealState = GetScriptFunction( statename );
  824. }
  825. savefile->ReadInt(damageCap);
  826. }
  827. /*
  828. ================
  829. idActor::Hide
  830. ================
  831. */
  832. void idActor::Hide() {
  833. idEntity *ent;
  834. idEntity *next;
  835. idAFEntity_Base::Hide();
  836. if ( head.GetEntity() ) {
  837. head.GetEntity()->Hide();
  838. }
  839. for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) {
  840. next = ent->GetNextTeamEntity();
  841. if ( ent->GetBindMaster() == this ) {
  842. ent->Hide();
  843. if ( ent->IsType( idLight::Type ) ) {
  844. static_cast<idLight *>( ent )->Off();
  845. }
  846. }
  847. }
  848. UnlinkCombat();
  849. }
  850. /*
  851. ================
  852. idActor::Show
  853. ================
  854. */
  855. void idActor::Show() {
  856. idEntity *ent;
  857. idEntity *next;
  858. idAFEntity_Base::Show();
  859. if ( head.GetEntity() ) {
  860. head.GetEntity()->Show();
  861. }
  862. for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) {
  863. next = ent->GetNextTeamEntity();
  864. if ( ent->GetBindMaster() == this ) {
  865. ent->Show();
  866. if ( ent->IsType( idLight::Type ) ) {
  867. if(!spawnArgs.GetBool("lights_off", "0")) {
  868. static_cast<idLight *>( ent )->On();
  869. }
  870. }
  871. }
  872. }
  873. LinkCombat();
  874. }
  875. /*
  876. ==============
  877. idActor::GetDefaultSurfaceType
  878. ==============
  879. */
  880. int idActor::GetDefaultSurfaceType() const {
  881. return SURFTYPE_FLESH;
  882. }
  883. /*
  884. ================
  885. idActor::ProjectOverlay
  886. ================
  887. */
  888. void idActor::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
  889. idEntity *ent;
  890. idEntity *next;
  891. idEntity::ProjectOverlay( origin, dir, size, material );
  892. for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) {
  893. next = ent->GetNextTeamEntity();
  894. if ( ent->GetBindMaster() == this ) {
  895. if ( ent->fl.takedamage && ent->spawnArgs.GetBool( "bleed" ) ) {
  896. ent->ProjectOverlay( origin, dir, size, material );
  897. }
  898. }
  899. }
  900. }
  901. /*
  902. ================
  903. idActor::LoadAF
  904. ================
  905. */
  906. bool idActor::LoadAF() {
  907. idStr fileName;
  908. if ( !spawnArgs.GetString( "ragdoll", "*unknown*", fileName ) || !fileName.Length() ) {
  909. return false;
  910. }
  911. af.SetAnimator( GetAnimator() );
  912. return af.Load( this, fileName );
  913. }
  914. /*
  915. =====================
  916. idActor::SetupBody
  917. =====================
  918. */
  919. void idActor::SetupBody() {
  920. const char *jointname;
  921. animator.ClearAllAnims( gameLocal.time, 0 );
  922. animator.ClearAllJoints();
  923. idEntity *headEnt = head.GetEntity();
  924. if ( headEnt ) {
  925. jointname = spawnArgs.GetString( "bone_leftEye" );
  926. leftEyeJoint = headEnt->GetAnimator()->GetJointHandle( jointname );
  927. jointname = spawnArgs.GetString( "bone_rightEye" );
  928. rightEyeJoint = headEnt->GetAnimator()->GetJointHandle( jointname );
  929. // set up the eye height. check if it's specified in the def.
  930. if ( !spawnArgs.GetFloat( "eye_height", "0", eyeOffset.z ) ) {
  931. // if not in the def, then try to base it off the idle animation
  932. int anim = headEnt->GetAnimator()->GetAnim( "idle" );
  933. if ( anim && ( leftEyeJoint != INVALID_JOINT ) ) {
  934. idVec3 pos;
  935. idMat3 axis;
  936. headEnt->GetAnimator()->PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, 0 );
  937. headEnt->GetAnimator()->GetJointTransform( leftEyeJoint, gameLocal.time, pos, axis );
  938. headEnt->GetAnimator()->ClearAllAnims( gameLocal.time, 0 );
  939. headEnt->GetAnimator()->ForceUpdate();
  940. pos += headEnt->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  941. eyeOffset = pos + modelOffset;
  942. } else {
  943. // just base it off the bounding box size
  944. eyeOffset.z = GetPhysics()->GetBounds()[ 1 ].z - 6;
  945. }
  946. }
  947. headAnim.Init( this, headEnt->GetAnimator(), ANIMCHANNEL_ALL );
  948. } else {
  949. jointname = spawnArgs.GetString( "bone_leftEye" );
  950. leftEyeJoint = animator.GetJointHandle( jointname );
  951. jointname = spawnArgs.GetString( "bone_rightEye" );
  952. rightEyeJoint = animator.GetJointHandle( jointname );
  953. // set up the eye height. check if it's specified in the def.
  954. if ( !spawnArgs.GetFloat( "eye_height", "0", eyeOffset.z ) ) {
  955. // if not in the def, then try to base it off the idle animation
  956. int anim = animator.GetAnim( "idle" );
  957. if ( anim && ( leftEyeJoint != INVALID_JOINT ) ) {
  958. idVec3 pos;
  959. idMat3 axis;
  960. animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, 0 );
  961. animator.GetJointTransform( leftEyeJoint, gameLocal.time, pos, axis );
  962. animator.ClearAllAnims( gameLocal.time, 0 );
  963. animator.ForceUpdate();
  964. eyeOffset = pos + modelOffset;
  965. } else {
  966. // just base it off the bounding box size
  967. eyeOffset.z = GetPhysics()->GetBounds()[ 1 ].z - 6;
  968. }
  969. }
  970. headAnim.Init( this, &animator, ANIMCHANNEL_HEAD );
  971. }
  972. waitState = "";
  973. torsoAnim.Init( this, &animator, ANIMCHANNEL_TORSO );
  974. legsAnim.Init( this, &animator, ANIMCHANNEL_LEGS );
  975. }
  976. /*
  977. =====================
  978. idActor::CheckBlink
  979. =====================
  980. */
  981. void idActor::CheckBlink() {
  982. // check if it's time to blink
  983. if ( !blink_anim || ( health <= 0 ) || !allowEyeFocus || ( blink_time > gameLocal.time ) ) {
  984. return;
  985. }
  986. idEntity *headEnt = head.GetEntity();
  987. if ( headEnt ) {
  988. headEnt->GetAnimator()->PlayAnim( ANIMCHANNEL_EYELIDS, blink_anim, gameLocal.time, 1 );
  989. } else {
  990. animator.PlayAnim( ANIMCHANNEL_EYELIDS, blink_anim, gameLocal.time, 1 );
  991. }
  992. // set the next blink time
  993. blink_time = gameLocal.time + blink_min + gameLocal.random.RandomFloat() * ( blink_max - blink_min );
  994. }
  995. /*
  996. ================
  997. idActor::GetPhysicsToVisualTransform
  998. ================
  999. */
  1000. bool idActor::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
  1001. if ( af.IsActive() ) {
  1002. af.GetPhysicsToVisualTransform( origin, axis );
  1003. return true;
  1004. }
  1005. origin = modelOffset;
  1006. axis = viewAxis;
  1007. return true;
  1008. }
  1009. /*
  1010. ================
  1011. idActor::GetPhysicsToSoundTransform
  1012. ================
  1013. */
  1014. bool idActor::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
  1015. if ( soundJoint != INVALID_JOINT ) {
  1016. animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis );
  1017. origin += modelOffset;
  1018. axis = viewAxis;
  1019. } else {
  1020. origin = GetPhysics()->GetGravityNormal() * -eyeOffset.z;
  1021. axis.Identity();
  1022. }
  1023. return true;
  1024. }
  1025. /***********************************************************************
  1026. script state management
  1027. ***********************************************************************/
  1028. /*
  1029. ================
  1030. idActor::ShutdownThreads
  1031. ================
  1032. */
  1033. void idActor::ShutdownThreads() {
  1034. headAnim.Shutdown();
  1035. torsoAnim.Shutdown();
  1036. legsAnim.Shutdown();
  1037. if ( scriptThread ) {
  1038. scriptThread->EndThread();
  1039. scriptThread->PostEventMS( &EV_Remove, 0 );
  1040. delete scriptThread;
  1041. scriptThread = NULL;
  1042. }
  1043. }
  1044. /*
  1045. ================
  1046. idActor::ShouldConstructScriptObjectAtSpawn
  1047. Called during idEntity::Spawn to see if it should construct the script object or not.
  1048. Overridden by subclasses that need to spawn the script object themselves.
  1049. ================
  1050. */
  1051. bool idActor::ShouldConstructScriptObjectAtSpawn() const {
  1052. return false;
  1053. }
  1054. /*
  1055. ================
  1056. idActor::ConstructScriptObject
  1057. Called during idEntity::Spawn. Calls the constructor on the script object.
  1058. Can be overridden by subclasses when a thread doesn't need to be allocated.
  1059. ================
  1060. */
  1061. idThread *idActor::ConstructScriptObject() {
  1062. const function_t *constructor;
  1063. // make sure we have a scriptObject
  1064. if ( !scriptObject.HasObject() ) {
  1065. gameLocal.Error( "No scriptobject set on '%s'. Check the '%s' entityDef.", name.c_str(), GetEntityDefName() );
  1066. }
  1067. if ( !scriptThread ) {
  1068. // create script thread
  1069. scriptThread = new idThread();
  1070. scriptThread->ManualDelete();
  1071. scriptThread->ManualControl();
  1072. scriptThread->SetThreadName( name.c_str() );
  1073. } else {
  1074. scriptThread->EndThread();
  1075. }
  1076. // call script object's constructor
  1077. constructor = scriptObject.GetConstructor();
  1078. if ( !constructor ) {
  1079. gameLocal.Error( "Missing constructor on '%s' for entity '%s'", scriptObject.GetTypeName(), name.c_str() );
  1080. }
  1081. // init the script object's data
  1082. scriptObject.ClearObject();
  1083. // just set the current function on the script. we'll execute in the subclasses.
  1084. scriptThread->CallFunction( this, constructor, true );
  1085. return scriptThread;
  1086. }
  1087. /*
  1088. =====================
  1089. idActor::GetScriptFunction
  1090. =====================
  1091. */
  1092. const function_t *idActor::GetScriptFunction( const char *funcname ) {
  1093. const function_t *func;
  1094. func = scriptObject.GetFunction( funcname );
  1095. if ( !func ) {
  1096. scriptThread->Error( "Unknown function '%s' in '%s'", funcname, scriptObject.GetTypeName() );
  1097. }
  1098. return func;
  1099. }
  1100. /*
  1101. =====================
  1102. idActor::SetState
  1103. =====================
  1104. */
  1105. void idActor::SetState( const function_t *newState ) {
  1106. if ( newState == NULL ) {
  1107. gameLocal.Error( "idActor::SetState: Null state" );
  1108. return;
  1109. }
  1110. if ( ai_debugScript.GetInteger() == entityNumber ) {
  1111. gameLocal.Printf( "%d: %s: State: %s\n", gameLocal.time, name.c_str(), newState->Name() );
  1112. }
  1113. state = newState;
  1114. idealState = state;
  1115. scriptThread->CallFunction( this, state, true );
  1116. }
  1117. /*
  1118. =====================
  1119. idActor::SetState
  1120. =====================
  1121. */
  1122. void idActor::SetState( const char *statename ) {
  1123. const function_t *newState;
  1124. newState = GetScriptFunction( statename );
  1125. SetState( newState );
  1126. }
  1127. /*
  1128. =====================
  1129. idActor::UpdateScript
  1130. =====================
  1131. */
  1132. void idActor::UpdateScript() {
  1133. int i;
  1134. if ( ai_debugScript.GetInteger() == entityNumber ) {
  1135. scriptThread->EnableDebugInfo();
  1136. } else {
  1137. scriptThread->DisableDebugInfo();
  1138. }
  1139. // a series of state changes can happen in a single frame.
  1140. // this loop limits them in case we've entered an infinite loop.
  1141. for( i = 0; i < 20; i++ ) {
  1142. if ( idealState != state ) {
  1143. SetState( idealState );
  1144. }
  1145. // don't call script until it's done waiting
  1146. if ( scriptThread->IsWaiting() ) {
  1147. break;
  1148. }
  1149. scriptThread->Execute();
  1150. if ( idealState == state ) {
  1151. break;
  1152. }
  1153. }
  1154. if ( i == 20 ) {
  1155. scriptThread->Warning( "idActor::UpdateScript: exited loop to prevent lockup" );
  1156. }
  1157. }
  1158. /***********************************************************************
  1159. vision
  1160. ***********************************************************************/
  1161. /*
  1162. =====================
  1163. idActor::setFov
  1164. =====================
  1165. */
  1166. void idActor::SetFOV( float fov ) {
  1167. fovDot = (float)cos( DEG2RAD( fov * 0.5f ) );
  1168. }
  1169. /*
  1170. =====================
  1171. idActor::SetEyeHeight
  1172. =====================
  1173. */
  1174. void idActor::SetEyeHeight( float height ) {
  1175. eyeOffset.z = height;
  1176. }
  1177. /*
  1178. =====================
  1179. idActor::EyeHeight
  1180. =====================
  1181. */
  1182. float idActor::EyeHeight() const {
  1183. return eyeOffset.z;
  1184. }
  1185. /*
  1186. =====================
  1187. idActor::EyeOffset
  1188. =====================
  1189. */
  1190. idVec3 idActor::EyeOffset() const {
  1191. return GetPhysics()->GetGravityNormal() * -eyeOffset.z;
  1192. }
  1193. /*
  1194. =====================
  1195. idActor::GetEyePosition
  1196. =====================
  1197. */
  1198. idVec3 idActor::GetEyePosition() const {
  1199. return GetPhysics()->GetOrigin() + ( GetPhysics()->GetGravityNormal() * -eyeOffset.z );
  1200. }
  1201. /*
  1202. =====================
  1203. idActor::GetViewPos
  1204. =====================
  1205. */
  1206. void idActor::GetViewPos( idVec3 &origin, idMat3 &axis ) const {
  1207. origin = GetEyePosition();
  1208. axis = viewAxis;
  1209. }
  1210. /*
  1211. =====================
  1212. idActor::CheckFOV
  1213. =====================
  1214. */
  1215. bool idActor::CheckFOV( const idVec3 &pos ) const {
  1216. if ( fovDot == 1.0f ) {
  1217. return true;
  1218. }
  1219. float dot;
  1220. idVec3 delta;
  1221. delta = pos - GetEyePosition();
  1222. // get our gravity normal
  1223. const idVec3 &gravityDir = GetPhysics()->GetGravityNormal();
  1224. // infinite vertical vision, so project it onto our orientation plane
  1225. delta -= gravityDir * ( gravityDir * delta );
  1226. delta.Normalize();
  1227. dot = viewAxis[ 0 ] * delta;
  1228. return ( dot >= fovDot );
  1229. }
  1230. /*
  1231. =====================
  1232. idActor::CanSee
  1233. =====================
  1234. */
  1235. bool idActor::CanSee( idEntity *ent, bool useFov ) const {
  1236. trace_t tr;
  1237. idVec3 eye;
  1238. idVec3 toPos;
  1239. if ( ent->IsHidden() ) {
  1240. return false;
  1241. }
  1242. if ( ent->IsType( idActor::Type ) ) {
  1243. toPos = ( ( idActor * )ent )->GetEyePosition();
  1244. } else {
  1245. toPos = ent->GetPhysics()->GetOrigin();
  1246. }
  1247. if ( useFov && !CheckFOV( toPos ) ) {
  1248. return false;
  1249. }
  1250. eye = GetEyePosition();
  1251. gameLocal.clip.TracePoint( tr, eye, toPos, MASK_OPAQUE, this );
  1252. if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == ent ) ) {
  1253. return true;
  1254. }
  1255. return false;
  1256. }
  1257. /*
  1258. =====================
  1259. idActor::PointVisible
  1260. =====================
  1261. */
  1262. bool idActor::PointVisible( const idVec3 &point ) const {
  1263. trace_t results;
  1264. idVec3 start, end;
  1265. start = GetEyePosition();
  1266. end = point;
  1267. end[2] += 1.0f;
  1268. gameLocal.clip.TracePoint( results, start, end, MASK_OPAQUE, this );
  1269. return ( results.fraction >= 1.0f );
  1270. }
  1271. /*
  1272. =====================
  1273. idActor::GetAIAimTargets
  1274. Returns positions for the AI to aim at.
  1275. =====================
  1276. */
  1277. void idActor::GetAIAimTargets( const idVec3 &lastSightPos, idVec3 &headPos, idVec3 &chestPos ) {
  1278. headPos = lastSightPos + EyeOffset();
  1279. chestPos = ( headPos + lastSightPos + GetPhysics()->GetBounds().GetCenter() ) * 0.5f;
  1280. }
  1281. /*
  1282. =====================
  1283. idActor::GetRenderView
  1284. =====================
  1285. */
  1286. renderView_t *idActor::GetRenderView() {
  1287. renderView_t *rv = idEntity::GetRenderView();
  1288. rv->viewaxis = viewAxis;
  1289. rv->vieworg = GetEyePosition();
  1290. return rv;
  1291. }
  1292. /***********************************************************************
  1293. Model/Ragdoll
  1294. ***********************************************************************/
  1295. /*
  1296. ================
  1297. idActor::SetCombatModel
  1298. ================
  1299. */
  1300. void idActor::SetCombatModel() {
  1301. idAFAttachment *headEnt;
  1302. if ( !use_combat_bbox ) {
  1303. if ( combatModel ) {
  1304. combatModel->Unlink();
  1305. combatModel->LoadModel( modelDefHandle );
  1306. } else {
  1307. combatModel = new (TAG_PHYSICS_CLIP_ENTITY) idClipModel( modelDefHandle );
  1308. }
  1309. headEnt = head.GetEntity();
  1310. if ( headEnt ) {
  1311. headEnt->SetCombatModel();
  1312. }
  1313. }
  1314. }
  1315. /*
  1316. ================
  1317. idActor::GetCombatModel
  1318. ================
  1319. */
  1320. idClipModel *idActor::GetCombatModel() const {
  1321. return combatModel;
  1322. }
  1323. /*
  1324. ================
  1325. idActor::LinkCombat
  1326. ================
  1327. */
  1328. void idActor::LinkCombat() {
  1329. idAFAttachment *headEnt;
  1330. if ( fl.hidden || use_combat_bbox ) {
  1331. return;
  1332. }
  1333. if ( combatModel ) {
  1334. combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  1335. }
  1336. headEnt = head.GetEntity();
  1337. if ( headEnt ) {
  1338. headEnt->LinkCombat();
  1339. }
  1340. }
  1341. /*
  1342. ================
  1343. idActor::UnlinkCombat
  1344. ================
  1345. */
  1346. void idActor::UnlinkCombat() {
  1347. idAFAttachment *headEnt;
  1348. if ( combatModel ) {
  1349. combatModel->Unlink();
  1350. }
  1351. headEnt = head.GetEntity();
  1352. if ( headEnt ) {
  1353. headEnt->UnlinkCombat();
  1354. }
  1355. }
  1356. /*
  1357. ================
  1358. idActor::StartRagdoll
  1359. ================
  1360. */
  1361. bool idActor::StartRagdoll() {
  1362. float slomoStart, slomoEnd;
  1363. float jointFrictionDent, jointFrictionDentStart, jointFrictionDentEnd;
  1364. float contactFrictionDent, contactFrictionDentStart, contactFrictionDentEnd;
  1365. // if no AF loaded
  1366. if ( !af.IsLoaded() ) {
  1367. return false;
  1368. }
  1369. // if the AF is already active
  1370. if ( af.IsActive() ) {
  1371. return true;
  1372. }
  1373. // disable the monster bounding box
  1374. GetPhysics()->DisableClip();
  1375. // start using the AF
  1376. af.StartFromCurrentPose( spawnArgs.GetInt( "velocityTime", "0" ) );
  1377. slomoStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_slomoStart", "-1.6" );
  1378. slomoEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_slomoEnd", "0.8" );
  1379. // do the first part of the death in slow motion
  1380. af.GetPhysics()->SetTimeScaleRamp( slomoStart, slomoEnd );
  1381. jointFrictionDent = spawnArgs.GetFloat( "ragdoll_jointFrictionDent", "0.1" );
  1382. jointFrictionDentStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_jointFrictionStart", "0.2" );
  1383. jointFrictionDentEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_jointFrictionEnd", "1.2" );
  1384. // set joint friction dent
  1385. af.GetPhysics()->SetJointFrictionDent( jointFrictionDent, jointFrictionDentStart, jointFrictionDentEnd );
  1386. contactFrictionDent = spawnArgs.GetFloat( "ragdoll_contactFrictionDent", "0.1" );
  1387. contactFrictionDentStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_contactFrictionStart", "1.0" );
  1388. contactFrictionDentEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_contactFrictionEnd", "2.0" );
  1389. // set contact friction dent
  1390. af.GetPhysics()->SetContactFrictionDent( contactFrictionDent, contactFrictionDentStart, contactFrictionDentEnd );
  1391. // drop any items the actor is holding
  1392. idMoveableItem::DropItems( this, "death", NULL );
  1393. // drop any articulated figures the actor is holding
  1394. idAFEntity_Base::DropAFs( this, "death", NULL );
  1395. RemoveAttachments();
  1396. return true;
  1397. }
  1398. /*
  1399. ================
  1400. idActor::StopRagdoll
  1401. ================
  1402. */
  1403. void idActor::StopRagdoll() {
  1404. if ( af.IsActive() ) {
  1405. af.Stop();
  1406. }
  1407. }
  1408. /*
  1409. ================
  1410. idActor::UpdateAnimationControllers
  1411. ================
  1412. */
  1413. bool idActor::UpdateAnimationControllers() {
  1414. if ( af.IsActive() ) {
  1415. return idAFEntity_Base::UpdateAnimationControllers();
  1416. } else {
  1417. animator.ClearAFPose();
  1418. }
  1419. if ( walkIK.IsInitialized() ) {
  1420. walkIK.Evaluate();
  1421. return true;
  1422. }
  1423. return false;
  1424. }
  1425. /*
  1426. ================
  1427. idActor::RemoveAttachments
  1428. ================
  1429. */
  1430. void idActor::RemoveAttachments() {
  1431. int i;
  1432. idEntity *ent;
  1433. // remove any attached entities
  1434. for( i = 0; i < attachments.Num(); i++ ) {
  1435. ent = attachments[ i ].ent.GetEntity();
  1436. if ( ent != NULL && ent->spawnArgs.GetBool( "remove" ) ) {
  1437. ent->PostEventMS( &EV_Remove, 0 );
  1438. }
  1439. }
  1440. }
  1441. /*
  1442. ================
  1443. idActor::Attach
  1444. ================
  1445. */
  1446. void idActor::Attach( idEntity *ent ) {
  1447. idVec3 origin;
  1448. idMat3 axis;
  1449. jointHandle_t joint;
  1450. idStr jointName;
  1451. idAttachInfo &attach = attachments.Alloc();
  1452. idAngles angleOffset;
  1453. idVec3 originOffset;
  1454. jointName = ent->spawnArgs.GetString( "joint" );
  1455. joint = animator.GetJointHandle( jointName );
  1456. if ( joint == INVALID_JOINT ) {
  1457. gameLocal.Error( "Joint '%s' not found for attaching '%s' on '%s'", jointName.c_str(), ent->GetClassname(), name.c_str() );
  1458. }
  1459. angleOffset = ent->spawnArgs.GetAngles( "angles" );
  1460. originOffset = ent->spawnArgs.GetVector( "origin" );
  1461. attach.channel = animator.GetChannelForJoint( joint );
  1462. GetJointWorldTransform( joint, gameLocal.time, origin, axis );
  1463. attach.ent = ent;
  1464. ent->SetOrigin( origin + originOffset * renderEntity.axis );
  1465. idMat3 rotate = angleOffset.ToMat3();
  1466. idMat3 newAxis = rotate * axis;
  1467. ent->SetAxis( newAxis );
  1468. ent->BindToJoint( this, joint, true );
  1469. ent->cinematic = cinematic;
  1470. }
  1471. /*
  1472. ================
  1473. idActor::Teleport
  1474. ================
  1475. */
  1476. void idActor::Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ) {
  1477. GetPhysics()->SetOrigin( origin + idVec3( 0, 0, CM_CLIP_EPSILON ) );
  1478. GetPhysics()->SetLinearVelocity( vec3_origin );
  1479. viewAxis = angles.ToMat3();
  1480. UpdateVisuals();
  1481. if ( !IsHidden() ) {
  1482. // kill anything at the new position
  1483. gameLocal.KillBox( this );
  1484. }
  1485. }
  1486. /*
  1487. ================
  1488. idActor::GetDeltaViewAngles
  1489. ================
  1490. */
  1491. const idAngles &idActor::GetDeltaViewAngles() const {
  1492. return deltaViewAngles;
  1493. }
  1494. /*
  1495. ================
  1496. idActor::SetDeltaViewAngles
  1497. ================
  1498. */
  1499. void idActor::SetDeltaViewAngles( const idAngles &delta ) {
  1500. deltaViewAngles = delta;
  1501. }
  1502. /*
  1503. ================
  1504. idActor::HasEnemies
  1505. ================
  1506. */
  1507. bool idActor::HasEnemies() const {
  1508. idActor *ent;
  1509. for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  1510. if ( !ent->fl.hidden ) {
  1511. return true;
  1512. }
  1513. }
  1514. return false;
  1515. }
  1516. /*
  1517. ================
  1518. idActor::ClosestEnemyToPoint
  1519. ================
  1520. */
  1521. idActor *idActor::ClosestEnemyToPoint( const idVec3 &pos ) {
  1522. idActor *ent;
  1523. idActor *bestEnt;
  1524. float bestDistSquared;
  1525. float distSquared;
  1526. idVec3 delta;
  1527. bestDistSquared = idMath::INFINITY;
  1528. bestEnt = NULL;
  1529. for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  1530. if ( ent->fl.hidden ) {
  1531. continue;
  1532. }
  1533. delta = ent->GetPhysics()->GetOrigin() - pos;
  1534. distSquared = delta.LengthSqr();
  1535. if ( distSquared < bestDistSquared ) {
  1536. bestEnt = ent;
  1537. bestDistSquared = distSquared;
  1538. }
  1539. }
  1540. return bestEnt;
  1541. }
  1542. /*
  1543. ================
  1544. idActor::EnemyWithMostHealth
  1545. ================
  1546. */
  1547. idActor *idActor::EnemyWithMostHealth() {
  1548. idActor *ent;
  1549. idActor *bestEnt;
  1550. int most = -9999;
  1551. bestEnt = NULL;
  1552. for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  1553. if ( !ent->fl.hidden && ( ent->health > most ) ) {
  1554. bestEnt = ent;
  1555. most = ent->health;
  1556. }
  1557. }
  1558. return bestEnt;
  1559. }
  1560. /*
  1561. ================
  1562. idActor::OnLadder
  1563. ================
  1564. */
  1565. bool idActor::OnLadder() const {
  1566. return false;
  1567. }
  1568. /*
  1569. ==============
  1570. idActor::GetAASLocation
  1571. ==============
  1572. */
  1573. void idActor::GetAASLocation( idAAS *aas, idVec3 &pos, int &areaNum ) const {
  1574. idVec3 size;
  1575. idBounds bounds;
  1576. GetFloorPos( 64.0f, pos );
  1577. if ( !aas ) {
  1578. areaNum = 0;
  1579. return;
  1580. }
  1581. size = aas->GetSettings()->boundingBoxes[0][1];
  1582. bounds[0] = -size;
  1583. size.z = 32.0f;
  1584. bounds[1] = size;
  1585. areaNum = aas->PointReachableAreaNum( pos, bounds, AREA_REACHABLE_WALK );
  1586. if ( areaNum ) {
  1587. aas->PushPointIntoAreaNum( areaNum, pos );
  1588. }
  1589. }
  1590. /***********************************************************************
  1591. animation state
  1592. ***********************************************************************/
  1593. /*
  1594. =====================
  1595. idActor::SetAnimState
  1596. =====================
  1597. */
  1598. void idActor::SetAnimState( int channel, const char *statename, int blendFrames ) {
  1599. const function_t *func;
  1600. func = scriptObject.GetFunction( statename );
  1601. if ( !func ) {
  1602. assert( 0 );
  1603. gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() );
  1604. }
  1605. switch( channel ) {
  1606. case ANIMCHANNEL_HEAD :
  1607. headAnim.SetState( statename, blendFrames );
  1608. allowEyeFocus = true;
  1609. break;
  1610. case ANIMCHANNEL_TORSO :
  1611. torsoAnim.SetState( statename, blendFrames );
  1612. legsAnim.Enable( blendFrames );
  1613. allowPain = true;
  1614. allowEyeFocus = true;
  1615. break;
  1616. case ANIMCHANNEL_LEGS :
  1617. legsAnim.SetState( statename, blendFrames );
  1618. torsoAnim.Enable( blendFrames );
  1619. allowPain = true;
  1620. allowEyeFocus = true;
  1621. break;
  1622. default:
  1623. gameLocal.Error( "idActor::SetAnimState: Unknown anim group" );
  1624. break;
  1625. }
  1626. }
  1627. /*
  1628. =====================
  1629. idActor::GetAnimState
  1630. =====================
  1631. */
  1632. const char *idActor::GetAnimState( int channel ) const {
  1633. switch( channel ) {
  1634. case ANIMCHANNEL_HEAD :
  1635. return headAnim.state;
  1636. break;
  1637. case ANIMCHANNEL_TORSO :
  1638. return torsoAnim.state;
  1639. break;
  1640. case ANIMCHANNEL_LEGS :
  1641. return legsAnim.state;
  1642. break;
  1643. default:
  1644. gameLocal.Error( "idActor::GetAnimState: Unknown anim group" );
  1645. return NULL;
  1646. break;
  1647. }
  1648. }
  1649. /*
  1650. =====================
  1651. idActor::InAnimState
  1652. =====================
  1653. */
  1654. bool idActor::InAnimState( int channel, const char *statename ) const {
  1655. switch( channel ) {
  1656. case ANIMCHANNEL_HEAD :
  1657. if ( headAnim.state == statename ) {
  1658. return true;
  1659. }
  1660. break;
  1661. case ANIMCHANNEL_TORSO :
  1662. if ( torsoAnim.state == statename ) {
  1663. return true;
  1664. }
  1665. break;
  1666. case ANIMCHANNEL_LEGS :
  1667. if ( legsAnim.state == statename ) {
  1668. return true;
  1669. }
  1670. break;
  1671. default:
  1672. gameLocal.Error( "idActor::InAnimState: Unknown anim group" );
  1673. break;
  1674. }
  1675. return false;
  1676. }
  1677. /*
  1678. =====================
  1679. idActor::WaitState
  1680. =====================
  1681. */
  1682. const char *idActor::WaitState() const {
  1683. if ( waitState.Length() ) {
  1684. return waitState;
  1685. } else {
  1686. return NULL;
  1687. }
  1688. }
  1689. /*
  1690. =====================
  1691. idActor::SetWaitState
  1692. =====================
  1693. */
  1694. void idActor::SetWaitState( const char *_waitstate ) {
  1695. waitState = _waitstate;
  1696. }
  1697. /*
  1698. =====================
  1699. idActor::UpdateAnimState
  1700. =====================
  1701. */
  1702. void idActor::UpdateAnimState() {
  1703. headAnim.UpdateState();
  1704. torsoAnim.UpdateState();
  1705. legsAnim.UpdateState();
  1706. }
  1707. /*
  1708. =====================
  1709. idActor::GetAnim
  1710. =====================
  1711. */
  1712. int idActor::GetAnim( int channel, const char *animname ) {
  1713. int anim;
  1714. const char *temp;
  1715. idAnimator *animatorPtr;
  1716. if ( channel == ANIMCHANNEL_HEAD ) {
  1717. if ( !head.GetEntity() ) {
  1718. return 0;
  1719. }
  1720. animatorPtr = head.GetEntity()->GetAnimator();
  1721. } else {
  1722. animatorPtr = &animator;
  1723. }
  1724. if ( animPrefix.Length() ) {
  1725. temp = va( "%s_%s", animPrefix.c_str(), animname );
  1726. anim = animatorPtr->GetAnim( temp );
  1727. if ( anim ) {
  1728. return anim;
  1729. }
  1730. }
  1731. anim = animatorPtr->GetAnim( animname );
  1732. return anim;
  1733. }
  1734. /*
  1735. ===============
  1736. idActor::SyncAnimChannels
  1737. ===============
  1738. */
  1739. void idActor::SyncAnimChannels( int channel, int syncToChannel, int blendFrames ) {
  1740. idAnimator *headAnimator;
  1741. idAFAttachment *headEnt;
  1742. int anim;
  1743. idAnimBlend *syncAnim;
  1744. int starttime;
  1745. int blendTime;
  1746. int cycle;
  1747. blendTime = FRAME2MS( blendFrames );
  1748. if ( channel == ANIMCHANNEL_HEAD ) {
  1749. headEnt = head.GetEntity();
  1750. if ( headEnt ) {
  1751. headAnimator = headEnt->GetAnimator();
  1752. syncAnim = animator.CurrentAnim( syncToChannel );
  1753. if ( syncAnim ) {
  1754. anim = headAnimator->GetAnim( syncAnim->AnimFullName() );
  1755. if ( !anim ) {
  1756. anim = headAnimator->GetAnim( syncAnim->AnimName() );
  1757. }
  1758. if ( anim ) {
  1759. cycle = animator.CurrentAnim( syncToChannel )->GetCycleCount();
  1760. starttime = animator.CurrentAnim( syncToChannel )->GetStartTime();
  1761. headAnimator->PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, blendTime );
  1762. headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
  1763. headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->SetStartTime( starttime );
  1764. } else {
  1765. headEnt->PlayIdleAnim( blendTime );
  1766. }
  1767. }
  1768. }
  1769. } else if ( syncToChannel == ANIMCHANNEL_HEAD ) {
  1770. headEnt = head.GetEntity();
  1771. if ( headEnt ) {
  1772. headAnimator = headEnt->GetAnimator();
  1773. syncAnim = headAnimator->CurrentAnim( ANIMCHANNEL_ALL );
  1774. if ( syncAnim ) {
  1775. anim = GetAnim( channel, syncAnim->AnimFullName() );
  1776. if ( !anim ) {
  1777. anim = GetAnim( channel, syncAnim->AnimName() );
  1778. }
  1779. if ( anim ) {
  1780. cycle = headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetCycleCount();
  1781. starttime = headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime();
  1782. animator.PlayAnim( channel, anim, gameLocal.time, blendTime );
  1783. animator.CurrentAnim( channel )->SetCycleCount( cycle );
  1784. animator.CurrentAnim( channel )->SetStartTime( starttime );
  1785. }
  1786. }
  1787. }
  1788. } else {
  1789. animator.SyncAnimChannels( channel, syncToChannel, gameLocal.time, blendTime );
  1790. }
  1791. }
  1792. /***********************************************************************
  1793. Damage
  1794. ***********************************************************************/
  1795. /*
  1796. ============
  1797. idActor::Gib
  1798. ============
  1799. */
  1800. void idActor::Gib( const idVec3 &dir, const char *damageDefName ) {
  1801. // no gibbing in multiplayer - by self damage or by moving objects
  1802. if ( common->IsMultiplayer() ) {
  1803. return;
  1804. }
  1805. // only gib once
  1806. if ( gibbed ) {
  1807. return;
  1808. }
  1809. idAFEntity_Gibbable::Gib( dir, damageDefName );
  1810. if ( head.GetEntity() ) {
  1811. head.GetEntity()->Hide();
  1812. }
  1813. StopSound( SND_CHANNEL_VOICE, false );
  1814. }
  1815. /*
  1816. ============
  1817. idActor::Damage
  1818. this entity that is being damaged
  1819. inflictor entity that is causing the damage
  1820. attacker entity that caused the inflictor to damage targ
  1821. example: this=monster, inflictor=rocket, attacker=player
  1822. dir direction of the attack for knockback in global space
  1823. point point at which the damage is being inflicted, used for headshots
  1824. damage amount of damage being inflicted
  1825. inflictor, attacker, dir, and point can be NULL for environmental effects
  1826. Bleeding wounds and surface overlays are applied in the collision code that
  1827. calls Damage()
  1828. ============
  1829. */
  1830. idCVar actor_noDamage( "actor_noDamage", "0", CVAR_BOOL, "actors don't take damage -- for testing" );
  1831. void idActor::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir,
  1832. const char *damageDefName, const float damageScale, const int location ) {
  1833. if ( !fl.takedamage || actor_noDamage.GetBool() ) {
  1834. return;
  1835. }
  1836. if ( !inflictor ) {
  1837. inflictor = gameLocal.world;
  1838. }
  1839. if ( !attacker ) {
  1840. attacker = gameLocal.world;
  1841. }
  1842. if ( finalBoss && idStr::FindText( GetEntityDefName(), "monster_boss_cyberdemon" ) == 0 && !inflictor->IsType( idSoulCubeMissile::Type ) ) {
  1843. return;
  1844. }
  1845. // for killed by fists achievement
  1846. if ( attacker->IsType( idPlayer::Type ) && idStr::Cmp( "damage_fists", damageDefName ) ) {
  1847. damageNotByFists = true;
  1848. }
  1849. SetTimeState ts( timeGroup );
  1850. // Helltime boss is immune to all projectiles except the helltime killer
  1851. if ( finalBoss && idStr::Icmp( GetEntityDefName(), "monster_hunter_helltime" ) == 0 && idStr::Icmp(inflictor->GetEntityDefName(), "projectile_helltime_killer") ) {
  1852. return;
  1853. }
  1854. // Maledict is immume to the falling asteroids
  1855. if ( !idStr::Icmp( GetEntityDefName(), "monster_boss_d3xp_maledict" ) &&
  1856. (!idStr::Icmp( damageDefName, "damage_maledict_asteroid" ) || !idStr::Icmp( damageDefName, "damage_maledict_asteroid_splash" ) ) ) {
  1857. return;
  1858. }
  1859. const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
  1860. if ( damageDef == NULL ) {
  1861. gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
  1862. return;
  1863. }
  1864. int damage = damageDef->GetInt( "damage" ) * damageScale;
  1865. damage = GetDamageForLocation( damage, location );
  1866. // inform the attacker that they hit someone
  1867. if ( attacker ) {
  1868. attacker->DamageFeedback( this, inflictor, damage );
  1869. }
  1870. if ( damage > 0 ) {
  1871. int oldHealth = health;
  1872. health -= damage;
  1873. //Check the health against any damage cap that is currently set
  1874. if(damageCap >= 0 && health < damageCap) {
  1875. health = damageCap;
  1876. }
  1877. if ( health <= 0 ) {
  1878. if ( health < -999 ) {
  1879. health = -999;
  1880. }
  1881. if ( oldHealth > 0 ) {
  1882. idPlayer *player = NULL;
  1883. if ( ( attacker && attacker->IsType( idPlayer::Type ) ) ) {
  1884. player = static_cast< idPlayer* >( attacker );
  1885. }
  1886. if ( player != NULL ) {
  1887. if ( !damageNotByFists && player->GetExpansionType() == GAME_BASE ) {
  1888. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_KILL_20_ENEMY_FISTS_HANDS );
  1889. }
  1890. if ( player->PowerUpActive( HELLTIME ) ) {
  1891. player->GetAchievementManager().IncrementHellTimeKills();
  1892. }
  1893. if ( player->PowerUpActive( BERSERK ) && player->GetExpansionType() == GAME_D3XP && !damageNotByFists ) {
  1894. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_ARTIFACT_WITH_BERSERK_PUNCH_20 );
  1895. }
  1896. if ( player->GetCurrentWeaponSlot() == player->weapon_chainsaw ) {
  1897. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_KILL_20_ENEMY_WITH_CHAINSAW );
  1898. }
  1899. if ( ( !name.Find( "monster_boss_vagary") || !name.Find( "vagaryaftercin") ) && player->GetExpansionType() == GAME_BASE ) {
  1900. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_DEFEAT_VAGARY_BOSS );
  1901. }
  1902. if ( !name.Find( "monster_boss_sabaoth") ) {
  1903. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_DEFEAT_SABAOTH_BOSS );
  1904. }
  1905. if ( !name.Find( "monster_boss_cyberdemon") ) {
  1906. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_DEFEAT_CYBERDEMON_BOSS );
  1907. }
  1908. if ( name.Icmp( "hunter_berzerk") == 0 ) {
  1909. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_DEFEAT_BERSERK_HUNTER );
  1910. }
  1911. if ( !name.Find( "monster_hunter_helltime") ) {
  1912. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_DEFEAT_HELLTIME_HUNTER );
  1913. }
  1914. if ( name.Icmp( "hunter") == 0 ) {
  1915. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_DEFEAT_INVULNERABILITY_HUNTER );
  1916. }
  1917. if ( inflictor && inflictor->IsType( idSoulCubeMissile::Type ) ) {
  1918. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_USE_SOUL_CUBE_TO_DEFEAT_20_ENEMY );
  1919. }
  1920. if ( inflictor && inflictor->IsType( idMoveable::Type ) ) {
  1921. idMoveable * moveable = static_cast< idMoveable * >( inflictor );
  1922. // if a moveable is doing damage
  1923. // AND it has an attacker (set when the grabber picks up a moveable )
  1924. // AND the moveable's attacker is the attacker here (the player)
  1925. // then the player has killed an enemy with a launched moveable from the Grabber
  1926. if ( moveable != NULL && moveable->GetAttacker() != NULL && moveable->GetAttacker()->IsType( idPlayer::Type ) && moveable->GetAttacker() == attacker && player->GetExpansionType() == GAME_D3XP && team != player->team ) {
  1927. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_GRABBER_KILL_20_ENEMY );
  1928. }
  1929. }
  1930. idProjectile *projectile = NULL;
  1931. if ( inflictor != NULL && inflictor->IsType( idProjectile::Type ) ) {
  1932. projectile = static_cast< idProjectile* >( inflictor );
  1933. if ( projectile != NULL ) {
  1934. if ( projectile->GetLaunchedFromGrabber() && player->GetExpansionType() == GAME_D3XP && team != player->team ) {
  1935. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_GRABBER_KILL_20_ENEMY );
  1936. }
  1937. if ( renderEntity.hModel && idStr::Icmp( renderEntity.hModel->Name(), "models/md5/monsters/imp/imp.md5mesh" ) == 0 ) {
  1938. if ( idStr::FindText( inflictor->GetName(), "shotgun" ) > -1 ) {
  1939. idStr impName;
  1940. int lastKilledImpTime = player->GetAchievementManager().GetLastImpKilledTime();
  1941. if ( ( gameLocal.GetTime() - lastKilledImpTime ) <= 100 && ( impName.Icmp( name ) != 0 ) ) {
  1942. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_KILL_TWO_IMPS_ONE_SHOTGUN );
  1943. } else {
  1944. player->GetAchievementManager().SetLastImpKilledTime( gameLocal.GetTime() );
  1945. }
  1946. }
  1947. }
  1948. }
  1949. }
  1950. if ( player->health == 1 && player->team != this->team ) { // make sure it doesn't unlock if you kill a friendly dude when you have 1 heath....
  1951. player->GetAchievementManager().EventCompletesAchievement( ACHIEVEMENT_KILL_MONSTER_WITH_1_HEALTH_LEFT );
  1952. }
  1953. }
  1954. }
  1955. Killed( inflictor, attacker, damage, dir, location );
  1956. if ( ( health < -20 ) && spawnArgs.GetBool( "gib" ) && damageDef->GetBool( "gib" ) ) {
  1957. Gib( dir, damageDefName );
  1958. }
  1959. } else {
  1960. Pain( inflictor, attacker, damage, dir, location );
  1961. }
  1962. } else {
  1963. // don't accumulate knockback
  1964. if ( af.IsLoaded() ) {
  1965. // clear impacts
  1966. af.Rest();
  1967. // physics is turned off by calling af.Rest()
  1968. BecomeActive( TH_PHYSICS );
  1969. }
  1970. }
  1971. }
  1972. /*
  1973. =====================
  1974. idActor::ClearPain
  1975. =====================
  1976. */
  1977. void idActor::ClearPain() {
  1978. pain_debounce_time = 0;
  1979. }
  1980. /*
  1981. =====================
  1982. idActor::Pain
  1983. =====================
  1984. */
  1985. bool idActor::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  1986. if ( af.IsLoaded() ) {
  1987. // clear impacts
  1988. af.Rest();
  1989. // physics is turned off by calling af.Rest()
  1990. BecomeActive( TH_PHYSICS );
  1991. }
  1992. if ( gameLocal.time < pain_debounce_time ) {
  1993. return false;
  1994. }
  1995. // don't play pain sounds more than necessary
  1996. pain_debounce_time = gameLocal.time + pain_delay;
  1997. if ( health > 75 ) {
  1998. StartSound( "snd_pain_small", SND_CHANNEL_VOICE, 0, false, NULL );
  1999. } else if ( health > 50 ) {
  2000. StartSound( "snd_pain_medium", SND_CHANNEL_VOICE, 0, false, NULL );
  2001. } else if ( health > 25 ) {
  2002. StartSound( "snd_pain_large", SND_CHANNEL_VOICE, 0, false, NULL );
  2003. } else {
  2004. StartSound( "snd_pain_huge", SND_CHANNEL_VOICE, 0, false, NULL );
  2005. }
  2006. if ( !allowPain || ( gameLocal.time < painTime ) ) {
  2007. // don't play a pain anim
  2008. return false;
  2009. }
  2010. if ( pain_threshold && ( damage < pain_threshold ) ) {
  2011. return false;
  2012. }
  2013. // set the pain anim
  2014. idStr damageGroup = GetDamageGroup( location );
  2015. painAnim = "";
  2016. if ( animPrefix.Length() ) {
  2017. if ( damageGroup.Length() && ( damageGroup != "legs" ) ) {
  2018. sprintf( painAnim, "%s_pain_%s", animPrefix.c_str(), damageGroup.c_str() );
  2019. if ( !animator.HasAnim( painAnim ) ) {
  2020. sprintf( painAnim, "pain_%s", damageGroup.c_str() );
  2021. if ( !animator.HasAnim( painAnim ) ) {
  2022. painAnim = "";
  2023. }
  2024. }
  2025. }
  2026. if ( !painAnim.Length() ) {
  2027. sprintf( painAnim, "%s_pain", animPrefix.c_str() );
  2028. if ( !animator.HasAnim( painAnim ) ) {
  2029. painAnim = "";
  2030. }
  2031. }
  2032. } else if ( damageGroup.Length() && ( damageGroup != "legs" ) ) {
  2033. sprintf( painAnim, "pain_%s", damageGroup.c_str() );
  2034. if ( !animator.HasAnim( painAnim ) ) {
  2035. sprintf( painAnim, "pain_%s", damageGroup.c_str() );
  2036. if ( !animator.HasAnim( painAnim ) ) {
  2037. painAnim = "";
  2038. }
  2039. }
  2040. }
  2041. if ( !painAnim.Length() ) {
  2042. painAnim = "pain";
  2043. }
  2044. if ( g_debugDamage.GetBool() ) {
  2045. gameLocal.Printf( "Damage: joint: '%s', zone '%s', anim '%s'\n", animator.GetJointName( ( jointHandle_t )location ),
  2046. damageGroup.c_str(), painAnim.c_str() );
  2047. }
  2048. return true;
  2049. }
  2050. /*
  2051. =====================
  2052. idActor::SpawnGibs
  2053. =====================
  2054. */
  2055. void idActor::SpawnGibs( const idVec3 &dir, const char *damageDefName ) {
  2056. idAFEntity_Gibbable::SpawnGibs( dir, damageDefName );
  2057. RemoveAttachments();
  2058. }
  2059. /*
  2060. =====================
  2061. idActor::SetupDamageGroups
  2062. FIXME: only store group names once and store an index for each joint
  2063. =====================
  2064. */
  2065. void idActor::SetupDamageGroups() {
  2066. int i;
  2067. const idKeyValue *arg;
  2068. idStr groupname;
  2069. idList<jointHandle_t> jointList;
  2070. int jointnum;
  2071. float scale;
  2072. // create damage zones
  2073. damageGroups.SetNum( animator.NumJoints() );
  2074. arg = spawnArgs.MatchPrefix( "damage_zone ", NULL );
  2075. while ( arg ) {
  2076. groupname = arg->GetKey();
  2077. groupname.Strip( "damage_zone " );
  2078. animator.GetJointList( arg->GetValue(), jointList );
  2079. for( i = 0; i < jointList.Num(); i++ ) {
  2080. jointnum = jointList[ i ];
  2081. damageGroups[ jointnum ] = groupname;
  2082. }
  2083. jointList.Clear();
  2084. arg = spawnArgs.MatchPrefix( "damage_zone ", arg );
  2085. }
  2086. // initilize the damage zones to normal damage
  2087. damageScale.SetNum( animator.NumJoints() );
  2088. for( i = 0; i < damageScale.Num(); i++ ) {
  2089. damageScale[ i ] = 1.0f;
  2090. }
  2091. // set the percentage on damage zones
  2092. arg = spawnArgs.MatchPrefix( "damage_scale ", NULL );
  2093. while ( arg ) {
  2094. scale = atof( arg->GetValue() );
  2095. groupname = arg->GetKey();
  2096. groupname.Strip( "damage_scale " );
  2097. for( i = 0; i < damageScale.Num(); i++ ) {
  2098. if ( damageGroups[ i ] == groupname ) {
  2099. damageScale[ i ] = scale;
  2100. }
  2101. }
  2102. arg = spawnArgs.MatchPrefix( "damage_scale ", arg );
  2103. }
  2104. }
  2105. /*
  2106. =====================
  2107. idActor::GetDamageForLocation
  2108. =====================
  2109. */
  2110. int idActor::GetDamageForLocation( int damage, int location ) {
  2111. if ( ( location < 0 ) || ( location >= damageScale.Num() ) ) {
  2112. return damage;
  2113. }
  2114. return (int)ceil( damage * damageScale[ location ] );
  2115. }
  2116. /*
  2117. =====================
  2118. idActor::GetDamageGroup
  2119. =====================
  2120. */
  2121. const char *idActor::GetDamageGroup( int location ) {
  2122. if ( ( location < 0 ) || ( location >= damageGroups.Num() ) ) {
  2123. return "";
  2124. }
  2125. return damageGroups[ location ];
  2126. }
  2127. /***********************************************************************
  2128. Events
  2129. ***********************************************************************/
  2130. /*
  2131. =====================
  2132. idActor::Event_EnableEyeFocus
  2133. =====================
  2134. */
  2135. void idActor::PlayFootStepSound() {
  2136. const char *sound = NULL;
  2137. const idMaterial *material;
  2138. if ( !GetPhysics()->HasGroundContacts() ) {
  2139. return;
  2140. }
  2141. // start footstep sound based on material type
  2142. material = GetPhysics()->GetContact( 0 ).material;
  2143. if ( material != NULL ) {
  2144. sound = spawnArgs.GetString( va( "snd_footstep_%s", gameLocal.sufaceTypeNames[ material->GetSurfaceType() ] ) );
  2145. }
  2146. if ( sound != NULL && *sound == '\0' ) {
  2147. sound = spawnArgs.GetString( "snd_footstep" );
  2148. }
  2149. if ( sound != NULL && *sound != '\0' ) {
  2150. StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL );
  2151. }
  2152. }
  2153. /*
  2154. =====================
  2155. idActor::Event_EnableEyeFocus
  2156. =====================
  2157. */
  2158. void idActor::Event_EnableEyeFocus() {
  2159. allowEyeFocus = true;
  2160. blink_time = gameLocal.time + blink_min + gameLocal.random.RandomFloat() * ( blink_max - blink_min );
  2161. }
  2162. /*
  2163. =====================
  2164. idActor::Event_DisableEyeFocus
  2165. =====================
  2166. */
  2167. void idActor::Event_DisableEyeFocus() {
  2168. allowEyeFocus = false;
  2169. idEntity *headEnt = head.GetEntity();
  2170. if ( headEnt ) {
  2171. headEnt->GetAnimator()->Clear( ANIMCHANNEL_EYELIDS, gameLocal.time, FRAME2MS( 2 ) );
  2172. } else {
  2173. animator.Clear( ANIMCHANNEL_EYELIDS, gameLocal.time, FRAME2MS( 2 ) );
  2174. }
  2175. }
  2176. /*
  2177. ===============
  2178. idActor::Event_Footstep
  2179. ===============
  2180. */
  2181. void idActor::Event_Footstep() {
  2182. PlayFootStepSound();
  2183. }
  2184. /*
  2185. =====================
  2186. idActor::Event_EnableWalkIK
  2187. =====================
  2188. */
  2189. void idActor::Event_EnableWalkIK() {
  2190. walkIK.EnableAll();
  2191. }
  2192. /*
  2193. =====================
  2194. idActor::Event_DisableWalkIK
  2195. =====================
  2196. */
  2197. void idActor::Event_DisableWalkIK() {
  2198. walkIK.DisableAll();
  2199. }
  2200. /*
  2201. =====================
  2202. idActor::Event_EnableLegIK
  2203. =====================
  2204. */
  2205. void idActor::Event_EnableLegIK( int num ) {
  2206. walkIK.EnableLeg( num );
  2207. }
  2208. /*
  2209. =====================
  2210. idActor::Event_DisableLegIK
  2211. =====================
  2212. */
  2213. void idActor::Event_DisableLegIK( int num ) {
  2214. walkIK.DisableLeg( num );
  2215. }
  2216. /*
  2217. =====================
  2218. idActor::Event_PreventPain
  2219. =====================
  2220. */
  2221. void idActor::Event_PreventPain( float duration ) {
  2222. painTime = gameLocal.time + SEC2MS( duration );
  2223. }
  2224. /*
  2225. ===============
  2226. idActor::Event_DisablePain
  2227. ===============
  2228. */
  2229. void idActor::Event_DisablePain() {
  2230. allowPain = false;
  2231. }
  2232. /*
  2233. ===============
  2234. idActor::Event_EnablePain
  2235. ===============
  2236. */
  2237. void idActor::Event_EnablePain() {
  2238. allowPain = true;
  2239. }
  2240. /*
  2241. =====================
  2242. idActor::Event_GetPainAnim
  2243. =====================
  2244. */
  2245. void idActor::Event_GetPainAnim() {
  2246. if ( !painAnim.Length() ) {
  2247. idThread::ReturnString( "pain" );
  2248. } else {
  2249. idThread::ReturnString( painAnim );
  2250. }
  2251. }
  2252. /*
  2253. =====================
  2254. idActor::Event_SetAnimPrefix
  2255. =====================
  2256. */
  2257. void idActor::Event_SetAnimPrefix( const char *prefix ) {
  2258. animPrefix = prefix;
  2259. }
  2260. /*
  2261. ===============
  2262. idActor::Event_StopAnim
  2263. ===============
  2264. */
  2265. void idActor::Event_StopAnim( int channel, int frames ) {
  2266. switch( channel ) {
  2267. case ANIMCHANNEL_HEAD :
  2268. headAnim.StopAnim( frames );
  2269. break;
  2270. case ANIMCHANNEL_TORSO :
  2271. torsoAnim.StopAnim( frames );
  2272. break;
  2273. case ANIMCHANNEL_LEGS :
  2274. legsAnim.StopAnim( frames );
  2275. break;
  2276. default:
  2277. gameLocal.Error( "Unknown anim group" );
  2278. break;
  2279. }
  2280. }
  2281. /*
  2282. ===============
  2283. idActor::Event_PlayAnim
  2284. ===============
  2285. */
  2286. void idActor::Event_PlayAnim( int channel, const char *animname ) {
  2287. animFlags_t flags;
  2288. idEntity *headEnt;
  2289. int anim;
  2290. anim = GetAnim( channel, animname );
  2291. if ( !anim ) {
  2292. if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) {
  2293. gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) );
  2294. } else {
  2295. gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), GetEntityDefName() );
  2296. }
  2297. idThread::ReturnInt( 0 );
  2298. return;
  2299. }
  2300. switch( channel ) {
  2301. case ANIMCHANNEL_HEAD :
  2302. headEnt = head.GetEntity();
  2303. if ( headEnt ) {
  2304. headAnim.idleAnim = false;
  2305. headAnim.PlayAnim( anim );
  2306. flags = headAnim.GetAnimFlags();
  2307. if ( !flags.prevent_idle_override ) {
  2308. if ( torsoAnim.IsIdle() ) {
  2309. torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  2310. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  2311. if ( legsAnim.IsIdle() ) {
  2312. legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  2313. SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  2314. }
  2315. }
  2316. }
  2317. }
  2318. break;
  2319. case ANIMCHANNEL_TORSO :
  2320. torsoAnim.idleAnim = false;
  2321. torsoAnim.PlayAnim( anim );
  2322. flags = torsoAnim.GetAnimFlags();
  2323. if ( !flags.prevent_idle_override ) {
  2324. if ( headAnim.IsIdle() ) {
  2325. headAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  2326. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2327. }
  2328. if ( legsAnim.IsIdle() ) {
  2329. legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  2330. SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2331. }
  2332. }
  2333. break;
  2334. case ANIMCHANNEL_LEGS :
  2335. legsAnim.idleAnim = false;
  2336. legsAnim.PlayAnim( anim );
  2337. flags = legsAnim.GetAnimFlags();
  2338. if ( !flags.prevent_idle_override ) {
  2339. if ( torsoAnim.IsIdle() ) {
  2340. torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  2341. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  2342. if ( headAnim.IsIdle() ) {
  2343. headAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  2344. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  2345. }
  2346. }
  2347. }
  2348. break;
  2349. default :
  2350. gameLocal.Error( "Unknown anim group" );
  2351. break;
  2352. }
  2353. idThread::ReturnInt( 1 );
  2354. }
  2355. /*
  2356. ===============
  2357. idActor::Event_PlayCycle
  2358. ===============
  2359. */
  2360. void idActor::Event_PlayCycle( int channel, const char *animname ) {
  2361. animFlags_t flags;
  2362. int anim;
  2363. anim = GetAnim( channel, animname );
  2364. if ( !anim ) {
  2365. if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) {
  2366. gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) );
  2367. } else {
  2368. gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), GetEntityDefName() );
  2369. }
  2370. idThread::ReturnInt( false );
  2371. return;
  2372. }
  2373. switch( channel ) {
  2374. case ANIMCHANNEL_HEAD :
  2375. headAnim.idleAnim = false;
  2376. headAnim.CycleAnim( anim );
  2377. flags = headAnim.GetAnimFlags();
  2378. if ( !flags.prevent_idle_override ) {
  2379. if ( torsoAnim.IsIdle() && legsAnim.IsIdle() ) {
  2380. torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  2381. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  2382. legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  2383. SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  2384. }
  2385. }
  2386. break;
  2387. case ANIMCHANNEL_TORSO :
  2388. torsoAnim.idleAnim = false;
  2389. torsoAnim.CycleAnim( anim );
  2390. flags = torsoAnim.GetAnimFlags();
  2391. if ( !flags.prevent_idle_override ) {
  2392. if ( headAnim.IsIdle() ) {
  2393. headAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  2394. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2395. }
  2396. if ( legsAnim.IsIdle() ) {
  2397. legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  2398. SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2399. }
  2400. }
  2401. break;
  2402. case ANIMCHANNEL_LEGS :
  2403. legsAnim.idleAnim = false;
  2404. legsAnim.CycleAnim( anim );
  2405. flags = legsAnim.GetAnimFlags();
  2406. if ( !flags.prevent_idle_override ) {
  2407. if ( torsoAnim.IsIdle() ) {
  2408. torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  2409. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  2410. if ( headAnim.IsIdle() ) {
  2411. headAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  2412. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  2413. }
  2414. }
  2415. }
  2416. break;
  2417. default:
  2418. gameLocal.Error( "Unknown anim group" );
  2419. }
  2420. idThread::ReturnInt( true );
  2421. }
  2422. /*
  2423. ===============
  2424. idActor::Event_IdleAnim
  2425. ===============
  2426. */
  2427. void idActor::Event_IdleAnim( int channel, const char *animname ) {
  2428. int anim;
  2429. anim = GetAnim( channel, animname );
  2430. if ( !anim ) {
  2431. if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) {
  2432. gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) );
  2433. } else {
  2434. gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), GetEntityDefName() );
  2435. }
  2436. switch( channel ) {
  2437. case ANIMCHANNEL_HEAD :
  2438. headAnim.BecomeIdle();
  2439. break;
  2440. case ANIMCHANNEL_TORSO :
  2441. torsoAnim.BecomeIdle();
  2442. break;
  2443. case ANIMCHANNEL_LEGS :
  2444. legsAnim.BecomeIdle();
  2445. break;
  2446. default:
  2447. gameLocal.Error( "Unknown anim group" );
  2448. }
  2449. idThread::ReturnInt( false );
  2450. return;
  2451. }
  2452. switch( channel ) {
  2453. case ANIMCHANNEL_HEAD :
  2454. headAnim.BecomeIdle();
  2455. if ( torsoAnim.GetAnimFlags().prevent_idle_override ) {
  2456. // don't sync to torso body if it doesn't override idle anims
  2457. headAnim.CycleAnim( anim );
  2458. } else if ( torsoAnim.IsIdle() && legsAnim.IsIdle() ) {
  2459. // everything is idle, so play the anim on the head and copy it to the torso and legs
  2460. headAnim.CycleAnim( anim );
  2461. torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  2462. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  2463. legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  2464. SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  2465. } else if ( torsoAnim.IsIdle() ) {
  2466. // sync the head and torso to the legs
  2467. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, headAnim.animBlendFrames );
  2468. torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  2469. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, torsoAnim.animBlendFrames );
  2470. } else {
  2471. // sync the head to the torso
  2472. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, headAnim.animBlendFrames );
  2473. }
  2474. break;
  2475. case ANIMCHANNEL_TORSO :
  2476. torsoAnim.BecomeIdle();
  2477. if ( legsAnim.GetAnimFlags().prevent_idle_override ) {
  2478. // don't sync to legs if legs anim doesn't override idle anims
  2479. torsoAnim.CycleAnim( anim );
  2480. } else if ( legsAnim.IsIdle() ) {
  2481. // play the anim in both legs and torso
  2482. torsoAnim.CycleAnim( anim );
  2483. legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  2484. SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2485. } else {
  2486. // sync the anim to the legs
  2487. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, torsoAnim.animBlendFrames );
  2488. }
  2489. if ( headAnim.IsIdle() ) {
  2490. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2491. }
  2492. break;
  2493. case ANIMCHANNEL_LEGS :
  2494. legsAnim.BecomeIdle();
  2495. if ( torsoAnim.GetAnimFlags().prevent_idle_override ) {
  2496. // don't sync to torso if torso anim doesn't override idle anims
  2497. legsAnim.CycleAnim( anim );
  2498. } else if ( torsoAnim.IsIdle() ) {
  2499. // play the anim in both legs and torso
  2500. legsAnim.CycleAnim( anim );
  2501. torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  2502. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  2503. if ( headAnim.IsIdle() ) {
  2504. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  2505. }
  2506. } else {
  2507. // sync the anim to the torso
  2508. SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, legsAnim.animBlendFrames );
  2509. }
  2510. break;
  2511. default:
  2512. gameLocal.Error( "Unknown anim group" );
  2513. }
  2514. idThread::ReturnInt( true );
  2515. }
  2516. /*
  2517. ================
  2518. idActor::Event_SetSyncedAnimWeight
  2519. ================
  2520. */
  2521. void idActor::Event_SetSyncedAnimWeight( int channel, int anim, float weight ) {
  2522. idEntity *headEnt;
  2523. headEnt = head.GetEntity();
  2524. switch( channel ) {
  2525. case ANIMCHANNEL_HEAD :
  2526. if ( headEnt ) {
  2527. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetSyncedAnimWeight( anim, weight );
  2528. } else {
  2529. animator.CurrentAnim( ANIMCHANNEL_HEAD )->SetSyncedAnimWeight( anim, weight );
  2530. }
  2531. if ( torsoAnim.IsIdle() ) {
  2532. animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight );
  2533. if ( legsAnim.IsIdle() ) {
  2534. animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  2535. }
  2536. }
  2537. break;
  2538. case ANIMCHANNEL_TORSO :
  2539. animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight );
  2540. if ( legsAnim.IsIdle() ) {
  2541. animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  2542. }
  2543. if ( headEnt && headAnim.IsIdle() ) {
  2544. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetSyncedAnimWeight( anim, weight );
  2545. }
  2546. break;
  2547. case ANIMCHANNEL_LEGS :
  2548. animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  2549. if ( torsoAnim.IsIdle() ) {
  2550. animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight );
  2551. if ( headEnt && headAnim.IsIdle() ) {
  2552. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetSyncedAnimWeight( anim, weight );
  2553. }
  2554. }
  2555. break;
  2556. default:
  2557. gameLocal.Error( "Unknown anim group" );
  2558. }
  2559. }
  2560. /*
  2561. ===============
  2562. idActor::Event_OverrideAnim
  2563. ===============
  2564. */
  2565. void idActor::Event_OverrideAnim( int channel ) {
  2566. switch( channel ) {
  2567. case ANIMCHANNEL_HEAD :
  2568. headAnim.Disable();
  2569. if ( !torsoAnim.IsIdle() ) {
  2570. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2571. } else {
  2572. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  2573. }
  2574. break;
  2575. case ANIMCHANNEL_TORSO :
  2576. torsoAnim.Disable();
  2577. SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  2578. if ( headAnim.IsIdle() ) {
  2579. SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2580. }
  2581. break;
  2582. case ANIMCHANNEL_LEGS :
  2583. legsAnim.Disable();
  2584. SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  2585. break;
  2586. default:
  2587. gameLocal.Error( "Unknown anim group" );
  2588. break;
  2589. }
  2590. }
  2591. /*
  2592. ===============
  2593. idActor::Event_EnableAnim
  2594. ===============
  2595. */
  2596. void idActor::Event_EnableAnim( int channel, int blendFrames ) {
  2597. switch( channel ) {
  2598. case ANIMCHANNEL_HEAD :
  2599. headAnim.Enable( blendFrames );
  2600. break;
  2601. case ANIMCHANNEL_TORSO :
  2602. torsoAnim.Enable( blendFrames );
  2603. break;
  2604. case ANIMCHANNEL_LEGS :
  2605. legsAnim.Enable( blendFrames );
  2606. break;
  2607. default:
  2608. gameLocal.Error( "Unknown anim group" );
  2609. break;
  2610. }
  2611. }
  2612. /*
  2613. ===============
  2614. idActor::Event_SetBlendFrames
  2615. ===============
  2616. */
  2617. void idActor::Event_SetBlendFrames( int channel, int blendFrames ) {
  2618. switch( channel ) {
  2619. case ANIMCHANNEL_HEAD :
  2620. headAnim.animBlendFrames = blendFrames;
  2621. headAnim.lastAnimBlendFrames = blendFrames;
  2622. break;
  2623. case ANIMCHANNEL_TORSO :
  2624. torsoAnim.animBlendFrames = blendFrames;
  2625. torsoAnim.lastAnimBlendFrames = blendFrames;
  2626. break;
  2627. case ANIMCHANNEL_LEGS :
  2628. legsAnim.animBlendFrames = blendFrames;
  2629. legsAnim.lastAnimBlendFrames = blendFrames;
  2630. break;
  2631. default:
  2632. gameLocal.Error( "Unknown anim group" );
  2633. break;
  2634. }
  2635. }
  2636. /*
  2637. ===============
  2638. idActor::Event_GetBlendFrames
  2639. ===============
  2640. */
  2641. void idActor::Event_GetBlendFrames( int channel ) {
  2642. switch( channel ) {
  2643. case ANIMCHANNEL_HEAD :
  2644. idThread::ReturnInt( headAnim.animBlendFrames );
  2645. break;
  2646. case ANIMCHANNEL_TORSO :
  2647. idThread::ReturnInt( torsoAnim.animBlendFrames );
  2648. break;
  2649. case ANIMCHANNEL_LEGS :
  2650. idThread::ReturnInt( legsAnim.animBlendFrames );
  2651. break;
  2652. default:
  2653. gameLocal.Error( "Unknown anim group" );
  2654. break;
  2655. }
  2656. }
  2657. /*
  2658. ===============
  2659. idActor::Event_AnimState
  2660. ===============
  2661. */
  2662. void idActor::Event_AnimState( int channel, const char *statename, int blendFrames ) {
  2663. SetAnimState( channel, statename, blendFrames );
  2664. }
  2665. /*
  2666. ===============
  2667. idActor::Event_GetAnimState
  2668. ===============
  2669. */
  2670. void idActor::Event_GetAnimState( int channel ) {
  2671. const char *state;
  2672. state = GetAnimState( channel );
  2673. idThread::ReturnString( state );
  2674. }
  2675. /*
  2676. ===============
  2677. idActor::Event_InAnimState
  2678. ===============
  2679. */
  2680. void idActor::Event_InAnimState( int channel, const char *statename ) {
  2681. bool instate;
  2682. instate = InAnimState( channel, statename );
  2683. idThread::ReturnInt( instate );
  2684. }
  2685. /*
  2686. ===============
  2687. idActor::Event_FinishAction
  2688. ===============
  2689. */
  2690. void idActor::Event_FinishAction( const char *actionname ) {
  2691. if ( waitState == actionname ) {
  2692. SetWaitState( "" );
  2693. }
  2694. }
  2695. /*
  2696. ===============
  2697. idActor::Event_AnimDone
  2698. ===============
  2699. */
  2700. void idActor::Event_AnimDone( int channel, int blendFrames ) {
  2701. bool result;
  2702. switch( channel ) {
  2703. case ANIMCHANNEL_HEAD :
  2704. result = headAnim.AnimDone( blendFrames );
  2705. idThread::ReturnInt( result );
  2706. break;
  2707. case ANIMCHANNEL_TORSO :
  2708. result = torsoAnim.AnimDone( blendFrames );
  2709. idThread::ReturnInt( result );
  2710. break;
  2711. case ANIMCHANNEL_LEGS :
  2712. result = legsAnim.AnimDone( blendFrames );
  2713. idThread::ReturnInt( result );
  2714. break;
  2715. default:
  2716. gameLocal.Error( "Unknown anim group" );
  2717. }
  2718. }
  2719. /*
  2720. ================
  2721. idActor::Event_HasAnim
  2722. ================
  2723. */
  2724. void idActor::Event_HasAnim( int channel, const char *animname ) {
  2725. if ( GetAnim( channel, animname ) != NULL ) {
  2726. idThread::ReturnFloat( 1.0f );
  2727. } else {
  2728. idThread::ReturnFloat( 0.0f );
  2729. }
  2730. }
  2731. /*
  2732. ================
  2733. idActor::Event_CheckAnim
  2734. ================
  2735. */
  2736. void idActor::Event_CheckAnim( int channel, const char *animname ) {
  2737. if ( !GetAnim( channel, animname ) ) {
  2738. if ( animPrefix.Length() ) {
  2739. gameLocal.Error( "Can't find anim '%s_%s' for '%s'", animPrefix.c_str(), animname, name.c_str() );
  2740. } else {
  2741. gameLocal.Error( "Can't find anim '%s' for '%s'", animname, name.c_str() );
  2742. }
  2743. }
  2744. }
  2745. /*
  2746. ================
  2747. idActor::Event_ChooseAnim
  2748. ================
  2749. */
  2750. void idActor::Event_ChooseAnim( int channel, const char *animname ) {
  2751. int anim;
  2752. anim = GetAnim( channel, animname );
  2753. if ( anim ) {
  2754. if ( channel == ANIMCHANNEL_HEAD ) {
  2755. if ( head.GetEntity() ) {
  2756. idThread::ReturnString( head.GetEntity()->GetAnimator()->AnimFullName( anim ) );
  2757. return;
  2758. }
  2759. } else {
  2760. idThread::ReturnString( animator.AnimFullName( anim ) );
  2761. return;
  2762. }
  2763. }
  2764. idThread::ReturnString( "" );
  2765. }
  2766. /*
  2767. ================
  2768. idActor::Event_AnimLength
  2769. ================
  2770. */
  2771. void idActor::Event_AnimLength( int channel, const char *animname ) {
  2772. int anim;
  2773. anim = GetAnim( channel, animname );
  2774. if ( anim ) {
  2775. if ( channel == ANIMCHANNEL_HEAD ) {
  2776. if ( head.GetEntity() ) {
  2777. idThread::ReturnFloat( MS2SEC( head.GetEntity()->GetAnimator()->AnimLength( anim ) ) );
  2778. return;
  2779. }
  2780. } else {
  2781. idThread::ReturnFloat( MS2SEC( animator.AnimLength( anim ) ) );
  2782. return;
  2783. }
  2784. }
  2785. idThread::ReturnFloat( 0.0f );
  2786. }
  2787. /*
  2788. ================
  2789. idActor::Event_AnimDistance
  2790. ================
  2791. */
  2792. void idActor::Event_AnimDistance( int channel, const char *animname ) {
  2793. int anim;
  2794. anim = GetAnim( channel, animname );
  2795. if ( anim ) {
  2796. if ( channel == ANIMCHANNEL_HEAD ) {
  2797. if ( head.GetEntity() ) {
  2798. idThread::ReturnFloat( head.GetEntity()->GetAnimator()->TotalMovementDelta( anim ).Length() );
  2799. return;
  2800. }
  2801. } else {
  2802. idThread::ReturnFloat( animator.TotalMovementDelta( anim ).Length() );
  2803. return;
  2804. }
  2805. }
  2806. idThread::ReturnFloat( 0.0f );
  2807. }
  2808. /*
  2809. ================
  2810. idActor::Event_HasEnemies
  2811. ================
  2812. */
  2813. void idActor::Event_HasEnemies() {
  2814. bool hasEnemy;
  2815. hasEnemy = HasEnemies();
  2816. idThread::ReturnInt( hasEnemy );
  2817. }
  2818. /*
  2819. ================
  2820. idActor::Event_NextEnemy
  2821. ================
  2822. */
  2823. void idActor::Event_NextEnemy( idEntity *ent ) {
  2824. idActor *actor;
  2825. if ( !ent || ( ent == this ) ) {
  2826. actor = enemyList.Next();
  2827. } else {
  2828. if ( !ent->IsType( idActor::Type ) ) {
  2829. gameLocal.Error( "'%s' cannot be an enemy", ent->name.c_str() );
  2830. }
  2831. actor = static_cast<idActor *>( ent );
  2832. if ( actor->enemyNode.ListHead() != &enemyList ) {
  2833. gameLocal.Error( "'%s' is not in '%s' enemy list", actor->name.c_str(), name.c_str() );
  2834. }
  2835. }
  2836. for( ; actor != NULL; actor = actor->enemyNode.Next() ) {
  2837. if ( !actor->fl.hidden ) {
  2838. idThread::ReturnEntity( actor );
  2839. return;
  2840. }
  2841. }
  2842. idThread::ReturnEntity( NULL );
  2843. }
  2844. /*
  2845. ================
  2846. idActor::Event_ClosestEnemyToPoint
  2847. ================
  2848. */
  2849. void idActor::Event_ClosestEnemyToPoint( const idVec3 &pos ) {
  2850. idActor *bestEnt = ClosestEnemyToPoint( pos );
  2851. idThread::ReturnEntity( bestEnt );
  2852. }
  2853. /*
  2854. ================
  2855. idActor::Event_StopSound
  2856. ================
  2857. */
  2858. void idActor::Event_StopSound( int channel, int netSync ) {
  2859. if ( channel == SND_CHANNEL_VOICE ) {
  2860. idEntity *headEnt = head.GetEntity();
  2861. if ( headEnt ) {
  2862. headEnt->StopSound( channel, ( netSync != 0 ) );
  2863. }
  2864. }
  2865. StopSound( channel, ( netSync != 0 ) );
  2866. }
  2867. /*
  2868. =====================
  2869. idActor::Event_SetNextState
  2870. =====================
  2871. */
  2872. void idActor::Event_SetNextState( const char *name ) {
  2873. idealState = GetScriptFunction( name );
  2874. if ( idealState == state ) {
  2875. state = NULL;
  2876. }
  2877. }
  2878. /*
  2879. =====================
  2880. idActor::Event_SetState
  2881. =====================
  2882. */
  2883. void idActor::Event_SetState( const char *name ) {
  2884. idealState = GetScriptFunction( name );
  2885. if ( idealState == state ) {
  2886. state = NULL;
  2887. }
  2888. scriptThread->DoneProcessing();
  2889. }
  2890. /*
  2891. =====================
  2892. idActor::Event_GetState
  2893. =====================
  2894. */
  2895. void idActor::Event_GetState() {
  2896. if ( state ) {
  2897. idThread::ReturnString( state->Name() );
  2898. } else {
  2899. idThread::ReturnString( "" );
  2900. }
  2901. }
  2902. /*
  2903. =====================
  2904. idActor::Event_GetHead
  2905. =====================
  2906. */
  2907. void idActor::Event_GetHead() {
  2908. idThread::ReturnEntity( head.GetEntity() );
  2909. }
  2910. /*
  2911. ================
  2912. idActor::Event_SetDamageGroupScale
  2913. ================
  2914. */
  2915. void idActor::Event_SetDamageGroupScale( const char* groupName, float scale) {
  2916. for( int i = 0; i < damageScale.Num(); i++ ) {
  2917. if ( damageGroups[ i ] == groupName ) {
  2918. damageScale[ i ] = scale;
  2919. }
  2920. }
  2921. }
  2922. /*
  2923. ================
  2924. idActor::Event_SetDamageGroupScaleAll
  2925. ================
  2926. */
  2927. void idActor::Event_SetDamageGroupScaleAll( float scale ) {
  2928. for( int i = 0; i < damageScale.Num(); i++ ) {
  2929. damageScale[ i ] = scale;
  2930. }
  2931. }
  2932. void idActor::Event_GetDamageGroupScale( const char* groupName ) {
  2933. for( int i = 0; i < damageScale.Num(); i++ ) {
  2934. if ( damageGroups[ i ] == groupName ) {
  2935. idThread::ReturnFloat(damageScale[i]);
  2936. return;
  2937. }
  2938. }
  2939. idThread::ReturnFloat(0);
  2940. }
  2941. void idActor::Event_SetDamageCap( float _damageCap ) {
  2942. damageCap = _damageCap;
  2943. }
  2944. void idActor::Event_SetWaitState( const char* waitState) {
  2945. SetWaitState(waitState);
  2946. }
  2947. void idActor::Event_GetWaitState() {
  2948. if(WaitState()) {
  2949. idThread::ReturnString(WaitState());
  2950. } else {
  2951. idThread::ReturnString("");
  2952. }
  2953. }