aiPlayer.cpp

Engine/source/T3D/aiPlayer.cpp

More...

Public Variables

_setAimObject ("@brief Sets the AIPlayer's target object.  May optionally set an offset from target location\n\n" "@param targetObject The object to target\n" "@param offset Optional three-element offset vector which will be added to the position of the aim object.\n\n" "@tsexample\n" "// Without an offset\n" "%ai.setAimObject(%target);\n\n" "// With an offset\n" "// Cause our AI object to aim at the target\n" "// offset (0, 0, 1) so you don't aim at the target's feet\n" "%ai.setAimObject(%target, \"0 0 1\");\n" "@endtsexample\n\n" "@see getAimLocation()\n" "@see getAimObject()\n" "@see clearAim()\n", "AIPlayer", "void setAimObject(GameBase targetObject, Point3F offset);")

Public Functions

ConsoleDocClass(AIPlayer , "@brief A <a href="/coding/class/classplayer/">Player</a> object not controlled by conventional input, but by an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">engine.\n\n</a>" "The <a href="/coding/class/classaiplayer/">AIPlayer</a> provides <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classplayer/">Player</a> object that may be controlled from script. You <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> " "where the player moves and how fast. You may also set where the <a href="/coding/class/classaiplayer/">AIPlayer</a> is aiming at " "-- either <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> location or another game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "The <a href="/coding/class/classaiplayer/">AIPlayer</a> class does not have <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> datablock of its own. It makes use of the <a href="/coding/class/structplayerdata/">PlayerData</a> " "datablock <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> define how it looks, etc. As the <a href="/coding/class/classaiplayer/">AIPlayer</a> is an extension of the <a href="/coding/class/classplayer/">Player</a> class " "it can mount objects and fire weapons, or mount vehicles and drive <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">them.\n\n</a>" "While the <a href="/coding/class/structplayerdata/">PlayerData</a> datablock is used, there are <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> number of additional callbacks that are " "implemented by <a href="/coding/class/classaiplayer/">AIPlayer</a> on the datablock. These are listed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">here:\n\n</a>" "<a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> onReachDestination(<a href="/coding/class/classaiplayer/">AIPlayer</a> obj) \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "Called when the player has reached its set destination using the setMoveDestination() method. " "The actual point at which this callback is called is when the <a href="/coding/class/classaiplayer/">AIPlayer</a> is within the mMoveTolerance " "of the defined <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destination.\n\n</a>" "<a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> onMoveStuck(<a href="/coding/class/classaiplayer/">AIPlayer</a> obj) \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "While in motion, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> an <a href="/coding/class/classaiplayer/">AIPlayer</a> has moved less than moveStuckTolerance within <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single tick, this " "callback is called. From here you could choose an alternate destination <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> get the <a href="/coding/class/classaiplayer/">AIPlayer</a> moving " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">again.\n\n</a>" "<a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> onTargetEnterLOS(<a href="/coding/class/classaiplayer/">AIPlayer</a> obj) \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "When an object is being aimed at(following <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> call <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> setAimObject()) and the targeted object enters " "the <a href="/coding/class/classaiplayer/">AIPlayer</a> 's line of sight, this callback is called. The LOS test is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> ray from the <a href="/coding/class/classaiplayer/">AIPlayer</a> 's eye " "position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the center of the target 's bounding box. The LOS ray test only checks against interiors, " "statis shapes, and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">terrain.\n\n</a>" "<a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> onTargetExitLOS(<a href="/coding/class/classaiplayer/">AIPlayer</a> obj) \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "When an object is being aimed at(following <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> call <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> setAimObject()) and the targeted object leaves " "the <a href="/coding/class/classaiplayer/">AIPlayer</a> 's line of sight, this callback is called. The LOS test is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> ray from the <a href="/coding/class/classaiplayer/">AIPlayer</a> 's eye " "position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the center of the target 's bounding box. The LOS ray test only checks against interiors, " "statis shapes, and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">terrain.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Create the demo player <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "% player, variables , and base <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">description\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AI\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(AIPlayer , checkInFoV , bool , (ShapeBase *obj, F32 fov, bool checkEnabled) , (nullAsType< ShapeBase * >(), 45.0f, false) , "@brief Check whether an object is within <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> specified veiw <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cone.\n</a>" "@obj <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> check. (If blank, it will check the current target).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@fov view angle in degrees.(Defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> 45)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@checkEnabled check whether the object can take damage and <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> so is still alive.(Defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , checkInLos , bool , (ShapeBase *obj, bool useMuzzle, bool checkEnabled) , (nullAsType< ShapeBase * >(), false, false) , "@brief Check whether an object is in line of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sight.\n</a>" "@obj <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> check. (If blank, it will check the current target).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@useMuzzle Use muzzle position. Otherwise use eye position. (defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@checkEnabled check whether the object can take damage and <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> so is still alive.(Defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , clearAim , void , () , "@brief Use this <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> stop aiming at an object or <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n\n</a>" "@see setAimLocation()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see setAimObject()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , clearMoveTrigger , void , (U32 slot) , "@brief Clears <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> movement trigger on an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param slot The trigger slot <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "@see setMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see getMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTriggers()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , clearMoveTriggers , void , () , "@brief Clear ALL movement triggers on an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@see setMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see getMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , getAimLocation , Point3F , () , "@brief Returns the point the <a href="/coding/class/classaiplayer/">AIPlayer</a> is aiming <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">at.\n\n</a>" "This will reflect the position set by  setAimLocation, " "or the position of the object that the bot is now aiming at. " "If the bot is not aiming at anything, this <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> will " "change <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> whatever point the bot 's current line-of-sight intercepts." " @return <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> space coordinates of the object AI is aiming at. Formatted as \"X Y Z\".\n\n" "@see setAimLocation()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see setAimObject()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , getAimObject , S32 , () , "@brief Gets the object the <a href="/coding/class/classaiplayer/">AIPlayer</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">targeting.\n\n</a>" "@return Returns -1 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> no object is being aimed at, " "or the SimObjectID of the object the <a href="/coding/class/classaiplayer/">AIPlayer</a> is aiming <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">at.\n\n</a>" " @see setAimObject()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , getAiPose , S32 , () , "@brief Get the object's current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AiPose.\n</a>" "@return StandPose, CrouchPose , PronePose )
DefineEngineMethod(AIPlayer , getMoveDestination , Point3F , () , "@brief Get the <a href="/coding/class/classaiplayer/">AIPlayer</a>'s current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destination.\n\n</a>" "@return Returns <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> point containing the \"x y z\" position " "of the <a href="/coding/class/classaiplayer/">AIPlayer</a>'s current move destination. If no move destination " "has yet been set, this returns \"0 0 0\"." "@see setMoveDestination()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , getMoveSpeed , F32 , () , "@brief Gets the move speed of an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@return A speed multiplier between 0.0 and 1.0.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@see setMoveSpeed()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , getMoveTrigger , bool , (U32 slot) , "@brief Tests <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> movement trigger on an AI object is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n\n</a>" "@param slot The trigger slot <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> boolean indicating <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the trigger is set/<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">unset.\n</a>" "@see setMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTriggers()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , getTargetDistance , F32 , (ShapeBase *obj, bool checkEnabled) , (nullAsType< ShapeBase * >(), false) , "@brief The distance <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@obj <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> check. (If blank, it will check the current target).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@checkEnabled check whether the object can take damage and <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> so is still alive.(Defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , setAimLocation , void , (Point3F target) , "@brief Tells the <a href="/coding/class/classaiplayer/">AIPlayer</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> aim at the location <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">provided.\n\n</a>" "@param target An \"x y z\" position in the game world <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">target.\n\n</a>" "@see getAimLocation()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , setAimObject , void , (const char *objName, Point3F offset) , (Point3F::Zero) , "( GameBase obj, [<a href="/coding/class/classpoint3f/">Point3F</a> offset] )" "Sets the bot's target object. Optionally set an offset from target location." "@hide" )
DefineEngineMethod(AIPlayer , setAiPose , void , (S32 pose) , "@brief Sets the AiPose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pose StandPose, CrouchPose , PronePose )
DefineEngineMethod(AIPlayer , setMoveDestination , void , (Point3F goal, bool slowDown) , (true) , "@brief Tells the AI <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> move <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the location <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">provided\n\n</a>" "@param goal Coordinates in world space representing location <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> move <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@param slowDown A boolean value. If set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true, the bot will slow down " "when it gets within 5-meters of its move destination. If false, the bot " "will stop abruptly when it reaches the move destination. By default, this is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">true.\n\n</a>" " @note Upon reaching <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> move destination, the bot will clear its move destination and " "calls <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> getMoveDestination will return \"0 0 0\"." "@see getMoveDestination()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , setMoveSpeed , void , (F32 speed) , "@brief Sets the move speed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param speed A speed multiplier between 0.0 and 1.0. " "This is multiplied by the <a href="/coding/class/classaiplayer/">AIPlayer</a>'s base movement rates (as defined in " "its <a href="/coding/class/structplayerdata/">PlayerData</a> datablock)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@see getMoveDestination()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , setMoveTrigger , void , (U32 slot) , "@brief Sets <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> movement trigger on an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param slot The trigger slot <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "@see getMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTriggers()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(AIPlayer , stop , void , () , "@brief Tells the <a href="/coding/class/classaiplayer/">AIPlayer</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> stop <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moving.\n\n</a>" )

Detailed Description

Public Variables

ConsoleDocFragment _setAimObject ("@brief Sets the AIPlayer's target object.  May optionally set an offset from target location\n\n" "@param targetObject The object to target\n" "@param offset Optional three-element offset vector which will be added to the position of the aim object.\n\n" "@tsexample\n" "// Without an offset\n" "%ai.setAimObject(%target);\n\n" "// With an offset\n" "// Cause our AI object to aim at the target\n" "// offset (0, 0, 1) so you don't aim at the target's feet\n" "%ai.setAimObject(%target, \"0 0 1\");\n" "@endtsexample\n\n" "@see getAimLocation()\n" "@see getAimObject()\n" "@see clearAim()\n", "AIPlayer", "void setAimObject(GameBase targetObject, Point3F offset);")
U32 sAIPlayerLoSMask 

Public Functions

ConsoleDocClass(AIPlayer , "@brief A <a href="/coding/class/classplayer/">Player</a> object not controlled by conventional input, but by an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">engine.\n\n</a>" "The <a href="/coding/class/classaiplayer/">AIPlayer</a> provides <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classplayer/">Player</a> object that may be controlled from script. You <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> " "where the player moves and how fast. You may also set where the <a href="/coding/class/classaiplayer/">AIPlayer</a> is aiming at " "-- either <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> location or another game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "The <a href="/coding/class/classaiplayer/">AIPlayer</a> class does not have <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> datablock of its own. It makes use of the <a href="/coding/class/structplayerdata/">PlayerData</a> " "datablock <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> define how it looks, etc. As the <a href="/coding/class/classaiplayer/">AIPlayer</a> is an extension of the <a href="/coding/class/classplayer/">Player</a> class " "it can mount objects and fire weapons, or mount vehicles and drive <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">them.\n\n</a>" "While the <a href="/coding/class/structplayerdata/">PlayerData</a> datablock is used, there are <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> number of additional callbacks that are " "implemented by <a href="/coding/class/classaiplayer/">AIPlayer</a> on the datablock. These are listed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">here:\n\n</a>" "<a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> onReachDestination(<a href="/coding/class/classaiplayer/">AIPlayer</a> obj) \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "Called when the player has reached its set destination using the setMoveDestination() method. " "The actual point at which this callback is called is when the <a href="/coding/class/classaiplayer/">AIPlayer</a> is within the mMoveTolerance " "of the defined <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destination.\n\n</a>" "<a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> onMoveStuck(<a href="/coding/class/classaiplayer/">AIPlayer</a> obj) \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "While in motion, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> an <a href="/coding/class/classaiplayer/">AIPlayer</a> has moved less than moveStuckTolerance within <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single tick, this " "callback is called. From here you could choose an alternate destination <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> get the <a href="/coding/class/classaiplayer/">AIPlayer</a> moving " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">again.\n\n</a>" "<a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> onTargetEnterLOS(<a href="/coding/class/classaiplayer/">AIPlayer</a> obj) \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "When an object is being aimed at(following <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> call <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> setAimObject()) and the targeted object enters " "the <a href="/coding/class/classaiplayer/">AIPlayer</a> 's line of sight, this callback is called. The LOS test is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> ray from the <a href="/coding/class/classaiplayer/">AIPlayer</a> 's eye " "position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the center of the target 's bounding box. The LOS ray test only checks against interiors, " "statis shapes, and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">terrain.\n\n</a>" "<a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1ac9c84fa68bbad002983e35ce3663c686">void</a> onTargetExitLOS(<a href="/coding/class/classaiplayer/">AIPlayer</a> obj) \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "When an object is being aimed at(following <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> call <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> setAimObject()) and the targeted object leaves " "the <a href="/coding/class/classaiplayer/">AIPlayer</a> 's line of sight, this callback is called. The LOS test is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> ray from the <a href="/coding/class/classaiplayer/">AIPlayer</a> 's eye " "position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the center of the target 's bounding box. The LOS ray test only checks against interiors, " "statis shapes, and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">terrain.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Create the demo player <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "% player, variables , and base <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">description\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AI\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )

DefineEngineMethod(AIPlayer , checkInFoV , bool , (ShapeBase *obj, F32 fov, bool checkEnabled) , (nullAsType< ShapeBase * >(), 45.0f, false) , "@brief Check whether an object is within <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> specified veiw <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cone.\n</a>" "@obj <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> check. (If blank, it will check the current target).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@fov view angle in degrees.(Defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> 45)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@checkEnabled check whether the object can take damage and <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> so is still alive.(Defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , checkInLos , bool , (ShapeBase *obj, bool useMuzzle, bool checkEnabled) , (nullAsType< ShapeBase * >(), false, false) , "@brief Check whether an object is in line of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sight.\n</a>" "@obj <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> check. (If blank, it will check the current target).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@useMuzzle Use muzzle position. Otherwise use eye position. (defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@checkEnabled check whether the object can take damage and <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> so is still alive.(Defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , clearAim , void , () , "@brief Use this <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> stop aiming at an object or <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n\n</a>" "@see setAimLocation()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see setAimObject()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , clearMoveTrigger , void , (U32 slot) , "@brief Clears <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> movement trigger on an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param slot The trigger slot <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "@see setMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see getMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTriggers()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , clearMoveTriggers , void , () , "@brief Clear ALL movement triggers on an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@see setMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see getMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , getAimLocation , Point3F , () , "@brief Returns the point the <a href="/coding/class/classaiplayer/">AIPlayer</a> is aiming <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">at.\n\n</a>" "This will reflect the position set by  setAimLocation, " "or the position of the object that the bot is now aiming at. " "If the bot is not aiming at anything, this <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> will " "change <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> whatever point the bot 's current line-of-sight intercepts." " @return <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> space coordinates of the object AI is aiming at. Formatted as \"X Y Z\".\n\n" "@see setAimLocation()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see setAimObject()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , getAimObject , S32 , () , "@brief Gets the object the <a href="/coding/class/classaiplayer/">AIPlayer</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">targeting.\n\n</a>" "@return Returns -1 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> no object is being aimed at, " "or the SimObjectID of the object the <a href="/coding/class/classaiplayer/">AIPlayer</a> is aiming <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">at.\n\n</a>" " @see setAimObject()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , getAiPose , S32 , () , "@brief Get the object's current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AiPose.\n</a>" "@return StandPose, CrouchPose , PronePose )

DefineEngineMethod(AIPlayer , getMoveDestination , Point3F , () , "@brief Get the <a href="/coding/class/classaiplayer/">AIPlayer</a>'s current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destination.\n\n</a>" "@return Returns <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> point containing the \"x y z\" position " "of the <a href="/coding/class/classaiplayer/">AIPlayer</a>'s current move destination. If no move destination " "has yet been set, this returns \"0 0 0\"." "@see setMoveDestination()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , getMoveSpeed , F32 , () , "@brief Gets the move speed of an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@return A speed multiplier between 0.0 and 1.0.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@see setMoveSpeed()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , getMoveTrigger , bool , (U32 slot) , "@brief Tests <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> movement trigger on an AI object is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n\n</a>" "@param slot The trigger slot <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> boolean indicating <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the trigger is set/<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">unset.\n</a>" "@see setMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTriggers()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , getTargetDistance , F32 , (ShapeBase *obj, bool checkEnabled) , (nullAsType< ShapeBase * >(), false) , "@brief The distance <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@obj <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> check. (If blank, it will check the current target).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@checkEnabled check whether the object can take damage and <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> so is still alive.(Defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , setAimLocation , void , (Point3F target) , "@brief Tells the <a href="/coding/class/classaiplayer/">AIPlayer</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> aim at the location <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">provided.\n\n</a>" "@param target An \"x y z\" position in the game world <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">target.\n\n</a>" "@see getAimLocation()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , setAimObject , void , (const char *objName, Point3F offset) , (Point3F::Zero) , "( GameBase obj, [<a href="/coding/class/classpoint3f/">Point3F</a> offset] )" "Sets the bot's target object. Optionally set an offset from target location." "@hide" )

DefineEngineMethod(AIPlayer , setAiPose , void , (S32 pose) , "@brief Sets the AiPose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pose StandPose, CrouchPose , PronePose )

DefineEngineMethod(AIPlayer , setMoveDestination , void , (Point3F goal, bool slowDown) , (true) , "@brief Tells the AI <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> move <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the location <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">provided\n\n</a>" "@param goal Coordinates in world space representing location <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> move <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@param slowDown A boolean value. If set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true, the bot will slow down " "when it gets within 5-meters of its move destination. If false, the bot " "will stop abruptly when it reaches the move destination. By default, this is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">true.\n\n</a>" " @note Upon reaching <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> move destination, the bot will clear its move destination and " "calls <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> getMoveDestination will return \"0 0 0\"." "@see getMoveDestination()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , setMoveSpeed , void , (F32 speed) , "@brief Sets the move speed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param speed A speed multiplier between 0.0 and 1.0. " "This is multiplied by the <a href="/coding/class/classaiplayer/">AIPlayer</a>'s base movement rates (as defined in " "its <a href="/coding/class/structplayerdata/">PlayerData</a> datablock)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@see getMoveDestination()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , setMoveTrigger , void , (U32 slot) , "@brief Sets <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> movement trigger on an AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param slot The trigger slot <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "@see getMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTrigger()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@see clearMoveTriggers()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

DefineEngineMethod(AIPlayer , stop , void , () , "@brief Tells the <a href="/coding/class/classaiplayer/">AIPlayer</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> stop <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moving.\n\n</a>" )

IMPLEMENT_CO_NETOBJECT_V1(AIPlayer )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  26// Copyright (C) 2015 Faust Logic, Inc.
  27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  28
  29#include "platform/platform.h"
  30#include "T3D/aiPlayer.h"
  31
  32#include "console/consoleInternal.h"
  33#include "math/mMatrix.h"
  34#include "T3D/gameBase/moveManager.h"
  35#include "console/engineAPI.h"
  36
  37#include <cfloat>
  38
  39static U32 sAIPlayerLoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
  40
  41IMPLEMENT_CO_NETOBJECT_V1(AIPlayer);
  42
  43ConsoleDocClass( AIPlayer,
  44   "@brief A Player object not controlled by conventional input, but by an AI engine.\n\n"
  45
  46   "The AIPlayer provides a Player object that may be controlled from script.  You control "
  47   "where the player moves and how fast.  You may also set where the AIPlayer is aiming at "
  48   "-- either a location or another game object.\n\n"
  49
  50   "The AIPlayer class does not have a datablock of its own.  It makes use of the PlayerData "
  51   "datablock to define how it looks, etc.  As the AIPlayer is an extension of the Player class "
  52   "it can mount objects and fire weapons, or mount vehicles and drive them.\n\n"
  53
  54   "While the PlayerData datablock is used, there are a number of additional callbacks that are "
  55   "implemented by AIPlayer on the datablock.  These are listed here:\n\n"
  56
  57   "void onReachDestination(AIPlayer obj) \n"
  58   "Called when the player has reached its set destination using the setMoveDestination() method.  "
  59   "The actual point at which this callback is called is when the AIPlayer is within the mMoveTolerance "
  60   "of the defined destination.\n\n"
  61
  62   "void onMoveStuck(AIPlayer obj) \n"
  63   "While in motion, if an AIPlayer has moved less than moveStuckTolerance within a single tick, this "
  64   "callback is called.  From here you could choose an alternate destination to get the AIPlayer moving "
  65   "again.\n\n"
  66
  67   "void onTargetEnterLOS(AIPlayer obj) \n"
  68   "When an object is being aimed at (following a call to setAimObject()) and the targeted object enters "
  69   "the AIPlayer's line of sight, this callback is called.  The LOS test is a ray from the AIPlayer's eye "
  70   "position to the center of the target's bounding box.  The LOS ray test only checks against interiors, "
  71   "statis shapes, and terrain.\n\n"
  72
  73   "void onTargetExitLOS(AIPlayer obj) \n"
  74   "When an object is being aimed at (following a call to setAimObject()) and the targeted object leaves "
  75   "the AIPlayer's line of sight, this callback is called.  The LOS test is a ray from the AIPlayer's eye "
  76   "position to the center of the target's bounding box.  The LOS ray test only checks against interiors, "
  77   "statis shapes, and terrain.\n\n"
  78
  79   "@tsexample\n"
  80   "// Create the demo player object\n"
  81   "%player = new AiPlayer()\n"
  82   "{\n"
  83   "  dataBlock = DemoPlayer;\n"
  84   "  path = \"\";\n"
  85   "};\n"
  86   "@endtsexample\n\n"
  87
  88   "@see Player for a list of all inherited functions, variables, and base description\n"
  89
  90   "@ingroup AI\n"
  91   "@ingroup gameObjects\n");
  92/**
  93 * Constructor
  94 */
  95AIPlayer::AIPlayer()
  96{
  97   mMoveDestination.set( 0.0f, 0.0f, 0.0f );
  98   mMoveSpeed = 1.0f;
  99   mMoveTolerance = 0.25f;
 100   mMoveStuckTolerance = 0.01f;
 101   mMoveStuckTestDelay = 30;
 102   mMoveStuckTestCountdown = 0;
 103   mMoveSlowdown = true;
 104   mMoveState = ModeStop;
 105
 106   // This new member saves the movement state of the AI so that
 107   // it can be restored after a substituted animation is finished.
 108   mMoveState_saved = -1;
 109   mAimObject = 0;
 110   mAimLocationSet = false;
 111   mTargetInLOS = false;
 112   mAimOffset = Point3F(0.0f, 0.0f, 0.0f);
 113
 114#ifdef TORQUE_NAVIGATION_ENABLED
 115   mJump = None;
 116   mNavSize = Regular;
 117   mLinkTypes = LinkData(AllFlags);
 118#endif
 119
 120   mIsAiControlled = true;
 121
 122   for( S32 i = 0; i < MaxTriggerKeys; i ++ )
 123      mMoveTriggers[ i ] = false;
 124
 125   mAttackRadius = 1;
 126}
 127
 128/**
 129 * Destructor
 130 */
 131AIPlayer::~AIPlayer()
 132{
 133}
 134
 135void AIPlayer::initPersistFields()
 136{
 137   addGroup( "AI" );
 138
 139      addField( "mMoveTolerance", TypeF32, Offset( mMoveTolerance, AIPlayer ), 
 140         "@brief Distance from destination before stopping.\n\n"
 141         "When the AIPlayer is moving to a given destination it will move to within "
 142         "this distance of the destination and then stop.  By providing this tolerance "
 143         "it helps the AIPlayer from never reaching its destination due to minor obstacles, "
 144         "rounding errors on its position calculation, etc.  By default it is set to 0.25.\n");
 145
 146      addField( "moveStuckTolerance", TypeF32, Offset( mMoveStuckTolerance, AIPlayer ), 
 147         "@brief Distance tolerance on stuck check.\n\n"
 148         "When the AIPlayer is moving to a given destination, if it ever moves less than "
 149         "this tolerance during a single tick, the AIPlayer is considered stuck.  At this point "
 150         "the onMoveStuck() callback is called on the datablock.\n");
 151
 152      addField( "moveStuckTestDelay", TypeS32, Offset( mMoveStuckTestDelay, AIPlayer ), 
 153         "@brief The number of ticks to wait before testing if the AIPlayer is stuck.\n\n"
 154         "When the AIPlayer is asked to move, this property is the number of ticks to wait "
 155         "before the AIPlayer starts to check if it is stuck.  This delay allows the AIPlayer "
 156         "to accelerate to full speed without its initial slow start being considered as stuck.\n"
 157         "@note Set to zero to have the stuck test start immediately.\n");
 158
 159      addField( "AttackRadius", TypeF32, Offset( mAttackRadius, AIPlayer ), 
 160         "@brief Distance considered in firing range for callback purposes.");
 161           
 162   endGroup( "AI" );
 163
 164#ifdef TORQUE_NAVIGATION_ENABLED
 165   addGroup("Pathfinding");
 166
 167      addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIPlayer),
 168         "Allow the character to walk on dry land.");
 169      addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIPlayer),
 170         "Allow the character to use jump links.");
 171      addField("allowDrop", TypeBool, Offset(mLinkTypes.drop, AIPlayer),
 172         "Allow the character to use drop links.");
 173      addField("allowSwim", TypeBool, Offset(mLinkTypes.swim, AIPlayer),
 174         "Allow the character to move in water.");
 175      addField("allowLedge", TypeBool, Offset(mLinkTypes.ledge, AIPlayer),
 176         "Allow the character to jump ledges.");
 177      addField("allowClimb", TypeBool, Offset(mLinkTypes.climb, AIPlayer),
 178         "Allow the character to use climb links.");
 179      addField("allowTeleport", TypeBool, Offset(mLinkTypes.teleport, AIPlayer),
 180         "Allow the character to use teleporters.");
 181
 182   endGroup("Pathfinding");
 183#endif // TORQUE_NAVIGATION_ENABLED
 184
 185   Parent::initPersistFields();
 186}
 187
 188bool AIPlayer::onAdd()
 189{
 190   if (!Parent::onAdd())
 191      return false;
 192
 193   // Use the eye as the current position (see getAIMove)
 194   MatrixF eye;
 195   getEyeTransform(&eye);
 196   mLastLocation = eye.getPosition();
 197
 198   return true;
 199}
 200
 201void AIPlayer::onRemove()
 202{
 203#ifdef TORQUE_NAVIGATION_ENABLED
 204   clearPath();
 205   clearCover();
 206   clearFollow();
 207#endif
 208   Parent::onRemove();
 209}
 210
 211/**
 212 * Sets the speed at which this AI moves
 213 *
 214 * @param speed Speed to move, default player was 10
 215 */
 216void AIPlayer::setMoveSpeed( F32 speed )
 217{
 218   mMoveSpeed = getMax(0.0f, getMin( 1.0f, speed ));
 219}
 220
 221/**
 222 * Stops movement for this AI
 223 */
 224void AIPlayer::stopMove()
 225{
 226   mMoveState = ModeStop;
 227#ifdef TORQUE_NAVIGATION_ENABLED
 228   clearPath();
 229   clearCover();
 230   clearFollow();
 231#endif
 232}
 233
 234/**
 235 * Sets how far away from the move location is considered
 236 * "on target"
 237 *
 238 * @param tolerance Movement tolerance for error
 239 */
 240void AIPlayer::setMoveTolerance( const F32 tolerance )
 241{
 242   mMoveTolerance = getMax( 0.1f, tolerance );
 243}
 244
 245/**
 246 * Sets the location for the bot to run to
 247 *
 248 * @param location Point to run to
 249 */
 250void AIPlayer::setMoveDestination( const Point3F &location, bool slowdown )
 251{
 252   mMoveDestination = location;
 253   mMoveState = ModeMove;
 254   mMoveSlowdown = slowdown;
 255   mMoveStuckTestCountdown = mMoveStuckTestDelay;
 256}
 257
 258/**
 259 * Sets the object the bot is targeting
 260 *
 261 * @param targetObject The object to target
 262 */
 263void AIPlayer::setAimObject( GameBase *targetObject )
 264{
 265   mAimObject = targetObject;
 266   mTargetInLOS = false;
 267   mAimOffset = Point3F(0.0f, 0.0f, 0.0f);
 268}
 269
 270/**
 271 * Sets the object the bot is targeting and an offset to add to target location
 272 *
 273 * @param targetObject The object to target
 274 * @param offset       The offest from the target location to aim at
 275 */
 276void AIPlayer::setAimObject(GameBase *targetObject, const Point3F& offset)
 277{
 278   mAimObject = targetObject;
 279   mTargetInLOS = false;
 280   mAimOffset = offset;
 281}
 282
 283/**
 284 * Sets the location for the bot to aim at
 285 *
 286 * @param location Point to aim at
 287 */
 288void AIPlayer::setAimLocation( const Point3F &location )
 289{
 290   mAimObject = 0;
 291   mAimLocationSet = true;
 292   mAimLocation = location;
 293   mAimOffset = Point3F(0.0f, 0.0f, 0.0f);
 294}
 295
 296/**
 297 * Clears the aim location and sets it to the bot's
 298 * current destination so he looks where he's going
 299 */
 300void AIPlayer::clearAim()
 301{
 302   mAimObject = 0;
 303   mAimLocationSet = false;
 304   mAimOffset = Point3F(0.0f, 0.0f, 0.0f);
 305}
 306
 307/**
 308 * Sets the correct aim for the bot to the target
 309 */
 310void AIPlayer::getMuzzleVector(U32 imageSlot,VectorF* vec)
 311{
 312   MatrixF mat;
 313   getMuzzleTransform(imageSlot,&mat);
 314
 315   MountedImage& image = mMountedImageList[imageSlot];
 316
 317   if (image.dataBlock->correctMuzzleVector)
 318   {
 319      disableHeadZCalc();
 320      if (getCorrectedAim(mat, vec))
 321      {
 322         enableHeadZCalc();
 323         return;
 324      }
 325      enableHeadZCalc();
 326
 327   }
 328   mat.getColumn(1,vec);
 329}
 330
 331/**
 332 * Set the state of a movement trigger.
 333 *
 334 * @param slot The trigger slot to set
 335 * @param isSet set/unset the trigger
 336 */
 337void AIPlayer::setMoveTrigger( U32 slot, const bool isSet )
 338{
 339   if(slot >= MaxTriggerKeys)
 340   {
 341      Con::errorf("Attempting to set an invalid trigger slot (%i)", slot);
 342   }
 343   else
 344   {
 345      mMoveTriggers[ slot ] = isSet;   // set the trigger
 346      setMaskBits(NoWarpMask);         // force the client to updateMove
 347   }
 348}
 349
 350/**
 351 * Get the state of a movement trigger.
 352 *
 353 * @param slot The trigger slot to query
 354 * @return True if the trigger is set, false if it is not set
 355 */
 356bool AIPlayer::getMoveTrigger( U32 slot ) const
 357{
 358   if(slot >= MaxTriggerKeys)
 359   {
 360      Con::errorf("Attempting to get an invalid trigger slot (%i)", slot);
 361      return false;
 362   }
 363   else
 364   {
 365      return mMoveTriggers[ slot ];
 366   }
 367}
 368
 369/**
 370 * Clear the trigger state for all movement triggers.
 371 */
 372void AIPlayer::clearMoveTriggers()
 373{
 374   for( U32 i = 0; i < MaxTriggerKeys; i ++ )
 375      setMoveTrigger( i, false );
 376}
 377
 378/**
 379 * This method calculates the moves for the AI player
 380 *
 381 * @param movePtr Pointer to move the move list into
 382 */
 383bool AIPlayer::getAIMove(Move *movePtr)
 384{
 385   *movePtr = NullMove;
 386
 387   // Use the eye as the current position.
 388   MatrixF eye;
 389   getEyeTransform(&eye);
 390   Point3F location = eye.getPosition();
 391   Point3F rotation = getRotation();
 392
 393#ifdef TORQUE_NAVIGATION_ENABLED
 394   if(mDamageState == Enabled)
 395   {
 396      if(mMoveState != ModeStop)
 397         updateNavMesh();
 398      if(!mFollowData.object.isNull())
 399      {
 400         if(mPathData.path.isNull())
 401         {
 402            if((getPosition() - mFollowData.object->getPosition()).len() > mFollowData.radius)
 403               followObject(mFollowData.object, mFollowData.radius);
 404         }
 405         else
 406         {
 407            if((mPathData.path->mTo - mFollowData.object->getPosition()).len() > mFollowData.radius)
 408               repath();
 409            else if((getPosition() - mFollowData.object->getPosition()).len() < mFollowData.radius)
 410            {
 411               clearPath();
 412               mMoveState = ModeStop;
 413            throwCallback("onTargetInRange");
 414            }
 415            else if((getPosition() - mFollowData.object->getPosition()).len() < mAttackRadius)
 416            {
 417            throwCallback("onTargetInFiringRange");
 418            }
 419         }
 420      }
 421   }
 422#endif // TORQUE_NAVIGATION_ENABLED
 423
 424   // Orient towards the aim point, aim object, or towards
 425   // our destination.
 426   if (mAimObject || mAimLocationSet || mMoveState != ModeStop) 
 427   {
 428      // Update the aim position if we're aiming for an object
 429      if (mAimObject)
 430         mAimLocation = mAimObject->getPosition() + mAimOffset;
 431      else
 432         if (!mAimLocationSet)
 433            mAimLocation = mMoveDestination;
 434
 435      F32 xDiff = mAimLocation.x - location.x;
 436      F32 yDiff = mAimLocation.y - location.y;
 437
 438      if (!mIsZero(xDiff) || !mIsZero(yDiff)) 
 439      {
 440         // First do Yaw
 441         // use the cur yaw between -Pi and Pi
 442         F32 curYaw = rotation.z;
 443         while (curYaw > M_2PI_F)
 444            curYaw -= M_2PI_F;
 445         while (curYaw < -M_2PI_F)
 446            curYaw += M_2PI_F;
 447
 448         // find the yaw offset
 449         F32 newYaw = mAtan2( xDiff, yDiff );
 450         F32 yawDiff = newYaw - curYaw;
 451
 452         // make it between 0 and 2PI
 453         if( yawDiff < 0.0f )
 454            yawDiff += M_2PI_F;
 455         else if( yawDiff >= M_2PI_F )
 456            yawDiff -= M_2PI_F;
 457
 458         // now make sure we take the short way around the circle
 459         if( yawDiff > M_PI_F )
 460            yawDiff -= M_2PI_F;
 461         else if( yawDiff < -M_PI_F )
 462            yawDiff += M_2PI_F;
 463
 464         movePtr->yaw = yawDiff;
 465
 466         // Next do pitch.
 467         if (!mAimObject && !mAimLocationSet) 
 468         {
 469            // Level out if were just looking at our next way point.
 470            Point3F headRotation = getHeadRotation();
 471            movePtr->pitch = -headRotation.x;
 472         }
 473         else 
 474         {
 475            // This should be adjusted to run from the
 476            // eye point to the object's center position. Though this
 477            // works well enough for now.
 478            F32 vertDist = mAimLocation.z - location.z;
 479            F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
 480            F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f );
 481            if (mFabs(newPitch) > 0.01f) 
 482            {
 483               Point3F headRotation = getHeadRotation();
 484               movePtr->pitch = newPitch - headRotation.x;
 485            }
 486         }
 487      }
 488   }
 489   else 
 490   {
 491      // Level out if we're not doing anything else
 492      Point3F headRotation = getHeadRotation();
 493      movePtr->pitch = -headRotation.x;
 494   }
 495
 496   // Move towards the destination
 497   if (mMoveState != ModeStop) 
 498   {
 499      F32 xDiff = mMoveDestination.x - location.x;
 500      F32 yDiff = mMoveDestination.y - location.y;
 501
 502      // Check if we should mMove, or if we are 'close enough'
 503      if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) 
 504      {
 505         mMoveState = ModeStop;
 506         onReachDestination();
 507      }
 508      else 
 509      {
 510         // Build move direction in world space
 511         if (mIsZero(xDiff))
 512            movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f;
 513         else
 514            if (mIsZero(yDiff))
 515               movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f;
 516            else
 517               if (mFabs(xDiff) > mFabs(yDiff)) 
 518               {
 519                  F32 value = mFabs(yDiff / xDiff);
 520                  movePtr->y = (location.y > mMoveDestination.y) ? -value : value;
 521                  movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f;
 522               }
 523               else 
 524               {
 525                  F32 value = mFabs(xDiff / yDiff);
 526                  movePtr->x = (location.x > mMoveDestination.x) ? -value : value;
 527                  movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f;
 528               }
 529
 530         // Rotate the move into object space (this really only needs
 531         // a 2D matrix)
 532         Point3F newMove;
 533         MatrixF moveMatrix;
 534         moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw)));
 535         moveMatrix.mulV( Point3F( movePtr->x, movePtr->y, 0.0f ), &newMove );
 536         movePtr->x = newMove.x;
 537         movePtr->y = newMove.y;
 538
 539         // Set movement speed.  We'll slow down once we get close
 540         // to try and stop on the spot...
 541         if (mMoveSlowdown) 
 542         {
 543            F32 speed = mMoveSpeed;
 544            F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff);
 545            F32 maxDist = mMoveTolerance*2;
 546            if (dist < maxDist)
 547               speed *= dist / maxDist;
 548            movePtr->x *= speed;
 549            movePtr->y *= speed;
 550
 551            mMoveState = ModeSlowing;
 552         }
 553         else 
 554         {
 555            movePtr->x *= mMoveSpeed;
 556            movePtr->y *= mMoveSpeed;
 557
 558            mMoveState = ModeMove;
 559         }
 560
 561         // Don't check for ai stuckness if animation during
 562         // an anim-clip effect override.
 563         if (mDamageState == Enabled && !(anim_clip_flags & ANIM_OVERRIDDEN) && !isAnimationLocked()) {
 564            if (mMoveStuckTestCountdown > 0)
 565               --mMoveStuckTestCountdown;
 566            else
 567            {
 568               // We should check to see if we are stuck...
 569               F32 locationDelta = (location - mLastLocation).len();
 570            if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled) 
 571            {
 572               // If we are slowing down, then it's likely that our location delta will be less than
 573               // our move stuck tolerance. Because we can be both slowing and stuck
 574               // we should TRY to check if we've moved. This could use better detection.
 575               if ( mMoveState != ModeSlowing || locationDelta == 0 )
 576                  {
 577                     mMoveState = ModeStuck;
 578                     onStuck();
 579                  }
 580               }
 581            }
 582         }
 583      }
 584   }
 585
 586   // Test for target location in sight if it's an object. The LOS is
 587   // run from the eye position to the center of the object's bounding,
 588   // which is not very accurate.
 589   if (mAimObject)
 590   {
 591      if (checkInLos(mAimObject.getPointer()))
 592      {
 593         if (!mTargetInLOS)
 594         {
 595            throwCallback( "onTargetEnterLOS" );
 596            mTargetInLOS = true;
 597         }
 598   }
 599      else if (mTargetInLOS)
 600      {
 601            throwCallback( "onTargetExitLOS" );
 602            mTargetInLOS = false;
 603         }
 604      }
 605
 606   Pose desiredPose = mPose;
 607
 608   if ( mSwimming )  
 609      desiredPose = SwimPose;   
 610   else if ( mAiPose == 1 && canCrouch() )   
 611      desiredPose = CrouchPose;  
 612   else if ( mAiPose == 2 && canProne() )  
 613      desiredPose = PronePose;  
 614   else if ( mAiPose == 3 && canSprint() )  
 615      desiredPose = SprintPose;  
 616   else if ( canStand() )  
 617      desiredPose = StandPose;  
 618  
 619   setPose( desiredPose );
 620   
 621   // Replicate the trigger state into the move so that
 622   // triggers can be controlled from scripts.
 623   for( U32 i = 0; i < MaxTriggerKeys; i++ )
 624      movePtr->trigger[ i ] = getImageTriggerState( i );
 625
 626#ifdef TORQUE_NAVIGATION_ENABLED
 627   if(mJump == Now)
 628   {
 629      movePtr->trigger[2] = true;
 630      mJump = None;
 631   }
 632   else if(mJump == Ledge)
 633   {
 634      // If we're not touching the ground, jump!
 635      RayInfo info;
 636      if(!getContainer()->castRay(getPosition(), getPosition() - Point3F(0, 0, 0.4f), StaticShapeObjectType, &info))
 637      {
 638         movePtr->trigger[2] = true;
 639         mJump = None;
 640      }
 641   }
 642#endif // TORQUE_NAVIGATION_ENABLED
 643
 644   if (!(anim_clip_flags & ANIM_OVERRIDDEN) && !isAnimationLocked())
 645   mLastLocation = location;
 646
 647   return true;
 648}
 649
 650void AIPlayer::updateMove(const Move* move)
 651{
 652   if (!getControllingClient() && isGhost())
 653      return;
 654
 655   Parent::updateMove(move);
 656}
 657
 658void AIPlayer::setAiPose( S32 pose )  
 659{  
 660   if (!getControllingClient() && isGhost())  
 661      return;  
 662   mAiPose = pose;  
 663}  
 664  
 665S32 AIPlayer::getAiPose()  
 666{  
 667   return mAiPose;  
 668}
 669
 670/**
 671 * Utility function to throw callbacks. Callbacks always occure
 672 * on the datablock class.
 673 *
 674 * @param name Name of script function to call
 675 */
 676void AIPlayer::throwCallback( const char *name )
 677{
 678   Con::executef(getDataBlock(), name, getIdString());
 679}
 680
 681/**
 682 * Called when we get within mMoveTolerance of our destination set using
 683 * setMoveDestination(). Only fires the script callback if we are at the end
 684 * of a pathfinding path, or have no pathfinding path.
 685 */
 686void AIPlayer::onReachDestination()
 687{
 688#ifdef TORQUE_NAVIGATION_ENABLED
 689   if(!mPathData.path.isNull())
 690   {
 691      if(mPathData.index == mPathData.path->size() - 1)
 692      {
 693         // Handle looping paths.
 694         if(mPathData.path->mIsLooping)
 695            moveToNode(0);
 696         // Otherwise end path.
 697         else
 698         {
 699            clearPath();
 700            throwCallback("onReachDestination");
 701         }
 702      }
 703      else
 704      {
 705         moveToNode(mPathData.index + 1);
 706         // Throw callback every time if we're on a looping path.
 707         //if(mPathData.path->mIsLooping)
 708            //throwCallback("onReachDestination");
 709      }
 710   }
 711   else
 712#endif
 713      throwCallback("onReachDestination");
 714}
 715
 716/**
 717 * Called when we move less than mMoveStuckTolerance in a tick, signalling
 718 * that some obstacle is preventing us from getting where we need to go.
 719 */
 720void AIPlayer::onStuck()
 721{
 722   throwCallback("onMoveStuck");
 723#ifdef TORQUE_NAVIGATION_ENABLED
 724   if(!mPathData.path.isNull())
 725      repath();
 726#endif
 727}
 728
 729#ifdef TORQUE_NAVIGATION_ENABLED
 730// --------------------------------------------------------------------------------------------
 731// Pathfinding
 732// --------------------------------------------------------------------------------------------
 733
 734void AIPlayer::clearPath()
 735{
 736   // Only delete if we own the path.
 737   if(!mPathData.path.isNull() && mPathData.owned)
 738      mPathData.path->deleteObject();
 739   // Reset path data.
 740   mPathData = PathData();
 741}
 742
 743void AIPlayer::clearCover()
 744{
 745   // Notify cover that we are no longer on our way.
 746   if(!mCoverData.cover.isNull())
 747      mCoverData.cover->setOccupied(false);
 748   mCoverData = CoverData();
 749}
 750
 751void AIPlayer::clearFollow()
 752{
 753   mFollowData = FollowData();
 754}
 755
 756void AIPlayer::moveToNode(S32 node)
 757{
 758   if(mPathData.path.isNull())
 759      return;
 760
 761   // -1 is shorthand for 'last path node'.
 762   if(node == -1)
 763      node = mPathData.path->size() - 1;
 764
 765   // Consider slowing down on the last path node.
 766   setMoveDestination(mPathData.path->getNode(node), false);
 767
 768   // Check flags for this segment.
 769   if(mPathData.index)
 770   {
 771      U16 flags = mPathData.path->getFlags(node - 1);
 772      // Jump if we must.
 773      if(flags & LedgeFlag)
 774         mJump = Ledge;
 775      else if(flags & JumpFlag)
 776         mJump = Now;
 777      else
 778         // Catch pathing errors.
 779         mJump = None;
 780   }
 781
 782   // Store current index.
 783   mPathData.index = node;
 784}
 785
 786bool AIPlayer::setPathDestination(const Point3F &pos)
 787{
 788   // Pathfinding only happens on the server.
 789   if(!isServerObject())
 790      return false;
 791
 792   if(!getNavMesh())
 793      updateNavMesh();
 794   // If we can't find a mesh, just move regularly.
 795   if(!getNavMesh())
 796   {
 797      //setMoveDestination(pos);
 798      throwCallback("onPathFailed");
 799      return false;
 800   }
 801
 802   // Create a new path.
 803   NavPath *path = new NavPath();
 804
 805   path->mMesh = getNavMesh();
 806   path->mFrom = getPosition();
 807   path->mTo = pos;
 808   path->mFromSet = path->mToSet = true;
 809   path->mAlwaysRender = true;
 810   path->mLinkTypes = mLinkTypes;
 811   path->mXray = true;
 812   // Paths plan automatically upon being registered.
 813   if(!path->registerObject())
 814   {
 815      delete path;
 816      return false;
 817   }
 818
 819   if(path->success())
 820   {
 821      // Clear any current path we might have.
 822      clearPath();
 823      clearCover();
 824      clearFollow();
 825      // Store new path.
 826      mPathData.path = path;
 827      mPathData.owned = true;
 828      // Skip node 0, which we are currently standing on.
 829      moveToNode(1);
 830      throwCallback("onPathSuccess");
 831      return true;
 832   }
 833   else
 834   {
 835      // Just move normally if we can't path.
 836      //setMoveDestination(pos, true);
 837      //return;
 838      throwCallback("onPathFailed");
 839      path->deleteObject();
 840      return false;
 841   }
 842}
 843
 844DefineEngineMethod(AIPlayer, setPathDestination, bool, (Point3F goal),,
 845   "@brief Tells the AI to find a path to the location provided\n\n"
 846
 847   "@param goal Coordinates in world space representing location to move to.\n"
 848   "@return True if a path was found.\n\n"
 849
 850   "@see getPathDestination()\n"
 851   "@see setMoveDestination()\n")
 852{
 853   return object->setPathDestination(goal);
 854}
 855
 856Point3F AIPlayer::getPathDestination() const
 857{
 858   if(!mPathData.path.isNull())
 859      return mPathData.path->mTo;
 860   return Point3F(0, 0, 0);
 861}
 862
 863DefineEngineMethod(AIPlayer, getPathDestination, Point3F, (),,
 864   "@brief Get the AIPlayer's current pathfinding destination.\n\n"
 865
 866   "@return Returns a point containing the \"x y z\" position "
 867   "of the AIPlayer's current path destination. If no path destination "
 868   "has yet been set, this returns \"0 0 0\"."
 869
 870   "@see setPathDestination()\n")
 871{
 872   return object->getPathDestination();
 873}
 874
 875void AIPlayer::followNavPath(NavPath *path)
 876{
 877   if(!isServerObject())
 878      return;
 879
 880   // Get rid of our current path.
 881   clearPath();
 882   clearCover();
 883   clearFollow();
 884
 885   // Follow new path.
 886   mPathData.path = path;
 887   mPathData.owned = false;
 888   // Start from 0 since we might not already be there.
 889   moveToNode(0);
 890}
 891
 892DefineEngineMethod(AIPlayer, followNavPath, void, (SimObjectId obj),,
 893   "@brief Tell the AIPlayer to follow a path.\n\n"
 894
 895   "@param obj ID of a NavPath object for the character to follow.")
 896{
 897   NavPath *path;
 898   if(Sim::findObject(obj, path))
 899      object->followNavPath(path);
 900}
 901
 902void AIPlayer::followObject(SceneObject *obj, F32 radius)
 903{
 904   if(!isServerObject())
 905      return;
 906
 907   if ((mFollowData.lastPos - obj->getPosition()).len()<mMoveTolerance)
 908      return;
 909
 910   if(setPathDestination(obj->getPosition()))
 911   {
 912      clearCover();
 913      mFollowData.object = obj;
 914      mFollowData.radius = radius;
 915      mFollowData.lastPos = obj->getPosition();
 916   }
 917}
 918
 919DefineEngineMethod(AIPlayer, followObject, void, (SimObjectId obj, F32 radius),,
 920   "@brief Tell the AIPlayer to follow another object.\n\n"
 921
 922   "@param obj ID of the object to follow.\n"
 923   "@param radius Maximum distance we let the target escape to.")
 924{
 925   SceneObject *follow;
 926   object->clearPath();
 927   object->clearCover();
 928   object->clearFollow();
 929
 930   if(Sim::findObject(obj, follow))
 931      object->followObject(follow, radius);
 932}
 933
 934void AIPlayer::repath()
 935{
 936   // Ineffectual if we don't have a path, or are using someone else's.
 937   if(mPathData.path.isNull() || !mPathData.owned)
 938      return;
 939
 940   // If we're following, get their position.
 941   if(!mFollowData.object.isNull())
 942      mPathData.path->mTo = mFollowData.object->getPosition();
 943   // Update from position and replan.
 944   mPathData.path->mFrom = getPosition();
 945   mPathData.path->plan();
 946   // Move to first node (skip start pos).
 947   moveToNode(1);
 948}
 949
 950DefineEngineMethod(AIPlayer, repath, void, (),,
 951   "@brief Tells the AI to re-plan its path. Does nothing if the character "
 952   "has no path, or if it is following a mission path.\n\n")
 953{
 954   object->repath();
 955}
 956
 957struct CoverSearch
 958{
 959   Point3F loc;
 960   Point3F from;
 961   F32 dist;
 962   F32 best;
 963   CoverPoint *point;
 964   CoverSearch() : loc(0, 0, 0), from(0, 0, 0)
 965   {
 966      best = -FLT_MAX;
 967      point = NULL;
 968      dist = FLT_MAX;
 969   }
 970};
 971
 972static void findCoverCallback(SceneObject *obj, void *key)
 973{
 974   CoverPoint *p = dynamic_cast<CoverPoint*>(obj);
 975   if(!p || p->isOccupied())
 976      return;
 977   CoverSearch *s = static_cast<CoverSearch*>(key);
 978   Point3F dir = s->from - p->getPosition();
 979   dir.normalizeSafe();
 980   // Score first based on angle of cover point to enemy.
 981   F32 score = mDot(p->getNormal(), dir);
 982   // Score also based on distance from seeker.
 983   score -= (p->getPosition() - s->loc).len() / s->dist;
 984   // Finally, consider cover size.
 985   score += (p->getSize() + 1) / CoverPoint::NumSizes;
 986   score *= p->getQuality();
 987   if(score > s->best)
 988   {
 989      s->best = score;
 990      s->point = p;
 991   }
 992}
 993
 994bool AIPlayer::findCover(const Point3F &from, F32 radius)
 995{
 996   if(radius <= 0)
 997      return false;
 998
 999   // Create a search state.
1000   CoverSearch s;
1001   s.loc = getPosition();
1002   s.dist = radius;
1003   // Direction we seek cover FROM.
1004   s.from = from;
1005
1006   // Find cover points.
1007   Box3F box(radius * 2.0f);
1008   box.setCenter(getPosition());
1009   getContainer()->findObjects(box, MarkerObjectType, findCoverCallback, &s);
1010
1011   // Go to cover!
1012   if(s.point)
1013   {
1014      // Calling setPathDestination clears cover...
1015      bool foundPath = setPathDestination(s.point->getPosition());
1016      // Now store the cover info.
1017      mCoverData.cover = s.point;
1018      s.point->setOccupied(true);
1019      return foundPath;
1020   }
1021   return false;
1022}
1023
1024DefineEngineMethod(AIPlayer, findCover, S32, (Point3F from, F32 radius),,
1025   "@brief Tells the AI to find cover nearby.\n\n"
1026
1027   "@param from   Location to find cover from (i.e., enemy position).\n"
1028   "@param radius Distance to search for cover.\n"
1029   "@return Cover point ID if cover was found, -1 otherwise.\n\n")
1030{
1031   if(object->findCover(from, radius))
1032   {
1033      CoverPoint* cover = object->getCover();
1034      return cover ? cover->getId() : -1;
1035   }
1036   else
1037   {
1038      return -1;
1039   }
1040}
1041
1042NavMesh *AIPlayer::findNavMesh() const
1043{
1044   // Search for NavMeshes that contain us entirely with the smallest possible
1045   // volume.
1046   NavMesh *mesh = NULL;
1047   SimSet *set = NavMesh::getServerSet();
1048   for(U32 i = 0; i < set->size(); i++)
1049   {
1050      NavMesh *m = static_cast<NavMesh*>(set->at(i));
1051      if(m->getWorldBox().isContained(getWorldBox()))
1052      {
1053         // Check that mesh size is appropriate.
1054         if(mMount.object) // Should use isMounted() but it's not const. Grr.
1055         {
1056            if(!m->mVehicles)
1057               continue;
1058         }
1059         else
1060         {
1061            if((getNavSize() == Small && !m->mSmallCharacters) ||
1062               (getNavSize() == Regular && !m->mRegularCharacters) ||
1063               (getNavSize() == Large && !m->mLargeCharacters))
1064               continue;
1065         }
1066         if(!mesh || m->getWorldBox().getVolume() < mesh->getWorldBox().getVolume())
1067            mesh = m;
1068      }
1069   }
1070   return mesh;
1071}
1072
1073DefineEngineMethod(AIPlayer, findNavMesh, S32, (),,
1074   "@brief Get the NavMesh object this AIPlayer is currently using.\n\n"
1075
1076   "@return The ID of the NavPath object this character is using for "
1077   "pathfinding. This is determined by the character's location, "
1078   "navigation type and other factors. Returns -1 if no NavMesh is "
1079   "found.")
1080{
1081   NavMesh *mesh = object->getNavMesh();
1082   return mesh ? mesh->getId() : -1;
1083}
1084
1085void AIPlayer::updateNavMesh()
1086{
1087   NavMesh *old = mNavMesh;
1088   if(mNavMesh.isNull())
1089      mNavMesh = findNavMesh();
1090   else
1091   {
1092      if(!mNavMesh->getWorldBox().isContained(getWorldBox()))
1093         mNavMesh = findNavMesh();
1094   }
1095   // See if we need to update our path.
1096   if(mNavMesh != old && !mPathData.path.isNull())
1097   {
1098      setPathDestination(mPathData.path->mTo);
1099   }
1100}
1101
1102DefineEngineMethod(AIPlayer, getNavMesh, S32, (),,
1103   "@brief Return the NavMesh this AIPlayer is using to navigate.\n\n")
1104{
1105   NavMesh *m = object->getNavMesh();
1106   return m ? m->getId() : 0;
1107}
1108
1109DefineEngineMethod(AIPlayer, setNavSize, void, (const char *size),,
1110   "@brief Set the size of NavMesh this character uses. One of \"Small\", \"Regular\" or \"Large\".")
1111{
1112   if(!String::compare(size, "Small"))
1113      object->setNavSize(AIPlayer::Small);
1114   else if(!String::compare(size, "Regular"))
1115      object->setNavSize(AIPlayer::Regular);
1116   else if(!String::compare(size, "Large"))
1117      object->setNavSize(AIPlayer::Large);
1118   else
1119      Con::errorf("AIPlayer::setNavSize: no such size '%s'.", size);
1120}
1121
1122DefineEngineMethod(AIPlayer, getNavSize, const char*, (),,
1123   "@brief Return the size of NavMesh this character uses for pathfinding.")
1124{
1125   switch(object->getNavSize())
1126   {
1127   case AIPlayer::Small:
1128      return "Small";
1129   case AIPlayer::Regular:
1130      return "Regular";
1131   case AIPlayer::Large:
1132      return "Large";
1133   }
1134   return "";
1135}
1136#endif // TORQUE_NAVIGATION_ENABLED
1137
1138// --------------------------------------------------------------------------------------------
1139// Console Functions
1140// --------------------------------------------------------------------------------------------
1141
1142DefineEngineMethod( AIPlayer, stop, void, ( ),,
1143   "@brief Tells the AIPlayer to stop moving.\n\n")
1144{
1145   object->stopMove();
1146}
1147
1148DefineEngineMethod( AIPlayer, clearAim, void, ( ),,
1149   "@brief Use this to stop aiming at an object or a point.\n\n"
1150   
1151   "@see setAimLocation()\n"
1152   "@see setAimObject()\n")
1153{
1154   object->clearAim();
1155}
1156
1157DefineEngineMethod( AIPlayer, setMoveSpeed, void, ( F32 speed ),,
1158   "@brief Sets the move speed for an AI object.\n\n"
1159
1160   "@param speed A speed multiplier between 0.0 and 1.0.  "
1161   "This is multiplied by the AIPlayer's base movement rates (as defined in "
1162   "its PlayerData datablock)\n\n"
1163   
1164   "@see getMoveDestination()\n")
1165{
1166   object->setMoveSpeed(speed);
1167}
1168
1169DefineEngineMethod( AIPlayer, getMoveSpeed, F32, ( ),,
1170   "@brief Gets the move speed of an AI object.\n\n"
1171
1172   "@return A speed multiplier between 0.0 and 1.0.\n\n"
1173
1174   "@see setMoveSpeed()\n")
1175{
1176   return object->getMoveSpeed();
1177}
1178
1179DefineEngineMethod( AIPlayer, setMoveDestination, void, ( Point3F goal, bool slowDown ), ( true ),
1180   "@brief Tells the AI to move to the location provided\n\n"
1181
1182   "@param goal Coordinates in world space representing location to move to.\n"
1183   "@param slowDown A boolean value. If set to true, the bot will slow down "
1184   "when it gets within 5-meters of its move destination. If false, the bot "
1185   "will stop abruptly when it reaches the move destination. By default, this is true.\n\n"
1186
1187   "@note Upon reaching a move destination, the bot will clear its move destination and "
1188   "calls to getMoveDestination will return \"0 0 0\"."
1189   
1190   "@see getMoveDestination()\n")
1191{
1192   object->setMoveDestination( goal, slowDown);
1193}
1194
1195DefineEngineMethod( AIPlayer, getMoveDestination, Point3F, (),,
1196   "@brief Get the AIPlayer's current destination.\n\n"
1197
1198   "@return Returns a point containing the \"x y z\" position "
1199   "of the AIPlayer's current move destination. If no move destination "
1200   "has yet been set, this returns \"0 0 0\"."
1201   
1202   "@see setMoveDestination()\n")
1203{
1204   return object->getMoveDestination();
1205}
1206
1207DefineEngineMethod( AIPlayer, setAimLocation, void, ( Point3F target ),,
1208   "@brief Tells the AIPlayer to aim at the location provided.\n\n"
1209
1210   "@param target An \"x y z\" position in the game world to target.\n\n"
1211   
1212   "@see getAimLocation()\n")
1213{
1214   object->setAimLocation(target);
1215}
1216
1217DefineEngineMethod( AIPlayer, getAimLocation, Point3F, (),,
1218   "@brief Returns the point the AIPlayer is aiming at.\n\n"
1219
1220   "This will reflect the position set by setAimLocation(), "
1221   "or the position of the object that the bot is now aiming at.  "
1222   "If the bot is not aiming at anything, this value will "
1223   "change to whatever point the bot's current line-of-sight intercepts."
1224
1225   "@return World space coordinates of the object AI is aiming at. Formatted as \"X Y Z\".\n\n"
1226   
1227   "@see setAimLocation()\n"
1228   "@see setAimObject()\n")
1229{
1230   return object->getAimLocation();
1231}
1232
1233ConsoleDocFragment _setAimObject(
1234   "@brief Sets the AIPlayer's target object.  May optionally set an offset from target location\n\n"
1235
1236   "@param targetObject The object to target\n"
1237   "@param offset Optional three-element offset vector which will be added to the position of the aim object.\n\n"
1238
1239   "@tsexample\n"
1240   "// Without an offset\n"
1241   "%ai.setAimObject(%target);\n\n"
1242   "// With an offset\n"
1243   "// Cause our AI object to aim at the target\n"
1244   "// offset (0, 0, 1) so you don't aim at the target's feet\n"
1245   "%ai.setAimObject(%target, \"0 0 1\");\n"
1246   "@endtsexample\n\n"
1247   
1248   "@see getAimLocation()\n"
1249   "@see getAimObject()\n"
1250   "@see clearAim()\n",
1251
1252   "AIPlayer",
1253   "void setAimObject(GameBase targetObject, Point3F offset);"
1254);
1255
1256DefineEngineMethod( AIPlayer, setAimObject, void, ( const char * objName, Point3F offset ), (Point3F::Zero), "( GameBase obj, [Point3F offset] )"
1257              "Sets the bot's target object. Optionally set an offset from target location."
1258           "@hide")
1259{
1260
1261   // Find the target
1262   GameBase *targetObject;
1263   if( Sim::findObject( objName, targetObject ) )
1264   {
1265
1266      object->setAimObject( targetObject, offset );
1267   }
1268   else
1269      object->setAimObject( 0, offset );
1270}
1271
1272DefineEngineMethod( AIPlayer, getAimObject, S32, (),,
1273   "@brief Gets the object the AIPlayer is targeting.\n\n"
1274
1275   "@return Returns -1 if no object is being aimed at, "
1276   "or the SimObjectID of the object the AIPlayer is aiming at.\n\n"
1277   
1278   "@see setAimObject()\n")
1279{
1280   GameBase* obj = object->getAimObject();
1281   return obj? obj->getId(): -1;
1282}
1283
1284bool AIPlayer::checkInLos(GameBase* target, bool _useMuzzle, bool _checkEnabled)
1285{
1286   if (!isServerObject()) return false;
1287   if (!target)
1288   {
1289      target = mAimObject.getPointer();
1290      if (!target)
1291         return false;
1292   }
1293   if (_checkEnabled)
1294   {
1295       if (target->getTypeMask() & ShapeBaseObjectType)
1296       {
1297           ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
1298           if (shapeBaseCheck)
1299               if (shapeBaseCheck->getDamageState() != Enabled) return false;
1300       }
1301       else
1302           return false;
1303   }
1304
1305   RayInfo ri;
1306
1307   disableCollision();
1308
1309   S32 mountCount = target->getMountedObjectCount();
1310   for (S32 i = 0; i < mountCount; i++)
1311   {
1312      target->getMountedObject(i)->disableCollision();
1313   }
1314
1315   Point3F checkPoint ;
1316   if (_useMuzzle)
1317      getMuzzlePointAI(0, &checkPoint );
1318   else
1319   {
1320      MatrixF eyeMat;
1321      getEyeTransform(&eyeMat);
1322      eyeMat.getColumn(3, &checkPoint );
1323   }
1324
1325   bool hit = !gServerContainer.castRay(checkPoint, target->getBoxCenter(), sAIPlayerLoSMask, &ri);
1326   enableCollision();
1327
1328   for (S32 i = 0; i < mountCount; i++)
1329   {
1330      target->getMountedObject(i)->enableCollision();
1331   }
1332   return hit;
1333}
1334
1335DefineEngineMethod(AIPlayer, checkInLos, bool, (ShapeBase* obj,  bool useMuzzle, bool checkEnabled),(nullAsType<ShapeBase*>(), false, false),
1336   "@brief Check whether an object is in line of sight.\n"
1337   "@obj Object to check. (If blank, it will check the current target).\n"
1338   "@useMuzzle Use muzzle position. Otherwise use eye position. (defaults to false).\n"
1339   "@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
1340{
1341   return object->checkInLos(obj, useMuzzle, checkEnabled);
1342}
1343
1344bool AIPlayer::checkInFoV(GameBase* target, F32 camFov, bool _checkEnabled)
1345{
1346   if (!isServerObject()) return false;
1347   if (!target)
1348   {
1349      target = mAimObject.getPointer();
1350      if (!target)
1351         return false;
1352   }
1353   if (_checkEnabled)
1354   {
1355       if (target->getTypeMask() & ShapeBaseObjectType)
1356       {
1357           ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
1358           if (shapeBaseCheck)
1359               if (shapeBaseCheck->getDamageState() != Enabled) return false;
1360       }
1361       else
1362           return false;
1363   }
1364
1365   MatrixF cam = getTransform();
1366   Point3F camPos;
1367   VectorF camDir;
1368
1369   cam.getColumn(3, &camPos);
1370   cam.getColumn(1, &camDir);
1371
1372   camFov = mDegToRad(camFov) / 2;
1373
1374   Point3F shapePos = target->getBoxCenter();
1375   VectorF shapeDir = shapePos - camPos;
1376   // Test to see if it's within our viewcone, this test doesn't
1377   // actually match the viewport very well, should consider
1378   // projection and box test.
1379   shapeDir.normalize();
1380   F32 dot = mDot(shapeDir, camDir);
1381   return (dot > mCos(camFov));
1382}
1383
1384DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool checkEnabled), (nullAsType<ShapeBase*>(), 45.0f, false),
1385   "@brief Check whether an object is within a specified veiw cone.\n"
1386   "@obj Object to check. (If blank, it will check the current target).\n"
1387   "@fov view angle in degrees.(Defaults to 45)\n"
1388   "@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
1389{
1390   return object->checkInFoV(obj, fov, checkEnabled);
1391}
1392
1393DefineEngineMethod( AIPlayer, setMoveTrigger, void, ( U32 slot ),,
1394   "@brief Sets a movement trigger on an AI object.\n\n"
1395   "@param slot The trigger slot to set.\n"
1396   "@see getMoveTrigger()\n"
1397   "@see clearMoveTrigger()\n"
1398   "@see clearMoveTriggers()\n")
1399{
1400   object->setMoveTrigger( slot, true );
1401}
1402
1403DefineEngineMethod( AIPlayer, clearMoveTrigger, void, ( U32 slot ),,
1404   "@brief Clears a movement trigger on an AI object.\n\n"
1405   "@param slot The trigger slot to set.\n"
1406   "@see setMoveTrigger()\n"
1407   "@see getMoveTrigger()\n"
1408   "@see clearMoveTriggers()\n")
1409{
1410   object->setMoveTrigger( slot, false );
1411}
1412
1413DefineEngineMethod( AIPlayer, getMoveTrigger, bool, ( U32 slot ),,
1414   "@brief Tests if a movement trigger on an AI object is set.\n\n"
1415   "@param slot The trigger slot to check.\n"
1416   "@return a boolean indicating if the trigger is set/unset.\n"
1417   "@see setMoveTrigger()\n"
1418   "@see clearMoveTrigger()\n"
1419   "@see clearMoveTriggers()\n")
1420{
1421   return object->getMoveTrigger( slot );
1422}
1423
1424DefineEngineMethod( AIPlayer, clearMoveTriggers, void, ( ),,
1425   "@brief Clear ALL movement triggers on an AI object.\n"
1426   "@see setMoveTrigger()\n"
1427   "@see getMoveTrigger()\n"
1428   "@see clearMoveTrigger()\n")
1429{
1430   object->clearMoveTriggers();
1431}
1432
1433// These changes coordinate with anim-clip mods to parent class, Player.
1434
1435// New method, restartMove(), restores the AIPlayer to its normal move-state
1436// following animation overrides from AFX. The tag argument is used to match
1437// the latest override and prevents interruption of overlapping animation
1438// overrides. See related anim-clip changes in Player.[h,cc].
1439void AIPlayer::restartMove(U32 tag)
1440{
1441   if (tag != 0 && tag == last_anim_tag)
1442   {
1443      if (mMoveState_saved != -1)
1444      {
1445         mMoveState = (MoveState) mMoveState_saved;
1446         mMoveState_saved = -1;
1447      }
1448
1449      bool is_death_anim = ((anim_clip_flags & IS_DEATH_ANIM) != 0);
1450
1451      last_anim_tag = 0;
1452      anim_clip_flags &= ~(ANIM_OVERRIDDEN | IS_DEATH_ANIM);
1453
1454      if (mDamageState != Enabled)
1455      {
1456         if (!is_death_anim)
1457         {
1458            // this is a bit hardwired and desperate,
1459            // but if he's dead he needs to look like it.
1460            setActionThread("death10", false, false, false);
1461         }
1462      }
1463   }
1464}
1465
1466// New method, saveMoveState(), stores the current movement state
1467// so that it can be restored when restartMove() is called.
1468void AIPlayer::saveMoveState()
1469{
1470   if (mMoveState_saved == -1)
1471      mMoveState_saved = (S32) mMoveState;
1472}
1473
1474F32 AIPlayer::getTargetDistance(GameBase* target, bool _checkEnabled)
1475{
1476   if (!isServerObject()) return false;
1477   if (!target)
1478   {
1479      target = mAimObject.getPointer();
1480      if (!target)
1481         return F32_MAX;
1482   }
1483
1484   if (_checkEnabled)
1485   {
1486      if (target->getTypeMask() & ShapeBaseObjectType)
1487      {
1488         ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
1489         if (shapeBaseCheck)
1490            if (shapeBaseCheck->getDamageState() != Enabled) return false;
1491      }
1492      else
1493         return F32_MAX;
1494   }
1495
1496   return (getPosition() - target->getPosition()).len();
1497}
1498
1499DefineEngineMethod(AIPlayer, getTargetDistance, F32, (ShapeBase* obj, bool checkEnabled), (nullAsType<ShapeBase*>(), false),
1500   "@brief The distance to a given object.\n"
1501   "@obj Object to check. (If blank, it will check the current target).\n"
1502   "@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
1503{
1504   return object->getTargetDistance(obj, checkEnabled);
1505}
1506
1507DefineEngineMethod( AIPlayer, setAiPose, void, ( S32 pose ),,  
1508   "@brief Sets the AiPose for an AI object.\n"
1509   "@param pose StandPose=0, CrouchPose=1, PronePose=2, SprintPose=3.\n"
1510   "Uses the new AiPose variable from shapebase (as defined in its PlayerData datablock).\n")  
1511{  
1512   object->setAiPose(pose);  
1513}  
1514  
1515DefineEngineMethod( AIPlayer, getAiPose, S32, (),,  
1516   "@brief Get the object's current AiPose.\n"
1517   "@return StandPose=0, CrouchPose=1, PronePose=2, SprintPose=3.\n")  
1518{  
1519   return object->getAiPose();  
1520}
1521