aiPlayer.cpp
Engine/source/T3D/aiPlayer.cpp
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