AI_events.cpp 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../../idlib/precompiled.h"
  22. #include "../Game_local.h"
  23. /***********************************************************************
  24. AI Events
  25. ***********************************************************************/
  26. const idEventDef AI_FindEnemy( "findEnemy", "d", 'e' );
  27. const idEventDef AI_FindEnemyAI( "findEnemyAI", "d", 'e' );
  28. const idEventDef AI_FindEnemyInCombatNodes( "findEnemyInCombatNodes", NULL, 'e' );
  29. const idEventDef AI_ClosestReachableEnemyOfEntity( "closestReachableEnemyOfEntity", "E", 'e' );
  30. const idEventDef AI_HeardSound( "heardSound", "d", 'e' );
  31. const idEventDef AI_SetEnemy( "setEnemy", "E" );
  32. const idEventDef AI_ClearEnemy( "clearEnemy" );
  33. const idEventDef AI_MuzzleFlash( "muzzleFlash", "s" );
  34. const idEventDef AI_CreateMissile( "createMissile", "s", 'e' );
  35. const idEventDef AI_AttackMissile( "attackMissile", "s", 'e' );
  36. const idEventDef AI_FireMissileAtTarget( "fireMissileAtTarget", "ss", 'e' );
  37. const idEventDef AI_LaunchMissile( "launchMissile", "vv", 'e' );
  38. const idEventDef AI_LaunchHomingMissile( "launchHomingMissile" );
  39. const idEventDef AI_SetHomingMissileGoal( "setHomingMissileGoal" );
  40. const idEventDef AI_LaunchProjectile( "launchProjectile", "s" );
  41. const idEventDef AI_AttackMelee( "attackMelee", "s", 'd' );
  42. const idEventDef AI_DirectDamage( "directDamage", "es" );
  43. const idEventDef AI_RadiusDamageFromJoint( "radiusDamageFromJoint", "ss" );
  44. const idEventDef AI_BeginAttack( "attackBegin", "s" );
  45. const idEventDef AI_EndAttack( "attackEnd" );
  46. const idEventDef AI_MeleeAttackToJoint( "meleeAttackToJoint", "ss", 'd' );
  47. const idEventDef AI_RandomPath( "randomPath", NULL, 'e' );
  48. const idEventDef AI_CanBecomeSolid( "canBecomeSolid", NULL, 'f' );
  49. const idEventDef AI_BecomeSolid( "becomeSolid" );
  50. const idEventDef AI_BecomeRagdoll( "becomeRagdoll", NULL, 'd' );
  51. const idEventDef AI_StopRagdoll( "stopRagdoll" );
  52. const idEventDef AI_SetHealth( "setHealth", "f" );
  53. const idEventDef AI_GetHealth( "getHealth", NULL, 'f' );
  54. const idEventDef AI_AllowDamage( "allowDamage" );
  55. const idEventDef AI_IgnoreDamage( "ignoreDamage" );
  56. const idEventDef AI_GetCurrentYaw( "getCurrentYaw", NULL, 'f' );
  57. const idEventDef AI_TurnTo( "turnTo", "f" );
  58. const idEventDef AI_TurnToPos( "turnToPos", "v" );
  59. const idEventDef AI_TurnToEntity( "turnToEntity", "E" );
  60. const idEventDef AI_MoveStatus( "moveStatus", NULL, 'd' );
  61. const idEventDef AI_StopMove( "stopMove" );
  62. const idEventDef AI_MoveToCover( "moveToCover" );
  63. const idEventDef AI_MoveToEnemy( "moveToEnemy" );
  64. const idEventDef AI_MoveToEnemyHeight( "moveToEnemyHeight" );
  65. const idEventDef AI_MoveOutOfRange( "moveOutOfRange", "ef" );
  66. const idEventDef AI_MoveToAttackPosition( "moveToAttackPosition", "es" );
  67. const idEventDef AI_Wander( "wander" );
  68. const idEventDef AI_MoveToEntity( "moveToEntity", "e" );
  69. const idEventDef AI_MoveToPosition( "moveToPosition", "v" );
  70. const idEventDef AI_SlideTo( "slideTo", "vf" );
  71. const idEventDef AI_FacingIdeal( "facingIdeal", NULL, 'd' );
  72. const idEventDef AI_FaceEnemy( "faceEnemy" );
  73. const idEventDef AI_FaceEntity( "faceEntity", "E" );
  74. const idEventDef AI_GetCombatNode( "getCombatNode", NULL, 'e' );
  75. const idEventDef AI_EnemyInCombatCone( "enemyInCombatCone", "Ed", 'd' );
  76. const idEventDef AI_WaitMove( "waitMove" );
  77. const idEventDef AI_GetJumpVelocity( "getJumpVelocity", "vff", 'v' );
  78. const idEventDef AI_GetTrajectoryToPlayer( "getTrajectoryToPlayer", NULL, 'v' );
  79. const idEventDef AI_EntityInAttackCone( "entityInAttackCone", "E", 'd' );
  80. const idEventDef AI_CanSeeEntity( "canSee", "E", 'd' );
  81. const idEventDef AI_SetTalkTarget( "setTalkTarget", "E" );
  82. const idEventDef AI_GetTalkTarget( "getTalkTarget", NULL, 'e' );
  83. const idEventDef AI_SetTalkState( "setTalkState", "d" );
  84. const idEventDef AI_EnemyRange( "enemyRange", NULL, 'f' );
  85. const idEventDef AI_EnemyRange2D( "enemyRange2D", NULL, 'f' );
  86. const idEventDef AI_GetEnemy( "getEnemy", NULL, 'e' );
  87. const idEventDef AI_GetEnemyPos( "getEnemyPos", NULL, 'v' );
  88. const idEventDef AI_GetEnemyEyePos( "getEnemyEyePos", NULL, 'v' );
  89. const idEventDef AI_PredictEnemyPos( "predictEnemyPos", "f", 'v' );
  90. const idEventDef AI_CanHitEnemy( "canHitEnemy", NULL, 'd' );
  91. const idEventDef AI_CanHitEnemyFromAnim( "canHitEnemyFromAnim", "s", 'd' );
  92. const idEventDef AI_CanHitEnemyFromJoint( "canHitEnemyFromJoint", "s", 'd' );
  93. const idEventDef AI_EnemyPositionValid( "enemyPositionValid", NULL, 'd' );
  94. const idEventDef AI_ChargeAttack( "chargeAttack", "s" );
  95. const idEventDef AI_TestChargeAttack( "testChargeAttack", NULL, 'f' );
  96. const idEventDef AI_TestMoveToPosition( "testMoveToPosition", "v", 'd' );
  97. const idEventDef AI_TestAnimMoveTowardEnemy( "testAnimMoveTowardEnemy", "s", 'd' );
  98. const idEventDef AI_TestAnimMove( "testAnimMove", "s", 'd' );
  99. const idEventDef AI_TestMeleeAttack( "testMeleeAttack", NULL, 'd' );
  100. const idEventDef AI_TestAnimAttack( "testAnimAttack", "s", 'd' );
  101. const idEventDef AI_Burn( "burn" );
  102. const idEventDef AI_ClearBurn( "clearBurn" );
  103. const idEventDef AI_PreBurn( "preBurn" );
  104. const idEventDef AI_SetSmokeVisibility( "setSmokeVisibility", "dd" );
  105. const idEventDef AI_NumSmokeEmitters( "numSmokeEmitters", NULL, 'd' );
  106. const idEventDef AI_WaitAction( "waitAction", "s" );
  107. const idEventDef AI_StopThinking( "stopThinking" );
  108. const idEventDef AI_GetTurnDelta( "getTurnDelta", NULL, 'f' );
  109. const idEventDef AI_GetMoveType( "getMoveType", NULL, 'd' );
  110. const idEventDef AI_SetMoveType( "setMoveType", "d" );
  111. const idEventDef AI_SaveMove( "saveMove" );
  112. const idEventDef AI_RestoreMove( "restoreMove" );
  113. const idEventDef AI_AllowMovement( "allowMovement", "f" );
  114. const idEventDef AI_JumpFrame( "<jumpframe>" );
  115. const idEventDef AI_EnableClip( "enableClip" );
  116. const idEventDef AI_DisableClip( "disableClip" );
  117. const idEventDef AI_EnableGravity( "enableGravity" );
  118. const idEventDef AI_DisableGravity( "disableGravity" );
  119. const idEventDef AI_EnableAFPush( "enableAFPush" );
  120. const idEventDef AI_DisableAFPush( "disableAFPush" );
  121. const idEventDef AI_SetFlySpeed( "setFlySpeed", "f" );
  122. const idEventDef AI_SetFlyOffset( "setFlyOffset", "d" );
  123. const idEventDef AI_ClearFlyOffset( "clearFlyOffset" );
  124. const idEventDef AI_GetClosestHiddenTarget( "getClosestHiddenTarget", "s", 'e' );
  125. const idEventDef AI_GetRandomTarget( "getRandomTarget", "s", 'e' );
  126. const idEventDef AI_TravelDistanceToPoint( "travelDistanceToPoint", "v", 'f' );
  127. const idEventDef AI_TravelDistanceToEntity( "travelDistanceToEntity", "e", 'f' );
  128. const idEventDef AI_TravelDistanceBetweenPoints( "travelDistanceBetweenPoints", "vv", 'f' );
  129. const idEventDef AI_TravelDistanceBetweenEntities( "travelDistanceBetweenEntities", "ee", 'f' );
  130. const idEventDef AI_LookAtEntity( "lookAt", "Ef" );
  131. const idEventDef AI_LookAtEnemy( "lookAtEnemy", "f" );
  132. const idEventDef AI_SetJointMod( "setBoneMod", "d" );
  133. const idEventDef AI_ThrowMoveable( "throwMoveable" );
  134. const idEventDef AI_ThrowAF( "throwAF" );
  135. const idEventDef AI_RealKill( "<kill>" );
  136. const idEventDef AI_Kill( "kill" );
  137. const idEventDef AI_WakeOnFlashlight( "wakeOnFlashlight", "d" );
  138. const idEventDef AI_LocateEnemy( "locateEnemy" );
  139. const idEventDef AI_KickObstacles( "kickObstacles", "Ef" );
  140. const idEventDef AI_GetObstacle( "getObstacle", NULL, 'e' );
  141. const idEventDef AI_PushPointIntoAAS( "pushPointIntoAAS", "v", 'v' );
  142. const idEventDef AI_GetTurnRate( "getTurnRate", NULL, 'f' );
  143. const idEventDef AI_SetTurnRate( "setTurnRate", "f" );
  144. const idEventDef AI_AnimTurn( "animTurn", "f" );
  145. const idEventDef AI_AllowHiddenMovement( "allowHiddenMovement", "d" );
  146. const idEventDef AI_TriggerParticles( "triggerParticles", "s" );
  147. const idEventDef AI_FindActorsInBounds( "findActorsInBounds", "vv", 'e' );
  148. const idEventDef AI_CanReachPosition( "canReachPosition", "v", 'd' );
  149. const idEventDef AI_CanReachEntity( "canReachEntity", "E", 'd' );
  150. const idEventDef AI_CanReachEnemy( "canReachEnemy", NULL, 'd' );
  151. const idEventDef AI_GetReachableEntityPosition( "getReachableEntityPosition", "e", 'v' );
  152. const idEventDef AI_MoveToPositionDirect( "moveToPositionDirect", "v" );
  153. const idEventDef AI_AvoidObstacles( "avoidObstacles", "d" );
  154. const idEventDef AI_TriggerFX( "triggerFX", "ss" );
  155. const idEventDef AI_StartEmitter( "startEmitter", "sss", 'e' );
  156. const idEventDef AI_GetEmitter( "getEmitter", "s", 'e' );
  157. const idEventDef AI_StopEmitter( "stopEmitter", "s" );
  158. CLASS_DECLARATION( idActor, idAI )
  159. EVENT( EV_Activate, idAI::Event_Activate )
  160. EVENT( EV_Touch, idAI::Event_Touch )
  161. EVENT( AI_FindEnemy, idAI::Event_FindEnemy )
  162. EVENT( AI_FindEnemyAI, idAI::Event_FindEnemyAI )
  163. EVENT( AI_FindEnemyInCombatNodes, idAI::Event_FindEnemyInCombatNodes )
  164. EVENT( AI_ClosestReachableEnemyOfEntity, idAI::Event_ClosestReachableEnemyOfEntity )
  165. EVENT( AI_HeardSound, idAI::Event_HeardSound )
  166. EVENT( AI_SetEnemy, idAI::Event_SetEnemy )
  167. EVENT( AI_ClearEnemy, idAI::Event_ClearEnemy )
  168. EVENT( AI_MuzzleFlash, idAI::Event_MuzzleFlash )
  169. EVENT( AI_CreateMissile, idAI::Event_CreateMissile )
  170. EVENT( AI_AttackMissile, idAI::Event_AttackMissile )
  171. EVENT( AI_FireMissileAtTarget, idAI::Event_FireMissileAtTarget )
  172. EVENT( AI_LaunchMissile, idAI::Event_LaunchMissile )
  173. EVENT( AI_LaunchHomingMissile, idAI::Event_LaunchHomingMissile )
  174. EVENT( AI_SetHomingMissileGoal, idAI::Event_SetHomingMissileGoal )
  175. EVENT( AI_LaunchProjectile, idAI::Event_LaunchProjectile )
  176. EVENT( AI_AttackMelee, idAI::Event_AttackMelee )
  177. EVENT( AI_DirectDamage, idAI::Event_DirectDamage )
  178. EVENT( AI_RadiusDamageFromJoint, idAI::Event_RadiusDamageFromJoint )
  179. EVENT( AI_BeginAttack, idAI::Event_BeginAttack )
  180. EVENT( AI_EndAttack, idAI::Event_EndAttack )
  181. EVENT( AI_MeleeAttackToJoint, idAI::Event_MeleeAttackToJoint )
  182. EVENT( AI_RandomPath, idAI::Event_RandomPath )
  183. EVENT( AI_CanBecomeSolid, idAI::Event_CanBecomeSolid )
  184. EVENT( AI_BecomeSolid, idAI::Event_BecomeSolid )
  185. EVENT( EV_BecomeNonSolid, idAI::Event_BecomeNonSolid )
  186. EVENT( AI_BecomeRagdoll, idAI::Event_BecomeRagdoll )
  187. EVENT( AI_StopRagdoll, idAI::Event_StopRagdoll )
  188. EVENT( AI_SetHealth, idAI::Event_SetHealth )
  189. EVENT( AI_GetHealth, idAI::Event_GetHealth )
  190. EVENT( AI_AllowDamage, idAI::Event_AllowDamage )
  191. EVENT( AI_IgnoreDamage, idAI::Event_IgnoreDamage )
  192. EVENT( AI_GetCurrentYaw, idAI::Event_GetCurrentYaw )
  193. EVENT( AI_TurnTo, idAI::Event_TurnTo )
  194. EVENT( AI_TurnToPos, idAI::Event_TurnToPos )
  195. EVENT( AI_TurnToEntity, idAI::Event_TurnToEntity )
  196. EVENT( AI_MoveStatus, idAI::Event_MoveStatus )
  197. EVENT( AI_StopMove, idAI::Event_StopMove )
  198. EVENT( AI_MoveToCover, idAI::Event_MoveToCover )
  199. EVENT( AI_MoveToEnemy, idAI::Event_MoveToEnemy )
  200. EVENT( AI_MoveToEnemyHeight, idAI::Event_MoveToEnemyHeight )
  201. EVENT( AI_MoveOutOfRange, idAI::Event_MoveOutOfRange )
  202. EVENT( AI_MoveToAttackPosition, idAI::Event_MoveToAttackPosition )
  203. EVENT( AI_Wander, idAI::Event_Wander )
  204. EVENT( AI_MoveToEntity, idAI::Event_MoveToEntity )
  205. EVENT( AI_MoveToPosition, idAI::Event_MoveToPosition )
  206. EVENT( AI_SlideTo, idAI::Event_SlideTo )
  207. EVENT( AI_FacingIdeal, idAI::Event_FacingIdeal )
  208. EVENT( AI_FaceEnemy, idAI::Event_FaceEnemy )
  209. EVENT( AI_FaceEntity, idAI::Event_FaceEntity )
  210. EVENT( AI_WaitAction, idAI::Event_WaitAction )
  211. EVENT( AI_GetCombatNode, idAI::Event_GetCombatNode )
  212. EVENT( AI_EnemyInCombatCone, idAI::Event_EnemyInCombatCone )
  213. EVENT( AI_WaitMove, idAI::Event_WaitMove )
  214. EVENT( AI_GetJumpVelocity, idAI::Event_GetJumpVelocity )
  215. EVENT( AI_GetTrajectoryToPlayer, idAI::Event_GetTrajectoryToPlayer )
  216. EVENT( AI_EntityInAttackCone, idAI::Event_EntityInAttackCone )
  217. EVENT( AI_CanSeeEntity, idAI::Event_CanSeeEntity )
  218. EVENT( AI_SetTalkTarget, idAI::Event_SetTalkTarget )
  219. EVENT( AI_GetTalkTarget, idAI::Event_GetTalkTarget )
  220. EVENT( AI_SetTalkState, idAI::Event_SetTalkState )
  221. EVENT( AI_EnemyRange, idAI::Event_EnemyRange )
  222. EVENT( AI_EnemyRange2D, idAI::Event_EnemyRange2D )
  223. EVENT( AI_GetEnemy, idAI::Event_GetEnemy )
  224. EVENT( AI_GetEnemyPos, idAI::Event_GetEnemyPos )
  225. EVENT( AI_GetEnemyEyePos, idAI::Event_GetEnemyEyePos )
  226. EVENT( AI_PredictEnemyPos, idAI::Event_PredictEnemyPos )
  227. EVENT( AI_CanHitEnemy, idAI::Event_CanHitEnemy )
  228. EVENT( AI_CanHitEnemyFromAnim, idAI::Event_CanHitEnemyFromAnim )
  229. EVENT( AI_CanHitEnemyFromJoint, idAI::Event_CanHitEnemyFromJoint )
  230. EVENT( AI_EnemyPositionValid, idAI::Event_EnemyPositionValid )
  231. EVENT( AI_ChargeAttack, idAI::Event_ChargeAttack )
  232. EVENT( AI_TestChargeAttack, idAI::Event_TestChargeAttack )
  233. EVENT( AI_TestAnimMoveTowardEnemy, idAI::Event_TestAnimMoveTowardEnemy )
  234. EVENT( AI_TestAnimMove, idAI::Event_TestAnimMove )
  235. EVENT( AI_TestMoveToPosition, idAI::Event_TestMoveToPosition )
  236. EVENT( AI_TestMeleeAttack, idAI::Event_TestMeleeAttack )
  237. EVENT( AI_TestAnimAttack, idAI::Event_TestAnimAttack )
  238. EVENT( AI_Burn, idAI::Event_Burn )
  239. EVENT( AI_PreBurn, idAI::Event_PreBurn )
  240. EVENT( AI_SetSmokeVisibility, idAI::Event_SetSmokeVisibility )
  241. EVENT( AI_NumSmokeEmitters, idAI::Event_NumSmokeEmitters )
  242. EVENT( AI_ClearBurn, idAI::Event_ClearBurn )
  243. EVENT( AI_StopThinking, idAI::Event_StopThinking )
  244. EVENT( AI_GetTurnDelta, idAI::Event_GetTurnDelta )
  245. EVENT( AI_GetMoveType, idAI::Event_GetMoveType )
  246. EVENT( AI_SetMoveType, idAI::Event_SetMoveType )
  247. EVENT( AI_SaveMove, idAI::Event_SaveMove )
  248. EVENT( AI_RestoreMove, idAI::Event_RestoreMove )
  249. EVENT( AI_AllowMovement, idAI::Event_AllowMovement )
  250. EVENT( AI_JumpFrame, idAI::Event_JumpFrame )
  251. EVENT( AI_EnableClip, idAI::Event_EnableClip )
  252. EVENT( AI_DisableClip, idAI::Event_DisableClip )
  253. EVENT( AI_EnableGravity, idAI::Event_EnableGravity )
  254. EVENT( AI_DisableGravity, idAI::Event_DisableGravity )
  255. EVENT( AI_EnableAFPush, idAI::Event_EnableAFPush )
  256. EVENT( AI_DisableAFPush, idAI::Event_DisableAFPush )
  257. EVENT( AI_SetFlySpeed, idAI::Event_SetFlySpeed )
  258. EVENT( AI_SetFlyOffset, idAI::Event_SetFlyOffset )
  259. EVENT( AI_ClearFlyOffset, idAI::Event_ClearFlyOffset )
  260. EVENT( AI_GetClosestHiddenTarget, idAI::Event_GetClosestHiddenTarget )
  261. EVENT( AI_GetRandomTarget, idAI::Event_GetRandomTarget )
  262. EVENT( AI_TravelDistanceToPoint, idAI::Event_TravelDistanceToPoint )
  263. EVENT( AI_TravelDistanceToEntity, idAI::Event_TravelDistanceToEntity )
  264. EVENT( AI_TravelDistanceBetweenPoints, idAI::Event_TravelDistanceBetweenPoints )
  265. EVENT( AI_TravelDistanceBetweenEntities, idAI::Event_TravelDistanceBetweenEntities )
  266. EVENT( AI_LookAtEntity, idAI::Event_LookAtEntity )
  267. EVENT( AI_LookAtEnemy, idAI::Event_LookAtEnemy )
  268. EVENT( AI_SetJointMod, idAI::Event_SetJointMod )
  269. EVENT( AI_ThrowMoveable, idAI::Event_ThrowMoveable )
  270. EVENT( AI_ThrowAF, idAI::Event_ThrowAF )
  271. EVENT( EV_GetAngles, idAI::Event_GetAngles )
  272. EVENT( EV_SetAngles, idAI::Event_SetAngles )
  273. EVENT( AI_RealKill, idAI::Event_RealKill )
  274. EVENT( AI_Kill, idAI::Event_Kill )
  275. EVENT( AI_WakeOnFlashlight, idAI::Event_WakeOnFlashlight )
  276. EVENT( AI_LocateEnemy, idAI::Event_LocateEnemy )
  277. EVENT( AI_KickObstacles, idAI::Event_KickObstacles )
  278. EVENT( AI_GetObstacle, idAI::Event_GetObstacle )
  279. EVENT( AI_PushPointIntoAAS, idAI::Event_PushPointIntoAAS )
  280. EVENT( AI_GetTurnRate, idAI::Event_GetTurnRate )
  281. EVENT( AI_SetTurnRate, idAI::Event_SetTurnRate )
  282. EVENT( AI_AnimTurn, idAI::Event_AnimTurn )
  283. EVENT( AI_AllowHiddenMovement, idAI::Event_AllowHiddenMovement )
  284. EVENT( AI_TriggerParticles, idAI::Event_TriggerParticles )
  285. EVENT( AI_FindActorsInBounds, idAI::Event_FindActorsInBounds )
  286. EVENT( AI_CanReachPosition, idAI::Event_CanReachPosition )
  287. EVENT( AI_CanReachEntity, idAI::Event_CanReachEntity )
  288. EVENT( AI_CanReachEnemy, idAI::Event_CanReachEnemy )
  289. EVENT( AI_GetReachableEntityPosition, idAI::Event_GetReachableEntityPosition )
  290. EVENT( AI_MoveToPositionDirect, idAI::Event_MoveToPositionDirect )
  291. EVENT( AI_AvoidObstacles, idAI::Event_AvoidObstacles )
  292. EVENT( AI_TriggerFX, idAI::Event_TriggerFX )
  293. EVENT( AI_StartEmitter, idAI::Event_StartEmitter )
  294. EVENT( AI_GetEmitter, idAI::Event_GetEmitter )
  295. EVENT( AI_StopEmitter, idAI::Event_StopEmitter )
  296. END_CLASS
  297. /*
  298. =====================
  299. idAI::Event_Activate
  300. =====================
  301. */
  302. void idAI::Event_Activate( idEntity *activator ) {
  303. Activate( activator );
  304. }
  305. /*
  306. =====================
  307. idAI::Event_Touch
  308. =====================
  309. */
  310. void idAI::Event_Touch( idEntity *other, trace_t *trace ) {
  311. if ( !enemy.GetEntity() && !other->fl.notarget && ( ReactionTo( other ) & ATTACK_ON_ACTIVATE ) ) {
  312. Activate( other );
  313. }
  314. AI_PUSHED = true;
  315. }
  316. /*
  317. =====================
  318. idAI::Event_FindEnemy
  319. =====================
  320. */
  321. void idAI::Event_FindEnemy( int useFOV ) {
  322. int i;
  323. idEntity *ent;
  324. idActor *actor;
  325. if ( gameLocal.InPlayerPVS( this ) ) {
  326. for ( i = 0; i < gameLocal.numClients ; i++ ) {
  327. ent = gameLocal.entities[ i ];
  328. if ( !ent || !ent->IsType( idActor::Type ) ) {
  329. continue;
  330. }
  331. actor = static_cast<idActor *>( ent );
  332. if ( ( actor->health <= 0 ) || !( ReactionTo( actor ) & ATTACK_ON_SIGHT ) ) {
  333. continue;
  334. }
  335. if ( CanSee( actor, useFOV != 0 ) ) {
  336. idThread::ReturnEntity( actor );
  337. return;
  338. }
  339. }
  340. }
  341. idThread::ReturnEntity( NULL );
  342. }
  343. /*
  344. =====================
  345. idAI::Event_FindEnemyAI
  346. =====================
  347. */
  348. void idAI::Event_FindEnemyAI( int useFOV ) {
  349. idEntity *ent;
  350. idActor *actor;
  351. idActor *bestEnemy;
  352. float bestDist;
  353. float dist;
  354. idVec3 delta;
  355. pvsHandle_t pvs;
  356. pvs = gameLocal.pvs.SetupCurrentPVS( GetPVSAreas(), GetNumPVSAreas() );
  357. bestDist = idMath::INFINITY;
  358. bestEnemy = NULL;
  359. for ( ent = gameLocal.activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
  360. if ( ent->fl.hidden || ent->fl.isDormant || !ent->IsType( idActor::Type ) ) {
  361. continue;
  362. }
  363. actor = static_cast<idActor *>( ent );
  364. if ( ( actor->health <= 0 ) || !( ReactionTo( actor ) & ATTACK_ON_SIGHT ) ) {
  365. continue;
  366. }
  367. if ( !gameLocal.pvs.InCurrentPVS( pvs, actor->GetPVSAreas(), actor->GetNumPVSAreas() ) ) {
  368. continue;
  369. }
  370. delta = physicsObj.GetOrigin() - actor->GetPhysics()->GetOrigin();
  371. dist = delta.LengthSqr();
  372. if ( ( dist < bestDist ) && CanSee( actor, useFOV != 0 ) ) {
  373. bestDist = dist;
  374. bestEnemy = actor;
  375. }
  376. }
  377. gameLocal.pvs.FreeCurrentPVS( pvs );
  378. idThread::ReturnEntity( bestEnemy );
  379. }
  380. /*
  381. =====================
  382. idAI::Event_FindEnemyInCombatNodes
  383. =====================
  384. */
  385. void idAI::Event_FindEnemyInCombatNodes() {
  386. int i, j;
  387. idCombatNode *node;
  388. idEntity *ent;
  389. idEntity *targetEnt;
  390. idActor *actor;
  391. if ( !gameLocal.InPlayerPVS( this ) ) {
  392. // don't locate the player when we're not in his PVS
  393. idThread::ReturnEntity( NULL );
  394. return;
  395. }
  396. for ( i = 0; i < gameLocal.numClients ; i++ ) {
  397. ent = gameLocal.entities[ i ];
  398. if ( !ent || !ent->IsType( idActor::Type ) ) {
  399. continue;
  400. }
  401. actor = static_cast<idActor *>( ent );
  402. if ( ( actor->health <= 0 ) || !( ReactionTo( actor ) & ATTACK_ON_SIGHT ) ) {
  403. continue;
  404. }
  405. for( j = 0; j < targets.Num(); j++ ) {
  406. targetEnt = targets[ j ].GetEntity();
  407. if ( !targetEnt || !targetEnt->IsType( idCombatNode::Type ) ) {
  408. continue;
  409. }
  410. node = static_cast<idCombatNode *>( targetEnt );
  411. if ( !node->IsDisabled() && node->EntityInView( actor, actor->GetPhysics()->GetOrigin() ) ) {
  412. idThread::ReturnEntity( actor );
  413. return;
  414. }
  415. }
  416. }
  417. idThread::ReturnEntity( NULL );
  418. }
  419. /*
  420. =====================
  421. idAI::Event_ClosestReachableEnemyOfEntity
  422. =====================
  423. */
  424. void idAI::Event_ClosestReachableEnemyOfEntity( idEntity *team_mate ) {
  425. idActor *actor;
  426. idActor *ent;
  427. idActor *bestEnt;
  428. float bestDistSquared;
  429. float distSquared;
  430. idVec3 delta;
  431. int areaNum;
  432. int enemyAreaNum;
  433. aasPath_t path;
  434. if ( !team_mate->IsType( idActor::Type ) ) {
  435. gameLocal.Error( "Entity '%s' is not an AI character or player", team_mate->GetName() );
  436. }
  437. actor = static_cast<idActor *>( team_mate );
  438. const idVec3 &origin = physicsObj.GetOrigin();
  439. areaNum = PointReachableAreaNum( origin );
  440. bestDistSquared = idMath::INFINITY;
  441. bestEnt = NULL;
  442. for( ent = actor->enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  443. if ( ent->fl.hidden ) {
  444. continue;
  445. }
  446. delta = ent->GetPhysics()->GetOrigin() - origin;
  447. distSquared = delta.LengthSqr();
  448. if ( distSquared < bestDistSquared ) {
  449. const idVec3 &enemyPos = ent->GetPhysics()->GetOrigin();
  450. enemyAreaNum = PointReachableAreaNum( enemyPos );
  451. if ( ( areaNum != 0 ) && PathToGoal( path, areaNum, origin, enemyAreaNum, enemyPos ) ) {
  452. bestEnt = ent;
  453. bestDistSquared = distSquared;
  454. }
  455. }
  456. }
  457. idThread::ReturnEntity( bestEnt );
  458. }
  459. /*
  460. =====================
  461. idAI::Event_HeardSound
  462. =====================
  463. */
  464. void idAI::Event_HeardSound( int ignore_team ) {
  465. // check if we heard any sounds in the last frame
  466. idActor *actor = gameLocal.GetAlertEntity();
  467. if ( actor != NULL && ( !ignore_team || ( ReactionTo( actor ) & ATTACK_ON_SIGHT ) ) && gameLocal.InPlayerPVS( this ) ) {
  468. idVec3 pos = actor->GetPhysics()->GetOrigin();
  469. idVec3 org = physicsObj.GetOrigin();
  470. float dist = ( pos - org ).LengthSqr();
  471. if ( dist < Square( AI_HEARING_RANGE ) ) {
  472. idThread::ReturnEntity( actor );
  473. return;
  474. }
  475. }
  476. idThread::ReturnEntity( NULL );
  477. }
  478. /*
  479. =====================
  480. idAI::Event_SetEnemy
  481. =====================
  482. */
  483. void idAI::Event_SetEnemy( idEntity *ent ) {
  484. if ( !ent ) {
  485. ClearEnemy();
  486. } else if ( !ent->IsType( idActor::Type ) ) {
  487. gameLocal.Error( "'%s' is not an idActor (player or ai controlled character)", ent->name.c_str() );
  488. } else {
  489. SetEnemy( static_cast<idActor *>( ent ) );
  490. }
  491. }
  492. /*
  493. =====================
  494. idAI::Event_ClearEnemy
  495. =====================
  496. */
  497. void idAI::Event_ClearEnemy() {
  498. ClearEnemy();
  499. }
  500. /*
  501. =====================
  502. idAI::Event_MuzzleFlash
  503. =====================
  504. */
  505. void idAI::Event_MuzzleFlash( const char *jointname ) {
  506. idVec3 muzzle;
  507. idMat3 axis;
  508. GetMuzzle( jointname, muzzle, axis );
  509. TriggerWeaponEffects( muzzle );
  510. }
  511. /*
  512. =====================
  513. idAI::Event_CreateMissile
  514. =====================
  515. */
  516. void idAI::Event_CreateMissile( const char *jointname ) {
  517. idVec3 muzzle;
  518. idMat3 axis;
  519. if ( !projectileDef ) {
  520. gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
  521. return idThread::ReturnEntity( NULL );
  522. }
  523. GetMuzzle( jointname, muzzle, axis );
  524. CreateProjectile( muzzle, viewAxis[ 0 ] * physicsObj.GetGravityAxis() );
  525. if ( projectile.GetEntity() ) {
  526. if ( !jointname || !jointname[ 0 ] ) {
  527. projectile.GetEntity()->Bind( this, true );
  528. } else {
  529. projectile.GetEntity()->BindToJoint( this, jointname, true );
  530. }
  531. }
  532. idThread::ReturnEntity( projectile.GetEntity() );
  533. }
  534. /*
  535. =====================
  536. idAI::Event_AttackMissile
  537. =====================
  538. */
  539. void idAI::Event_AttackMissile( const char *jointname ) {
  540. idProjectile *proj;
  541. proj = LaunchProjectile( jointname, enemy.GetEntity(), true );
  542. idThread::ReturnEntity( proj );
  543. }
  544. /*
  545. =====================
  546. idAI::Event_FireMissileAtTarget
  547. =====================
  548. */
  549. void idAI::Event_FireMissileAtTarget( const char *jointname, const char *targetname ) {
  550. idEntity *aent;
  551. idProjectile *proj;
  552. aent = gameLocal.FindEntity( targetname );
  553. if ( !aent ) {
  554. gameLocal.Warning( "Entity '%s' not found for 'fireMissileAtTarget'", targetname );
  555. }
  556. proj = LaunchProjectile( jointname, aent, false );
  557. idThread::ReturnEntity( proj );
  558. }
  559. /*
  560. =====================
  561. idAI::Event_LaunchMissile
  562. =====================
  563. */
  564. void idAI::Event_LaunchMissile( const idVec3 &org, const idAngles &ang ) {
  565. idVec3 start;
  566. trace_t tr;
  567. idBounds projBounds;
  568. const idClipModel *projClip;
  569. idMat3 axis;
  570. float distance;
  571. if ( !projectileDef ) {
  572. gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
  573. idThread::ReturnEntity( NULL );
  574. return;
  575. }
  576. axis = ang.ToMat3();
  577. if ( !projectile.GetEntity() ) {
  578. CreateProjectile( org, axis[ 0 ] );
  579. }
  580. // make sure the projectile starts inside the monster bounding box
  581. const idBounds &ownerBounds = physicsObj.GetAbsBounds();
  582. projClip = projectile.GetEntity()->GetPhysics()->GetClipModel();
  583. projBounds = projClip->GetBounds().Rotate( projClip->GetAxis() );
  584. // check if the owner bounds is bigger than the projectile bounds
  585. if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
  586. ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
  587. ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
  588. if ( (ownerBounds - projBounds).RayIntersection( org, viewAxis[ 0 ], distance ) ) {
  589. start = org + distance * viewAxis[ 0 ];
  590. } else {
  591. start = ownerBounds.GetCenter();
  592. }
  593. } else {
  594. // projectile bounds bigger than the owner bounds, so just start it from the center
  595. start = ownerBounds.GetCenter();
  596. }
  597. gameLocal.clip.Translation( tr, start, org, projClip, projClip->GetAxis(), MASK_SHOT_RENDERMODEL, this );
  598. // launch the projectile
  599. idThread::ReturnEntity( projectile.GetEntity() );
  600. projectile.GetEntity()->Launch( tr.endpos, axis[ 0 ], vec3_origin );
  601. projectile = NULL;
  602. TriggerWeaponEffects( tr.endpos );
  603. lastAttackTime = gameLocal.time;
  604. }
  605. /*
  606. =====================
  607. idAI::Event_LaunchProjectile
  608. =====================
  609. */
  610. void idAI::Event_LaunchProjectile( const char *entityDefName ) {
  611. idVec3 muzzle, start, dir;
  612. const idDict *projDef;
  613. idMat3 axis;
  614. const idClipModel *projClip;
  615. idBounds projBounds;
  616. trace_t tr;
  617. idEntity *ent;
  618. const char *clsname;
  619. float distance;
  620. idProjectile *proj = NULL;
  621. projDef = gameLocal.FindEntityDefDict( entityDefName );
  622. gameLocal.SpawnEntityDef( *projDef, &ent, false );
  623. if ( ent == NULL ) {
  624. clsname = projectileDef->GetString( "classname" );
  625. gameLocal.Error( "Could not spawn entityDef '%s'", clsname );
  626. return;
  627. }
  628. if ( !ent->IsType( idProjectile::Type ) ) {
  629. clsname = ent->GetClassname();
  630. gameLocal.Error( "'%s' is not an idProjectile", clsname );
  631. }
  632. proj = ( idProjectile * )ent;
  633. GetMuzzle( "pistol", muzzle, axis );
  634. proj->Create( this, muzzle, axis[0] );
  635. // make sure the projectile starts inside the monster bounding box
  636. const idBounds &ownerBounds = physicsObj.GetAbsBounds();
  637. projClip = proj->GetPhysics()->GetClipModel();
  638. projBounds = projClip->GetBounds().Rotate( projClip->GetAxis() );
  639. if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) {
  640. start = muzzle + distance * viewAxis[ 0 ];
  641. } else {
  642. start = ownerBounds.GetCenter();
  643. }
  644. gameLocal.clip.Translation( tr, start, muzzle, projClip, projClip->GetAxis(), MASK_SHOT_RENDERMODEL, this );
  645. muzzle = tr.endpos;
  646. GetAimDir( muzzle, enemy.GetEntity(), this, dir );
  647. proj->Launch( muzzle, dir, vec3_origin );
  648. TriggerWeaponEffects( muzzle );
  649. }
  650. /*
  651. =====================
  652. idAI::Event_AttackMelee
  653. =====================
  654. */
  655. void idAI::Event_AttackMelee( const char *meleeDefName ) {
  656. bool hit;
  657. hit = AttackMelee( meleeDefName );
  658. idThread::ReturnInt( hit );
  659. }
  660. /*
  661. =====================
  662. idAI::Event_DirectDamage
  663. =====================
  664. */
  665. void idAI::Event_DirectDamage( idEntity *damageTarget, const char *damageDefName ) {
  666. DirectDamage( damageDefName, damageTarget );
  667. }
  668. /*
  669. =====================
  670. idAI::Event_RadiusDamageFromJoint
  671. =====================
  672. */
  673. void idAI::Event_RadiusDamageFromJoint( const char *jointname, const char *damageDefName ) {
  674. jointHandle_t joint;
  675. idVec3 org;
  676. idMat3 axis;
  677. if ( !jointname || !jointname[ 0 ] ) {
  678. org = physicsObj.GetOrigin();
  679. } else {
  680. joint = animator.GetJointHandle( jointname );
  681. if ( joint == INVALID_JOINT ) {
  682. gameLocal.Error( "Unknown joint '%s' on %s", jointname, GetEntityDefName() );
  683. }
  684. GetJointWorldTransform( joint, gameLocal.time, org, axis );
  685. }
  686. gameLocal.RadiusDamage( org, this, this, this, this, damageDefName );
  687. }
  688. /*
  689. =====================
  690. idAI::Event_RandomPath
  691. =====================
  692. */
  693. void idAI::Event_RandomPath() {
  694. idPathCorner *path;
  695. path = idPathCorner::RandomPath( this, NULL );
  696. idThread::ReturnEntity( path );
  697. }
  698. /*
  699. =====================
  700. idAI::Event_BeginAttack
  701. =====================
  702. */
  703. void idAI::Event_BeginAttack( const char *name ) {
  704. BeginAttack( name );
  705. }
  706. /*
  707. =====================
  708. idAI::Event_EndAttack
  709. =====================
  710. */
  711. void idAI::Event_EndAttack() {
  712. EndAttack();
  713. }
  714. /*
  715. =====================
  716. idAI::Event_MeleeAttackToJoint
  717. =====================
  718. */
  719. void idAI::Event_MeleeAttackToJoint( const char *jointname, const char *meleeDefName ) {
  720. jointHandle_t joint;
  721. idVec3 start;
  722. idVec3 end;
  723. idMat3 axis;
  724. trace_t trace;
  725. idEntity *hitEnt;
  726. joint = animator.GetJointHandle( jointname );
  727. if ( joint == INVALID_JOINT ) {
  728. gameLocal.Error( "Unknown joint '%s' on %s", jointname, GetEntityDefName() );
  729. }
  730. animator.GetJointTransform( joint, gameLocal.time, end, axis );
  731. end = physicsObj.GetOrigin() + ( end + modelOffset ) * viewAxis * physicsObj.GetGravityAxis();
  732. start = GetEyePosition();
  733. if ( ai_debugMove.GetBool() ) {
  734. gameRenderWorld->DebugLine( colorYellow, start, end, 1 );
  735. }
  736. gameLocal.clip.TranslationEntities( trace, start, end, NULL, mat3_identity, MASK_SHOT_BOUNDINGBOX, this );
  737. if ( trace.fraction < 1.0f ) {
  738. hitEnt = gameLocal.GetTraceEntity( trace );
  739. if ( hitEnt != NULL && hitEnt->IsType( idActor::Type ) ) {
  740. DirectDamage( meleeDefName, hitEnt );
  741. idThread::ReturnInt( true );
  742. return;
  743. }
  744. }
  745. idThread::ReturnInt( false );
  746. }
  747. /*
  748. =====================
  749. idAI::Event_CanBecomeSolid
  750. =====================
  751. */
  752. void idAI::Event_CanBecomeSolid() {
  753. int i;
  754. int num;
  755. bool returnValue = true;
  756. idEntity * hit;
  757. idClipModel *cm;
  758. idClipModel *clipModels[ MAX_GENTITIES ];
  759. num = gameLocal.clip.ClipModelsTouchingBounds( physicsObj.GetAbsBounds(), MASK_MONSTERSOLID, clipModels, MAX_GENTITIES );
  760. for ( i = 0; i < num; i++ ) {
  761. cm = clipModels[ i ];
  762. // don't check render entities
  763. if ( cm->IsRenderModel() ) {
  764. continue;
  765. }
  766. hit = cm->GetEntity();
  767. if ( ( hit == this ) || !hit->fl.takedamage ) {
  768. continue;
  769. }
  770. if ( spawnClearMoveables && hit->IsType( idMoveable::Type ) || hit->IsType( idBarrel::Type ) || hit->IsType( idExplodingBarrel::Type ) ) {
  771. idVec3 push;
  772. push = hit->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  773. push.z = 30.f;
  774. push.NormalizeFast();
  775. if ( (idMath::Fabs(push.x) < 0.15f) && (idMath::Fabs(push.y) < 0.15f) ) {
  776. push.x = 10.f; push.y = 10.f; push.z = 15.f;
  777. push.NormalizeFast();
  778. }
  779. push *= 300.f;
  780. hit->GetPhysics()->SetLinearVelocity( push );
  781. }
  782. if ( physicsObj.ClipContents( cm ) ) {
  783. returnValue = false;
  784. }
  785. }
  786. idThread::ReturnFloat( returnValue );
  787. }
  788. /*
  789. =====================
  790. idAI::Event_BecomeSolid
  791. =====================
  792. */
  793. void idAI::Event_BecomeSolid() {
  794. physicsObj.EnableClip();
  795. if ( spawnArgs.GetBool( "big_monster" ) ) {
  796. physicsObj.SetContents( 0 );
  797. } else if ( use_combat_bbox ) {
  798. physicsObj.SetContents( CONTENTS_BODY|CONTENTS_SOLID );
  799. } else {
  800. physicsObj.SetContents( CONTENTS_BODY );
  801. }
  802. physicsObj.GetClipModel()->Link( gameLocal.clip );
  803. fl.takedamage = !spawnArgs.GetBool( "noDamage" );
  804. }
  805. /*
  806. =====================
  807. idAI::Event_BecomeNonSolid
  808. =====================
  809. */
  810. void idAI::Event_BecomeNonSolid() {
  811. fl.takedamage = false;
  812. physicsObj.SetContents( 0 );
  813. physicsObj.GetClipModel()->Unlink();
  814. }
  815. /*
  816. =====================
  817. idAI::Event_BecomeRagdoll
  818. =====================
  819. */
  820. void idAI::Event_BecomeRagdoll() {
  821. bool result;
  822. result = StartRagdoll();
  823. idThread::ReturnInt( result );
  824. }
  825. /*
  826. =====================
  827. idAI::Event_StopRagdoll
  828. =====================
  829. */
  830. void idAI::Event_StopRagdoll() {
  831. StopRagdoll();
  832. // set back the monster physics
  833. SetPhysics( &physicsObj );
  834. }
  835. /*
  836. =====================
  837. idAI::Event_SetHealth
  838. =====================
  839. */
  840. void idAI::Event_SetHealth( float newHealth ) {
  841. health = newHealth;
  842. fl.takedamage = true;
  843. if ( health > 0 ) {
  844. AI_DEAD = false;
  845. } else {
  846. AI_DEAD = true;
  847. }
  848. }
  849. /*
  850. =====================
  851. idAI::Event_GetHealth
  852. =====================
  853. */
  854. void idAI::Event_GetHealth() {
  855. idThread::ReturnFloat( health );
  856. }
  857. /*
  858. =====================
  859. idAI::Event_AllowDamage
  860. =====================
  861. */
  862. void idAI::Event_AllowDamage() {
  863. fl.takedamage = true;
  864. }
  865. /*
  866. =====================
  867. idAI::Event_IgnoreDamage
  868. =====================
  869. */
  870. void idAI::Event_IgnoreDamage() {
  871. fl.takedamage = false;
  872. }
  873. /*
  874. =====================
  875. idAI::Event_GetCurrentYaw
  876. =====================
  877. */
  878. void idAI::Event_GetCurrentYaw() {
  879. idThread::ReturnFloat( current_yaw );
  880. }
  881. /*
  882. =====================
  883. idAI::Event_TurnTo
  884. =====================
  885. */
  886. void idAI::Event_TurnTo( float angle ) {
  887. TurnToward( angle );
  888. }
  889. /*
  890. =====================
  891. idAI::Event_TurnToPos
  892. =====================
  893. */
  894. void idAI::Event_TurnToPos( const idVec3 &pos ) {
  895. TurnToward( pos );
  896. }
  897. /*
  898. =====================
  899. idAI::Event_TurnToEntity
  900. =====================
  901. */
  902. void idAI::Event_TurnToEntity( idEntity *ent ) {
  903. if ( ent ) {
  904. TurnToward( ent->GetPhysics()->GetOrigin() );
  905. }
  906. }
  907. /*
  908. =====================
  909. idAI::Event_MoveStatus
  910. =====================
  911. */
  912. void idAI::Event_MoveStatus() {
  913. idThread::ReturnInt( move.moveStatus );
  914. }
  915. /*
  916. =====================
  917. idAI::Event_StopMove
  918. =====================
  919. */
  920. void idAI::Event_StopMove() {
  921. StopMove( MOVE_STATUS_DONE );
  922. }
  923. /*
  924. =====================
  925. idAI::Event_MoveToCover
  926. =====================
  927. */
  928. void idAI::Event_MoveToCover() {
  929. idActor *enemyEnt = enemy.GetEntity();
  930. StopMove( MOVE_STATUS_DEST_NOT_FOUND );
  931. if ( !enemyEnt || !MoveToCover( enemyEnt, lastVisibleEnemyPos ) ) {
  932. return;
  933. }
  934. }
  935. /*
  936. =====================
  937. idAI::Event_MoveToEnemy
  938. =====================
  939. */
  940. void idAI::Event_MoveToEnemy() {
  941. StopMove( MOVE_STATUS_DEST_NOT_FOUND );
  942. if ( !enemy.GetEntity() || !MoveToEnemy() ) {
  943. return;
  944. }
  945. }
  946. /*
  947. =====================
  948. idAI::Event_MoveToEnemyHeight
  949. =====================
  950. */
  951. void idAI::Event_MoveToEnemyHeight() {
  952. StopMove( MOVE_STATUS_DEST_NOT_FOUND );
  953. MoveToEnemyHeight();
  954. }
  955. /*
  956. =====================
  957. idAI::Event_MoveOutOfRange
  958. =====================
  959. */
  960. void idAI::Event_MoveOutOfRange( idEntity *entity, float range ) {
  961. StopMove( MOVE_STATUS_DEST_NOT_FOUND );
  962. MoveOutOfRange( entity, range );
  963. }
  964. /*
  965. =====================
  966. idAI::Event_MoveToAttackPosition
  967. =====================
  968. */
  969. void idAI::Event_MoveToAttackPosition( idEntity *entity, const char *attack_anim ) {
  970. int anim;
  971. StopMove( MOVE_STATUS_DEST_NOT_FOUND );
  972. anim = GetAnim( ANIMCHANNEL_LEGS, attack_anim );
  973. if ( !anim ) {
  974. gameLocal.Error( "Unknown anim '%s'", attack_anim );
  975. }
  976. MoveToAttackPosition( entity, anim );
  977. }
  978. /*
  979. =====================
  980. idAI::Event_MoveToEntity
  981. =====================
  982. */
  983. void idAI::Event_MoveToEntity( idEntity *ent ) {
  984. StopMove( MOVE_STATUS_DEST_NOT_FOUND );
  985. if ( ent ) {
  986. MoveToEntity( ent );
  987. }
  988. }
  989. /*
  990. =====================
  991. idAI::Event_MoveToPosition
  992. =====================
  993. */
  994. void idAI::Event_MoveToPosition( const idVec3 &pos ) {
  995. StopMove( MOVE_STATUS_DONE );
  996. MoveToPosition( pos );
  997. }
  998. /*
  999. =====================
  1000. idAI::Event_SlideTo
  1001. =====================
  1002. */
  1003. void idAI::Event_SlideTo( const idVec3 &pos, float time ) {
  1004. SlideToPosition( pos, time );
  1005. }
  1006. /*
  1007. =====================
  1008. idAI::Event_Wander
  1009. =====================
  1010. */
  1011. void idAI::Event_Wander() {
  1012. WanderAround();
  1013. }
  1014. /*
  1015. =====================
  1016. idAI::Event_FacingIdeal
  1017. =====================
  1018. */
  1019. void idAI::Event_FacingIdeal() {
  1020. bool facing = FacingIdeal();
  1021. idThread::ReturnInt( facing );
  1022. }
  1023. /*
  1024. =====================
  1025. idAI::Event_FaceEnemy
  1026. =====================
  1027. */
  1028. void idAI::Event_FaceEnemy() {
  1029. FaceEnemy();
  1030. }
  1031. /*
  1032. =====================
  1033. idAI::Event_FaceEntity
  1034. =====================
  1035. */
  1036. void idAI::Event_FaceEntity( idEntity *ent ) {
  1037. FaceEntity( ent );
  1038. }
  1039. /*
  1040. =====================
  1041. idAI::Event_WaitAction
  1042. =====================
  1043. */
  1044. void idAI::Event_WaitAction( const char *waitForState ) {
  1045. if ( idThread::BeginMultiFrameEvent( this, &AI_WaitAction ) ) {
  1046. SetWaitState( waitForState );
  1047. }
  1048. if ( !WaitState() ) {
  1049. idThread::EndMultiFrameEvent( this, &AI_WaitAction );
  1050. }
  1051. }
  1052. /*
  1053. =====================
  1054. idAI::Event_GetCombatNode
  1055. =====================
  1056. */
  1057. void idAI::Event_GetCombatNode() {
  1058. int i;
  1059. float dist;
  1060. idEntity *targetEnt;
  1061. idCombatNode *node;
  1062. float bestDist;
  1063. idCombatNode *bestNode;
  1064. idActor *enemyEnt = enemy.GetEntity();
  1065. if ( !targets.Num() ) {
  1066. // no combat nodes
  1067. idThread::ReturnEntity( NULL );
  1068. return;
  1069. }
  1070. if ( !enemyEnt || !EnemyPositionValid() ) {
  1071. // don't return a combat node if we don't have an enemy or
  1072. // if we can see he's not in the last place we saw him
  1073. if ( team == 0 ) {
  1074. // find the closest attack node to the player
  1075. bestNode = NULL;
  1076. const idVec3 &myPos = physicsObj.GetOrigin();
  1077. const idVec3 &playerPos = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin();
  1078. bestDist = ( myPos - playerPos ).LengthSqr();
  1079. for( i = 0; i < targets.Num(); i++ ) {
  1080. targetEnt = targets[ i ].GetEntity();
  1081. if ( !targetEnt || !targetEnt->IsType( idCombatNode::Type ) ) {
  1082. continue;
  1083. }
  1084. node = static_cast<idCombatNode *>( targetEnt );
  1085. if ( !node->IsDisabled() ) {
  1086. idVec3 org = node->GetPhysics()->GetOrigin();
  1087. dist = ( playerPos - org ).LengthSqr();
  1088. if ( dist < bestDist ) {
  1089. bestNode = node;
  1090. bestDist = dist;
  1091. }
  1092. }
  1093. }
  1094. idThread::ReturnEntity( bestNode );
  1095. return;
  1096. }
  1097. idThread::ReturnEntity( NULL );
  1098. return;
  1099. }
  1100. // find the closest attack node that can see our enemy and is closer than our enemy
  1101. bestNode = NULL;
  1102. const idVec3 &myPos = physicsObj.GetOrigin();
  1103. bestDist = ( myPos - lastVisibleEnemyPos ).LengthSqr();
  1104. for( i = 0; i < targets.Num(); i++ ) {
  1105. targetEnt = targets[ i ].GetEntity();
  1106. if ( !targetEnt || !targetEnt->IsType( idCombatNode::Type ) ) {
  1107. continue;
  1108. }
  1109. node = static_cast<idCombatNode *>( targetEnt );
  1110. if ( !node->IsDisabled() && node->EntityInView( enemyEnt, lastVisibleEnemyPos ) ) {
  1111. idVec3 org = node->GetPhysics()->GetOrigin();
  1112. dist = ( myPos - org ).LengthSqr();
  1113. if ( dist < bestDist ) {
  1114. bestNode = node;
  1115. bestDist = dist;
  1116. }
  1117. }
  1118. }
  1119. idThread::ReturnEntity( bestNode );
  1120. }
  1121. /*
  1122. =====================
  1123. idAI::Event_EnemyInCombatCone
  1124. =====================
  1125. */
  1126. void idAI::Event_EnemyInCombatCone( idEntity *ent, int use_current_enemy_location ) {
  1127. idCombatNode *node;
  1128. bool result;
  1129. idActor *enemyEnt = enemy.GetEntity();
  1130. if ( !targets.Num() ) {
  1131. // no combat nodes
  1132. idThread::ReturnInt( false );
  1133. return;
  1134. }
  1135. if ( !enemyEnt ) {
  1136. // have to have an enemy
  1137. idThread::ReturnInt( false );
  1138. return;
  1139. }
  1140. if ( !ent || !ent->IsType( idCombatNode::Type ) ) {
  1141. // not a combat node
  1142. idThread::ReturnInt( false );
  1143. return;
  1144. }
  1145. //Allow the level designers define attack nodes that the enemy should never leave.
  1146. //This is different that the turrent type combat nodes because they can play an animation
  1147. if(ent->spawnArgs.GetBool("neverLeave", "0")) {
  1148. idThread::ReturnInt( true );
  1149. return;
  1150. }
  1151. node = static_cast<idCombatNode *>( ent );
  1152. if ( use_current_enemy_location ) {
  1153. const idVec3 &pos = enemyEnt->GetPhysics()->GetOrigin();
  1154. result = node->EntityInView( enemyEnt, pos );
  1155. } else {
  1156. result = node->EntityInView( enemyEnt, lastVisibleEnemyPos );
  1157. }
  1158. idThread::ReturnInt( result );
  1159. }
  1160. /*
  1161. =====================
  1162. idAI::Event_WaitMove
  1163. =====================
  1164. */
  1165. void idAI::Event_WaitMove() {
  1166. idThread::BeginMultiFrameEvent( this, &AI_WaitMove );
  1167. if ( MoveDone() ) {
  1168. idThread::EndMultiFrameEvent( this, &AI_WaitMove );
  1169. }
  1170. }
  1171. /*
  1172. =====================
  1173. idAI::Event_GetJumpVelocity
  1174. =====================
  1175. */
  1176. void idAI::Event_GetJumpVelocity( const idVec3 &pos, float speed, float max_height ) {
  1177. idVec3 start;
  1178. idVec3 end;
  1179. idVec3 dir;
  1180. float dist;
  1181. bool result;
  1182. idEntity *enemyEnt = enemy.GetEntity();
  1183. if ( !enemyEnt ) {
  1184. idThread::ReturnVector( vec3_zero );
  1185. return;
  1186. }
  1187. start = physicsObj.GetOrigin();
  1188. end = pos;
  1189. dir = end - start;
  1190. dist = dir.Normalize();
  1191. if ( dist > 16.0f ) {
  1192. dist -= 16.0f;
  1193. end -= dir * 16.0f;
  1194. }
  1195. result = PredictTrajectory( start, end, speed, physicsObj.GetGravity(), physicsObj.GetClipModel(), MASK_MONSTERSOLID, max_height, this, enemyEnt, ai_debugMove.GetBool() ? 4000 : 0, dir );
  1196. if ( result ) {
  1197. idThread::ReturnVector( dir * speed );
  1198. } else {
  1199. idThread::ReturnVector( vec3_zero );
  1200. }
  1201. }
  1202. /*
  1203. =====================
  1204. idAI::Event_EntityInAttackCone
  1205. =====================
  1206. */
  1207. void idAI::Event_EntityInAttackCone( idEntity *ent ) {
  1208. float attack_cone;
  1209. idVec3 delta;
  1210. float yaw;
  1211. float relYaw;
  1212. if ( !ent ) {
  1213. idThread::ReturnInt( false );
  1214. return;
  1215. }
  1216. delta = ent->GetPhysics()->GetOrigin() - GetEyePosition();
  1217. // get our gravity normal
  1218. const idVec3 &gravityDir = GetPhysics()->GetGravityNormal();
  1219. // infinite vertical vision, so project it onto our orientation plane
  1220. delta -= gravityDir * ( gravityDir * delta );
  1221. delta.Normalize();
  1222. yaw = delta.ToYaw();
  1223. attack_cone = spawnArgs.GetFloat( "attack_cone", "70" );
  1224. relYaw = idMath::AngleNormalize180( ideal_yaw - yaw );
  1225. if ( idMath::Fabs( relYaw ) < ( attack_cone * 0.5f ) ) {
  1226. idThread::ReturnInt( true );
  1227. } else {
  1228. idThread::ReturnInt( false );
  1229. }
  1230. }
  1231. /*
  1232. =====================
  1233. idAI::Event_CanSeeEntity
  1234. =====================
  1235. */
  1236. void idAI::Event_CanSeeEntity( idEntity *ent ) {
  1237. if ( !ent ) {
  1238. idThread::ReturnInt( false );
  1239. return;
  1240. }
  1241. bool cansee = CanSee( ent, false );
  1242. idThread::ReturnInt( cansee );
  1243. }
  1244. /*
  1245. =====================
  1246. idAI::Event_SetTalkTarget
  1247. =====================
  1248. */
  1249. void idAI::Event_SetTalkTarget( idEntity *target ) {
  1250. if ( target && !target->IsType( idActor::Type ) ) {
  1251. gameLocal.Error( "Cannot set talk target to '%s'. Not a character or player.", target->GetName() );
  1252. }
  1253. talkTarget = static_cast<idActor *>( target );
  1254. if ( target ) {
  1255. AI_TALK = true;
  1256. } else {
  1257. AI_TALK = false;
  1258. }
  1259. }
  1260. /*
  1261. =====================
  1262. idAI::Event_GetTalkTarget
  1263. =====================
  1264. */
  1265. void idAI::Event_GetTalkTarget() {
  1266. idThread::ReturnEntity( talkTarget.GetEntity() );
  1267. }
  1268. /*
  1269. ================
  1270. idAI::Event_SetTalkState
  1271. ================
  1272. */
  1273. void idAI::Event_SetTalkState( int state ) {
  1274. if ( ( state < 0 ) || ( state >= NUM_TALK_STATES ) ) {
  1275. gameLocal.Error( "Invalid talk state (%d)", state );
  1276. }
  1277. talk_state = static_cast<talkState_t>( state );
  1278. }
  1279. /*
  1280. =====================
  1281. idAI::Event_EnemyRange
  1282. =====================
  1283. */
  1284. void idAI::Event_EnemyRange() {
  1285. float dist;
  1286. idActor *enemyEnt = enemy.GetEntity();
  1287. if ( enemyEnt ) {
  1288. dist = ( enemyEnt->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ).Length();
  1289. } else {
  1290. // Just some really high number
  1291. dist = idMath::INFINITY;
  1292. }
  1293. idThread::ReturnFloat( dist );
  1294. }
  1295. /*
  1296. =====================
  1297. idAI::Event_EnemyRange2D
  1298. =====================
  1299. */
  1300. void idAI::Event_EnemyRange2D() {
  1301. float dist;
  1302. idActor *enemyEnt = enemy.GetEntity();
  1303. if ( enemyEnt ) {
  1304. dist = ( enemyEnt->GetPhysics()->GetOrigin().ToVec2() - GetPhysics()->GetOrigin().ToVec2() ).Length();
  1305. } else {
  1306. // Just some really high number
  1307. dist = idMath::INFINITY;
  1308. }
  1309. idThread::ReturnFloat( dist );
  1310. }
  1311. /*
  1312. =====================
  1313. idAI::Event_GetEnemy
  1314. =====================
  1315. */
  1316. void idAI::Event_GetEnemy() {
  1317. idThread::ReturnEntity( enemy.GetEntity() );
  1318. }
  1319. /*
  1320. =====================
  1321. idAI::Event_GetEnemyPos
  1322. =====================
  1323. */
  1324. void idAI::Event_GetEnemyPos() {
  1325. idThread::ReturnVector( lastVisibleEnemyPos );
  1326. }
  1327. /*
  1328. =====================
  1329. idAI::Event_GetEnemyEyePos
  1330. =====================
  1331. */
  1332. void idAI::Event_GetEnemyEyePos() {
  1333. idThread::ReturnVector( lastVisibleEnemyPos + lastVisibleEnemyEyeOffset );
  1334. }
  1335. /*
  1336. =====================
  1337. idAI::Event_PredictEnemyPos
  1338. =====================
  1339. */
  1340. void idAI::Event_PredictEnemyPos( float time ) {
  1341. predictedPath_t path;
  1342. idActor *enemyEnt = enemy.GetEntity();
  1343. // if no enemy set
  1344. if ( !enemyEnt ) {
  1345. idThread::ReturnVector( physicsObj.GetOrigin() );
  1346. return;
  1347. }
  1348. // predict the enemy movement
  1349. idAI::PredictPath( enemyEnt, aas, lastVisibleEnemyPos, enemyEnt->GetPhysics()->GetLinearVelocity(), SEC2MS( time ), SEC2MS( time ), ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
  1350. idThread::ReturnVector( path.endPos );
  1351. }
  1352. /*
  1353. =====================
  1354. idAI::Event_CanHitEnemy
  1355. =====================
  1356. */
  1357. void idAI::Event_CanHitEnemy() {
  1358. trace_t tr;
  1359. idEntity *hit;
  1360. idActor *enemyEnt = enemy.GetEntity();
  1361. if ( !AI_ENEMY_VISIBLE || !enemyEnt ) {
  1362. idThread::ReturnInt( false );
  1363. return;
  1364. }
  1365. // don't check twice per frame
  1366. if ( gameLocal.time == lastHitCheckTime ) {
  1367. idThread::ReturnInt( lastHitCheckResult );
  1368. return;
  1369. }
  1370. lastHitCheckTime = gameLocal.time;
  1371. idVec3 toPos = enemyEnt->GetEyePosition();
  1372. idVec3 eye = GetEyePosition();
  1373. idVec3 dir;
  1374. // expand the ray out as far as possible so we can detect anything behind the enemy
  1375. dir = toPos - eye;
  1376. dir.Normalize();
  1377. toPos = eye + dir * MAX_WORLD_SIZE;
  1378. gameLocal.clip.TracePoint( tr, eye, toPos, MASK_SHOT_BOUNDINGBOX, this );
  1379. hit = gameLocal.GetTraceEntity( tr );
  1380. if ( tr.fraction >= 1.0f || ( hit == enemyEnt ) ) {
  1381. lastHitCheckResult = true;
  1382. } else if ( ( tr.fraction < 1.0f ) && ( hit->IsType( idAI::Type ) ) &&
  1383. ( static_cast<idAI *>( hit )->team != team ) ) {
  1384. lastHitCheckResult = true;
  1385. } else {
  1386. lastHitCheckResult = false;
  1387. }
  1388. idThread::ReturnInt( lastHitCheckResult );
  1389. }
  1390. /*
  1391. =====================
  1392. idAI::Event_CanHitEnemyFromAnim
  1393. =====================
  1394. */
  1395. void idAI::Event_CanHitEnemyFromAnim( const char *animname ) {
  1396. int anim;
  1397. idVec3 dir;
  1398. idVec3 local_dir;
  1399. idVec3 fromPos;
  1400. idMat3 axis;
  1401. idVec3 start;
  1402. trace_t tr;
  1403. float distance;
  1404. idActor *enemyEnt = enemy.GetEntity();
  1405. if ( !AI_ENEMY_VISIBLE || !enemyEnt ) {
  1406. idThread::ReturnInt( false );
  1407. return;
  1408. }
  1409. anim = GetAnim( ANIMCHANNEL_LEGS, animname );
  1410. if ( !anim ) {
  1411. idThread::ReturnInt( false );
  1412. return;
  1413. }
  1414. // just do a ray test if close enough
  1415. if ( enemyEnt->GetPhysics()->GetAbsBounds().IntersectsBounds( physicsObj.GetAbsBounds().Expand( 16.0f ) ) ) {
  1416. Event_CanHitEnemy();
  1417. return;
  1418. }
  1419. // calculate the world transform of the launch position
  1420. const idVec3 &org = physicsObj.GetOrigin();
  1421. dir = lastVisibleEnemyPos - org;
  1422. physicsObj.GetGravityAxis().ProjectVector( dir, local_dir );
  1423. local_dir.z = 0.0f;
  1424. local_dir.ToVec2().Normalize();
  1425. axis = local_dir.ToMat3();
  1426. fromPos = physicsObj.GetOrigin() + missileLaunchOffset[ anim ] * axis;
  1427. if ( projectileClipModel == NULL ) {
  1428. CreateProjectileClipModel();
  1429. }
  1430. // check if the owner bounds is bigger than the projectile bounds
  1431. const idBounds &ownerBounds = physicsObj.GetAbsBounds();
  1432. const idBounds &projBounds = projectileClipModel->GetBounds();
  1433. if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
  1434. ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
  1435. ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
  1436. if ( (ownerBounds - projBounds).RayIntersection( org, viewAxis[ 0 ], distance ) ) {
  1437. start = org + distance * viewAxis[ 0 ];
  1438. } else {
  1439. start = ownerBounds.GetCenter();
  1440. }
  1441. } else {
  1442. // projectile bounds bigger than the owner bounds, so just start it from the center
  1443. start = ownerBounds.GetCenter();
  1444. }
  1445. gameLocal.clip.Translation( tr, start, fromPos, projectileClipModel, mat3_identity, MASK_SHOT_RENDERMODEL, this );
  1446. fromPos = tr.endpos;
  1447. if ( GetAimDir( fromPos, enemy.GetEntity(), this, dir ) ) {
  1448. idThread::ReturnInt( true );
  1449. } else {
  1450. idThread::ReturnInt( false );
  1451. }
  1452. }
  1453. /*
  1454. =====================
  1455. idAI::Event_CanHitEnemyFromJoint
  1456. =====================
  1457. */
  1458. void idAI::Event_CanHitEnemyFromJoint( const char *jointname ) {
  1459. trace_t tr;
  1460. idVec3 muzzle;
  1461. idMat3 axis;
  1462. idVec3 start;
  1463. float distance;
  1464. idActor *enemyEnt = enemy.GetEntity();
  1465. if ( !AI_ENEMY_VISIBLE || !enemyEnt ) {
  1466. idThread::ReturnInt( false );
  1467. return;
  1468. }
  1469. // don't check twice per frame
  1470. if ( gameLocal.time == lastHitCheckTime ) {
  1471. idThread::ReturnInt( lastHitCheckResult );
  1472. return;
  1473. }
  1474. lastHitCheckTime = gameLocal.time;
  1475. const idVec3 &org = physicsObj.GetOrigin();
  1476. idVec3 toPos = enemyEnt->GetEyePosition();
  1477. jointHandle_t joint = animator.GetJointHandle( jointname );
  1478. if ( joint == INVALID_JOINT ) {
  1479. gameLocal.Error( "Unknown joint '%s' on %s", jointname, GetEntityDefName() );
  1480. }
  1481. animator.GetJointTransform( joint, gameLocal.time, muzzle, axis );
  1482. muzzle = org + ( muzzle + modelOffset ) * viewAxis * physicsObj.GetGravityAxis();
  1483. if ( projectileClipModel == NULL ) {
  1484. CreateProjectileClipModel();
  1485. }
  1486. // check if the owner bounds is bigger than the projectile bounds
  1487. const idBounds &ownerBounds = physicsObj.GetAbsBounds();
  1488. const idBounds &projBounds = projectileClipModel->GetBounds();
  1489. if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
  1490. ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
  1491. ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
  1492. if ( (ownerBounds - projBounds).RayIntersection( org, viewAxis[ 0 ], distance ) ) {
  1493. start = org + distance * viewAxis[ 0 ];
  1494. } else {
  1495. start = ownerBounds.GetCenter();
  1496. }
  1497. } else {
  1498. // projectile bounds bigger than the owner bounds, so just start it from the center
  1499. start = ownerBounds.GetCenter();
  1500. }
  1501. gameLocal.clip.Translation( tr, start, muzzle, projectileClipModel, mat3_identity, MASK_SHOT_BOUNDINGBOX, this );
  1502. muzzle = tr.endpos;
  1503. gameLocal.clip.Translation( tr, muzzle, toPos, projectileClipModel, mat3_identity, MASK_SHOT_BOUNDINGBOX, this );
  1504. if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == enemyEnt ) ) {
  1505. lastHitCheckResult = true;
  1506. } else {
  1507. lastHitCheckResult = false;
  1508. }
  1509. idThread::ReturnInt( lastHitCheckResult );
  1510. }
  1511. /*
  1512. =====================
  1513. idAI::Event_EnemyPositionValid
  1514. =====================
  1515. */
  1516. void idAI::Event_EnemyPositionValid() {
  1517. bool result;
  1518. result = EnemyPositionValid();
  1519. idThread::ReturnInt( result );
  1520. }
  1521. /*
  1522. =====================
  1523. idAI::Event_ChargeAttack
  1524. =====================
  1525. */
  1526. void idAI::Event_ChargeAttack( const char *damageDef ) {
  1527. idActor *enemyEnt = enemy.GetEntity();
  1528. StopMove( MOVE_STATUS_DEST_NOT_FOUND );
  1529. if ( enemyEnt ) {
  1530. idVec3 enemyOrg;
  1531. if ( move.moveType == MOVETYPE_FLY ) {
  1532. // position destination so that we're in the enemy's view
  1533. enemyOrg = enemyEnt->GetEyePosition();
  1534. enemyOrg -= enemyEnt->GetPhysics()->GetGravityNormal() * fly_offset;
  1535. } else {
  1536. enemyOrg = enemyEnt->GetPhysics()->GetOrigin();
  1537. }
  1538. BeginAttack( damageDef );
  1539. DirectMoveToPosition( enemyOrg );
  1540. TurnToward( enemyOrg );
  1541. }
  1542. }
  1543. /*
  1544. =====================
  1545. idAI::Event_TestChargeAttack
  1546. =====================
  1547. */
  1548. void idAI::Event_TestChargeAttack() {
  1549. trace_t trace;
  1550. idActor *enemyEnt = enemy.GetEntity();
  1551. predictedPath_t path;
  1552. idVec3 end;
  1553. if ( !enemyEnt ) {
  1554. idThread::ReturnFloat( 0.0f );
  1555. return;
  1556. }
  1557. if ( move.moveType == MOVETYPE_FLY ) {
  1558. // position destination so that we're in the enemy's view
  1559. end = enemyEnt->GetEyePosition();
  1560. end -= enemyEnt->GetPhysics()->GetGravityNormal() * fly_offset;
  1561. } else {
  1562. end = enemyEnt->GetPhysics()->GetOrigin();
  1563. }
  1564. idAI::PredictPath( this, aas, physicsObj.GetOrigin(), end - physicsObj.GetOrigin(), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
  1565. if ( ai_debugMove.GetBool() ) {
  1566. gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), end, 1 );
  1567. gameRenderWorld->DebugBounds( path.endEvent == 0 ? colorYellow : colorRed, physicsObj.GetBounds(), end, 1 );
  1568. }
  1569. if ( ( path.endEvent == 0 ) || ( path.blockingEntity == enemyEnt ) ) {
  1570. idVec3 delta = end - physicsObj.GetOrigin();
  1571. float time = delta.LengthFast();
  1572. idThread::ReturnFloat( time );
  1573. } else {
  1574. idThread::ReturnFloat( 0.0f );
  1575. }
  1576. }
  1577. /*
  1578. =====================
  1579. idAI::Event_TestAnimMoveTowardEnemy
  1580. =====================
  1581. */
  1582. void idAI::Event_TestAnimMoveTowardEnemy( const char *animname ) {
  1583. int anim;
  1584. predictedPath_t path;
  1585. idVec3 moveVec;
  1586. float yaw;
  1587. idVec3 delta;
  1588. idActor *enemyEnt;
  1589. enemyEnt = enemy.GetEntity();
  1590. if ( !enemyEnt ) {
  1591. idThread::ReturnInt( false );
  1592. return;
  1593. }
  1594. anim = GetAnim( ANIMCHANNEL_LEGS, animname );
  1595. if ( !anim ) {
  1596. gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  1597. idThread::ReturnInt( false );
  1598. return;
  1599. }
  1600. delta = enemyEnt->GetPhysics()->GetOrigin() - physicsObj.GetOrigin();
  1601. yaw = delta.ToYaw();
  1602. moveVec = animator.TotalMovementDelta( anim ) * idAngles( 0.0f, yaw, 0.0f ).ToMat3() * physicsObj.GetGravityAxis();
  1603. idAI::PredictPath( this, aas, physicsObj.GetOrigin(), moveVec, 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
  1604. if ( ai_debugMove.GetBool() ) {
  1605. gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), physicsObj.GetOrigin() + moveVec, 1 );
  1606. gameRenderWorld->DebugBounds( path.endEvent == 0 ? colorYellow : colorRed, physicsObj.GetBounds(), physicsObj.GetOrigin() + moveVec, 1 );
  1607. }
  1608. idThread::ReturnInt( path.endEvent == 0 );
  1609. }
  1610. /*
  1611. =====================
  1612. idAI::Event_TestAnimMove
  1613. =====================
  1614. */
  1615. void idAI::Event_TestAnimMove( const char *animname ) {
  1616. int anim;
  1617. predictedPath_t path;
  1618. idVec3 moveVec;
  1619. anim = GetAnim( ANIMCHANNEL_LEGS, animname );
  1620. if ( !anim ) {
  1621. gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  1622. idThread::ReturnInt( false );
  1623. return;
  1624. }
  1625. moveVec = animator.TotalMovementDelta( anim ) * idAngles( 0.0f, ideal_yaw, 0.0f ).ToMat3() * physicsObj.GetGravityAxis();
  1626. idAI::PredictPath( this, aas, physicsObj.GetOrigin(), moveVec, 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
  1627. if ( ai_debugMove.GetBool() ) {
  1628. gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), physicsObj.GetOrigin() + moveVec, 1 );
  1629. gameRenderWorld->DebugBounds( path.endEvent == 0 ? colorYellow : colorRed, physicsObj.GetBounds(), physicsObj.GetOrigin() + moveVec, 1 );
  1630. }
  1631. idThread::ReturnInt( path.endEvent == 0 );
  1632. }
  1633. /*
  1634. =====================
  1635. idAI::Event_TestMoveToPosition
  1636. =====================
  1637. */
  1638. void idAI::Event_TestMoveToPosition( const idVec3 &position ) {
  1639. predictedPath_t path;
  1640. idAI::PredictPath( this, aas, physicsObj.GetOrigin(), position - physicsObj.GetOrigin(), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
  1641. if ( ai_debugMove.GetBool() ) {
  1642. gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), position, 1 );
  1643. gameRenderWorld->DebugBounds( colorYellow, physicsObj.GetBounds(), position, 1 );
  1644. if ( path.endEvent ) {
  1645. gameRenderWorld->DebugBounds( colorRed, physicsObj.GetBounds(), path.endPos, 1 );
  1646. }
  1647. }
  1648. idThread::ReturnInt( path.endEvent == 0 );
  1649. }
  1650. /*
  1651. =====================
  1652. idAI::Event_TestMeleeAttack
  1653. =====================
  1654. */
  1655. void idAI::Event_TestMeleeAttack() {
  1656. bool result = TestMelee();
  1657. idThread::ReturnInt( result );
  1658. }
  1659. /*
  1660. =====================
  1661. idAI::Event_TestAnimAttack
  1662. =====================
  1663. */
  1664. void idAI::Event_TestAnimAttack( const char *animname ) {
  1665. int anim;
  1666. predictedPath_t path;
  1667. anim = GetAnim( ANIMCHANNEL_LEGS, animname );
  1668. if ( !anim ) {
  1669. gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  1670. idThread::ReturnInt( false );
  1671. return;
  1672. }
  1673. idAI::PredictPath( this, aas, physicsObj.GetOrigin(), animator.TotalMovementDelta( anim ), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path );
  1674. idThread::ReturnInt( path.blockingEntity && ( path.blockingEntity == enemy.GetEntity() ) );
  1675. }
  1676. /*
  1677. =====================
  1678. idAI::Event_PreBurn
  1679. =====================
  1680. */
  1681. void idAI::Event_PreBurn() {
  1682. // No grabbing after the burn has started!
  1683. noGrab = true;
  1684. // for now this just turns shadows off
  1685. renderEntity.noShadow = true;
  1686. }
  1687. /*
  1688. =====================
  1689. idAI::Event_Burn
  1690. =====================
  1691. */
  1692. void idAI::Event_Burn() {
  1693. renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  1694. SpawnParticles( "smoke_burnParticleSystem" );
  1695. UpdateVisuals();
  1696. }
  1697. /*
  1698. =====================
  1699. idAI::Event_ClearBurn
  1700. =====================
  1701. */
  1702. void idAI::Event_ClearBurn() {
  1703. renderEntity.noShadow = spawnArgs.GetBool( "noshadows" );
  1704. renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = 0.0f;
  1705. UpdateVisuals();
  1706. }
  1707. /*
  1708. =====================
  1709. idAI::Event_SetSmokeVisibility
  1710. =====================
  1711. */
  1712. void idAI::Event_SetSmokeVisibility( int num, int on ) {
  1713. int i;
  1714. int time;
  1715. if ( num >= particles.Num() ) {
  1716. gameLocal.Warning( "Particle #%d out of range (%d particles) on entity '%s'", num, particles.Num(), name.c_str() );
  1717. return;
  1718. }
  1719. if ( on != 0 ) {
  1720. time = gameLocal.time;
  1721. BecomeActive( TH_UPDATEPARTICLES );
  1722. } else {
  1723. time = 0;
  1724. }
  1725. if ( num >= 0 ) {
  1726. particles[ num ].time = time;
  1727. } else {
  1728. for ( i = 0; i < particles.Num(); i++ ) {
  1729. particles[ i ].time = time;
  1730. }
  1731. }
  1732. UpdateVisuals();
  1733. }
  1734. /*
  1735. =====================
  1736. idAI::Event_NumSmokeEmitters
  1737. =====================
  1738. */
  1739. void idAI::Event_NumSmokeEmitters() {
  1740. idThread::ReturnInt( particles.Num() );
  1741. }
  1742. /*
  1743. =====================
  1744. idAI::Event_StopThinking
  1745. =====================
  1746. */
  1747. void idAI::Event_StopThinking() {
  1748. BecomeInactive( TH_THINK );
  1749. idThread *thread = idThread::CurrentThread();
  1750. if ( thread ) {
  1751. thread->DoneProcessing();
  1752. }
  1753. }
  1754. /*
  1755. =====================
  1756. idAI::Event_GetTurnDelta
  1757. =====================
  1758. */
  1759. void idAI::Event_GetTurnDelta() {
  1760. float amount;
  1761. if ( turnRate ) {
  1762. amount = idMath::AngleNormalize180( ideal_yaw - current_yaw );
  1763. idThread::ReturnFloat( amount );
  1764. } else {
  1765. idThread::ReturnFloat( 0.0f );
  1766. }
  1767. }
  1768. /*
  1769. =====================
  1770. idAI::Event_GetMoveType
  1771. =====================
  1772. */
  1773. void idAI::Event_GetMoveType() {
  1774. idThread::ReturnInt( move.moveType );
  1775. }
  1776. /*
  1777. =====================
  1778. idAI::Event_SetMoveTypes
  1779. =====================
  1780. */
  1781. void idAI::Event_SetMoveType( int moveType ) {
  1782. if ( ( moveType < 0 ) || ( moveType >= NUM_MOVETYPES ) ) {
  1783. gameLocal.Error( "Invalid movetype %d", moveType );
  1784. }
  1785. move.moveType = static_cast<moveType_t>( moveType );
  1786. if ( move.moveType == MOVETYPE_FLY ) {
  1787. travelFlags = TFL_WALK|TFL_AIR|TFL_FLY;
  1788. } else {
  1789. travelFlags = TFL_WALK|TFL_AIR;
  1790. }
  1791. }
  1792. /*
  1793. =====================
  1794. idAI::Event_SaveMove
  1795. =====================
  1796. */
  1797. void idAI::Event_SaveMove() {
  1798. savedMove = move;
  1799. }
  1800. /*
  1801. =====================
  1802. idAI::Event_RestoreMove
  1803. =====================
  1804. */
  1805. void idAI::Event_RestoreMove() {
  1806. idVec3 goalPos;
  1807. idVec3 dest;
  1808. switch( savedMove.moveCommand ) {
  1809. case MOVE_NONE :
  1810. StopMove( savedMove.moveStatus );
  1811. break;
  1812. case MOVE_FACE_ENEMY :
  1813. FaceEnemy();
  1814. break;
  1815. case MOVE_FACE_ENTITY :
  1816. FaceEntity( savedMove.goalEntity.GetEntity() );
  1817. break;
  1818. case MOVE_TO_ENEMY :
  1819. MoveToEnemy();
  1820. break;
  1821. case MOVE_TO_ENEMYHEIGHT :
  1822. MoveToEnemyHeight();
  1823. break;
  1824. case MOVE_TO_ENTITY :
  1825. MoveToEntity( savedMove.goalEntity.GetEntity() );
  1826. break;
  1827. case MOVE_OUT_OF_RANGE :
  1828. MoveOutOfRange( savedMove.goalEntity.GetEntity(), savedMove.range );
  1829. break;
  1830. case MOVE_TO_ATTACK_POSITION :
  1831. MoveToAttackPosition( savedMove.goalEntity.GetEntity(), savedMove.anim );
  1832. break;
  1833. case MOVE_TO_COVER :
  1834. MoveToCover( savedMove.goalEntity.GetEntity(), lastVisibleEnemyPos );
  1835. break;
  1836. case MOVE_TO_POSITION :
  1837. MoveToPosition( savedMove.moveDest );
  1838. break;
  1839. case MOVE_TO_POSITION_DIRECT :
  1840. DirectMoveToPosition( savedMove.moveDest );
  1841. break;
  1842. case MOVE_SLIDE_TO_POSITION :
  1843. SlideToPosition( savedMove.moveDest, savedMove.duration );
  1844. break;
  1845. case MOVE_WANDER :
  1846. WanderAround();
  1847. break;
  1848. }
  1849. if ( GetMovePos( goalPos ) ) {
  1850. CheckObstacleAvoidance( goalPos, dest );
  1851. }
  1852. }
  1853. /*
  1854. =====================
  1855. idAI::Event_AllowMovement
  1856. =====================
  1857. */
  1858. void idAI::Event_AllowMovement( float flag ) {
  1859. allowMove = ( flag != 0.0f );
  1860. }
  1861. /*
  1862. =====================
  1863. idAI::Event_JumpFrame
  1864. =====================
  1865. */
  1866. void idAI::Event_JumpFrame() {
  1867. AI_JUMP = true;
  1868. }
  1869. /*
  1870. =====================
  1871. idAI::Event_EnableClip
  1872. =====================
  1873. */
  1874. void idAI::Event_EnableClip() {
  1875. physicsObj.SetClipMask( MASK_MONSTERSOLID );
  1876. disableGravity = false;
  1877. }
  1878. /*
  1879. =====================
  1880. idAI::Event_DisableClip
  1881. =====================
  1882. */
  1883. void idAI::Event_DisableClip() {
  1884. physicsObj.SetClipMask( 0 );
  1885. disableGravity = true;
  1886. }
  1887. /*
  1888. =====================
  1889. idAI::Event_EnableGravity
  1890. =====================
  1891. */
  1892. void idAI::Event_EnableGravity() {
  1893. disableGravity = false;
  1894. }
  1895. /*
  1896. =====================
  1897. idAI::Event_DisableGravity
  1898. =====================
  1899. */
  1900. void idAI::Event_DisableGravity() {
  1901. disableGravity = true;
  1902. }
  1903. /*
  1904. =====================
  1905. idAI::Event_EnableAFPush
  1906. =====================
  1907. */
  1908. void idAI::Event_EnableAFPush() {
  1909. af_push_moveables = true;
  1910. }
  1911. /*
  1912. =====================
  1913. idAI::Event_DisableAFPush
  1914. =====================
  1915. */
  1916. void idAI::Event_DisableAFPush() {
  1917. af_push_moveables = false;
  1918. }
  1919. /*
  1920. =====================
  1921. idAI::Event_SetFlySpeed
  1922. =====================
  1923. */
  1924. void idAI::Event_SetFlySpeed( float speed ) {
  1925. if ( move.speed == fly_speed ) {
  1926. move.speed = speed;
  1927. }
  1928. fly_speed = speed;
  1929. }
  1930. /*
  1931. ================
  1932. idAI::Event_SetFlyOffset
  1933. ================
  1934. */
  1935. void idAI::Event_SetFlyOffset( int offset ) {
  1936. fly_offset = offset;
  1937. }
  1938. /*
  1939. ================
  1940. idAI::Event_ClearFlyOffset
  1941. ================
  1942. */
  1943. void idAI::Event_ClearFlyOffset() {
  1944. spawnArgs.GetInt( "fly_offset", "0", fly_offset );
  1945. }
  1946. /*
  1947. =====================
  1948. idAI::Event_GetClosestHiddenTarget
  1949. =====================
  1950. */
  1951. void idAI::Event_GetClosestHiddenTarget( const char *type ) {
  1952. int i;
  1953. idEntity *ent;
  1954. idEntity *bestEnt;
  1955. float time;
  1956. float bestTime;
  1957. const idVec3 &org = physicsObj.GetOrigin();
  1958. idActor *enemyEnt = enemy.GetEntity();
  1959. if ( !enemyEnt ) {
  1960. // no enemy to hide from
  1961. idThread::ReturnEntity( NULL );
  1962. return;
  1963. }
  1964. if ( targets.Num() == 1 ) {
  1965. ent = targets[ 0 ].GetEntity();
  1966. if ( ent != NULL && idStr::Cmp( ent->GetEntityDefName(), type ) == 0 ) {
  1967. if ( !EntityCanSeePos( enemyEnt, lastVisibleEnemyPos, ent->GetPhysics()->GetOrigin() ) ) {
  1968. idThread::ReturnEntity( ent );
  1969. return;
  1970. }
  1971. }
  1972. idThread::ReturnEntity( NULL );
  1973. return;
  1974. }
  1975. bestEnt = NULL;
  1976. bestTime = idMath::INFINITY;
  1977. for( i = 0; i < targets.Num(); i++ ) {
  1978. ent = targets[ i ].GetEntity();
  1979. if ( ent != NULL && idStr::Cmp( ent->GetEntityDefName(), type ) == 0 ) {
  1980. const idVec3 &destOrg = ent->GetPhysics()->GetOrigin();
  1981. time = TravelDistance( org, destOrg );
  1982. if ( ( time >= 0.0f ) && ( time < bestTime ) ) {
  1983. if ( !EntityCanSeePos( enemyEnt, lastVisibleEnemyPos, destOrg ) ) {
  1984. bestEnt = ent;
  1985. bestTime = time;
  1986. }
  1987. }
  1988. }
  1989. }
  1990. idThread::ReturnEntity( bestEnt );
  1991. }
  1992. /*
  1993. =====================
  1994. idAI::Event_GetRandomTarget
  1995. =====================
  1996. */
  1997. void idAI::Event_GetRandomTarget( const char *type ) {
  1998. int i;
  1999. int num;
  2000. int which;
  2001. idEntity *ent;
  2002. idEntity *ents[ MAX_GENTITIES ];
  2003. num = 0;
  2004. for( i = 0; i < targets.Num(); i++ ) {
  2005. ent = targets[ i ].GetEntity();
  2006. if ( ent != NULL && idStr::Cmp( ent->GetEntityDefName(), type ) == 0 ) {
  2007. ents[ num++ ] = ent;
  2008. if ( num >= MAX_GENTITIES ) {
  2009. break;
  2010. }
  2011. }
  2012. }
  2013. if ( !num ) {
  2014. idThread::ReturnEntity( NULL );
  2015. return;
  2016. }
  2017. which = gameLocal.random.RandomInt( num );
  2018. idThread::ReturnEntity( ents[ which ] );
  2019. }
  2020. /*
  2021. ================
  2022. idAI::Event_TravelDistanceToPoint
  2023. ================
  2024. */
  2025. void idAI::Event_TravelDistanceToPoint( const idVec3 &pos ) {
  2026. float time;
  2027. time = TravelDistance( physicsObj.GetOrigin(), pos );
  2028. idThread::ReturnFloat( time );
  2029. }
  2030. /*
  2031. ================
  2032. idAI::Event_TravelDistanceToEntity
  2033. ================
  2034. */
  2035. void idAI::Event_TravelDistanceToEntity( idEntity *ent ) {
  2036. float time;
  2037. time = TravelDistance( physicsObj.GetOrigin(), ent->GetPhysics()->GetOrigin() );
  2038. idThread::ReturnFloat( time );
  2039. }
  2040. /*
  2041. ================
  2042. idAI::Event_TravelDistanceBetweenPoints
  2043. ================
  2044. */
  2045. void idAI::Event_TravelDistanceBetweenPoints( const idVec3 &source, const idVec3 &dest ) {
  2046. float time;
  2047. time = TravelDistance( source, dest );
  2048. idThread::ReturnFloat( time );
  2049. }
  2050. /*
  2051. ================
  2052. idAI::Event_TravelDistanceBetweenEntities
  2053. ================
  2054. */
  2055. void idAI::Event_TravelDistanceBetweenEntities( idEntity *source, idEntity *dest ) {
  2056. float time;
  2057. assert( source );
  2058. assert( dest );
  2059. time = TravelDistance( source->GetPhysics()->GetOrigin(), dest->GetPhysics()->GetOrigin() );
  2060. idThread::ReturnFloat( time );
  2061. }
  2062. /*
  2063. =====================
  2064. idAI::Event_LookAtEntity
  2065. =====================
  2066. */
  2067. void idAI::Event_LookAtEntity( idEntity *ent, float duration ) {
  2068. if ( ent == this ) {
  2069. ent = NULL;
  2070. }
  2071. if ( ( ent != focusEntity.GetEntity() ) || ( focusTime < gameLocal.time ) ) {
  2072. focusEntity = ent;
  2073. alignHeadTime = gameLocal.time;
  2074. forceAlignHeadTime = gameLocal.time + SEC2MS( 1 );
  2075. blink_time = 0;
  2076. }
  2077. focusTime = gameLocal.time + SEC2MS( duration );
  2078. }
  2079. /*
  2080. =====================
  2081. idAI::Event_LookAtEnemy
  2082. =====================
  2083. */
  2084. void idAI::Event_LookAtEnemy( float duration ) {
  2085. idActor *enemyEnt;
  2086. enemyEnt = enemy.GetEntity();
  2087. if ( ( enemyEnt != focusEntity.GetEntity() ) || ( focusTime < gameLocal.time ) ) {
  2088. focusEntity = enemyEnt;
  2089. alignHeadTime = gameLocal.time;
  2090. forceAlignHeadTime = gameLocal.time + SEC2MS( 1 );
  2091. blink_time = 0;
  2092. }
  2093. focusTime = gameLocal.time + SEC2MS( duration );
  2094. }
  2095. /*
  2096. ===============
  2097. idAI::Event_SetJointMod
  2098. ===============
  2099. */
  2100. void idAI::Event_SetJointMod( int allow ) {
  2101. allowJointMod = ( allow != 0 );
  2102. }
  2103. /*
  2104. ================
  2105. idAI::Event_ThrowMoveable
  2106. ================
  2107. */
  2108. void idAI::Event_ThrowMoveable() {
  2109. idEntity *ent;
  2110. idEntity *moveable = NULL;
  2111. for ( ent = GetNextTeamEntity(); ent != NULL; ent = ent->GetNextTeamEntity() ) {
  2112. if ( ent->GetBindMaster() == this && ent->IsType( idMoveable::Type ) ) {
  2113. moveable = ent;
  2114. break;
  2115. }
  2116. }
  2117. if ( moveable ) {
  2118. moveable->Unbind();
  2119. moveable->PostEventMS( &EV_SetOwner, 200, NULL );
  2120. }
  2121. }
  2122. /*
  2123. ================
  2124. idAI::Event_ThrowAF
  2125. ================
  2126. */
  2127. void idAI::Event_ThrowAF() {
  2128. idEntity *ent;
  2129. idEntity *af = NULL;
  2130. for ( ent = GetNextTeamEntity(); ent != NULL; ent = ent->GetNextTeamEntity() ) {
  2131. if ( ent->GetBindMaster() == this && ent->IsType( idAFEntity_Base::Type ) ) {
  2132. af = ent;
  2133. break;
  2134. }
  2135. }
  2136. if ( af ) {
  2137. af->Unbind();
  2138. af->PostEventMS( &EV_SetOwner, 200, NULL );
  2139. }
  2140. }
  2141. /*
  2142. ================
  2143. idAI::Event_SetAngles
  2144. ================
  2145. */
  2146. void idAI::Event_SetAngles( idAngles const &ang ) {
  2147. current_yaw = ang.yaw;
  2148. viewAxis = idAngles( 0, current_yaw, 0 ).ToMat3();
  2149. }
  2150. /*
  2151. ================
  2152. idAI::Event_GetAngles
  2153. ================
  2154. */
  2155. void idAI::Event_GetAngles() {
  2156. idThread::ReturnVector( idVec3( 0.0f, current_yaw, 0.0f ) );
  2157. }
  2158. /*
  2159. ================
  2160. idAI::Event_GetTrajectoryToPlayer
  2161. ================
  2162. */
  2163. void idAI::Event_GetTrajectoryToPlayer() {
  2164. idVec3 start;
  2165. idVec3 end;
  2166. idVec3 dir;
  2167. float dist;
  2168. // bool result;
  2169. idEntity *enemyEnt = enemy.GetEntity();
  2170. if ( !enemyEnt ) {
  2171. idThread::ReturnVector( vec3_zero );
  2172. return;
  2173. }
  2174. end = enemyEnt->GetPhysics()->GetOrigin();
  2175. float speed = 400.0f;
  2176. if ( speed <= 0.0f ) {
  2177. gameLocal.Error( "Invalid speed. speed must be > 0." );
  2178. }
  2179. start = physicsObj.GetOrigin() + idVec3( 0.0f, 0.0f, 50.0f );
  2180. dir = end - start;
  2181. dist = dir.Normalize();
  2182. if ( dist > 16.0f ) {
  2183. dist -= 16.0f;
  2184. end -= dir * 16.0f;
  2185. }
  2186. idVec3 gravity;
  2187. ballistics_t ballistics[2];
  2188. Ballistics( start, end, speed, 0.0f, ballistics );
  2189. dir.y = ballistics[0].angle;
  2190. // result = PredictTrajectory( start, end, speed, physicsObj.GetGravity(), physicsObj.GetClipModel(), MASK_MONSTERSOLID, 1000.0f, this, enemyEnt, ai_debugMove.GetBool() ? 4000 : 0, dir );
  2191. // if ( result ) {
  2192. idThread::ReturnVector( dir * speed );
  2193. // } else {
  2194. // idThread::ReturnVector( vec3_zero );
  2195. // }
  2196. }
  2197. /*
  2198. ================
  2199. idAI::Event_RealKill
  2200. ================
  2201. */
  2202. void idAI::Event_RealKill() {
  2203. health = 0;
  2204. if ( af.IsLoaded() ) {
  2205. // clear impacts
  2206. af.Rest();
  2207. // physics is turned off by calling af.Rest()
  2208. BecomeActive( TH_PHYSICS );
  2209. }
  2210. Killed( this, this, 0, vec3_zero, INVALID_JOINT );
  2211. }
  2212. /*
  2213. ================
  2214. idAI::Event_Kill
  2215. ================
  2216. */
  2217. void idAI::Event_Kill() {
  2218. PostEventMS( &AI_RealKill, 0 );
  2219. }
  2220. /*
  2221. ================
  2222. idAI::Event_WakeOnFlashlight
  2223. ================
  2224. */
  2225. void idAI::Event_WakeOnFlashlight( int enable ) {
  2226. wakeOnFlashlight = ( enable != 0 );
  2227. }
  2228. /*
  2229. ================
  2230. idAI::Event_LocateEnemy
  2231. ================
  2232. */
  2233. void idAI::Event_LocateEnemy() {
  2234. idActor *enemyEnt;
  2235. int areaNum;
  2236. enemyEnt = enemy.GetEntity();
  2237. if ( !enemyEnt ) {
  2238. return;
  2239. }
  2240. enemyEnt->GetAASLocation( aas, lastReachableEnemyPos, areaNum );
  2241. SetEnemyPosition();
  2242. UpdateEnemyPosition();
  2243. }
  2244. /*
  2245. ================
  2246. idAI::Event_KickObstacles
  2247. ================
  2248. */
  2249. void idAI::Event_KickObstacles( idEntity *kickEnt, float force ) {
  2250. idVec3 dir;
  2251. idEntity *obEnt;
  2252. if ( kickEnt ) {
  2253. obEnt = kickEnt;
  2254. } else {
  2255. obEnt = move.obstacle.GetEntity();
  2256. }
  2257. if ( obEnt ) {
  2258. dir = obEnt->GetPhysics()->GetOrigin() - physicsObj.GetOrigin();
  2259. dir.Normalize();
  2260. } else {
  2261. dir = viewAxis[ 0 ];
  2262. }
  2263. KickObstacles( dir, force, obEnt );
  2264. }
  2265. /*
  2266. ================
  2267. idAI::Event_GetObstacle
  2268. ================
  2269. */
  2270. void idAI::Event_GetObstacle() {
  2271. idThread::ReturnEntity( move.obstacle.GetEntity() );
  2272. }
  2273. /*
  2274. ================
  2275. idAI::Event_PushPointIntoAAS
  2276. ================
  2277. */
  2278. void idAI::Event_PushPointIntoAAS( const idVec3 &pos ) {
  2279. int areaNum;
  2280. idVec3 newPos;
  2281. areaNum = PointReachableAreaNum( pos );
  2282. if ( areaNum ) {
  2283. newPos = pos;
  2284. aas->PushPointIntoAreaNum( areaNum, newPos );
  2285. idThread::ReturnVector( newPos );
  2286. } else {
  2287. idThread::ReturnVector( pos );
  2288. }
  2289. }
  2290. /*
  2291. ================
  2292. idAI::Event_GetTurnRate
  2293. ================
  2294. */
  2295. void idAI::Event_GetTurnRate() {
  2296. idThread::ReturnFloat( turnRate );
  2297. }
  2298. /*
  2299. ================
  2300. idAI::Event_SetTurnRate
  2301. ================
  2302. */
  2303. void idAI::Event_SetTurnRate( float rate ) {
  2304. turnRate = rate;
  2305. }
  2306. /*
  2307. ================
  2308. idAI::Event_AnimTurn
  2309. ================
  2310. */
  2311. void idAI::Event_AnimTurn( float angles ) {
  2312. turnVel = 0.0f;
  2313. anim_turn_angles = angles;
  2314. if ( angles ) {
  2315. anim_turn_yaw = current_yaw;
  2316. anim_turn_amount = idMath::Fabs( idMath::AngleNormalize180( current_yaw - ideal_yaw ) );
  2317. if ( anim_turn_amount > anim_turn_angles ) {
  2318. anim_turn_amount = anim_turn_angles;
  2319. }
  2320. } else {
  2321. anim_turn_amount = 0.0f;
  2322. animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 0, 1.0f );
  2323. animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 1, 0.0f );
  2324. animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 0, 1.0f );
  2325. animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 1, 0.0f );
  2326. }
  2327. }
  2328. /*
  2329. ================
  2330. idAI::Event_AllowHiddenMovement
  2331. ================
  2332. */
  2333. void idAI::Event_AllowHiddenMovement( int enable ) {
  2334. allowHiddenMovement = ( enable != 0 );
  2335. }
  2336. /*
  2337. ================
  2338. idAI::Event_TriggerParticles
  2339. ================
  2340. */
  2341. void idAI::Event_TriggerParticles( const char *jointName ) {
  2342. TriggerParticles( jointName );
  2343. }
  2344. /*
  2345. =====================
  2346. idAI::Event_FindActorsInBounds
  2347. =====================
  2348. */
  2349. void idAI::Event_FindActorsInBounds( const idVec3 &mins, const idVec3 &maxs ) {
  2350. idEntity * ent;
  2351. idEntity * entityList[ MAX_GENTITIES ];
  2352. int numListedEntities;
  2353. int i;
  2354. numListedEntities = gameLocal.clip.EntitiesTouchingBounds( idBounds( mins, maxs ), CONTENTS_BODY, entityList, MAX_GENTITIES );
  2355. for( i = 0; i < numListedEntities; i++ ) {
  2356. ent = entityList[ i ];
  2357. if ( ent != this && !ent->IsHidden() && ( ent->health > 0 ) && ent->IsType( idActor::Type ) ) {
  2358. idThread::ReturnEntity( ent );
  2359. return;
  2360. }
  2361. }
  2362. idThread::ReturnEntity( NULL );
  2363. }
  2364. /*
  2365. ================
  2366. idAI::Event_CanReachPosition
  2367. ================
  2368. */
  2369. void idAI::Event_CanReachPosition( const idVec3 &pos ) {
  2370. aasPath_t path;
  2371. int toAreaNum;
  2372. int areaNum;
  2373. toAreaNum = PointReachableAreaNum( pos );
  2374. areaNum = PointReachableAreaNum( physicsObj.GetOrigin() );
  2375. if ( !toAreaNum || !PathToGoal( path, areaNum, physicsObj.GetOrigin(), toAreaNum, pos ) ) {
  2376. idThread::ReturnInt( false );
  2377. } else {
  2378. idThread::ReturnInt( true );
  2379. }
  2380. }
  2381. /*
  2382. ================
  2383. idAI::Event_CanReachEntity
  2384. ================
  2385. */
  2386. void idAI::Event_CanReachEntity( idEntity *ent ) {
  2387. aasPath_t path;
  2388. int toAreaNum;
  2389. int areaNum;
  2390. idVec3 pos;
  2391. if ( !ent ) {
  2392. idThread::ReturnInt( false );
  2393. return;
  2394. }
  2395. if ( move.moveType != MOVETYPE_FLY ) {
  2396. if ( !ent->GetFloorPos( 64.0f, pos ) ) {
  2397. idThread::ReturnInt( false );
  2398. return;
  2399. }
  2400. if ( ent->IsType( idActor::Type ) && static_cast<idActor *>( ent )->OnLadder() ) {
  2401. idThread::ReturnInt( false );
  2402. return;
  2403. }
  2404. } else {
  2405. pos = ent->GetPhysics()->GetOrigin();
  2406. }
  2407. toAreaNum = PointReachableAreaNum( pos );
  2408. if ( !toAreaNum ) {
  2409. idThread::ReturnInt( false );
  2410. return;
  2411. }
  2412. const idVec3 &org = physicsObj.GetOrigin();
  2413. areaNum = PointReachableAreaNum( org );
  2414. if ( !toAreaNum || !PathToGoal( path, areaNum, org, toAreaNum, pos ) ) {
  2415. idThread::ReturnInt( false );
  2416. } else {
  2417. idThread::ReturnInt( true );
  2418. }
  2419. }
  2420. /*
  2421. ================
  2422. idAI::Event_CanReachEnemy
  2423. ================
  2424. */
  2425. void idAI::Event_CanReachEnemy() {
  2426. aasPath_t path;
  2427. int toAreaNum;
  2428. int areaNum;
  2429. idVec3 pos;
  2430. idActor *enemyEnt;
  2431. enemyEnt = enemy.GetEntity();
  2432. if ( !enemyEnt ) {
  2433. idThread::ReturnInt( false );
  2434. return;
  2435. }
  2436. if ( move.moveType != MOVETYPE_FLY ) {
  2437. if ( enemyEnt->OnLadder() ) {
  2438. idThread::ReturnInt( false );
  2439. return;
  2440. }
  2441. enemyEnt->GetAASLocation( aas, pos, toAreaNum );
  2442. } else {
  2443. pos = enemyEnt->GetPhysics()->GetOrigin();
  2444. toAreaNum = PointReachableAreaNum( pos );
  2445. }
  2446. if ( !toAreaNum ) {
  2447. idThread::ReturnInt( false );
  2448. return;
  2449. }
  2450. const idVec3 &org = physicsObj.GetOrigin();
  2451. areaNum = PointReachableAreaNum( org );
  2452. if ( !PathToGoal( path, areaNum, org, toAreaNum, pos ) ) {
  2453. idThread::ReturnInt( false );
  2454. } else {
  2455. idThread::ReturnInt( true );
  2456. }
  2457. }
  2458. /*
  2459. ================
  2460. idAI::Event_GetReachableEntityPosition
  2461. ================
  2462. */
  2463. void idAI::Event_GetReachableEntityPosition( idEntity *ent ) {
  2464. int toAreaNum;
  2465. idVec3 pos;
  2466. if ( move.moveType != MOVETYPE_FLY ) {
  2467. if ( !ent->GetFloorPos( 64.0f, pos ) ) {
  2468. // NOTE: not a good way to return 'false'
  2469. return idThread::ReturnVector( vec3_zero );
  2470. }
  2471. if ( ent->IsType( idActor::Type ) && static_cast<idActor *>( ent )->OnLadder() ) {
  2472. // NOTE: not a good way to return 'false'
  2473. return idThread::ReturnVector( vec3_zero );
  2474. }
  2475. } else {
  2476. pos = ent->GetPhysics()->GetOrigin();
  2477. }
  2478. if ( aas ) {
  2479. toAreaNum = PointReachableAreaNum( pos );
  2480. aas->PushPointIntoAreaNum( toAreaNum, pos );
  2481. }
  2482. idThread::ReturnVector( pos );
  2483. }
  2484. /*
  2485. ================
  2486. idAI::Event_MoveToPositionDirect
  2487. ================
  2488. */
  2489. void idAI::Event_MoveToPositionDirect( const idVec3 &pos ) {
  2490. StopMove( MOVE_STATUS_DONE );
  2491. DirectMoveToPosition( pos );
  2492. }
  2493. /*
  2494. ================
  2495. idAI::Event_AvoidObstacles
  2496. ================
  2497. */
  2498. void idAI::Event_AvoidObstacles( int ignore) {
  2499. ignore_obstacles = (ignore == 1) ? false : true;
  2500. }
  2501. /*
  2502. ================
  2503. idAI::Event_TriggerFX
  2504. ================
  2505. */
  2506. void idAI::Event_TriggerFX( const char* joint, const char* fx ) {
  2507. TriggerFX(joint, fx);
  2508. }
  2509. void idAI::Event_StartEmitter( const char* name, const char* joint, const char* particle ) {
  2510. idEntity *ent = StartEmitter(name, joint, particle);
  2511. idThread::ReturnEntity(ent);
  2512. }
  2513. void idAI::Event_GetEmitter( const char* name ) {
  2514. idThread::ReturnEntity(GetEmitter(name));
  2515. }
  2516. void idAI::Event_StopEmitter( const char* name ) {
  2517. StopEmitter(name);
  2518. }
  2519. /*
  2520. =====================
  2521. idAI::Event_LaunchHomingMissile
  2522. =====================
  2523. */
  2524. void idAI::Event_LaunchHomingMissile() {
  2525. idVec3 start;
  2526. trace_t tr;
  2527. idBounds projBounds;
  2528. const idClipModel *projClip;
  2529. idMat3 axis;
  2530. float distance;
  2531. if ( !projectileDef ) {
  2532. gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() );
  2533. idThread::ReturnEntity( NULL );
  2534. return;
  2535. }
  2536. idActor *enemy = GetEnemy();
  2537. if ( enemy == NULL ) {
  2538. idThread::ReturnEntity( NULL );
  2539. return;
  2540. }
  2541. idVec3 org = GetPhysics()->GetOrigin() + idVec3( 0.0f, 0.0f, 250.0f );
  2542. idVec3 goal = enemy->GetPhysics()->GetOrigin();
  2543. homingMissileGoal = goal;
  2544. // axis = ( goal - org ).ToMat3();
  2545. // axis.Identity();
  2546. if ( !projectile.GetEntity() ) {
  2547. idHomingProjectile *homing = ( idHomingProjectile * ) CreateProjectile( org, idVec3( 0.0f, 0.0f, 1.0f ) );
  2548. if ( homing != NULL ) {
  2549. homing->SetEnemy( enemy );
  2550. homing->SetSeekPos( homingMissileGoal );
  2551. }
  2552. }
  2553. // make sure the projectile starts inside the monster bounding box
  2554. const idBounds &ownerBounds = physicsObj.GetAbsBounds();
  2555. projClip = projectile.GetEntity()->GetPhysics()->GetClipModel();
  2556. projBounds = projClip->GetBounds().Rotate( projClip->GetAxis() );
  2557. // check if the owner bounds is bigger than the projectile bounds
  2558. if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) &&
  2559. ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) &&
  2560. ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) {
  2561. if ( (ownerBounds - projBounds).RayIntersection( org, viewAxis[ 0 ], distance ) ) {
  2562. start = org + distance * viewAxis[ 0 ];
  2563. } else {
  2564. start = ownerBounds.GetCenter();
  2565. }
  2566. } else {
  2567. // projectile bounds bigger than the owner bounds, so just start it from the center
  2568. start = ownerBounds.GetCenter();
  2569. }
  2570. gameLocal.clip.Translation( tr, start, org, projClip, projClip->GetAxis(), MASK_SHOT_RENDERMODEL, this );
  2571. // launch the projectile
  2572. idThread::ReturnEntity( projectile.GetEntity() );
  2573. idVec3 dir = homingMissileGoal - org;
  2574. idAngles ang = dir.ToAngles();
  2575. ang.pitch = -45.0f;
  2576. projectile.GetEntity()->Launch( org, ang.ToForward(), vec3_origin );
  2577. projectile = NULL;
  2578. TriggerWeaponEffects( tr.endpos );
  2579. lastAttackTime = gameLocal.time;
  2580. }
  2581. /*
  2582. =====================
  2583. idAI::Event_SetHomingMissileGoal
  2584. =====================
  2585. */
  2586. void idAI::Event_SetHomingMissileGoal() {
  2587. idActor *enemy = GetEnemy();
  2588. if ( enemy == NULL ) {
  2589. idThread::ReturnEntity( NULL );
  2590. return;
  2591. }
  2592. homingMissileGoal = enemy->GetPhysics()->GetOrigin();
  2593. }