aiClient.cpp

Engine/source/T3D/aiClient.cpp

More...

Public Functions

ConsoleDocClass(AIClient , "@brief Simulated client driven by AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">commands.\n\n</a>" "This object is derived from the <a href="/coding/class/classaiconnection/">AIConnection</a> class. It introduces its own <a href="/coding/class/classplayer/">Player</a> object " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> solidify the purpose of this class: Simulated client connecting as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">player\n\n</a>" "To get more specific, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> you want <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> strong alternative <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a>  AIPlayer, consider AIClient. <a href="/coding/class/classaiclient/">AIClient</a> inherits from AIConnection, " "contains quite <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> bit of functionality you will find in AIPlayer, and has its own <a href="/coding/class/classplayer/">Player</a> " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" " @note This is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> legacy class, which you are discouraged from using as it will " "most likely be deprecated in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> future version. For now it has been left in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "backwards compatibility with TGE and the old RTS Kit. Use <a href="/coding/class/classaiplayer/">AIPlayer</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instead.\n\n</a>" " @see AIPlayer, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AIConnection\n\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">Networking\n</a>" )
DefineEngineFunction(aiAddPlayer , S32 , (const char *name, const char *ns) , ("") , "'playerName' )

Adds an AI Player to the game.

DefineEngineMethod(AIClient , getAimLocation , Point3F , () , "ai.getAimLocation();" )

Returns the point the AI is aiming at.

DefineEngineMethod(AIClient , getLocation , Point3F , () , "ai.getLocation();" )

Gets the AI's location in the world.

DefineEngineMethod(AIClient , getMoveDestination , Point3F , () , "ai.getMoveDestination();" )

Returns the point the AI is set to move to.

DefineEngineMethod(AIClient , getTargetObject , S32 , () , "ai.getTargetObject();" )

Gets the object the AI is targeting.

DefineEngineMethod(AIClient , missionCycleCleanup , void , () , "ai.missionCycleCleanup();" )

Tells the bot the mission is cycling.

DefineEngineMethod(AIClient , move , void , () , "ai.move();" )

Sets the AI to run mode.

DefineEngineMethod(AIClient , moveForward , void , () , "ai.moveForward();" )

Tells the AI to move forward 100 units...TEST FXN.

DefineEngineMethod(AIClient , setAimLocation , void , (Point3F v) , "ai.setAimLocation( x y z );" )

Tells the AI to aim at the location provided.

DefineEngineMethod(AIClient , setMoveDestination , void , (Point3F v) , "ai.setMoveDestination( x y z );" )

Tells the AI to move to the location provided.

DefineEngineMethod(AIClient , setMoveSpeed , void , (F32 speed) , "ai.setMoveSpeed( float );" )

Sets the move speed for an AI object.

DefineEngineMethod(AIClient , setTargetObject , void , (const char *objName) , "ai.setTargetObject( obj );" )

Sets the bots target object.

DefineEngineMethod(AIClient , stop , void , () , "ai.stop();" )

Stops all AI movement, halt!

IMPLEMENT_CALLBACK(AIClient , onConnect , void , (const char *idString) , (idString) , "" )

Detailed Description

Public Functions

ConsoleDocClass(AIClient , "@brief Simulated client driven by AI <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">commands.\n\n</a>" "This object is derived from the <a href="/coding/class/classaiconnection/">AIConnection</a> class. It introduces its own <a href="/coding/class/classplayer/">Player</a> object " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> solidify the purpose of this class: Simulated client connecting as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">player\n\n</a>" "To get more specific, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> you want <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> strong alternative <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a>  AIPlayer, consider AIClient. <a href="/coding/class/classaiclient/">AIClient</a> inherits from AIConnection, " "contains quite <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> bit of functionality you will find in AIPlayer, and has its own <a href="/coding/class/classplayer/">Player</a> " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" " @note This is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> legacy class, which you are discouraged from using as it will " "most likely be deprecated in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> future version. For now it has been left in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "backwards compatibility with TGE and the old RTS Kit. Use <a href="/coding/class/classaiplayer/">AIPlayer</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instead.\n\n</a>" " @see AIPlayer, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AIConnection\n\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">Networking\n</a>" )

DefineEngineFunction(aiAddPlayer , S32 , (const char *name, const char *ns) , ("") , "'playerName' )

Adds an AI Player to the game.

DefineEngineMethod(AIClient , getAimLocation , Point3F , () , "ai.getAimLocation();" )

Returns the point the AI is aiming at.

DefineEngineMethod(AIClient , getLocation , Point3F , () , "ai.getLocation();" )

Gets the AI's location in the world.

DefineEngineMethod(AIClient , getMoveDestination , Point3F , () , "ai.getMoveDestination();" )

Returns the point the AI is set to move to.

DefineEngineMethod(AIClient , getTargetObject , S32 , () , "ai.getTargetObject();" )

Gets the object the AI is targeting.

DefineEngineMethod(AIClient , missionCycleCleanup , void , () , "ai.missionCycleCleanup();" )

Tells the bot the mission is cycling.

DefineEngineMethod(AIClient , move , void , () , "ai.move();" )

Sets the AI to run mode.

DefineEngineMethod(AIClient , moveForward , void , () , "ai.moveForward();" )

Tells the AI to move forward 100 units...TEST FXN.

DefineEngineMethod(AIClient , setAimLocation , void , (Point3F v) , "ai.setAimLocation( x y z );" )

Tells the AI to aim at the location provided.

DefineEngineMethod(AIClient , setMoveDestination , void , (Point3F v) , "ai.setMoveDestination( x y z );" )

Tells the AI to move to the location provided.

DefineEngineMethod(AIClient , setMoveSpeed , void , (F32 speed) , "ai.setMoveSpeed( float );" )

Sets the move speed for an AI object.

DefineEngineMethod(AIClient , setTargetObject , void , (const char *objName) , "ai.setTargetObject( obj );" )

Sets the bots target object.

DefineEngineMethod(AIClient , stop , void , () , "ai.stop();" )

Stops all AI movement, halt!

IMPLEMENT_CALLBACK(AIClient , onConnect , void , (const char *idString) , (idString) , "" )

IMPLEMENT_CONOBJECT(AIClient )

  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#include "platform/platform.h"
 25#include "T3D/aiClient.h"
 26
 27#include "math/mMatrix.h"
 28#include "T3D/shapeBase.h"
 29#include "T3D/player.h"
 30#include "T3D/gameBase/moveManager.h"
 31#include "console/consoleInternal.h"
 32#include "console/engineAPI.h"
 33
 34
 35IMPLEMENT_CONOBJECT( AIClient );
 36
 37ConsoleDocClass( AIClient,
 38   "@brief Simulated client driven by AI commands.\n\n"
 39
 40   "This object is derived from the AIConnection class. It introduces its own Player object "
 41   "to solidify the purpose of this class: Simulated client connecting as a player\n\n"
 42   "To get more specific, if you want a strong alternative to AIPlayer (and wish to make use "
 43   "of the AIConnection structure), consider AIClient. AIClient inherits from AIConnection, "
 44   "contains quite a bit of functionality you will find in AIPlayer, and has its own Player "
 45   "object.\n\n"
 46
 47   "@note This is a legacy class, which you are discouraged from using as it will "
 48   "most likely be deprecated in a future version. For now it has been left in for "
 49   "backwards compatibility with TGE and the old RTS Kit. Use AIPlayer instead.\n\n"
 50
 51   "@see AIPlayer, AIConnection\n\n"
 52
 53   "@ingroup AI\n"
 54   "@ingroup Networking\n"
 55);
 56
 57IMPLEMENT_CALLBACK(AIClient, onConnect, void, (const char* idString), (idString),"");
 58
 59/**
 60 * Constructor
 61 */
 62AIClient::AIClient() {
 63   mMoveMode = ModeStop;
 64   mMoveDestination.set( 0.0f, 0.0f, 0.0f );
 65   mAimLocation.set( 0.0f, 0.0f, 0.0f );
 66   mMoveSpeed = 1.0f;
 67   mMoveTolerance = 0.25f;
 68
 69   // Clear the triggers
 70   for( S32 i = 0; i < MaxTriggerKeys; i++ )
 71      mTriggers[i] = false;
 72 
 73   mAimToDestination = true;
 74   mTargetInLOS = false;
 75
 76   mLocation.set( 0.0f, 0.0f, 0.0f );
 77   mPlayer = NULL;
 78}
 79
 80/**
 81 * Destructor
 82 */
 83AIClient::~AIClient() {
 84   // Blah
 85}
 86
 87/**
 88 * Sets the object the bot is targeting
 89 *
 90 * @param targetObject The object to target
 91 */
 92void AIClient::setTargetObject( ShapeBase *targetObject ) {   
 93   if ( !targetObject || !bool( mTargetObject ) || targetObject->getId() != mTargetObject->getId() )
 94      mTargetInLOS = false;
 95   
 96   mTargetObject = targetObject;
 97}
 98
 99/**
100 * Returns the target object
101 *
102 * @return Object bot is targeting
103 */
104S32 AIClient::getTargetObject() const {
105   if( bool( mTargetObject ) )
106      return mTargetObject->getId();
107   else
108      return -1;
109}
110
111/**
112 * Sets the speed at which this AI moves
113 *
114 * @param speed Speed to move, default player was 10
115 */
116void AIClient::setMoveSpeed( F32 speed ) {
117   if( speed <= 0.0f )
118      mMoveSpeed = 0.0f;
119   else
120      mMoveSpeed = getMin( 1.0f, speed );
121}
122
123/**
124 * Sets the movement mode for this AI
125 *
126 * @param mode Movement mode, see enum
127 */
128void AIClient::setMoveMode( S32 mode ) {
129   if( mode < 0 || mode >= ModeCount )
130      mode = 0;
131
132   if( mode != mMoveMode ) {
133      switch( mode ) {
134         case ModeStuck:
135            throwCallback( "onStuck" );
136            break;
137         case ModeMove:
138            if( mMoveMode == ModeStuck )
139               throwCallback( "onUnStuck" );
140            else
141               throwCallback( "onMove" );
142            break;
143         case ModeStop:
144            throwCallback( "onStop" );
145            break;
146      }
147   }
148
149   mMoveMode = mode;
150}
151
152/**
153 * Sets how far away from the move location is considered
154 * "on target"
155 * 
156 * @param tolerance Movement tolerance for error
157 */
158void AIClient::setMoveTolerance( const F32 tolerance ) {
159   mMoveTolerance = getMax( 0.1f, tolerance );
160}
161
162/**
163 * Sets the location for the bot to run to
164 *
165 * @param location Point to run to
166 */
167void AIClient::setMoveDestination( const Point3F &location ) {
168   // Ok, here's the story...we're going to aim where we are going UNLESS told otherwise
169   if( mAimToDestination ) {
170      mAimLocation = location;
171      mAimLocation.z = 0.0f;
172   }
173
174   mMoveDestination = location;
175}
176
177/**
178 * Sets the location for the bot to aim at
179 * 
180 * @param location Point to aim at
181 */
182void AIClient::setAimLocation( const Point3F &location ) {
183   mAimLocation = location;
184   mAimToDestination = false;
185}
186
187/**
188 * Clears the aim location and sets it to the bot's
189 * current destination so he looks where he's going
190 */
191void AIClient::clearAim() {
192   mAimLocation = Point3F( 0.0f, 0.0f, 0.0f );
193   mAimToDestination = true;
194}
195
196/**
197 * This method gets the move list for an object, in the case
198 * of the AI, it actually calculates the moves, and then
199 * sends them down the pipe.
200 *
201 * @param movePtr Pointer to move the move list into
202 * @param numMoves Number of moves in the move list
203 */
204U32 AIClient::getMoveList( Move **movePtr,U32 *numMoves ) {
205   //initialize the move structure and return pointers
206   mMove = NullMove;
207   *movePtr = &mMove;
208   *numMoves = 1;
209
210   // Check if we got a player
211   mPlayer = NULL;
212   mPlayer = dynamic_cast<Player *>( getControlObject() );
213
214   // We got a something controling us?
215   if( !mPlayer )
216      return 1;
217
218   
219   // What is The Matrix?
220   MatrixF moveMatrix;
221   moveMatrix.set( EulerF( 0, 0, 0 ) );
222   moveMatrix.setColumn( 3, Point3F( 0, 0, 0 ) );
223   moveMatrix.transpose();
224      
225   // Position / rotation variables
226   F32 curYaw, curPitch;
227   F32 newYaw, newPitch;
228   F32 xDiff, yDiff;
229
230   
231   F32 moveSpeed = mMoveSpeed;
232
233   switch( mMoveMode ) {
234
235   case ModeStop:
236      return 1;     // Stop means no action
237      break;
238
239   case ModeStuck:
240      // Fall through, so we still try to move
241   case ModeMove:
242   
243      // Get my location
244      MatrixF const& myTransform = mPlayer->getTransform();
245      myTransform.getColumn( 3, &mLocation );
246   
247      // Set rotation variables
248      Point3F rotation = mPlayer->getRotation();
249      Point3F headRotation = mPlayer->getHeadRotation();
250      curYaw = rotation.z;
251      curPitch = headRotation.x;
252      xDiff = mAimLocation.x - mLocation.x;
253      yDiff = mAimLocation.y - mLocation.y;
254   
255      // first do Yaw
256      if( !mIsZero( xDiff ) || !mIsZero( yDiff ) ) {
257         // use the cur yaw between -Pi and Pi
258         while( curYaw > M_2PI_F )
259            curYaw -= M_2PI_F;
260         while( curYaw < -M_2PI_F )
261            curYaw += M_2PI_F;
262      
263         // find the new yaw
264         newYaw = mAtan2( xDiff, yDiff );
265      
266         // find the yaw diff 
267         F32 yawDiff = newYaw - curYaw;
268      
269         // make it between 0 and 2PI
270         if( yawDiff < 0.0f )
271            yawDiff += M_2PI_F;
272         else if( yawDiff >= M_2PI_F )
273            yawDiff -= M_2PI_F;
274      
275         // now make sure we take the short way around the circle
276         if( yawDiff > M_2PI_F )
277            yawDiff -= M_2PI_F;
278         else if( yawDiff < -M_2PI_F )
279            yawDiff += M_2PI_F;
280      
281         mMove.yaw = yawDiff;
282      
283         // set up the movement matrix
284         moveMatrix.set( EulerF( 0.0f, 0.0f, newYaw ) );
285      }
286      else
287         moveMatrix.set( EulerF( 0.0f, 0.0f, curYaw ) );
288   
289      // next do pitch
290      F32 horzDist = Point2F( mAimLocation.x, mAimLocation.y ).len();
291
292      if( !mIsZero( horzDist ) ) {
293         //we shoot from the gun, not the eye...
294         F32 vertDist = mAimLocation.z;
295      
296         newPitch = mAtan2( horzDist, vertDist ) - ( M_2PI_F / 2.0f );
297      
298         F32 pitchDiff = newPitch - curPitch;
299         mMove.pitch = pitchDiff;
300      }
301   
302      // finally, mMove towards mMoveDestination
303      xDiff = mMoveDestination.x - mLocation.x;
304      yDiff = mMoveDestination.y - mLocation.y;
305
306
307      // Check if we should mMove, or if we are 'close enough'
308      if( ( ( mFabs( xDiff ) > mMoveTolerance ) || 
309            ( mFabs( yDiff ) > mMoveTolerance ) ) && ( !mIsZero( mMoveSpeed ) ) )
310      {
311         if( mIsZero( xDiff ) )
312            mMove.y = ( mLocation.y > mMoveDestination.y ? -moveSpeed : moveSpeed );
313         else if( mIsZero( yDiff ) )
314            mMove.x = ( mLocation.x > mMoveDestination.x ? -moveSpeed : moveSpeed );
315         else if( mFabs( xDiff ) > mFabs( yDiff ) ) {
316            F32 value = mFabs( yDiff / xDiff ) * mMoveSpeed;
317            mMove.y = ( mLocation.y > mMoveDestination.y ? -value : value );
318            mMove.x = ( mLocation.x > mMoveDestination.x ? -moveSpeed : moveSpeed );
319         }
320         else {
321            F32 value = mFabs( xDiff / yDiff ) * mMoveSpeed;
322            mMove.x = ( mLocation.x > mMoveDestination.x ? -value : value );
323            mMove.y = ( mLocation.y > mMoveDestination.y ? -moveSpeed : moveSpeed );
324         }
325      
326         //now multiply the mMove vector by the transpose of the object rotation matrix
327         moveMatrix.transpose();
328         Point3F newMove;
329         moveMatrix.mulP( Point3F( mMove.x, mMove.y, 0.0f ), &newMove );
330      
331         //and sub the result back in the mMove structure
332         mMove.x = newMove.x;
333         mMove.y = newMove.y;
334
335         // We should check to see if we are stuck...
336         if( mLocation.x == mLastLocation.x && 
337             mLocation.y == mLastLocation.y &&
338             mLocation.z == mLastLocation.z ) {
339
340            // We're stuck...probably
341            setMoveMode( ModeStuck );
342         }
343         else
344            setMoveMode( ModeMove );
345      }
346      else {
347         // Ok, we are close enough, lets stop
348
349         // setMoveMode( ModeStop ); // DON'T use this, it'll throw the wrong callback
350         mMoveMode = ModeStop;
351         throwCallback(  "onReachDestination" ); // Callback
352
353      }
354      break;
355   }
356
357   // Test for target location in sight
358   RayInfo dummy;
359   Point3F targetLoc = mMoveDestination; // Change this
360
361   if( mPlayer ) {
362      if( !mPlayer->getContainer()->castRay( mLocation, targetLoc, 
363                                                StaticShapeObjectType | StaticObjectType |
364                                                TerrainObjectType, &dummy ) ) {
365         if( !mTargetInLOS )
366            throwCallback( "onTargetEnterLOS" );
367      }
368      else {
369         if( mTargetInLOS )
370            throwCallback( "onTargetExitLOS" );
371            
372      }
373   }
374   
375   // Copy over the trigger status
376   for( S32 i = 0; i < MaxTriggerKeys; i++ ) {
377      mMove.trigger[i] = mTriggers[i];
378      mTriggers[i] = false;
379   }
380
381   return 1;
382}
383
384/**
385 * This method is just called to stop the bots from running amuck
386 * while the mission cycles
387 */
388void AIClient::missionCycleCleanup() {
389   setMoveMode( ModeStop );
390}
391
392
393/**
394 * Utility function to throw callbacks
395 */
396void AIClient::throwCallback( const char *name ) {
397   Con::executef( this, name );
398}
399
400/**
401 * What gets called when this gets created, different from constructor
402 */
403void AIClient::onAdd( const char *nameSpace ) {
404
405   // This doesn't work...
406   //
407   if( String::compare( nameSpace, mNameSpace->mName ) ) {
408      Con::linkNamespaces( mNameSpace->mName, nameSpace );
409      mNameSpace = Con::lookupNamespace( nameSpace );
410   }
411
412   throwCallback( "onAdd" );
413}
414
415// --------------------------------------------------------------------------------------------
416// Console Functions
417// --------------------------------------------------------------------------------------------
418
419/**
420 * Sets the move speed for an AI object
421 */
422DefineEngineMethod( AIClient, setMoveSpeed, void, (F32 speed), , "ai.setMoveSpeed( float );" ) 
423{
424   AIClient *ai = static_cast<AIClient *>( object );
425   ai->setMoveSpeed( speed );
426}
427
428/**
429 * Stops all AI movement, halt!
430 */
431DefineEngineMethod( AIClient, stop, void, (),, "ai.stop();" ) 
432{
433   AIClient *ai = static_cast<AIClient *>( object );
434   ai->setMoveMode( AIClient::ModeStop );
435}
436
437/**
438 * Tells the AI to aim at the location provided
439 */
440DefineEngineMethod( AIClient, setAimLocation, void, (Point3F v), , "ai.setAimLocation( x y z );" ) 
441{
442   AIClient *ai = static_cast<AIClient *>( object );
443
444   ai->setAimLocation( v );
445}
446
447/**
448 * Tells the AI to move to the location provided
449 */
450DefineEngineMethod( AIClient, setMoveDestination, void, (Point3F v), , "ai.setMoveDestination( x y z );" )
451{
452   AIClient *ai = static_cast<AIClient *>( object );
453
454   ai->setMoveDestination( v );
455}
456
457/**
458 * Returns the point the AI is aiming at
459 */
460DefineEngineMethod( AIClient, getAimLocation, Point3F, (),, "ai.getAimLocation();" ) 
461{
462   AIClient *ai = static_cast<AIClient *>( object );
463   return ai->getAimLocation();
464}
465
466/**
467 * Returns the point the AI is set to move to
468 */
469DefineEngineMethod( AIClient, getMoveDestination, Point3F, (),, "ai.getMoveDestination();" ) 
470{
471   AIClient *ai = static_cast<AIClient *>( object );
472   return ai->getMoveDestination();
473}
474
475/**
476 * Sets the bots target object
477 */
478DefineEngineMethod( AIClient, setTargetObject, void, (const char * objName), , "ai.setTargetObject( obj );" ) 
479{
480   AIClient *ai = static_cast<AIClient *>( object );
481   
482   // Find the target
483   ShapeBase *targetObject;
484   if( Sim::findObject( objName, targetObject ) )
485      ai->setTargetObject( targetObject );
486   else
487      ai->setTargetObject( NULL );
488}
489
490/**
491 * Gets the object the AI is targeting
492 */
493DefineEngineMethod( AIClient, getTargetObject, S32, (),, "ai.getTargetObject();" ) 
494{
495   AIClient *ai = static_cast<AIClient *>( object );
496
497   return ai->getTargetObject();
498}
499
500/**
501 * Tells the bot the mission is cycling
502 */
503DefineEngineMethod( AIClient, missionCycleCleanup, void, (),, "ai.missionCycleCleanup();" ) 
504{
505   AIClient *ai = static_cast<AIClient*>( object );
506   ai->missionCycleCleanup();
507}
508
509/**
510 * Sets the AI to run mode
511 */
512DefineEngineMethod( AIClient, move, void, (),, "ai.move();" ) 
513{
514   AIClient *ai = static_cast<AIClient *>( object );
515   ai->setMoveMode( AIClient::ModeMove );
516}
517
518/**
519 * Gets the AI's location in the world
520 */
521DefineEngineMethod( AIClient, getLocation, Point3F, (),, "ai.getLocation();" ) 
522{
523   AIClient *ai = static_cast<AIClient *>( object );
524   return ai->getLocation();
525}
526
527/**
528 * Adds an AI Player to the game
529 */
530DefineEngineFunction( aiAddPlayer, S32, (const char * name, const char * ns), (""), "'playerName'[, 'AIClassType'] );")
531{
532   // Create the player
533   AIClient *aiPlayer = new AIClient();
534   aiPlayer->registerObject();
535   aiPlayer->setGhostFrom(false);
536   aiPlayer->setGhostTo(false);
537   aiPlayer->setSendingEvents(false);
538   aiPlayer->setTranslatesStrings(true);
539   aiPlayer->setEstablished();
540   
541   // Add the connection to the client group
542   SimGroup *g = Sim::getClientGroup();
543   g->addObject( aiPlayer );
544
545
546   // Execute the connect console function, this is the same 
547   // onConnect function invoked for normal client connections
548   aiPlayer->onConnect_callback( name );
549
550   // Now execute the onAdd command and feed it the namespace
551   if(String::compare( ns,"" ) != 0 )
552      aiPlayer->onAdd( ns );
553   else
554      aiPlayer->onAdd( "AIClient" );
555
556   return aiPlayer->getId();
557}
558
559
560/**
561 * Tells the AI to move forward 100 units...TEST FXN
562 */
563DefineEngineMethod( AIClient, moveForward, void, (),, "ai.moveForward();" ) 
564{
565   
566   AIClient *ai = static_cast<AIClient *>( object );
567   ShapeBase *player = dynamic_cast<ShapeBase*>(ai->getControlObject());
568   Point3F location;
569   MatrixF const &myTransform = player->getTransform();
570   myTransform.getColumn( 3, &location );
571
572   location.y += 100.0f;
573   
574   ai->setMoveDestination( location );
575} // *** /TEST FXN
576