Explorar el Código

Merge pull request #545 from blackberry-gaming/next-sgrenier

Next sgrenier
Steve Grenier hace 13 años
padre
commit
8b77b4dd37
Se han modificado 44 ficheros con 4659 adiciones y 5 borrados
  1. 26 0
      gameplay/gameplay.vcxproj
  2. 78 0
      gameplay/gameplay.vcxproj.filters
  3. 90 0
      gameplay/src/AIAgent.cpp
  4. 163 0
      gameplay/src/AIAgent.h
  5. 199 0
      gameplay/src/AIController.cpp
  6. 107 0
      gameplay/src/AIController.h
  7. 203 0
      gameplay/src/AIMessage.cpp
  8. 272 0
      gameplay/src/AIMessage.h
  9. 74 0
      gameplay/src/AIState.cpp
  10. 137 0
      gameplay/src/AIState.h
  11. 127 0
      gameplay/src/AIStateMachine.cpp
  12. 160 0
      gameplay/src/AIStateMachine.h
  13. 19 3
      gameplay/src/Game.cpp
  14. 10 0
      gameplay/src/Game.h
  15. 4 0
      gameplay/src/Game.inl
  16. 31 2
      gameplay/src/Node.cpp
  17. 20 0
      gameplay/src/Node.h
  18. 6 0
      gameplay/src/gameplay.h
  19. 469 0
      gameplay/src/lua/lua_AIAgent.cpp
  20. 24 0
      gameplay/src/lua/lua_AIAgent.h
  21. 115 0
      gameplay/src/lua/lua_AIAgentListener.cpp
  22. 15 0
      gameplay/src/lua/lua_AIAgentListener.h
  23. 144 0
      gameplay/src/lua/lua_AIController.cpp
  24. 15 0
      gameplay/src/lua/lua_AIController.h
  25. 838 0
      gameplay/src/lua/lua_AIMessage.cpp
  26. 32 0
      gameplay/src/lua/lua_AIMessage.h
  27. 58 0
      gameplay/src/lua/lua_AIMessageParameterType.cpp
  28. 15 0
      gameplay/src/lua/lua_AIMessageParameterType.h
  29. 309 0
      gameplay/src/lua/lua_AIState.cpp
  30. 20 0
      gameplay/src/lua/lua_AIState.h
  31. 243 0
      gameplay/src/lua/lua_AIStateListener.cpp
  32. 18 0
      gameplay/src/lua/lua_AIStateListener.h
  33. 343 0
      gameplay/src/lua/lua_AIStateMachine.cpp
  34. 19 0
      gameplay/src/lua/lua_AIStateMachine.h
  35. 47 0
      gameplay/src/lua/lua_Game.cpp
  36. 1 0
      gameplay/src/lua/lua_Game.h
  37. 17 0
      gameplay/src/lua/lua_Global.cpp
  38. 1 0
      gameplay/src/lua/lua_Global.h
  39. 86 0
      gameplay/src/lua/lua_Joint.cpp
  40. 2 0
      gameplay/src/lua/lua_Joint.h
  41. 86 0
      gameplay/src/lua/lua_Node.cpp
  42. 2 0
      gameplay/src/lua/lua_Node.h
  43. 7 0
      gameplay/src/lua/lua_all_bindings.cpp
  44. 7 0
      gameplay/src/lua/lua_all_bindings.h

+ 26 - 0
gameplay/gameplay.vcxproj

@@ -16,6 +16,11 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="src\AbsoluteLayout.cpp" />
+    <ClCompile Include="src\AIAgent.cpp" />
+    <ClCompile Include="src\AIController.cpp" />
+    <ClCompile Include="src\AIMessage.cpp" />
+    <ClCompile Include="src\AIState.cpp" />
+    <ClCompile Include="src\AIStateMachine.cpp" />
     <ClCompile Include="src\Animation.cpp" />
     <ClCompile Include="src\AnimationClip.cpp" />
     <ClCompile Include="src\AnimationController.cpp" />
@@ -54,6 +59,14 @@
     <ClCompile Include="src\Layout.cpp" />
     <ClCompile Include="src\Light.cpp" />
     <ClCompile Include="src\lua\lua_AbsoluteLayout.cpp" />
+    <ClCompile Include="src\lua\lua_AIAgent.cpp" />
+    <ClCompile Include="src\lua\lua_AIAgentListener.cpp" />
+    <ClCompile Include="src\lua\lua_AIController.cpp" />
+    <ClCompile Include="src\lua\lua_AIMessage.cpp" />
+    <ClCompile Include="src\lua\lua_AIMessageParameterType.cpp" />
+    <ClCompile Include="src\lua\lua_AIState.cpp" />
+    <ClCompile Include="src\lua\lua_AIStateListener.cpp" />
+    <ClCompile Include="src\lua\lua_AIStateMachine.cpp" />
     <ClCompile Include="src\lua\lua_all_bindings.cpp" />
     <ClCompile Include="src\lua\lua_Animation.cpp" />
     <ClCompile Include="src\lua\lua_AnimationClip.cpp" />
@@ -261,6 +274,11 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\AbsoluteLayout.h" />
+    <ClInclude Include="src\AIAgent.h" />
+    <ClInclude Include="src\AIController.h" />
+    <ClInclude Include="src\AIMessage.h" />
+    <ClInclude Include="src\AIState.h" />
+    <ClInclude Include="src\AIStateMachine.h" />
     <ClInclude Include="src\Animation.h" />
     <ClInclude Include="src\AnimationClip.h" />
     <ClInclude Include="src\AnimationController.h" />
@@ -299,6 +317,14 @@
     <ClInclude Include="src\Layout.h" />
     <ClInclude Include="src\Light.h" />
     <ClInclude Include="src\lua\lua_AbsoluteLayout.h" />
+    <ClInclude Include="src\lua\lua_AIAgent.h" />
+    <ClInclude Include="src\lua\lua_AIAgentListener.h" />
+    <ClInclude Include="src\lua\lua_AIController.h" />
+    <ClInclude Include="src\lua\lua_AIMessage.h" />
+    <ClInclude Include="src\lua\lua_AIMessageParameterType.h" />
+    <ClInclude Include="src\lua\lua_AIState.h" />
+    <ClInclude Include="src\lua\lua_AIStateListener.h" />
+    <ClInclude Include="src\lua\lua_AIStateMachine.h" />
     <ClInclude Include="src\lua\lua_all_bindings.h" />
     <ClInclude Include="src\lua\lua_Animation.h" />
     <ClInclude Include="src\lua\lua_AnimationClip.h" />

+ 78 - 0
gameplay/gameplay.vcxproj.filters

@@ -744,6 +744,45 @@
     <ClCompile Include="src\ScriptListener.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\AIAgent.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIController.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIMessage.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIState.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIStateMachine.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIAgent.cpp">
+      <Filter>lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIAgentListener.cpp">
+      <Filter>lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIController.cpp">
+      <Filter>lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIMessage.cpp">
+      <Filter>lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIMessageParameterType.cpp">
+      <Filter>lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIState.cpp">
+      <Filter>lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIStateListener.cpp">
+      <Filter>lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIStateMachine.cpp">
+      <Filter>lua</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -1481,6 +1520,45 @@
     <ClInclude Include="src\ScriptListener.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\AIStateMachine.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIAgent.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIController.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIMessage.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIState.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIAgent.h">
+      <Filter>lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIAgentListener.h">
+      <Filter>lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIController.h">
+      <Filter>lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIMessage.h">
+      <Filter>lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIMessageParameterType.h">
+      <Filter>lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIState.h">
+      <Filter>lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIStateListener.h">
+      <Filter>lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIStateMachine.h">
+      <Filter>lua</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\gameplay-main-macosx.mm">

+ 90 - 0
gameplay/src/AIAgent.cpp

@@ -0,0 +1,90 @@
+#include "Base.h"
+#include "AIAgent.h"
+#include "Node.h"
+
+namespace gameplay
+{
+
+AIAgent::AIAgent()
+    : _stateMachine(NULL), _node(NULL), _enabled(true), _next(NULL)
+{
+    _stateMachine = new AIStateMachine(this);
+}
+
+AIAgent::~AIAgent()
+{
+    SAFE_DELETE(_stateMachine);
+}
+
+AIAgent* AIAgent::create()
+{
+    return new AIAgent();
+}
+
+const char* AIAgent::getId() const
+{
+    if (_node)
+        return _node->getId();
+
+    return "";
+}
+
+Node* AIAgent::getNode() const
+{
+    return _node;
+}
+
+AIStateMachine* AIAgent::getStateMachine()
+{
+    return _stateMachine;
+}
+
+bool AIAgent::isEnabled() const
+{
+    return (_node && _enabled);
+}
+
+void AIAgent::setEnabled(bool enabled)
+{
+    _enabled = enabled;
+}
+
+void AIAgent::setListener(Listener* listener)
+{
+    _listener = listener;
+}
+
+void AIAgent::update(float elapsedTime)
+{
+    _stateMachine->update(elapsedTime);
+}
+
+bool AIAgent::processMessage(AIMessage* message)
+{
+    // Handle built-in message types.
+    switch (message->_messageType)
+    {
+    case AIMessage::MESSAGE_TYPE_STATE_CHANGE:
+        {
+            // Change state message
+            const char* stateId = message->getString(0);
+            if (stateId)
+            {
+                AIState* state = _stateMachine->getState(stateId);
+                if (state)
+                    _stateMachine->setStateInternal(state);
+            }
+        }
+        break;
+    }
+
+    // Dispatch message to registered listener.
+    if (_listener && _listener->messageReceived(message))
+        return true;
+    
+    // TODO: Fire script listener
+    
+    return false;
+}
+
+}

+ 163 - 0
gameplay/src/AIAgent.h

@@ -0,0 +1,163 @@
+#ifndef AIAGENT_H_
+#define AIAGENT_H_
+
+#include "Ref.h"
+#include "AIStateMachine.h"
+#include "AIMessage.h"
+
+namespace gameplay
+{
+
+class Node;
+
+/**
+ * Defines an AI agent that can be added to nodes in a scene.
+ *
+ * Agents represent a unit of intelligence in a game and can be used
+ * to program logic for a character or object in a game, using constrcuts
+ * such as state machines. By default, an AIAgent has an empty state 
+ * machine.
+ */
+class AIAgent : public Ref
+{
+    friend class Node;
+    friend class AIController;
+
+public:
+
+    /**
+     * Interface for listening to AIAgent events.
+     */
+    class Listener
+    {
+    public:
+
+        /**
+         * Virtual destructor.
+         */
+        virtual ~Listener() { };
+
+        /**
+         * Called when a new message is sent to the AIAgent.
+         *
+         * Both global/broadcast messages and messages sent explicitly to the
+         * AIAgent are sent through this method. Returning true from this method
+         * will mark the message as handled and it will dispose of the message
+         * and prevent any other possible recipients from receiving the message.
+         * Alternatively, returning false allows the message to continue being
+         * routed though the AI system.
+         *
+         * @param message The message received.
+         *
+         * @return true to mark the message as handled, false otherwise.
+         */
+        virtual bool messageReceived(AIMessage* message) = 0;
+    };
+
+    /**
+     * Creates a new AIAgent.
+     *
+     * @return A new AIAgent.
+     */
+    static AIAgent* create();
+
+    /**
+     * Returns the identifier for the AIAgent.
+     *
+     * @return The identifier for the agent.
+     */
+    const char* getId() const;
+
+    /**
+     * Returns the Node this AIAgent is assigned to.
+     *
+     * @return The Node this agent is assigned to.
+     */
+    Node* getNode() const;
+
+    /**
+     * Returns the state machine for the AIAgent.
+     *
+     * @return The agent's state machine.
+     */
+    AIStateMachine* getStateMachine();
+
+    /**
+     * Determines if this AIAgent is currently enabled.
+     *
+     * Agents are always disabled until they have been associated
+     * with a valid Node though Node::setAgent(AIAgent*). In addition,
+     * an AIAgent can be explicitly enabled or disabled using the
+     * setEnabled(bool) method.
+     *
+     * @return true if the agent is enabled, false otherwise.
+     */
+    bool isEnabled() const;
+
+    /**
+     * Sets whether this AIAgent is enabled.
+     *
+     * By default, AIAgents are enabled and they can receive messages and state
+     * changes. When disabled, AIAgents stop receiving messages and their state
+     * machines are halted until they are re-enabled.
+     *
+     * @param enabled true if the AIAgent should be enabled, false otherwise.
+     */
+    void setEnabled(bool enabled);
+
+    /**
+     * Sets an event listener for this AIAgent.
+     *
+     * @param listener The new AIAgent listener, or NULL to remove any existing listener.
+     */
+    void setListener(Listener* listener);
+
+private:
+
+    /**
+     * Constructor.
+     */
+    AIAgent();
+
+    /**
+     * Destructor.
+     *
+     * Hidden, use SAFE_RELEASE instead.
+     */
+    virtual ~AIAgent();
+
+    /**
+     * Hidden copy constructor.
+     */
+    AIAgent(const AIAgent&);
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    AIAgent& operator=(const AIAgent&);
+
+    /**
+     * Called by the AIController to process a message for the AIAgent.
+     *
+     * @param message The message to be processed.
+     *
+     * @return true if the message was handled, false otherwise.
+     */
+    bool processMessage(AIMessage* message);
+
+    /**
+     * Called once per frame by the AIController to update the agent.
+     */
+    void update(float elapsedTime);
+
+    AIStateMachine* _stateMachine;
+    Node* _node;
+    bool _enabled;
+    Listener* _listener;
+    AIAgent* _next;
+
+};
+
+}
+
+#endif

+ 199 - 0
gameplay/src/AIController.cpp

@@ -0,0 +1,199 @@
+#include "Base.h"
+#include "AIController.h"
+#include "Game.h"
+
+// TODO:
+//
+// 1) Is std::string OK for message sender/receiver?
+// 2) Is AIMessage ok and is "dobule" ok for message parameters?
+// 3) Design of creating and deleting message (AIController deletes them)??
+// 4) Is setListener(Listener*) OK for AIState and AIStateMachine, or do we need addListener(Listener*)???
+
+// TODO: Add a way to snif messages on AIController??
+
+// TODO: only dispatch messages to agents that are in this list AND enabled. If not in the list, discard the message (and log) and if they are in the list and DISABLED, just hold on to the message until they are re-enabled.
+
+namespace gameplay
+{
+
+AIController::AIController()
+    : _paused(false), _firstMessage(NULL), _firstAgent(NULL)
+{
+}
+
+AIController::~AIController()
+{
+}
+
+void AIController::initialize()
+{
+}
+
+void AIController::finalize()
+{
+    // Remove all agents
+    AIAgent* agent = _firstAgent;
+    while (agent)
+    {
+        AIAgent* temp = agent;
+        agent = agent->_next;
+        SAFE_RELEASE(temp);
+    }
+    _firstAgent = NULL;
+
+    // Remove all messages
+    AIMessage* message = _firstMessage;
+    while (message)
+    {
+        AIMessage* temp = message;
+        message = message->_next;
+        SAFE_DELETE(temp);
+    }
+    _firstMessage = NULL;
+}
+
+void AIController::pause()
+{
+    _paused = true;
+}
+
+void AIController::resume()
+{
+    _paused = false;
+}
+
+void AIController::sendMessage(AIMessage* message, float delay)
+{
+    if (delay <= 0)
+    {
+        // Send instantly
+        if (message->getReceiver() == NULL || strlen(message->getReceiver()) == 0)
+        {
+            // Broadcast message to all agents
+            AIAgent* agent = _firstAgent;
+            while (agent)
+            {
+                if (agent->processMessage(message))
+                    break; // message consumed by this agent - stop bubbling
+                agent = agent->_next;
+            }
+        }
+        else
+        {
+            // Single recipient
+            AIAgent* agent = findAgent(message->getReceiver());
+            if (agent)
+            {
+                agent->processMessage(message);
+            }
+            else
+            {
+                GP_WARN("Failed to locate AIAgent for message recipient: %s", message->getReceiver());
+            }
+        }
+
+        // Delete the message, since it is finished being processed
+        SAFE_DELETE(message);
+    }
+    else
+    {
+        // Queue for later delivery
+        if (_firstMessage)
+            message->_next = _firstMessage;
+        _firstMessage = message;
+    }
+}
+
+void AIController::update(float elapsedTime)
+{
+    if (_paused)
+        return;
+
+    static Game* game = Game::getInstance();
+
+    // Send all pending messages that have expired
+    AIMessage* prevMsg = NULL;
+    AIMessage* msg = _firstMessage;
+    while (msg)
+    {
+        // If the message delivery time has expired, send it (this also deletes it)
+        if (msg->getDeliveryTime() >= game->getGameTime())
+        {
+            // Link the message out of our list
+            if (prevMsg)
+                prevMsg->_next = msg->_next;
+
+            AIMessage* temp = msg;
+            msg = msg->_next;
+            temp->_next = NULL;
+            sendMessage(temp);
+        }
+        else
+        {
+            prevMsg = msg;
+            msg = msg->_next;
+        }
+    }
+
+    // Update all enabled agents
+    AIAgent* agent = _firstAgent;
+    while (agent)
+    {
+        if (agent->isEnabled())
+            agent->update(elapsedTime);
+
+        agent = agent->_next;
+    }
+}
+
+void AIController::addAgent(AIAgent* agent)
+{
+    agent->addRef();
+
+    if (_firstAgent)
+        agent->_next = _firstAgent;
+
+    _firstAgent = agent;
+}
+
+void AIController::removeAgent(AIAgent* agent)
+{
+    // Search our linked list of agents and link this agent out.
+    AIAgent* prevAgent = NULL;
+    AIAgent* itr = _firstAgent;
+    while (itr)
+    {
+        if (itr == agent)
+        {
+            if (prevAgent)
+                prevAgent->_next = agent->_next;
+            else
+                _firstAgent = agent->_next;
+
+            agent->_next = NULL;
+            agent->release();
+            break;
+        }
+
+        prevAgent = itr;
+        itr = itr->_next;
+    }
+}
+
+AIAgent* AIController::findAgent(const char* id) const
+{
+    GP_ASSERT(id);
+
+    AIAgent* agent = _firstAgent;
+    while (agent)
+    {
+        if (strcmp(id, agent->getId()) == 0)
+            return agent;
+
+        agent = agent->_next;
+    }
+
+    return NULL;
+}
+
+}

+ 107 - 0
gameplay/src/AIController.h

@@ -0,0 +1,107 @@
+#ifndef AICONTROLLER_H_
+#define AICONTROLLER_H_
+
+#include "AIAgent.h"
+#include "AIMessage.h"
+
+namespace gameplay
+{
+
+/**
+ * The AIController facilitates state machine execution and message passing
+ * between AI objects in the game. This class is generally not interfaced
+ * with directly.
+ */
+class AIController
+{
+    friend class Game;
+    friend class Node;
+
+public:
+
+    /**
+     * Routes the secified message to its intended recipient(s).
+     *
+     * Messages are arbitrary packets of data that are sent either to a single or to multiple
+     * recipients in the game.
+     *
+     * Once the specified message has been delivered, it is automatically destroyed by the AIController.
+     * For this reason, AIMessage pointers should NOT be held or explicity destroyed by any code after
+     * they are sent through the AIController.
+     *
+     * @param message The message to send.
+     * @param delay The delay (in milliseconds) to wait before sending the message.
+     */
+    void sendMessage(AIMessage* message, float delay = 0);
+
+    /**
+     * Searches for an AIAgent that is registered with the AIController with the specified ID.
+     *
+     * @param id ID of the agent to find.
+     *
+     * @return The first agent matching the specified ID, or NULL if no matching agent could be found.
+     */
+    AIAgent* findAgent(const char* id) const;
+
+private:
+
+    /**
+     * Constructor.
+     */
+    AIController();
+
+    /**
+     * Destructor.
+     */
+    ~AIController();
+
+    /**
+     * Hidden copy constructor.
+     */
+    AIController(const AIController&);
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    AIController& operator=(const AIController&);
+
+    /**
+     * Called during startup to initialize the AIController.
+     */
+    void initialize();
+
+    /**
+     * Called during shutdown to finalize the AIController.
+     */
+    void finalize();
+
+    /**
+     * Pauses the AIController.
+     */
+    void pause();
+
+    /**
+     * Resumes the AIController.
+     */
+    void resume();
+
+    /**
+     * Called each frame to update the AIController.
+     *
+     * @param elapsedTime The elapsed time, in milliseconds.
+     */
+    void update(float elapsedTime);
+
+    void addAgent(AIAgent* agent);
+
+    void removeAgent(AIAgent* agent);
+
+    bool _paused;
+    AIMessage* _firstMessage;
+    AIAgent* _firstAgent;
+
+};
+
+}
+
+#endif

+ 203 - 0
gameplay/src/AIMessage.cpp

@@ -0,0 +1,203 @@
+#include "Base.h"
+#include "AIMessage.h"
+
+namespace gameplay
+{
+
+AIMessage::AIMessage()
+    : _id(0), _deliveryTime(0), _parameters(NULL), _parameterCount(0), _messageType(MESSAGE_TYPE_CUSTOM), _next(NULL)
+{
+}
+
+AIMessage::~AIMessage()
+{
+    SAFE_DELETE_ARRAY(_parameters);
+}
+
+AIMessage* AIMessage::create(unsigned int id, const char* sender, const char* receiver, unsigned int parameterCount)
+{
+    AIMessage* message = new AIMessage();
+    message->_id = id;
+    message->_sender = sender;
+    message->_receiver = receiver;
+    message->_parameterCount = parameterCount;
+    if (parameterCount > 0)
+        message->_parameters = new AIMessage::Parameter[parameterCount];
+    return message;
+}
+
+unsigned int AIMessage::getId() const
+{
+    return _id;
+}
+
+const char* AIMessage::getSender() const
+{
+    return _sender.c_str();
+}
+
+const char* AIMessage::getReceiver() const
+{
+    return _receiver.c_str();
+}
+
+double AIMessage::getDeliveryTime() const
+{
+    return _deliveryTime;
+}
+
+int AIMessage::getInt(unsigned int index) const
+{
+    GP_ASSERT(index < _parameterCount);
+    GP_ASSERT(_parameters[index].type == AIMessage::INTEGER);
+
+    return _parameters[index].intValue;
+}
+
+void AIMessage::setInt(unsigned int index, int value)
+{
+    GP_ASSERT(index < _parameterCount);
+
+    clearParameter(index);
+
+    _parameters[index].intValue = value;
+    _parameters[index].type = AIMessage::INTEGER;
+}
+
+long AIMessage::getLong(unsigned int index) const
+{
+    GP_ASSERT(index < _parameterCount);
+    GP_ASSERT(_parameters[index].type == AIMessage::LONG);
+
+    return _parameters[index].longValue;
+}
+
+void AIMessage::setLong(unsigned int index, long value)
+{
+    GP_ASSERT(index < _parameterCount);
+
+    clearParameter(index);
+
+    _parameters[index].longValue = value;
+    _parameters[index].type = AIMessage::LONG;
+}
+
+float AIMessage::getFloat(unsigned int index) const
+{
+    GP_ASSERT(index < _parameterCount);
+    GP_ASSERT(_parameters[index].type == AIMessage::FLOAT);
+
+    return _parameters[index].floatValue;
+}
+
+void AIMessage::setFloat(unsigned int index, float value)
+{
+    GP_ASSERT(index < _parameterCount);
+
+    clearParameter(index);
+
+    _parameters[index].floatValue = value;
+    _parameters[index].type = AIMessage::FLOAT;
+}
+
+double AIMessage::getDouble(unsigned int index) const
+{
+    GP_ASSERT(index < _parameterCount);
+    GP_ASSERT(_parameters[index].type == AIMessage::DOUBLE);
+
+    return _parameters[index].doubleValue;
+}
+
+void AIMessage::setDouble(unsigned int index, double value)
+{
+    GP_ASSERT(index < _parameterCount);
+
+    clearParameter(index);
+
+    _parameters[index].doubleValue = value;
+    _parameters[index].type = AIMessage::DOUBLE;
+}
+
+bool AIMessage::getBoolean(unsigned int index) const
+{
+    GP_ASSERT(index < _parameterCount);
+    GP_ASSERT(_parameters[index].type == AIMessage::BOOLEAN);
+
+    return _parameters[index].boolValue;
+}
+
+void AIMessage::setBoolean(unsigned int index, bool value)
+{
+    GP_ASSERT(index < _parameterCount);
+
+    clearParameter(index);
+
+    _parameters[index].boolValue = value;
+    _parameters[index].type = AIMessage::BOOLEAN;
+}
+
+const char* AIMessage::getString(unsigned int index) const
+{
+    GP_ASSERT(index < _parameterCount);
+    GP_ASSERT(_parameters[index].type == AIMessage::STRING);
+
+    return _parameters[index].stringValue;
+}
+
+void AIMessage::setString(unsigned int index, const char* value)
+{
+    GP_ASSERT(index < _parameterCount);
+    GP_ASSERT(value);
+
+    clearParameter(index);
+
+    // Copy the string into our parameter
+    size_t len = strlen(value);
+    char* buffer = new char[len + 1];
+    strcpy(buffer, value);
+    _parameters[index].stringValue = buffer;
+    _parameters[index].type = AIMessage::STRING;
+}
+
+unsigned int AIMessage::getParameterCount() const
+{
+    return _parameterCount;
+}
+
+AIMessage::ParameterType AIMessage::getParameterType(unsigned int index) const
+{
+    GP_ASSERT(index < _parameterCount);
+
+    return _parameters[index].type;
+}
+
+void AIMessage::clearParameter(unsigned int index)
+{
+    GP_ASSERT(index < _parameterCount);
+
+    _parameters[index].clear();
+}
+
+AIMessage::Parameter::Parameter()
+    : type(UNDEFINED)
+{
+}
+
+AIMessage::Parameter::~Parameter()
+{
+    clear();
+}
+
+void AIMessage::Parameter::clear()
+{
+    switch (type)
+    {
+    case AIMessage::STRING:
+        SAFE_DELETE_ARRAY(stringValue);
+        break;
+    }
+
+    type = AIMessage::UNDEFINED;
+}
+
+}

+ 272 - 0
gameplay/src/AIMessage.h

@@ -0,0 +1,272 @@
+#ifndef AIMESSAGE_H_
+#define AIMESSAGE_H_
+
+namespace gameplay
+{
+
+/**
+ * Defines a simple, flexible message structure used for passing messages through
+ * the AI system.
+ *
+ * Messages can store an arbitrary number of parameters. For the sake of simplicity,
+ * each parameter is stored as type double, which is flexible enough to store most
+ * data that needs to be passed.
+ */
+class AIMessage
+{
+    friend class AIAgent;
+    friend class AIController;
+    friend class AIStateMachine;
+
+public:
+
+    /**
+     * Enumeration of supported AIMessage parameter types.
+     */
+    enum ParameterType
+    {
+        UNDEFINED,
+        INTEGER,
+        LONG,
+        FLOAT,
+        DOUBLE,
+        BOOLEAN,
+        STRING
+    };
+
+    /** 
+     * Destructor.
+     */
+    ~AIMessage();
+
+    /**
+     * Creates a new message.
+     *
+     * Once a message is constructed and populated with data, it can be routed to its
+     * intended recipient(s) by calling AIController::sendMessage(AIMessage*). The
+     * AIController will then handle scheduling and delivery of the message and it will
+     * also destroy the message after it has been successfully delivered. For this reason,
+     * once a message has been sent through AIController, it is unsafe to use or destroy
+     * the message pointer.
+     *
+     * @param id The message ID.
+     * @param sender AIAgent sender ID (can be empty or null for an annoymous message).
+     * @param receiver AIAgent receiver ID (can be empty or null for a broadcast message).
+     * @param parameterCount Number of parameters for this message.
+     *
+     * @return A new AIMessage.
+     */
+    static AIMessage* create(unsigned int id, const char* sender, const char* receiver, unsigned int paramterCount);
+
+    /**
+     * Returns the message ID.
+     *
+     * @return The message ID.
+     */
+    unsigned int getId() const;
+
+    /**
+     * Returns the sender for the message.
+     *
+     * @return The message sender ID.
+     */
+    const char* getSender() const;
+
+    /**
+     * Returns the receiver for the message.
+     *
+     * @return The message receiver.
+     */
+    const char* getReceiver() const;
+
+    /**
+     * Returns the value of the specified parameter as an integer.
+     *
+     * @param index Index of the paramter to get.
+     *
+     * @return The parameter value.
+     */
+    int getInt(unsigned int index) const;
+
+    /**
+     * Sets an integer parameter.
+     *
+     * @param index Index of the parameter to set.
+     * @param value The parameter value.
+     */
+    void setInt(unsigned int index, int value);
+
+    /**
+     * Returns the value of the specified parameter as a long integer.
+     *
+     * @param index Index of the paramter to get.
+     *
+     * @return The parameter value.
+     */
+    long getLong(unsigned int index) const;
+
+    /**
+     * Sets a long integer parameter.
+     *
+     * @param index Index of the parameter to set.
+     * @param value The parameter value.
+     */
+    void setLong(unsigned int index, long value);
+
+    /**
+     * Returns the value of the specified parameter as a float.
+     *
+     * @param index Index of the paramter to get.
+     *
+     * @return The parameter value.
+     */
+    float getFloat(unsigned int index) const;
+
+    /**
+     * Sets a float parameter.
+     *
+     * @param index Index of the parameter to set.
+     * @param value The parameter value.
+     */
+    void setFloat(unsigned int index, float value);
+
+    /**
+     * Returns the value of the specified parameter as a double.
+     *
+     * @param index Index of the paramter to get.
+     *
+     * @return The parameter value.
+     */
+    double getDouble(unsigned int index) const;
+
+    /**
+     * Sets a double parameter.
+     *
+     * @param index Index of the parameter to set.
+     * @param value The parameter value.
+     */
+    void setDouble(unsigned int index, double value);
+
+    /**
+     * Returns the value of the specified parameter as a boolean.
+     *
+     * @param index Index of the paramter to get.
+     *
+     * @return The parameter value.
+     */
+    bool getBoolean(unsigned int index) const;
+
+    /**
+     * Sets a long parameter.
+     *
+     * @param index Index of the parameter to set.
+     * @param value The parameter value.
+     */
+    void setBoolean(unsigned int index, bool value);
+
+    /**
+     * Returns the value of the specified parameter as a string.
+     *
+     * @param index Index of the paramter to get.
+     *
+     * @return The parameter value.
+     */
+    const char* getString(unsigned int index) const;
+
+    /**
+     * Sets a string parameter.
+     *
+     * @param index Index of the parameter to set.
+     * @param value The parameter value.
+     */
+    void setString(unsigned int index, const char* value);
+
+    /**
+     * Returns the number of parameters for this message.
+     * 
+     * @return The number of message parameters.
+     */
+    unsigned int getParameterCount() const;
+
+    /** 
+     * Returns the type of the specified parameter.
+     *
+     * @param index Index of the parameter to query.
+     *
+     * @return The parameter type.
+     */
+    ParameterType getParameterType(unsigned int index) const;
+
+private:
+
+    /**
+     * Internal message type enumeration.
+     */
+    enum MessageType
+    {
+        MESSAGE_TYPE_STATE_CHANGE,
+        MESSAGE_TYPE_CUSTOM
+    };
+
+    /**
+     * Defines a flexible message parameter.
+     */
+    struct Parameter
+    {
+        Parameter();
+
+        ~Parameter();
+
+        void clear();
+
+        union
+        {
+            int intValue;
+            long longValue;
+            float floatValue;
+            double doubleValue;
+            bool boolValue;
+            char* stringValue;
+        };
+
+        AIMessage::ParameterType type;
+    };
+
+    /**
+     * Constructor.
+     */
+    AIMessage();
+
+    /**
+     * Hidden copy construcotr.
+     */
+    AIMessage(const AIMessage&);
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    AIMessage& operator=(const AIMessage&);
+
+    /**
+     * Returns the delivery time for the message.
+     *
+     * @return The delivery time for the message, or zero if the message is not currently scheduled to be delivered.
+     */
+    double getDeliveryTime() const;
+
+    void clearParameter(unsigned int index);
+
+    unsigned int _id;
+    std::string _sender;
+    std::string _receiver;
+    double _deliveryTime;
+    Parameter* _parameters;
+    unsigned int _parameterCount;
+    MessageType _messageType;
+    AIMessage* _next;
+
+};
+
+}
+
+#endif

+ 74 - 0
gameplay/src/AIState.cpp

@@ -0,0 +1,74 @@
+#include "Base.h"
+#include "AIState.h"
+#include "AIStateMachine.h"
+
+namespace gameplay
+{
+
+AIState AIState::_empty("");
+
+AIState::AIState(const char* id)
+    : _id(id)
+{
+}
+
+AIState::~AIState()
+{
+}
+
+AIState* AIState::create(const char* id)
+{
+    return new AIState(id);
+}
+
+const char* AIState::getId() const
+{
+    return _id.c_str();
+}
+
+void AIState::setListener(Listener* listener)
+{
+    _listener = listener;
+}
+
+void AIState::enter(AIStateMachine* stateMachine)
+{
+    if (_listener)
+        _listener->stateEnter(stateMachine->getAgent(), this);
+
+    // TODO: Fire script event
+}
+
+void AIState::exit(AIStateMachine* stateMachine)
+{
+    if (_listener)
+        _listener->stateExit(stateMachine->getAgent(), this);
+
+    // TODO: Fire script event
+}
+
+void AIState::update(AIStateMachine* stateMachine, float elapsedTime)
+{
+    if (_listener)
+        _listener->stateUpdate(stateMachine->getAgent(), this, elapsedTime);
+
+    // TODO: Fire script event
+}
+
+AIState::Listener::~Listener()
+{
+}
+
+void AIState::Listener::stateEnter(AIAgent* agent, AIState* state)
+{
+}
+
+void AIState::Listener::stateExit(AIAgent* agent, AIState* state)
+{
+}
+
+void AIState::Listener::stateUpdate(AIAgent* agent, AIState* state, float elapsedTime)
+{
+}
+
+}

+ 137 - 0
gameplay/src/AIState.h

@@ -0,0 +1,137 @@
+#ifndef AISTATE_H_
+#define AISTATE_H_
+
+#include "Ref.h"
+
+namespace gameplay
+{
+
+class AIAgent;
+class AIStateMachine;
+
+/**
+ * Represents a single state in an AIStateMachine.
+ *
+ * An AIState encapsulates a state and unit of work within an AI
+ * state machine. Events can be programmed or scripted when the
+ * state is entered, exited and each frame/tick in its update event.
+ *
+ * 
+ */
+class AIState : public Ref
+{
+    friend class AIStateMachine;
+
+public:
+
+    /**
+     * Interface for listening to AIState events.
+     */
+    class Listener
+    {
+    public:
+
+        /**
+         * Virtual destructor.
+         */
+        virtual ~Listener();
+
+        /** 
+         * Called when a state is entered.
+         *
+         * @param agent The AIAgent this state event is for.
+         * @param state The state that was entered.
+         */
+        virtual void stateEnter(AIAgent* agent, AIState* state);
+
+        /**
+         * Called when a state is exited.
+         *
+         * @param agent The AIAgent this state event is for.
+         * @param state The state that was exited.
+         */
+        virtual void stateExit(AIAgent* agent, AIState* state);
+
+        /**
+         * Called once per frame when for a state when it is active.
+         *
+         * This method is normally where the logic for a state is implemented.
+         *
+         * @param agent The AIAgent this state event is for.
+         * @param state The active AIState.
+         * @param elapsedTime The elapsed time, in milliseconds.
+         */
+        virtual void stateUpdate(AIAgent* agent, AIState* state, float elapsedTime);
+    };
+
+    /**
+     * Creates a new AISTate.
+     *
+     * @param id The ID of the new AIState.
+     *
+     * @return The new AIState.
+     */
+    static AIState* create(const char* id);
+
+    /**
+     * Returns the ID of this state.
+     *
+     * @return The state ID.
+     */
+    const char* getId() const;
+
+    /**
+     * Sets a listener to dispatch state events to.
+     * 
+     * @param listener Listener to dispatch state events to, or NULL to disable event dispatching.
+     */
+    void setListener(Listener* listener);
+
+private:
+
+    /**
+     * Constructs a new AIState.
+     */
+    AIState(const char* id);
+
+    /**
+     * Destructor.
+     */
+    ~AIState();
+
+    /**
+     * Hidden copy constructor.
+     */
+    AIState(const AIState&);
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    AIState& operator=(const AIState&);
+
+    /**
+     * Called by AIStateMachine when this state is being entered.
+     */
+    void enter(AIStateMachine* stateMachine);
+
+    /**
+     * Called by AIStateMachine when this state is being exited.
+     */
+    void exit(AIStateMachine* stateMachine);
+
+    /**
+     * Called by AIStateMachine once per frame to update this state when it is active.
+     */
+    void update(AIStateMachine* stateMachine, float elapsedTime);
+
+    std::string _id;
+    Listener* _listener;
+
+    // The default/empty state.
+    static AIState _empty;
+
+};
+
+}
+
+#endif

+ 127 - 0
gameplay/src/AIStateMachine.cpp

@@ -0,0 +1,127 @@
+#include "Base.h"
+#include "AIStateMachine.h"
+#include "AIAgent.h"
+#include "AIMessage.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+AIStateMachine::AIStateMachine(AIAgent* agent)
+    : _agent(agent), _currentState(&AIState::_empty)
+{
+    GP_ASSERT(agent);
+}
+
+AIStateMachine::~AIStateMachine()
+{
+    // Release all states
+    for (std::list<AIState*>::iterator itr = _states.begin(); itr != _states.end(); ++itr)
+    {
+        (*itr)->release();
+    }
+}
+
+AIAgent* AIStateMachine::getAgent() const
+{
+    return _agent;
+}
+
+AIState* AIStateMachine::addState(const char* id)
+{
+    AIState* state = AIState::create(id);
+    _states.push_back(state);
+    return state;
+}
+
+void AIStateMachine::addState(AIState* state)
+{
+    state->addRef();
+    _states.push_back(state);
+}
+
+void AIStateMachine::removeState(AIState* state)
+{
+    std::list<AIState*>::iterator itr = std::find(_states.begin(), _states.end(), state);
+    if (itr != _states.end())
+    {
+        _states.erase(itr);
+        state->release();
+    }
+}
+
+AIState* AIStateMachine::getState(const char* id) const
+{
+    GP_ASSERT(id);
+
+    AIState* state;
+    for (std::list<AIState*>::const_iterator itr = _states.begin(); itr != _states.end(); ++itr)
+    {
+        state = (*itr);
+
+        if (strcmp(id, state->getId()) == 0)
+            return state;
+    }
+
+    return NULL;
+}
+
+AIState* AIStateMachine::getActiveState() const
+{
+    return _currentState;
+}
+
+bool AIStateMachine::hasState(AIState* state) const
+{
+    GP_ASSERT(state);
+
+    return (std::find(_states.begin(), _states.end(), state) != _states.end());
+}
+
+AIState* AIStateMachine::setState(const char* id)
+{
+    AIState* state = getState(id);
+    if (state)
+        sendChangeStateMessage(state);
+    return state;
+}
+
+bool AIStateMachine::setState(AIState* state)
+{
+    if (hasState(state))
+    {
+        sendChangeStateMessage(state);
+        return true;
+    }
+
+    return false;
+}
+
+void AIStateMachine::sendChangeStateMessage(AIState* newState)
+{
+    AIMessage* message = AIMessage::create(0, _agent->getId(), _agent->getId(), 1);
+    message->_messageType = AIMessage::MESSAGE_TYPE_STATE_CHANGE;
+    message->setString(0, newState->getId());
+    Game::getInstance()->getAIController()->sendMessage(message);
+}
+
+void AIStateMachine::setStateInternal(AIState* state)
+{
+    GP_ASSERT(hasState(state));
+
+    // Fire the exit event for the current state
+    _currentState->exit(this);
+
+    // Set the new state
+    _currentState = state;
+
+    // Fire the enter event for the new state
+    _currentState->enter(this);
+}
+
+void AIStateMachine::update(float elapsedTime)
+{
+    _currentState->update(this, elapsedTime);
+}
+
+}

+ 160 - 0
gameplay/src/AIStateMachine.h

@@ -0,0 +1,160 @@
+#ifndef AISTATEMACHINE_H_
+#define AISTATEMACHINE_H_
+
+#include "AIState.h"
+
+namespace gameplay
+{
+
+class AIAgent;
+
+/**
+ * Defines a simple AI state machine that can be used to program logic
+ * for an AIAgent in a game.
+ *
+ * A state machine uses AIState objects to represent different states
+ * of an object in the game. The state machine provides access to the
+ * current state of an AI agent and it controls state changes as well.
+ * When a new state is set, the stateExited event will be called for the
+ * previous state, the stateEntered event will be called for the new state
+ * and then the stateUpdate event will begin to be called each frame
+ * while the new state is active.
+ *
+ * Communication of state changes is facilated through the AIMessage class.
+ * Messages are dispatched by the AIController and can be used for purposes
+ * other than state changes as well. Messages may be sent to the state
+ * machines of any other agents in a game and can contain any arbitrary
+ * information. This mechanism provides a simple, flexible and easily
+ * debuggable method for communicating between AI objects in a game.
+ */
+class AIStateMachine
+{
+    friend class AIAgent;
+
+public:
+
+    /**
+     * Returns the AIAgent that owns this state machine.
+     *
+     * @return The AIAgent that owns this state machine.
+     */
+    AIAgent* getAgent() const;
+
+    /**
+     * Creates and adds a new state to the state machine.
+     *
+     * @param id ID of the new state.
+     *
+     * @return The newly created and added state.
+     */
+    AIState* addState(const char* id);
+
+    /**
+     * Adds a state to the state machine.
+     *
+     * The specified state may be shared by other state machines.
+     * Its reference count is increased while it is held by
+     * this state machine.
+     *
+     * @param state The state to add.
+     */
+    void addState(AIState* state);
+
+    /**
+     * Removes a state from the state machine.
+     *
+     * @param state The state to remove.
+     */
+    void removeState(AIState* state);
+
+    /**
+     * Returns a state registered with this state machine.
+     *
+     * @param id The ID of the state to return.
+     *
+     * @return The state with the given ID, or NULL if no such state exists.
+     */
+    AIState* getState(const char* id) const;
+
+    /**
+     * Returns the active state for this state machine.
+     *
+     * @return The active state for this state machine.
+     */
+    AIState* getActiveState() const;
+
+    /**
+     * Changes the state of this state machine to the given state.
+     *
+     * If no state with the given ID exists within this state machine,
+     * this method does nothing.
+     *
+     * @param id The ID of the new state.
+     *
+     * @return The new state, or NULL if no matching state could be found.
+     */
+    AIState* setState(const char* id);
+
+    /**
+     * Changes the state of this state machine to the given state.
+     *
+     * If the given state is not registered with this state machine,
+     * this method does nothing.
+     *
+     * @param state The new state.
+     *
+     * @return true if the state is successfully changed, false otherwise.
+     */
+    bool setState(AIState* state);
+
+private:
+
+    /**
+     * Constructor.
+     */
+    AIStateMachine(AIAgent* agent);
+
+    /**
+     * Destructor.
+     */
+    ~AIStateMachine();
+
+    /**
+     * Hidden copy constructor.
+     */
+    AIStateMachine(const AIStateMachine&);
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    AIStateMachine& operator=(const AIStateMachine&);
+
+    /**
+     * Sends a message to change the state of this state machine.
+     */
+    void sendChangeStateMessage(AIState* newState);
+
+    /**
+     * Changes the active state of the state machine.
+     */
+    void setStateInternal(AIState* state);
+
+    /**
+     * Determines if the specified state exists within this state machine.
+     */
+    bool hasState(AIState* state) const;
+
+    /**
+     * Called by AIController to update the state machine each frame.
+     */
+    void update(float elapsedTime);
+
+    AIAgent* _agent;
+    AIState* _currentState;
+    std::list<AIState*> _states;
+
+};
+
+}
+
+#endif

+ 19 - 3
gameplay/src/Game.cpp

@@ -22,8 +22,8 @@ Game::Game()
       _frameLastFPS(0), _frameCount(0), _frameRate(0), 
       _clearDepth(1.0f), _clearStencil(0), _properties(NULL),
       _animationController(NULL), _audioController(NULL), 
-      _physicsController(NULL), _audioListener(NULL), _scriptController(NULL),
-      _scriptListeners(NULL)
+      _physicsController(NULL), _aiController(NULL), _audioListener(NULL), 
+      _gamepads(NULL), _timeEvents(NULL), _scriptController(NULL), _scriptListeners(NULL)
 {
     GP_ASSERT(__gameInstance == NULL);
     __gameInstance = this;
@@ -120,6 +120,9 @@ bool Game::startup()
     _physicsController = new PhysicsController();
     _physicsController->initialize();
 
+    _aiController = new AIController();
+    _aiController->initialize();
+
     loadGamepads();
     
     _scriptController = new ScriptController();
@@ -173,6 +176,7 @@ void Game::shutdown()
         GP_ASSERT(_animationController);
         GP_ASSERT(_audioController);
         GP_ASSERT(_physicsController);
+        GP_ASSERT(_aiController);
 
         Platform::signalShutdown();
         finalize();
@@ -198,6 +202,8 @@ void Game::shutdown()
 
         _physicsController->finalize();
         SAFE_DELETE(_physicsController);
+        _aiController->finalize();
+        SAFE_DELETE(_aiController);
 
         // Note: we do not clean up the script controller here
         // because users can call Game::exit() from a script.
@@ -219,11 +225,13 @@ void Game::pause()
         GP_ASSERT(_animationController);
         GP_ASSERT(_audioController);
         GP_ASSERT(_physicsController);
+        GP_ASSERT(_aiController);
         _state = PAUSED;
         _pausedTimeLast = Platform::getAbsoluteTime();
         _animationController->pause();
         _audioController->pause();
         _physicsController->pause();
+        _aiController->pause();
     }
 }
 
@@ -234,11 +242,13 @@ void Game::resume()
         GP_ASSERT(_animationController);
         GP_ASSERT(_audioController);
         GP_ASSERT(_physicsController);
+        GP_ASSERT(_aiController);
         _state = RUNNING;
         _pausedTimeTotal += Platform::getAbsoluteTime() - _pausedTimeLast;
         _animationController->resume();
         _audioController->resume();
         _physicsController->resume();
+        _aiController->resume();
     }
 }
 
@@ -261,6 +271,7 @@ void Game::frame()
         GP_ASSERT(_animationController);
         GP_ASSERT(_audioController);
         GP_ASSERT(_physicsController);
+        GP_ASSERT(_aiController);
 
         // Update Time.
         static double lastFrameTime = Game::getGameTime();
@@ -276,7 +287,10 @@ void Game::frame()
     
         // Update the physics.
         _physicsController->update(elapsedTime);
-        
+
+        // Update AI.
+        _aiController->update(elapsedTime);
+
         // Application Update.
         update(elapsedTime);
 
@@ -328,6 +342,7 @@ void Game::updateOnce()
     GP_ASSERT(_animationController);
     GP_ASSERT(_audioController);
     GP_ASSERT(_physicsController);
+    GP_ASSERT(_aiController);
 
     // Update Time.
     static double lastFrameTime = getGameTime();
@@ -338,6 +353,7 @@ void Game::updateOnce()
     // Update the internal controllers.
     _animationController->update(elapsedTime);
     _physicsController->update(elapsedTime);
+    _aiController->update(elapsedTime);
     _audioController->update(elapsedTime);
     _scriptController->update(elapsedTime);
 }

+ 10 - 0
gameplay/src/Game.h

@@ -9,6 +9,7 @@
 #include "AudioController.h"
 #include "AnimationController.h"
 #include "PhysicsController.h"
+#include "AIController.h"
 #include "AudioListener.h"
 #include "Rectangle.h"
 #include "Vector4.h"
@@ -219,6 +220,14 @@ public:
      */
     inline PhysicsController* getPhysicsController() const;
 
+    /** 
+     * Gets the AI controller for managing control of artifical
+     * intelligence associated with the game.
+     *
+     * @return The AI controller for this game.
+     */
+    inline AIController* getAIController() const;
+
     /**
      * Gets the script controller for managing control of Lua scripts
      * associated with the game.
@@ -530,6 +539,7 @@ private:
     AnimationController* _animationController;  // Controls the scheduling and running of animations.
     AudioController* _audioController;          // Controls audio sources that are playing in the game.
     PhysicsController* _physicsController;      // Controls the simulation of a physics scene and entities.
+    AIController* _aiController;                // Controls AI siulation.
     AudioListener* _audioListener;              // The audio listener in 3D space.
     std::vector<Gamepad*>* _gamepads;           // The connected gamepads.
     std::priority_queue<TimeEvent, std::vector<TimeEvent>, std::less<TimeEvent> >* _timeEvents;     // Contains the scheduled time events.

+ 4 - 0
gameplay/src/Game.inl

@@ -53,6 +53,10 @@ inline ScriptController* Game::getScriptController() const
 {
     return _scriptController;
 }
+inline AIController* Game::getAIController() const
+{
+    return _aiController;
+}
 
 template <class T>
 void Game::renderOnce(T* instance, void (T::*method)(void*), void* cookie)

+ 31 - 2
gameplay/src/Node.cpp

@@ -24,7 +24,7 @@ namespace gameplay
 Node::Node(const char* id)
     : _scene(NULL), _firstChild(NULL), _nextSibling(NULL), _prevSibling(NULL), _parent(NULL), _childCount(0),
     _nodeFlags(NODE_FLAG_VISIBLE), _camera(NULL), _light(NULL), _model(NULL), _form(NULL), _audioSource(NULL), _particleEmitter(NULL),
-    _collisionObject(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true), _userData(NULL)
+    _collisionObject(NULL), _agent(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true), _userData(NULL)
 {
     if (id)
     {
@@ -53,6 +53,8 @@ Node::~Node()
     SAFE_RELEASE(_form);
     SAFE_DELETE(_collisionObject);
 
+    setAgent(NULL);
+
     // Cleanup user data
     if (_userData)
     {
@@ -1088,10 +1090,37 @@ PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
         GP_ERROR("Failed to load collision object from properties object; required attribute 'type' is missing.");
         return NULL;
     }
-    
+
     return _collisionObject;
 }
 
+AIAgent* Node::getAgent() const
+{
+    return _agent;
+}
+
+void Node::setAgent(AIAgent* agent)
+{
+    if (agent != _agent)
+    {
+        if (_agent)
+        {
+            Game::getInstance()->getAIController()->removeAgent(_agent);
+            _agent->_node = NULL;
+            SAFE_RELEASE(_agent);
+        }
+
+        _agent = agent;
+
+        if (_agent)
+        {
+            _agent->addRef();
+            _agent->_node = this;
+            Game::getInstance()->getAIController()->addAgent(_agent);
+        }
+    }
+}
+
 NodeCloneContext::NodeCloneContext()
 {
 }

+ 20 - 0
gameplay/src/Node.h

@@ -11,6 +11,7 @@
 #include "PhysicsCollisionObject.h"
 #include "PhysicsCollisionShape.h"
 #include "BoundingBox.h"
+#include "AIAgent.h"
 
 namespace gameplay
 {
@@ -557,6 +558,20 @@ public:
      */
     PhysicsCollisionObject* setCollisionObject(Properties* properties);
 
+    /**
+     * Returns the AI agent assigned to this node.
+     *
+     * @return The AI agent for this node.
+     */
+    AIAgent* getAgent() const;
+
+    /**
+     * Sets the AI agent for this node.
+     *
+     * @param agent The AI agent to set.
+     */
+    void setAgent(AIAgent* agent);
+
     /**
      * Returns the bounding sphere for the Node, in world space.
      *
@@ -753,6 +768,11 @@ protected:
      */
     PhysicsCollisionObject* _collisionObject;
     
+    /**
+     * Pointer to the AI agent attached to the Node.
+     */
+    AIAgent* _agent;
+
     /**
      * World Matrix representation of the Node.
      */

+ 6 - 0
gameplay/src/gameplay.h

@@ -74,6 +74,12 @@
 #include "PhysicsGhostObject.h"
 #include "PhysicsCharacter.h"
 
+// AI
+#include "AIController.h"
+#include "AIAgent.h"
+#include "AIState.h"
+#include "AIStateMachine.h"
+
 // UI
 #include "Theme.h"
 #include "Control.h"

+ 469 - 0
gameplay/src/lua/lua_AIAgent.cpp

@@ -0,0 +1,469 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_AIAgent.h"
+#include "AIAgent.h"
+#include "Base.h"
+#include "Game.h"
+#include "Node.h"
+#include "Ref.h"
+
+namespace gameplay
+{
+
+void luaRegister_AIAgent()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"addRef", lua_AIAgent_addRef},
+        {"getId", lua_AIAgent_getId},
+        {"getNode", lua_AIAgent_getNode},
+        {"getRefCount", lua_AIAgent_getRefCount},
+        {"getStateMachine", lua_AIAgent_getStateMachine},
+        {"isEnabled", lua_AIAgent_isEnabled},
+        {"release", lua_AIAgent_release},
+        {"setEnabled", lua_AIAgent_setEnabled},
+        {"setListener", lua_AIAgent_setListener},
+        {NULL, NULL}
+    };
+    const luaL_Reg lua_statics[] = 
+    {
+        {"create", lua_AIAgent_static_create},
+        {NULL, NULL}
+    };
+    std::vector<std::string> scopePath;
+
+    ScriptUtil::registerClass("AIAgent", lua_members, NULL, lua_AIAgent__gc, lua_statics, scopePath);
+}
+
+static AIAgent* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "AIAgent");
+    luaL_argcheck(state, userdata != NULL, 1, "'AIAgent' expected.");
+    return (AIAgent*)((ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_AIAgent__gc(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                void* userdata = luaL_checkudata(state, 1, "AIAgent");
+                luaL_argcheck(state, userdata != NULL, 1, "'AIAgent' expected.");
+                ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)userdata;
+                if (object->owns)
+                {
+                    AIAgent* instance = (AIAgent*)object->instance;
+                    SAFE_RELEASE(instance);
+                }
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent__gc - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_addRef(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIAgent* instance = getInstance(state);
+                instance->addRef();
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_addRef - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_getId(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIAgent* instance = getInstance(state);
+                const char* result = instance->getId();
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_getId - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_getNode(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIAgent* instance = getInstance(state);
+                void* returnPtr = (void*)instance->getNode();
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Node");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_getNode - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_getRefCount(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIAgent* instance = getInstance(state);
+                unsigned int result = instance->getRefCount();
+
+                // Push the return value onto the stack.
+                lua_pushunsigned(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_getRefCount - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_getStateMachine(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIAgent* instance = getInstance(state);
+                void* returnPtr = (void*)instance->getStateMachine();
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIStateMachine");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_getStateMachine - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_isEnabled(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIAgent* instance = getInstance(state);
+                bool result = instance->isEnabled();
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_isEnabled - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_release(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIAgent* instance = getInstance(state);
+                instance->release();
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_release - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_setEnabled(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                AIAgent* instance = getInstance(state);
+                instance->setEnabled(param1);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_setEnabled - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_setListener(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIAgent::Listener* param1 = ScriptUtil::getObjectPointer<AIAgent::Listener>(2, "AIAgentListener", false);
+
+                AIAgent* instance = getInstance(state);
+                instance->setListener(param1);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgent_setListener - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgent_static_create(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 0:
+        {
+            void* returnPtr = (void*)AIAgent::create();
+            if (returnPtr)
+            {
+                ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                object->instance = returnPtr;
+                object->owns = false;
+                luaL_getmetatable(state, "AIAgent");
+                lua_setmetatable(state, -2);
+            }
+            else
+            {
+                lua_pushnil(state);
+            }
+
+            return 1;
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 0).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+}

+ 24 - 0
gameplay/src/lua/lua_AIAgent.h

@@ -0,0 +1,24 @@
+#ifndef LUA_AIAGENT_H_
+#define LUA_AIAGENT_H_
+
+namespace gameplay
+{
+
+// Lua bindings for AIAgent.
+int lua_AIAgent__gc(lua_State* state);
+int lua_AIAgent_addRef(lua_State* state);
+int lua_AIAgent_getId(lua_State* state);
+int lua_AIAgent_getNode(lua_State* state);
+int lua_AIAgent_getRefCount(lua_State* state);
+int lua_AIAgent_getStateMachine(lua_State* state);
+int lua_AIAgent_isEnabled(lua_State* state);
+int lua_AIAgent_release(lua_State* state);
+int lua_AIAgent_setEnabled(lua_State* state);
+int lua_AIAgent_setListener(lua_State* state);
+int lua_AIAgent_static_create(lua_State* state);
+
+void luaRegister_AIAgent();
+
+}
+
+#endif

+ 115 - 0
gameplay/src/lua/lua_AIAgentListener.cpp

@@ -0,0 +1,115 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_AIAgentListener.h"
+#include "AIAgent.h"
+#include "Base.h"
+#include "Game.h"
+#include "Node.h"
+#include "Ref.h"
+
+namespace gameplay
+{
+
+void luaRegister_AIAgentListener()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"messageReceived", lua_AIAgentListener_messageReceived},
+        {NULL, NULL}
+    };
+    const luaL_Reg* lua_statics = NULL;
+    std::vector<std::string> scopePath;
+    scopePath.push_back("AIAgent");
+
+    ScriptUtil::registerClass("AIAgentListener", lua_members, NULL, lua_AIAgentListener__gc, lua_statics, scopePath);
+}
+
+static AIAgent::Listener* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "AIAgentListener");
+    luaL_argcheck(state, userdata != NULL, 1, "'AIAgentListener' expected.");
+    return (AIAgent::Listener*)((ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_AIAgentListener__gc(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                void* userdata = luaL_checkudata(state, 1, "AIAgentListener");
+                luaL_argcheck(state, userdata != NULL, 1, "'AIAgentListener' expected.");
+                ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)userdata;
+                if (object->owns)
+                {
+                    AIAgent::Listener* instance = (AIAgent::Listener*)object->instance;
+                    SAFE_DELETE(instance);
+                }
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgentListener__gc - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIAgentListener_messageReceived(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIMessage* param1 = ScriptUtil::getObjectPointer<AIMessage>(2, "AIMessage", false);
+
+                AIAgent::Listener* instance = getInstance(state);
+                bool result = instance->messageReceived(param1);
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIAgentListener_messageReceived - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+}

+ 15 - 0
gameplay/src/lua/lua_AIAgentListener.h

@@ -0,0 +1,15 @@
+#ifndef LUA_AIAGENTLISTENER_H_
+#define LUA_AIAGENTLISTENER_H_
+
+namespace gameplay
+{
+
+// Lua bindings for AIAgent::Listener.
+int lua_AIAgentListener__gc(lua_State* state);
+int lua_AIAgentListener_messageReceived(lua_State* state);
+
+void luaRegister_AIAgentListener();
+
+}
+
+#endif

+ 144 - 0
gameplay/src/lua/lua_AIController.cpp

@@ -0,0 +1,144 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_AIController.h"
+#include "AIController.h"
+#include "Base.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+void luaRegister_AIController()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"findAgent", lua_AIController_findAgent},
+        {"sendMessage", lua_AIController_sendMessage},
+        {NULL, NULL}
+    };
+    const luaL_Reg* lua_statics = NULL;
+    std::vector<std::string> scopePath;
+
+    ScriptUtil::registerClass("AIController", lua_members, NULL, NULL, lua_statics, scopePath);
+}
+
+static AIController* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "AIController");
+    luaL_argcheck(state, userdata != NULL, 1, "'AIController' expected.");
+    return (AIController*)((ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_AIController_findAgent(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = ScriptUtil::getString(2, false);
+
+                AIController* instance = getInstance(state);
+                void* returnPtr = (void*)instance->findAgent(param1);
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIAgent");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIController_findAgent - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIController_sendMessage(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIMessage* param1 = ScriptUtil::getObjectPointer<AIMessage>(2, "AIMessage", false);
+
+                AIController* instance = getInstance(state);
+                instance->sendMessage(param1);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIController_sendMessage - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                AIMessage* param1 = ScriptUtil::getObjectPointer<AIMessage>(2, "AIMessage", false);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 3);
+
+                AIController* instance = getInstance(state);
+                instance->sendMessage(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIController_sendMessage - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2 or 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+}

+ 15 - 0
gameplay/src/lua/lua_AIController.h

@@ -0,0 +1,15 @@
+#ifndef LUA_AICONTROLLER_H_
+#define LUA_AICONTROLLER_H_
+
+namespace gameplay
+{
+
+// Lua bindings for AIController.
+int lua_AIController_findAgent(lua_State* state);
+int lua_AIController_sendMessage(lua_State* state);
+
+void luaRegister_AIController();
+
+}
+
+#endif

+ 838 - 0
gameplay/src/lua/lua_AIMessage.cpp

@@ -0,0 +1,838 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_AIMessage.h"
+#include "AIMessage.h"
+#include "Base.h"
+#include "lua_AIMessageParameterType.h"
+
+namespace gameplay
+{
+
+void luaRegister_AIMessage()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"getBoolean", lua_AIMessage_getBoolean},
+        {"getDouble", lua_AIMessage_getDouble},
+        {"getFloat", lua_AIMessage_getFloat},
+        {"getId", lua_AIMessage_getId},
+        {"getInt", lua_AIMessage_getInt},
+        {"getLong", lua_AIMessage_getLong},
+        {"getParameterCount", lua_AIMessage_getParameterCount},
+        {"getParameterType", lua_AIMessage_getParameterType},
+        {"getReceiver", lua_AIMessage_getReceiver},
+        {"getSender", lua_AIMessage_getSender},
+        {"getString", lua_AIMessage_getString},
+        {"setBoolean", lua_AIMessage_setBoolean},
+        {"setDouble", lua_AIMessage_setDouble},
+        {"setFloat", lua_AIMessage_setFloat},
+        {"setInt", lua_AIMessage_setInt},
+        {"setLong", lua_AIMessage_setLong},
+        {"setString", lua_AIMessage_setString},
+        {NULL, NULL}
+    };
+    const luaL_Reg lua_statics[] = 
+    {
+        {"create", lua_AIMessage_static_create},
+        {NULL, NULL}
+    };
+    std::vector<std::string> scopePath;
+
+    ScriptUtil::registerClass("AIMessage", lua_members, NULL, lua_AIMessage__gc, lua_statics, scopePath);
+}
+
+static AIMessage* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "AIMessage");
+    luaL_argcheck(state, userdata != NULL, 1, "'AIMessage' expected.");
+    return (AIMessage*)((ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_AIMessage__gc(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                void* userdata = luaL_checkudata(state, 1, "AIMessage");
+                luaL_argcheck(state, userdata != NULL, 1, "'AIMessage' expected.");
+                ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)userdata;
+                if (object->owns)
+                {
+                    AIMessage* instance = (AIMessage*)object->instance;
+                    SAFE_DELETE(instance);
+                }
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage__gc - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getBoolean(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                AIMessage* instance = getInstance(state);
+                bool result = instance->getBoolean(param1);
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getBoolean - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getDouble(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                AIMessage* instance = getInstance(state);
+                double result = instance->getDouble(param1);
+
+                // Push the return value onto the stack.
+                lua_pushnumber(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getDouble - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getFloat(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                AIMessage* instance = getInstance(state);
+                float result = instance->getFloat(param1);
+
+                // Push the return value onto the stack.
+                lua_pushnumber(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getFloat - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getId(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIMessage* instance = getInstance(state);
+                unsigned int result = instance->getId();
+
+                // Push the return value onto the stack.
+                lua_pushunsigned(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getId - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getInt(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                AIMessage* instance = getInstance(state);
+                int result = instance->getInt(param1);
+
+                // Push the return value onto the stack.
+                lua_pushinteger(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getInt - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getLong(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                AIMessage* instance = getInstance(state);
+                long result = instance->getLong(param1);
+
+                // Push the return value onto the stack.
+                lua_pushinteger(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getLong - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getParameterCount(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIMessage* instance = getInstance(state);
+                unsigned int result = instance->getParameterCount();
+
+                // Push the return value onto the stack.
+                lua_pushunsigned(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getParameterCount - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getParameterType(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                AIMessage* instance = getInstance(state);
+                AIMessage::ParameterType result = instance->getParameterType(param1);
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, lua_stringFromEnum_AIMessageParameterType(result));
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getParameterType - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getReceiver(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIMessage* instance = getInstance(state);
+                const char* result = instance->getReceiver();
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getReceiver - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getSender(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIMessage* instance = getInstance(state);
+                const char* result = instance->getSender();
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getSender - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_getString(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                AIMessage* instance = getInstance(state);
+                const char* result = instance->getString(param1);
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_getString - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_setBoolean(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER &&
+                lua_type(state, 3) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                // Get parameter 2 off the stack.
+                bool param2 = ScriptUtil::luaCheckBool(state, 3);
+
+                AIMessage* instance = getInstance(state);
+                instance->setBoolean(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_setBoolean - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_setDouble(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER &&
+                lua_type(state, 3) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                // Get parameter 2 off the stack.
+                double param2 = (double)luaL_checknumber(state, 3);
+
+                AIMessage* instance = getInstance(state);
+                instance->setDouble(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_setDouble - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_setFloat(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER &&
+                lua_type(state, 3) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 3);
+
+                AIMessage* instance = getInstance(state);
+                instance->setFloat(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_setFloat - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_setInt(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER &&
+                lua_type(state, 3) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                // Get parameter 2 off the stack.
+                int param2 = (int)luaL_checkint(state, 3);
+
+                AIMessage* instance = getInstance(state);
+                instance->setInt(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_setInt - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_setLong(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER &&
+                lua_type(state, 3) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                // Get parameter 2 off the stack.
+                long param2 = (long)luaL_checklong(state, 3);
+
+                AIMessage* instance = getInstance(state);
+                instance->setLong(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_setLong - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_setString(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = ScriptUtil::getString(3, false);
+
+                AIMessage* instance = getInstance(state);
+                instance->setString(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_setString - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIMessage_static_create(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 4:
+        {
+            if (lua_type(state, 1) == LUA_TNUMBER &&
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL) &&
+                lua_type(state, 4) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 1);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = ScriptUtil::getString(2, false);
+
+                // Get parameter 3 off the stack.
+                const char* param3 = ScriptUtil::getString(3, false);
+
+                // Get parameter 4 off the stack.
+                unsigned int param4 = (unsigned int)luaL_checkunsigned(state, 4);
+
+                void* returnPtr = (void*)AIMessage::create(param1, param2, param3, param4);
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIMessage");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIMessage_static_create - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 4).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+}

+ 32 - 0
gameplay/src/lua/lua_AIMessage.h

@@ -0,0 +1,32 @@
+#ifndef LUA_AIMESSAGE_H_
+#define LUA_AIMESSAGE_H_
+
+namespace gameplay
+{
+
+// Lua bindings for AIMessage.
+int lua_AIMessage__gc(lua_State* state);
+int lua_AIMessage_getBoolean(lua_State* state);
+int lua_AIMessage_getDouble(lua_State* state);
+int lua_AIMessage_getFloat(lua_State* state);
+int lua_AIMessage_getId(lua_State* state);
+int lua_AIMessage_getInt(lua_State* state);
+int lua_AIMessage_getLong(lua_State* state);
+int lua_AIMessage_getParameterCount(lua_State* state);
+int lua_AIMessage_getParameterType(lua_State* state);
+int lua_AIMessage_getReceiver(lua_State* state);
+int lua_AIMessage_getSender(lua_State* state);
+int lua_AIMessage_getString(lua_State* state);
+int lua_AIMessage_setBoolean(lua_State* state);
+int lua_AIMessage_setDouble(lua_State* state);
+int lua_AIMessage_setFloat(lua_State* state);
+int lua_AIMessage_setInt(lua_State* state);
+int lua_AIMessage_setLong(lua_State* state);
+int lua_AIMessage_setString(lua_State* state);
+int lua_AIMessage_static_create(lua_State* state);
+
+void luaRegister_AIMessage();
+
+}
+
+#endif

+ 58 - 0
gameplay/src/lua/lua_AIMessageParameterType.cpp

@@ -0,0 +1,58 @@
+#include "Base.h"
+#include "lua_AIMessageParameterType.h"
+
+namespace gameplay
+{
+
+static const char* enumStringEmpty = "";
+
+static const char* luaEnumString_AIMessageParameterType_UNDEFINED = "UNDEFINED";
+static const char* luaEnumString_AIMessageParameterType_INTEGER = "INTEGER";
+static const char* luaEnumString_AIMessageParameterType_LONG = "LONG";
+static const char* luaEnumString_AIMessageParameterType_FLOAT = "FLOAT";
+static const char* luaEnumString_AIMessageParameterType_DOUBLE = "DOUBLE";
+static const char* luaEnumString_AIMessageParameterType_BOOLEAN = "BOOLEAN";
+static const char* luaEnumString_AIMessageParameterType_STRING = "STRING";
+
+AIMessage::ParameterType lua_enumFromString_AIMessageParameterType(const char* s)
+{
+    if (strcmp(s, luaEnumString_AIMessageParameterType_UNDEFINED) == 0)
+        return AIMessage::UNDEFINED;
+    if (strcmp(s, luaEnumString_AIMessageParameterType_INTEGER) == 0)
+        return AIMessage::INTEGER;
+    if (strcmp(s, luaEnumString_AIMessageParameterType_LONG) == 0)
+        return AIMessage::LONG;
+    if (strcmp(s, luaEnumString_AIMessageParameterType_FLOAT) == 0)
+        return AIMessage::FLOAT;
+    if (strcmp(s, luaEnumString_AIMessageParameterType_DOUBLE) == 0)
+        return AIMessage::DOUBLE;
+    if (strcmp(s, luaEnumString_AIMessageParameterType_BOOLEAN) == 0)
+        return AIMessage::BOOLEAN;
+    if (strcmp(s, luaEnumString_AIMessageParameterType_STRING) == 0)
+        return AIMessage::STRING;
+    GP_ERROR("Invalid enumeration value '%s' for enumeration AIMessage::ParameterType.", s);
+    return AIMessage::UNDEFINED;
+}
+
+const char* lua_stringFromEnum_AIMessageParameterType(AIMessage::ParameterType e)
+{
+    if (e == AIMessage::UNDEFINED)
+        return luaEnumString_AIMessageParameterType_UNDEFINED;
+    if (e == AIMessage::INTEGER)
+        return luaEnumString_AIMessageParameterType_INTEGER;
+    if (e == AIMessage::LONG)
+        return luaEnumString_AIMessageParameterType_LONG;
+    if (e == AIMessage::FLOAT)
+        return luaEnumString_AIMessageParameterType_FLOAT;
+    if (e == AIMessage::DOUBLE)
+        return luaEnumString_AIMessageParameterType_DOUBLE;
+    if (e == AIMessage::BOOLEAN)
+        return luaEnumString_AIMessageParameterType_BOOLEAN;
+    if (e == AIMessage::STRING)
+        return luaEnumString_AIMessageParameterType_STRING;
+    GP_ERROR("Invalid enumeration value '%d' for enumeration AIMessage::ParameterType.", e);
+    return enumStringEmpty;
+}
+
+}
+

+ 15 - 0
gameplay/src/lua/lua_AIMessageParameterType.h

@@ -0,0 +1,15 @@
+#ifndef LUA_AIMESSAGEPARAMETERTYPE_H_
+#define LUA_AIMESSAGEPARAMETERTYPE_H_
+
+#include "AIMessage.h"
+
+namespace gameplay
+{
+
+// Lua bindings for enum conversion functions for AIMessage::ParameterType.
+AIMessage::ParameterType lua_enumFromString_AIMessageParameterType(const char* s);
+const char* lua_stringFromEnum_AIMessageParameterType(AIMessage::ParameterType e);
+
+}
+
+#endif

+ 309 - 0
gameplay/src/lua/lua_AIState.cpp

@@ -0,0 +1,309 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_AIState.h"
+#include "AIState.h"
+#include "AIStateMachine.h"
+#include "Base.h"
+#include "Game.h"
+#include "Ref.h"
+
+namespace gameplay
+{
+
+void luaRegister_AIState()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"addRef", lua_AIState_addRef},
+        {"getId", lua_AIState_getId},
+        {"getRefCount", lua_AIState_getRefCount},
+        {"release", lua_AIState_release},
+        {"setListener", lua_AIState_setListener},
+        {NULL, NULL}
+    };
+    const luaL_Reg lua_statics[] = 
+    {
+        {"create", lua_AIState_static_create},
+        {NULL, NULL}
+    };
+    std::vector<std::string> scopePath;
+
+    ScriptUtil::registerClass("AIState", lua_members, NULL, lua_AIState__gc, lua_statics, scopePath);
+}
+
+static AIState* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "AIState");
+    luaL_argcheck(state, userdata != NULL, 1, "'AIState' expected.");
+    return (AIState*)((ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_AIState__gc(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                void* userdata = luaL_checkudata(state, 1, "AIState");
+                luaL_argcheck(state, userdata != NULL, 1, "'AIState' expected.");
+                ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)userdata;
+                if (object->owns)
+                {
+                    AIState* instance = (AIState*)object->instance;
+                    SAFE_RELEASE(instance);
+                }
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIState__gc - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIState_addRef(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIState* instance = getInstance(state);
+                instance->addRef();
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIState_addRef - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIState_getId(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIState* instance = getInstance(state);
+                const char* result = instance->getId();
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIState_getId - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIState_getRefCount(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIState* instance = getInstance(state);
+                unsigned int result = instance->getRefCount();
+
+                // Push the return value onto the stack.
+                lua_pushunsigned(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIState_getRefCount - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIState_release(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIState* instance = getInstance(state);
+                instance->release();
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIState_release - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIState_setListener(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIState::Listener* param1 = ScriptUtil::getObjectPointer<AIState::Listener>(2, "AIStateListener", false);
+
+                AIState* instance = getInstance(state);
+                instance->setListener(param1);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIState_setListener - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIState_static_create(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TSTRING || lua_type(state, 1) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = ScriptUtil::getString(1, false);
+
+                void* returnPtr = (void*)AIState::create(param1);
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIState");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIState_static_create - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+}

+ 20 - 0
gameplay/src/lua/lua_AIState.h

@@ -0,0 +1,20 @@
+#ifndef LUA_AISTATE_H_
+#define LUA_AISTATE_H_
+
+namespace gameplay
+{
+
+// Lua bindings for AIState.
+int lua_AIState__gc(lua_State* state);
+int lua_AIState_addRef(lua_State* state);
+int lua_AIState_getId(lua_State* state);
+int lua_AIState_getRefCount(lua_State* state);
+int lua_AIState_release(lua_State* state);
+int lua_AIState_setListener(lua_State* state);
+int lua_AIState_static_create(lua_State* state);
+
+void luaRegister_AIState();
+
+}
+
+#endif

+ 243 - 0
gameplay/src/lua/lua_AIStateListener.cpp

@@ -0,0 +1,243 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_AIStateListener.h"
+#include "AIState.h"
+#include "AIStateMachine.h"
+#include "Base.h"
+#include "Game.h"
+#include "Ref.h"
+
+namespace gameplay
+{
+
+void luaRegister_AIStateListener()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"stateEnter", lua_AIStateListener_stateEnter},
+        {"stateExit", lua_AIStateListener_stateExit},
+        {"stateUpdate", lua_AIStateListener_stateUpdate},
+        {NULL, NULL}
+    };
+    const luaL_Reg* lua_statics = NULL;
+    std::vector<std::string> scopePath;
+    scopePath.push_back("AIState");
+
+    ScriptUtil::registerClass("AIStateListener", lua_members, lua_AIStateListener__init, lua_AIStateListener__gc, lua_statics, scopePath);
+}
+
+static AIState::Listener* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "AIStateListener");
+    luaL_argcheck(state, userdata != NULL, 1, "'AIStateListener' expected.");
+    return (AIState::Listener*)((ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_AIStateListener__gc(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                void* userdata = luaL_checkudata(state, 1, "AIStateListener");
+                luaL_argcheck(state, userdata != NULL, 1, "'AIStateListener' expected.");
+                ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)userdata;
+                if (object->owns)
+                {
+                    AIState::Listener* instance = (AIState::Listener*)object->instance;
+                    SAFE_DELETE(instance);
+                }
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateListener__gc - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateListener__init(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 0:
+        {
+            void* returnPtr = (void*)new AIState::Listener();
+            if (returnPtr)
+            {
+                ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                object->instance = returnPtr;
+                object->owns = true;
+                luaL_getmetatable(state, "AIStateListener");
+                lua_setmetatable(state, -2);
+            }
+            else
+            {
+                lua_pushnil(state);
+            }
+
+            return 1;
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 0).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateListener_stateEnter(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TUSERDATA || lua_type(state, 3) == LUA_TTABLE || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIAgent* param1 = ScriptUtil::getObjectPointer<AIAgent>(2, "AIAgent", false);
+
+                // Get parameter 2 off the stack.
+                AIState* param2 = ScriptUtil::getObjectPointer<AIState>(3, "AIState", false);
+
+                AIState::Listener* instance = getInstance(state);
+                instance->stateEnter(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateListener_stateEnter - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateListener_stateExit(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 3:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TUSERDATA || lua_type(state, 3) == LUA_TTABLE || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIAgent* param1 = ScriptUtil::getObjectPointer<AIAgent>(2, "AIAgent", false);
+
+                // Get parameter 2 off the stack.
+                AIState* param2 = ScriptUtil::getObjectPointer<AIState>(3, "AIState", false);
+
+                AIState::Listener* instance = getInstance(state);
+                instance->stateExit(param1, param2);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateListener_stateExit - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateListener_stateUpdate(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 4:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TUSERDATA || lua_type(state, 3) == LUA_TTABLE || lua_type(state, 3) == LUA_TNIL) &&
+                lua_type(state, 4) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                AIAgent* param1 = ScriptUtil::getObjectPointer<AIAgent>(2, "AIAgent", false);
+
+                // Get parameter 2 off the stack.
+                AIState* param2 = ScriptUtil::getObjectPointer<AIState>(3, "AIState", false);
+
+                // Get parameter 3 off the stack.
+                float param3 = (float)luaL_checknumber(state, 4);
+
+                AIState::Listener* instance = getInstance(state);
+                instance->stateUpdate(param1, param2, param3);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateListener_stateUpdate - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 4).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+}

+ 18 - 0
gameplay/src/lua/lua_AIStateListener.h

@@ -0,0 +1,18 @@
+#ifndef LUA_AISTATELISTENER_H_
+#define LUA_AISTATELISTENER_H_
+
+namespace gameplay
+{
+
+// Lua bindings for AIState::Listener.
+int lua_AIStateListener__gc(lua_State* state);
+int lua_AIStateListener__init(lua_State* state);
+int lua_AIStateListener_stateEnter(lua_State* state);
+int lua_AIStateListener_stateExit(lua_State* state);
+int lua_AIStateListener_stateUpdate(lua_State* state);
+
+void luaRegister_AIStateListener();
+
+}
+
+#endif

+ 343 - 0
gameplay/src/lua/lua_AIStateMachine.cpp

@@ -0,0 +1,343 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_AIStateMachine.h"
+#include "AIAgent.h"
+#include "AIMessage.h"
+#include "AIStateMachine.h"
+#include "Base.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+void luaRegister_AIStateMachine()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"addState", lua_AIStateMachine_addState},
+        {"getActiveState", lua_AIStateMachine_getActiveState},
+        {"getAgent", lua_AIStateMachine_getAgent},
+        {"getState", lua_AIStateMachine_getState},
+        {"removeState", lua_AIStateMachine_removeState},
+        {"setState", lua_AIStateMachine_setState},
+        {NULL, NULL}
+    };
+    const luaL_Reg* lua_statics = NULL;
+    std::vector<std::string> scopePath;
+
+    ScriptUtil::registerClass("AIStateMachine", lua_members, NULL, NULL, lua_statics, scopePath);
+}
+
+static AIStateMachine* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "AIStateMachine");
+    luaL_argcheck(state, userdata != NULL, 1, "'AIStateMachine' expected.");
+    return (AIStateMachine*)((ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_AIStateMachine_addState(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = ScriptUtil::getString(2, false);
+
+                AIStateMachine* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addState(param1);
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIState");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIState* param1 = ScriptUtil::getObjectPointer<AIState>(2, "AIState", false);
+
+                AIStateMachine* instance = getInstance(state);
+                instance->addState(param1);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateMachine_addState - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateMachine_getActiveState(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIStateMachine* instance = getInstance(state);
+                void* returnPtr = (void*)instance->getActiveState();
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIState");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateMachine_getActiveState - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateMachine_getAgent(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                AIStateMachine* instance = getInstance(state);
+                void* returnPtr = (void*)instance->getAgent();
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIAgent");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateMachine_getAgent - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateMachine_getState(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = ScriptUtil::getString(2, false);
+
+                AIStateMachine* instance = getInstance(state);
+                void* returnPtr = (void*)instance->getState(param1);
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIState");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateMachine_getState - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateMachine_removeState(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIState* param1 = ScriptUtil::getObjectPointer<AIState>(2, "AIState", false);
+
+                AIStateMachine* instance = getInstance(state);
+                instance->removeState(param1);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateMachine_removeState - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_AIStateMachine_setState(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = ScriptUtil::getString(2, false);
+
+                AIStateMachine* instance = getInstance(state);
+                void* returnPtr = (void*)instance->setState(param1);
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIState");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIState* param1 = ScriptUtil::getObjectPointer<AIState>(2, "AIState", false);
+
+                AIStateMachine* instance = getInstance(state);
+                bool result = instance->setState(param1);
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_AIStateMachine_setState - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+}

+ 19 - 0
gameplay/src/lua/lua_AIStateMachine.h

@@ -0,0 +1,19 @@
+#ifndef LUA_AISTATEMACHINE_H_
+#define LUA_AISTATEMACHINE_H_
+
+namespace gameplay
+{
+
+// Lua bindings for AIStateMachine.
+int lua_AIStateMachine_addState(lua_State* state);
+int lua_AIStateMachine_getActiveState(lua_State* state);
+int lua_AIStateMachine_getAgent(lua_State* state);
+int lua_AIStateMachine_getState(lua_State* state);
+int lua_AIStateMachine_removeState(lua_State* state);
+int lua_AIStateMachine_setState(lua_State* state);
+
+void luaRegister_AIStateMachine();
+
+}
+
+#endif

+ 47 - 0
gameplay/src/lua/lua_Game.cpp

@@ -28,6 +28,7 @@ void luaRegister_Game()
         {"exit", lua_Game_exit},
         {"frame", lua_Game_frame},
         {"gamepadEvent", lua_Game_gamepadEvent},
+        {"getAIController", lua_Game_getAIController},
         {"getAccelerometerValues", lua_Game_getAccelerometerValues},
         {"getAnimationController", lua_Game_getAnimationController},
         {"getAudioController", lua_Game_getAudioController},
@@ -320,6 +321,52 @@ int lua_Game_gamepadEvent(lua_State* state)
     return 0;
 }
 
+int lua_Game_getAIController(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                Game* instance = getInstance(state);
+                void* returnPtr = (void*)instance->getAIController();
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIController");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Game_getAIController - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Game_getAccelerometerValues(lua_State* state)
 {
     // Get the number of parameters.

+ 1 - 0
gameplay/src/lua/lua_Game.h

@@ -11,6 +11,7 @@ int lua_Game_displayKeyboard(lua_State* state);
 int lua_Game_exit(lua_State* state);
 int lua_Game_frame(lua_State* state);
 int lua_Game_gamepadEvent(lua_State* state);
+int lua_Game_getAIController(lua_State* state);
 int lua_Game_getAccelerometerValues(lua_State* state);
 int lua_Game_getAnimationController(lua_State* state);
 int lua_Game_getAudioController(lua_State* state);

+ 17 - 0
gameplay/src/lua/lua_Global.cpp

@@ -63,6 +63,8 @@ void luaRegister_lua_Global()
     hierarchy["PhysicsGenericConstraint"].push_back("PhysicsFixedConstraint");
     hierarchy["PhysicsGenericConstraint"].push_back("PhysicsSpringConstraint");
     hierarchy["PhysicsGhostObject"].push_back("PhysicsCharacter");
+    hierarchy["Ref"].push_back("AIAgent");
+    hierarchy["Ref"].push_back("AIState");
     hierarchy["Ref"].push_back("AbsoluteLayout");
     hierarchy["Ref"].push_back("Animation");
     hierarchy["Ref"].push_back("AnimationClip");
@@ -128,6 +130,19 @@ void luaRegister_lua_Global()
     hierarchy["Transform::Listener"].push_back("classgameplay_1_1_script_listener");
     ScriptUtil::setGlobalHierarchy(hierarchy);
 
+    // Register enumeration AIMessage::ParameterType.
+    {
+        std::vector<std::string> scopePath;
+        scopePath.push_back("AIMessage");
+        ScriptUtil::registerConstantString("UNDEFINED", "UNDEFINED", scopePath);
+        ScriptUtil::registerConstantString("INTEGER", "INTEGER", scopePath);
+        ScriptUtil::registerConstantString("LONG", "LONG", scopePath);
+        ScriptUtil::registerConstantString("FLOAT", "FLOAT", scopePath);
+        ScriptUtil::registerConstantString("DOUBLE", "DOUBLE", scopePath);
+        ScriptUtil::registerConstantString("BOOLEAN", "BOOLEAN", scopePath);
+        ScriptUtil::registerConstantString("STRING", "STRING", scopePath);
+    }
+
     // Register enumeration AnimationClip::Listener::EventType.
     {
         std::vector<std::string> scopePath;
@@ -848,6 +863,8 @@ static const char* enumStringEmpty = "";
 
 const char* lua_stringFromEnumGlobal(std::string& enumname, unsigned int value)
 {
+    if (enumname == "AIMessage::ParameterType")
+        return lua_stringFromEnum_AIMessageParameterType((AIMessage::ParameterType)value);
     if (enumname == "AnimationClip::Listener::EventType")
         return lua_stringFromEnum_AnimationClipListenerEventType((AnimationClip::Listener::EventType)value);
     if (enumname == "AudioSource::State")

+ 1 - 0
gameplay/src/lua/lua_Global.h

@@ -1,6 +1,7 @@
 #ifndef LUA_GLOBAL_H_
 #define LUA_GLOBAL_H_
 
+#include "lua_AIMessageParameterType.h"
 #include "lua_AnimationClipListenerEventType.h"
 #include "lua_AudioSourceState.h"
 #include "lua_CameraType.h"

+ 86 - 0
gameplay/src/lua/lua_Joint.cpp

@@ -38,6 +38,7 @@ void luaRegister_Joint()
         {"findNode", lua_Joint_findNode},
         {"getActiveCameraTranslationView", lua_Joint_getActiveCameraTranslationView},
         {"getActiveCameraTranslationWorld", lua_Joint_getActiveCameraTranslationWorld},
+        {"getAgent", lua_Joint_getAgent},
         {"getAnimation", lua_Joint_getAnimation},
         {"getAnimationPropertyComponentCount", lua_Joint_getAnimationPropertyComponentCount},
         {"getAnimationPropertyValue", lua_Joint_getAnimationPropertyValue},
@@ -108,6 +109,7 @@ void luaRegister_Joint()
         {"scaleY", lua_Joint_scaleY},
         {"scaleZ", lua_Joint_scaleZ},
         {"set", lua_Joint_set},
+        {"setAgent", lua_Joint_setAgent},
         {"setAnimationPropertyValue", lua_Joint_setAnimationPropertyValue},
         {"setAudioSource", lua_Joint_setAudioSource},
         {"setCamera", lua_Joint_setCamera},
@@ -1023,6 +1025,52 @@ int lua_Joint_getActiveCameraTranslationWorld(lua_State* state)
     return 0;
 }
 
+int lua_Joint_getAgent(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                Joint* instance = getInstance(state);
+                void* returnPtr = (void*)instance->getAgent();
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIAgent");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Joint_getAgent - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Joint_getAnimation(lua_State* state)
 {
     // Get the number of parameters.
@@ -4438,6 +4486,44 @@ int lua_Joint_set(lua_State* state)
     return 0;
 }
 
+int lua_Joint_setAgent(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIAgent* param1 = ScriptUtil::getObjectPointer<AIAgent>(2, "AIAgent", false);
+
+                Joint* instance = getInstance(state);
+                instance->setAgent(param1);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Joint_setAgent - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Joint_setAnimationPropertyValue(lua_State* state)
 {
     // Get the number of parameters.

+ 2 - 0
gameplay/src/lua/lua_Joint.h

@@ -17,6 +17,7 @@ int lua_Joint_destroyAnimation(lua_State* state);
 int lua_Joint_findNode(lua_State* state);
 int lua_Joint_getActiveCameraTranslationView(lua_State* state);
 int lua_Joint_getActiveCameraTranslationWorld(lua_State* state);
+int lua_Joint_getAgent(lua_State* state);
 int lua_Joint_getAnimation(lua_State* state);
 int lua_Joint_getAnimationPropertyComponentCount(lua_State* state);
 int lua_Joint_getAnimationPropertyValue(lua_State* state);
@@ -87,6 +88,7 @@ int lua_Joint_scaleX(lua_State* state);
 int lua_Joint_scaleY(lua_State* state);
 int lua_Joint_scaleZ(lua_State* state);
 int lua_Joint_set(lua_State* state);
+int lua_Joint_setAgent(lua_State* state);
 int lua_Joint_setAnimationPropertyValue(lua_State* state);
 int lua_Joint_setAudioSource(lua_State* state);
 int lua_Joint_setCamera(lua_State* state);

+ 86 - 0
gameplay/src/lua/lua_Node.cpp

@@ -37,6 +37,7 @@ void luaRegister_Node()
         {"findNode", lua_Node_findNode},
         {"getActiveCameraTranslationView", lua_Node_getActiveCameraTranslationView},
         {"getActiveCameraTranslationWorld", lua_Node_getActiveCameraTranslationWorld},
+        {"getAgent", lua_Node_getAgent},
         {"getAnimation", lua_Node_getAnimation},
         {"getAnimationPropertyComponentCount", lua_Node_getAnimationPropertyComponentCount},
         {"getAnimationPropertyValue", lua_Node_getAnimationPropertyValue},
@@ -106,6 +107,7 @@ void luaRegister_Node()
         {"scaleY", lua_Node_scaleY},
         {"scaleZ", lua_Node_scaleZ},
         {"set", lua_Node_set},
+        {"setAgent", lua_Node_setAgent},
         {"setAnimationPropertyValue", lua_Node_setAnimationPropertyValue},
         {"setAudioSource", lua_Node_setAudioSource},
         {"setCamera", lua_Node_setCamera},
@@ -1022,6 +1024,52 @@ int lua_Node_getActiveCameraTranslationWorld(lua_State* state)
     return 0;
 }
 
+int lua_Node_getAgent(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                Node* instance = getInstance(state);
+                void* returnPtr = (void*)instance->getAgent();
+                if (returnPtr)
+                {
+                    ScriptUtil::LuaObject* object = (ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "AIAgent");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Node_getAgent - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Node_getAnimation(lua_State* state)
 {
     // Get the number of parameters.
@@ -4391,6 +4439,44 @@ int lua_Node_set(lua_State* state)
     return 0;
 }
 
+int lua_Node_setAgent(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                AIAgent* param1 = ScriptUtil::getObjectPointer<AIAgent>(2, "AIAgent", false);
+
+                Node* instance = getInstance(state);
+                instance->setAgent(param1);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Node_setAgent - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Node_setAnimationPropertyValue(lua_State* state)
 {
     // Get the number of parameters.

+ 2 - 0
gameplay/src/lua/lua_Node.h

@@ -17,6 +17,7 @@ int lua_Node_destroyAnimation(lua_State* state);
 int lua_Node_findNode(lua_State* state);
 int lua_Node_getActiveCameraTranslationView(lua_State* state);
 int lua_Node_getActiveCameraTranslationWorld(lua_State* state);
+int lua_Node_getAgent(lua_State* state);
 int lua_Node_getAnimation(lua_State* state);
 int lua_Node_getAnimationPropertyComponentCount(lua_State* state);
 int lua_Node_getAnimationPropertyValue(lua_State* state);
@@ -86,6 +87,7 @@ int lua_Node_scaleX(lua_State* state);
 int lua_Node_scaleY(lua_State* state);
 int lua_Node_scaleZ(lua_State* state);
 int lua_Node_set(lua_State* state);
+int lua_Node_setAgent(lua_State* state);
 int lua_Node_setAnimationPropertyValue(lua_State* state);
 int lua_Node_setAudioSource(lua_State* state);
 int lua_Node_setCamera(lua_State* state);

+ 7 - 0
gameplay/src/lua/lua_all_bindings.cpp

@@ -6,6 +6,13 @@ namespace gameplay
 
 void lua_RegisterAllBindings()
 {
+    luaRegister_AIAgent();
+    luaRegister_AIAgentListener();
+    luaRegister_AIController();
+    luaRegister_AIMessage();
+    luaRegister_AIState();
+    luaRegister_AIStateListener();
+    luaRegister_AIStateMachine();
     luaRegister_AbsoluteLayout();
     luaRegister_Animation();
     luaRegister_AnimationClip();

+ 7 - 0
gameplay/src/lua/lua_all_bindings.h

@@ -1,6 +1,13 @@
 #ifndef LUA_ALL_BINDINGS_H_
 #define LUA_ALL_BINDINGS_H_
 
+#include "lua_AIAgent.h"
+#include "lua_AIAgentListener.h"
+#include "lua_AIController.h"
+#include "lua_AIMessage.h"
+#include "lua_AIState.h"
+#include "lua_AIStateListener.h"
+#include "lua_AIStateMachine.h"
 #include "lua_AbsoluteLayout.h"
 #include "lua_Animation.h"
 #include "lua_AnimationClip.h"