AI_events.cpp 70 KB

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