Actor.cpp 78 KB

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