Bladeren bron

Finished most work for new prototype of scripting system.
Still a bit of cleanup, testing and review to do.

sgrenier 11 jaren geleden
bovenliggende
commit
2a3f6a3144
84 gewijzigde bestanden met toevoegingen van 5881 en 1581 verwijderingen
  1. 6 0
      gameplay/gameplay.vcxproj
  2. 18 0
      gameplay/gameplay.vcxproj.filters
  3. 3 8
      gameplay/src/AIAgent.cpp
  4. 2 2
      gameplay/src/AIAgent.h
  5. 11 9
      gameplay/src/AIState.cpp
  6. 1 2
      gameplay/src/AIState.h
  7. 1 0
      gameplay/src/AIStateMachine.h
  8. 14 104
      gameplay/src/AnimationClip.cpp
  9. 9 77
      gameplay/src/AnimationClip.h
  10. 2 7
      gameplay/src/Control.cpp
  11. 4 0
      gameplay/src/Control.h
  12. 42 77
      gameplay/src/Game.cpp
  13. 5 24
      gameplay/src/Game.h
  14. 11 6
      gameplay/src/Node.cpp
  15. 10 1
      gameplay/src/Node.h
  16. 45 7
      gameplay/src/PhysicsCollisionObject.cpp
  17. 28 6
      gameplay/src/PhysicsCollisionObject.h
  18. 2 7
      gameplay/src/PhysicsController.cpp
  19. 4 0
      gameplay/src/PhysicsController.h
  20. 10 2
      gameplay/src/SceneLoader.cpp
  21. 2 1
      gameplay/src/SceneLoader.h
  22. 42 0
      gameplay/src/Script.cpp
  23. 43 3
      gameplay/src/Script.h
  24. 538 196
      gameplay/src/ScriptController.cpp
  25. 300 80
      gameplay/src/ScriptController.h
  26. 21 5
      gameplay/src/ScriptController.inl
  27. 316 139
      gameplay/src/ScriptTarget.cpp
  28. 183 89
      gameplay/src/ScriptTarget.h
  29. 1 6
      gameplay/src/Transform.cpp
  30. 5 2
      gameplay/src/Transform.h
  31. 0 115
      gameplay/src/lua/lua_AIAgent.cpp
  32. 0 3
      gameplay/src/lua/lua_AIAgent.h
  33. 0 2
      gameplay/src/lua/lua_AIAgentListener.cpp
  34. 2 115
      gameplay/src/lua/lua_AIState.cpp
  35. 0 3
      gameplay/src/lua/lua_AIState.h
  36. 2 2
      gameplay/src/lua/lua_AIStateListener.cpp
  37. 359 180
      gameplay/src/lua/lua_AnimationClip.cpp
  38. 6 0
      gameplay/src/lua/lua_AnimationClip.h
  39. 1 0
      gameplay/src/lua/lua_AnimationClipListener.cpp
  40. 174 11
      gameplay/src/lua/lua_Button.cpp
  41. 3 0
      gameplay/src/lua/lua_Button.h
  42. 174 11
      gameplay/src/lua/lua_CheckBox.cpp
  43. 3 0
      gameplay/src/lua/lua_CheckBox.h
  44. 174 11
      gameplay/src/lua/lua_Container.cpp
  45. 3 0
      gameplay/src/lua/lua_Container.h
  46. 174 11
      gameplay/src/lua/lua_Control.cpp
  47. 3 0
      gameplay/src/lua/lua_Control.h
  48. 174 11
      gameplay/src/lua/lua_Form.cpp
  49. 3 0
      gameplay/src/lua/lua_Form.h
  50. 38 1
      gameplay/src/lua/lua_Game.cpp
  51. 1 0
      gameplay/src/lua/lua_Game.h
  52. 12 2
      gameplay/src/lua/lua_Global.cpp
  53. 174 11
      gameplay/src/lua/lua_ImageControl.cpp
  54. 3 0
      gameplay/src/lua/lua_ImageControl.h
  55. 174 11
      gameplay/src/lua/lua_Joint.cpp
  56. 3 0
      gameplay/src/lua/lua_Joint.h
  57. 174 11
      gameplay/src/lua/lua_JoystickControl.cpp
  58. 3 0
      gameplay/src/lua/lua_JoystickControl.h
  59. 174 11
      gameplay/src/lua/lua_Label.cpp
  60. 3 0
      gameplay/src/lua/lua_Label.h
  61. 174 11
      gameplay/src/lua/lua_Node.cpp
  62. 3 0
      gameplay/src/lua/lua_Node.h
  63. 174 11
      gameplay/src/lua/lua_PhysicsController.cpp
  64. 3 0
      gameplay/src/lua/lua_PhysicsController.h
  65. 174 11
      gameplay/src/lua/lua_RadioButton.cpp
  66. 3 0
      gameplay/src/lua/lua_RadioButton.h
  67. 320 0
      gameplay/src/lua/lua_Script.cpp
  68. 21 0
      gameplay/src/lua/lua_Script.h
  69. 84 119
      gameplay/src/lua/lua_ScriptController.cpp
  70. 1 3
      gameplay/src/lua/lua_ScriptController.h
  71. 174 11
      gameplay/src/lua/lua_ScriptTarget.cpp
  72. 3 0
      gameplay/src/lua/lua_ScriptTarget.h
  73. 178 0
      gameplay/src/lua/lua_ScriptTargetEvent.cpp
  74. 17 0
      gameplay/src/lua/lua_ScriptTargetEvent.h
  75. 304 0
      gameplay/src/lua/lua_ScriptTargetEventRegistry.cpp
  76. 18 0
      gameplay/src/lua/lua_ScriptTargetEventRegistry.h
  77. 174 11
      gameplay/src/lua/lua_Slider.cpp
  78. 3 0
      gameplay/src/lua/lua_Slider.h
  79. 174 11
      gameplay/src/lua/lua_TextBox.cpp
  80. 3 0
      gameplay/src/lua/lua_TextBox.h
  81. 174 11
      gameplay/src/lua/lua_Transform.cpp
  82. 3 0
      gameplay/src/lua/lua_Transform.h
  83. 3 0
      gameplay/src/lua/lua_all_bindings.cpp
  84. 3 0
      gameplay/src/lua/lua_all_bindings.h

+ 6 - 0
gameplay/gameplay.vcxproj

@@ -163,8 +163,11 @@
     <ClCompile Include="src\lua\lua_RenderTarget.cpp" />
     <ClCompile Include="src\lua\lua_Scene.cpp" />
     <ClCompile Include="src\lua\lua_ScreenDisplayer.cpp" />
+    <ClCompile Include="src\lua\lua_Script.cpp" />
     <ClCompile Include="src\lua\lua_ScriptController.cpp" />
     <ClCompile Include="src\lua\lua_ScriptTarget.cpp" />
+    <ClCompile Include="src\lua\lua_ScriptTargetEvent.cpp" />
+    <ClCompile Include="src\lua\lua_ScriptTargetEventRegistry.cpp" />
     <ClCompile Include="src\lua\lua_Slider.cpp" />
     <ClCompile Include="src\lua\lua_SpriteBatch.cpp" />
     <ClCompile Include="src\lua\lua_Technique.cpp" />
@@ -402,8 +405,11 @@
     <ClInclude Include="src\lua\lua_RenderTarget.h" />
     <ClInclude Include="src\lua\lua_Scene.h" />
     <ClInclude Include="src\lua\lua_ScreenDisplayer.h" />
+    <ClInclude Include="src\lua\lua_Script.h" />
     <ClInclude Include="src\lua\lua_ScriptController.h" />
     <ClInclude Include="src\lua\lua_ScriptTarget.h" />
+    <ClInclude Include="src\lua\lua_ScriptTargetEvent.h" />
+    <ClInclude Include="src\lua\lua_ScriptTargetEventRegistry.h" />
     <ClInclude Include="src\lua\lua_Slider.h" />
     <ClInclude Include="src\lua\lua_SpriteBatch.h" />
     <ClInclude Include="src\lua\lua_Technique.h" />

+ 18 - 0
gameplay/gameplay.vcxproj.filters

@@ -729,6 +729,15 @@
     <ClCompile Include="src\Script.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\lua\lua_Script.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ScriptTargetEvent.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ScriptTargetEventRegistry.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Plane.h">
@@ -1445,6 +1454,15 @@
     <ClInclude Include="src\Script.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\lua\lua_Script.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ScriptTargetEvent.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ScriptTargetEventRegistry.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\ScriptController.inl">

+ 3 - 8
gameplay/src/AIAgent.cpp

@@ -2,17 +2,12 @@
 #include "AIAgent.h"
 #include "Node.h"
 
-GP_SCRIPT_EVENTS();
-GP_SCRIPT_EVENT(message, "<AIMessage>");
-
 namespace gameplay
 {
 
 AIAgent::AIAgent()
     : _stateMachine(NULL), _node(NULL), _enabled(true), _listener(NULL), _next(NULL)
 {
-    GP_REGISTER_SCRIPT_EVENTS();
-
     _stateMachine = new AIStateMachine(this);
 }
 
@@ -88,10 +83,10 @@ bool AIAgent::processMessage(AIMessage* message)
     // Dispatch message to registered listener.
     if (_listener && _listener->messageReceived(message))
         return true;
-    
-    if (fireScriptEvent<bool>(SCRIPT_EVENT_message, message))
+
+    if (_node && _node->fireScriptEvent<bool>(GP_GET_SCRIPT_EVENT(Node, messageReceived), _node, message))
         return true;
-    
+
     return false;
 }
 

+ 2 - 2
gameplay/src/AIAgent.h

@@ -4,7 +4,6 @@
 #include "Ref.h"
 #include "AIStateMachine.h"
 #include "AIMessage.h"
-#include "ScriptTarget.h"
 
 namespace gameplay
 {
@@ -19,9 +18,10 @@ class Node;
  * such as state machines. By default, an AIAgent has an empty state 
  * machine.
  */
-class AIAgent : public Ref, public ScriptTarget
+class AIAgent : public Ref
 {
     friend class Node;
+    friend class AIState;
     friend class AIController;
 
 public:

+ 11 - 9
gameplay/src/AIState.cpp

@@ -1,11 +1,8 @@
 #include "Base.h"
 #include "AIState.h"
+#include "AIAgent.h"
 #include "AIStateMachine.h"
-
-GP_SCRIPT_EVENTS();
-GP_SCRIPT_EVENT(enter, "<AIAgent><AIState>");
-GP_SCRIPT_EVENT(exit, "<AIAgent><AIState>");
-GP_SCRIPT_EVENT(update, "<AIAgent><AIState>f");
+#include "Node.h"
 
 namespace gameplay
 {
@@ -15,7 +12,6 @@ AIState* AIState::_empty = NULL;
 AIState::AIState(const char* id)
     : _id(id), _listener(NULL)
 {
-    GP_REGISTER_SCRIPT_EVENTS();
 }
 
 AIState::~AIState()
@@ -42,7 +38,9 @@ void AIState::enter(AIStateMachine* stateMachine)
     if (_listener)
         _listener->stateEnter(stateMachine->getAgent(), this);
 
-    fireScriptEvent<void>(SCRIPT_EVENT_enter, stateMachine->getAgent(), this);
+    Node* node = stateMachine->_agent->_node;
+    if (node)
+        node->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(Node, stateEnter), node, this);
 }
 
 void AIState::exit(AIStateMachine* stateMachine)
@@ -50,7 +48,9 @@ void AIState::exit(AIStateMachine* stateMachine)
     if (_listener)
         _listener->stateExit(stateMachine->getAgent(), this);
 
-    fireScriptEvent<void>(SCRIPT_EVENT_exit, stateMachine->getAgent(), this);
+    Node* node = stateMachine->_agent->_node;
+    if (node)
+        node->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(Node, stateExit), node, this);
 }
 
 void AIState::update(AIStateMachine* stateMachine, float elapsedTime)
@@ -58,7 +58,9 @@ void AIState::update(AIStateMachine* stateMachine, float elapsedTime)
     if (_listener)
         _listener->stateUpdate(stateMachine->getAgent(), this, elapsedTime);
 
-    fireScriptEvent<void>(SCRIPT_EVENT_update, stateMachine->getAgent(), this, elapsedTime);
+    Node* node = stateMachine->_agent->_node;
+    if (node)
+        node->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(Node, stateUpdate), node, this, elapsedTime);
 }
 
 AIState::Listener::~Listener()

+ 1 - 2
gameplay/src/AIState.h

@@ -2,7 +2,6 @@
 #define AISTATE_H_
 
 #include "Ref.h"
-#include "ScriptTarget.h"
 
 namespace gameplay
 {
@@ -17,7 +16,7 @@ class AIStateMachine;
  * 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, public ScriptTarget
+class AIState : public Ref
 {
     friend class AIStateMachine;
 

+ 1 - 0
gameplay/src/AIStateMachine.h

@@ -30,6 +30,7 @@ class AIAgent;
 class AIStateMachine
 {
     friend class AIAgent;
+    friend class AIState;
 
 public:
 

+ 14 - 104
gameplay/src/AnimationClip.cpp

@@ -9,12 +9,16 @@
 namespace gameplay
 {
 
+extern void splitURL(const std::string& url, std::string* file, std::string* id);
+
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
     : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), 
       _stateBits(0x00), _repeatCount(1.0f), _loopBlendTime(0), _activeDuration(_duration * _repeatCount), _speed(1.0f), _timeStarted(0), 
       _elapsedTime(0), _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f),
-      _beginListeners(NULL), _endListeners(NULL), _listeners(NULL), _listenerItr(NULL), _scriptListeners(NULL)
+      _beginListeners(NULL), _endListeners(NULL), _listeners(NULL), _listenerItr(NULL)
 {
+    GP_REGISTER_SCRIPT_EVENTS();
+
     GP_ASSERT(_animation);
     GP_ASSERT(0 <= startTime && startTime <= _animation->_duration && 0 <= endTime && endTime <= _animation->_duration);
 
@@ -40,15 +44,6 @@ AnimationClip::~AnimationClip()
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_endListeners);
 
-    if (_scriptListeners)
-    {
-        for (size_t i = 0; i < _scriptListeners->size(); i++)
-        {
-            SAFE_DELETE((*_scriptListeners)[i]);
-        }
-        SAFE_DELETE(_scriptListeners);
-    }
-
     if (_listeners)
     {
         *_listenerItr = _listeners->begin();
@@ -392,88 +387,6 @@ void AnimationClip::removeEndListener(AnimationClip::Listener* listener)
     }
 }
 
-void AnimationClip::addBeginListener(const char* function)
-{
-    if (!_scriptListeners)
-        _scriptListeners = new std::vector<ScriptListener*>;
-
-    ScriptListener* listener = new ScriptListener(function);
-    _scriptListeners->push_back(listener);
-    addBeginListener(listener);
-}
-
-void AnimationClip::removeBeginListener(const char* function)
-{
-    if (_scriptListeners)
-    {
-        std::string functionRef = Game::getInstance()->getScriptController()->loadUrl(function);
-        std::vector<ScriptListener*>::iterator iter = std::find_if(_scriptListeners->begin(), _scriptListeners->end(), [&](ScriptListener* listener){ return listener->function == functionRef; });
-        if (iter != _scriptListeners->end())
-        {
-            ScriptListener* listener = *iter;
-
-            removeBeginListener(listener);
-            _scriptListeners->erase(iter);
-            SAFE_DELETE(listener);
-        }
-    }
-}
-
-void AnimationClip::addEndListener(const char* function)
-{
-    if (!_scriptListeners)
-        _scriptListeners = new std::vector<ScriptListener*>;
-
-    ScriptListener* listener = new ScriptListener(function);
-    _scriptListeners->push_back(listener);
-    addEndListener(listener);
-}
-
-void AnimationClip::removeEndListener(const char* function)
-{
-    if (_scriptListeners)
-    {
-        std::string functionRef = Game::getInstance()->getScriptController()->loadUrl(function);
-        std::vector<ScriptListener*>::iterator iter = std::find_if(_scriptListeners->begin(), _scriptListeners->end(), [&](ScriptListener* listener){ return listener->function == functionRef; });
-        if (iter != _scriptListeners->end())
-        {
-            ScriptListener* listener = *iter;
-
-            removeEndListener(listener);
-            _scriptListeners->erase(iter);
-            SAFE_DELETE(listener);
-        }
-    }
-}
-
-void AnimationClip::addListener(const char* function, unsigned long eventTime)
-{
-    if (!_scriptListeners)
-        _scriptListeners = new std::vector<ScriptListener*>;
-
-    ScriptListener* listener = new ScriptListener(function);
-    _scriptListeners->push_back(listener);
-    addListener(listener, eventTime);
-}
-
-void AnimationClip::removeListener(const char* function, unsigned long eventTime)
-{
-    if (_scriptListeners)
-    {
-        GP_ASSERT(eventTime < _activeDuration); // Do this check here, before we modify any state
-        std::string functionRef = Game::getInstance()->getScriptController()->loadUrl(function);
-        std::vector<ScriptListener*>::iterator iter = std::find_if(_scriptListeners->begin(), _scriptListeners->end(), [&](ScriptListener* listener){ return listener->function == functionRef; });
-        if (iter != _scriptListeners->end())
-        {
-            ScriptListener* listener = *iter;
-
-            removeListener(listener, eventTime);
-            _scriptListeners->erase(iter);
-            SAFE_DELETE(listener);
-        }
-    }
-}
-
 bool AnimationClip::update(float elapsedTime)
 {
     if (isClipStateBitSet(CLIP_IS_PAUSED_BIT))
@@ -566,6 +479,9 @@ bool AnimationClip::update(float elapsedTime)
         }
     }
 
+    // Fire script update event
+    fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(AnimationClip, clipUpdate), this, _elapsedTime);
+
     // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
     GP_ASSERT(_animation);
 
@@ -693,6 +609,9 @@ void AnimationClip::onBegin()
         }
     }
 
+    // Fire script begin event
+    fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(AnimationClip, clipBegin), this);
+
     release();
 }
 
@@ -715,6 +634,9 @@ void AnimationClip::onEnd()
         }
     }
 
+    // Fire script end event
+    fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(AnimationClip, clipEnd), this);
+
     release();
 }
 
@@ -757,16 +679,4 @@ AnimationClip* AnimationClip::clone(Animation* animation) const
     return newClip;
 }
 
-AnimationClip::ScriptListener::ScriptListener(const std::string& function)
-{
-    // Store the function name.
-    this->function = Game::getInstance()->getScriptController()->loadUrl(function.c_str());
-}
-
-void AnimationClip::ScriptListener::animationEvent(AnimationClip* clip, EventType type)
-{
-    Game::getInstance()->getScriptController()->executeFunction<void>(function.c_str(), "<AnimationClip>[AnimationClip::Listener::EventType]", clip, type);
-}
-
-
 }

+ 9 - 77
gameplay/src/AnimationClip.h

@@ -1,26 +1,31 @@
 #ifndef ANIMATIONCLIP_H_
 #define ANIMATIONCLIP_H_
 
-#include "Base.h"
 #include "AnimationValue.h"
 #include "Curve.h"
 #include "Animation.h"
+#include "ScriptTarget.h"
 
 namespace gameplay
 {
 
 class Animation;
 class AnimationValue;
-class ScriptListener;
 
 /**
  * Defines the runtime session of an Animation to be played.
  */
-class AnimationClip : public Ref
+class AnimationClip : public Ref, public ScriptTarget
 {
     friend class AnimationController;
     friend class Animation;
 
+    GP_SCRIPT_EVENTS_START();
+    GP_SCRIPT_EVENT(clipBegin, "<AnimationClip>");
+    GP_SCRIPT_EVENT(clipEnd, "<AnimationClip>");
+    GP_SCRIPT_EVENT(clipUpdate, "<AnimationClip>f");
+    GP_SCRIPT_EVENTS_END();
+
 public:
 
     /**
@@ -37,7 +42,7 @@ public:
 
     public:
 
-        /*
+        /**
          * Constructor.
          */
         Listener() 
@@ -271,59 +276,6 @@ public:
      */
     void removeListener(AnimationClip::Listener* listener, unsigned long eventTime);
 
-    /**
-     * Adds an animation begin listener.
-     * 
-     * Note: the given Lua function must have the same function signature as AnimationClip::Listener::animationEvent.
-     *
-     * @param function The Lua script function to be called when an AnimationClip begins.
-     */
-    void addBeginListener(const char* function);
-
-    /**
-     * Removes an animation begin listener.
-     *
-     * @param function The Lua script function to remove.
-     */
-    void removeBeginListener(const char* function);
-
-    /**
-     * Adds an animation end listener.
-     * 
-     * Note: the given Lua function must have the same function signature as AnimationClip::Listener::animationEvent.
-     *
-     * @param function The Lua script function to be called when an AnimationClip ends.
-     */
-    void addEndListener(const char* function);
-
-    /**
-     * Removes an animation end listener.
-     *
-     * @param function The Lua script function to remove.
-     */
-    void removeEndListener(const char* function);
-
-    /**
-     * Adds an animation listener to be called back at the specified eventTime during the playback 
-     * of the AnimationClip.
-     * 
-     * Note: the given Lua function must have the same function signature as AnimationClip::Listener::animationEvent.
-     * 
-     * @param function The Lua script function to be called when an AnimationClip reaches the 
-     *      specified time in its playback.
-     * @param eventTime The time the listener will be called during the playback of the AnimationClip. 
-     *      Must be between 0 and the duration of the AnimationClip.
-     */
-    void addListener(const char* function, unsigned long eventTime);
-
-    /**
-     * Removes an animation listener assigned to the specified eventTime.
-     *
-     * @param function The Lua script function to remove with the specified time.
-     * @param eventTime The time of the listener to be removed.
-     */
-    void removeListener(const char* function, unsigned long eventTime);
-
 private:
     
     static const unsigned char CLIP_IS_PLAYING_BIT = 0x01;             // Bit representing whether AnimationClip is a running clip in AnimationController
@@ -362,25 +314,6 @@ private:
         unsigned long _eventTime;   // The time at which the listener will be called back at during the playback of the AnimationClip.
     };
 
-    /**
-     * Listener implementation for script callbacks.
-     */
-    struct ScriptListener : public AnimationClip::Listener
-    {
-        /**
-         * Constructor.
-         */
-        ScriptListener(const std::string& function);
-
-        /**
-         * @see AnimationClip::Listener::animationEvent
-         */
-        void animationEvent(AnimationClip* clip, EventType type);
-
-        /** The function to call back when an animation event occurs. */
-        std::string function;
-    };
-
     /**
      * Constructor.
      */
@@ -466,7 +399,6 @@ private:
     std::vector<Listener*>* _endListeners;              // Collection of end listeners on the clip.
     std::list<ListenerEvent*>* _listeners;              // Ordered collection of listeners on the clip.
     std::list<ListenerEvent*>::iterator* _listenerItr;  // Iterator that points to the next listener event to be triggered.
-    std::vector<ScriptListener*>* _scriptListeners;     // Collection of listeners that are bound to Lua script functions.
 };
 
 }

+ 2 - 7
gameplay/src/Control.cpp

@@ -9,11 +9,6 @@
 #define BOUNDS_WIDTH_PERCENTAGE_BIT 4
 #define BOUNDS_HEIGHT_PERCENTAGE_BIT 8
 
-/** @script{ignore} */
-GP_SCRIPT_EVENTS();
-/** @script{ignore} */
-GP_SCRIPT_EVENT(controlEvent, "<Control>[Control::Listener::EventType]");
-
 namespace gameplay
 {
 
@@ -243,7 +238,7 @@ void Control::initialize(const char* typeName, Theme::Style* style, Properties*
 
 		// Register script listeners for control events
 		if (properties->exists("script"))
-			addScript(properties->getString("script"));
+			addScript(properties->getString("script"), Script::PRIVATE_INSTANCE);
 
 		// Potentially override themed properties for all states.
 		overrideThemedProperties(properties, STATE_ALL);
@@ -1103,7 +1098,7 @@ void Control::notifyListeners(Control::Listener::EventType eventType)
         }
     }
 
-    fireScriptEvent<void>(SCRIPT_EVENT_controlEvent, this, eventType);
+    fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(Control, controlEvent), this, eventType);
 
     release();
 }

+ 4 - 0
gameplay/src/Control.h

@@ -28,6 +28,10 @@ class Control : public Ref, public AnimationTarget, public ScriptTarget
     friend class Form;
     friend class Container;
 
+    GP_SCRIPT_EVENTS_START();
+    GP_SCRIPT_EVENT(controlEvent, "<Control>[Control::Listener::EventType]");
+    GP_SCRIPT_EVENTS_END();
+
 public:
 
     /**

+ 42 - 77
gameplay/src/Game.cpp

@@ -13,39 +13,6 @@ GLenum __gl_error_code = GL_NO_ERROR;
 /** @script{ignore} */
 ALenum __al_error_code = AL_NO_ERROR;
 
-/** @script{ignore} */
-GP_SCRIPT_EVENTS();
-/** @script{ignore} */
-GP_SCRIPT_EVENT(initialize, "");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(finalize, "");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(update, "f");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(render, "f");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(resizeEvent, "ii");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(keyEvent, "[Keyboard::KeyEvent]i");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(touchEvent, "[Touch::TouchEvent]iiui");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(mouseEvent, "[Mouse::MouseEvent]iii");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(gestureSwipeEvent, "iii");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(gesturePinchEvent, "iif");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(gestureTapEvent, "ii");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(gestureLongTapevent, "iif");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(gestureDragEvent, "ii");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(gestureDropEvent, "ii");
-/** @script{ignore} */
-GP_SCRIPT_EVENT(gamepadEvent, "[Gamepad::GamepadEvent]<Gamepad>");
-
 namespace gameplay
 {
 
@@ -59,7 +26,27 @@ double Game::_pausedTimeTotal = 0.0;
 class GameScriptTarget : public ScriptTarget
 {
     friend class Game;
+
+    GP_SCRIPT_EVENTS_START();
+    GP_SCRIPT_EVENT(initialize, "");
+    GP_SCRIPT_EVENT(finalize, "");
+    GP_SCRIPT_EVENT(update, "f");
+    GP_SCRIPT_EVENT(render, "f");
+    GP_SCRIPT_EVENT(resizeEvent, "ii");
+    GP_SCRIPT_EVENT(keyEvent, "[Keyboard::KeyEvent]i");
+    GP_SCRIPT_EVENT(touchEvent, "[Touch::TouchEvent]iiui");
+    GP_SCRIPT_EVENT(mouseEvent, "[Mouse::MouseEvent]iii");
+    GP_SCRIPT_EVENT(gestureSwipeEvent, "iii");
+    GP_SCRIPT_EVENT(gesturePinchEvent, "iif");
+    GP_SCRIPT_EVENT(gestureTapEvent, "ii");
+    GP_SCRIPT_EVENT(gestureLongTapevent, "iif");
+    GP_SCRIPT_EVENT(gestureDragEvent, "ii");
+    GP_SCRIPT_EVENT(gestureDropEvent, "ii");
+    GP_SCRIPT_EVENT(gamepadEvent, "[Gamepad::GamepadEvent]<Gamepad>");
+    GP_SCRIPT_EVENTS_END();
+
 public:
+
     GameScriptTarget()
     {
         GP_REGISTER_SCRIPT_EVENTS();
@@ -72,7 +59,7 @@ Game::Game()
       _clearDepth(1.0f), _clearStencil(0), _properties(NULL),
       _animationController(NULL), _audioController(NULL),
       _physicsController(NULL), _aiController(NULL), _audioListener(NULL),
-      _timeEvents(NULL), _scriptController(NULL), _scriptListeners(NULL), _scriptTarget(NULL)
+      _timeEvents(NULL), _scriptController(NULL), _scriptTarget(NULL)
 {
     GP_ASSERT(__gameInstance == NULL);
 
@@ -98,6 +85,7 @@ Game::~Game()
 
 Game* Game::getInstance()
 {
+    GP_ASSERT(__gameInstance);
     return __gameInstance;
 }
 
@@ -195,7 +183,7 @@ bool Game::startup()
         if (script)
         {
             _scriptTarget = new GameScriptTarget();
-            _scriptTarget->addScript(script);
+            _scriptTarget->addScript(script, Script::GLOBAL);
         }
     }
 
@@ -221,20 +209,12 @@ void Game::shutdown()
 
         // Call script finalize
         if (_scriptTarget)
-            _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_finalize);
+            _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, finalize));
 
         // Destroy script target so no more script events are fired
         SAFE_DELETE(_scriptTarget);
 
 		// Shutdown scripting system first so that any objects allocated in script are released before our subsystems are released
-		if (_scriptListeners)
-		{
-			for (size_t i = 0; i < _scriptListeners->size(); i++)
-			{
-				SAFE_DELETE((*_scriptListeners)[i]);
-			}
-			SAFE_DELETE(_scriptListeners);
-		}
 		_scriptController->finalize();
 
         unsigned int gamepadCount = Gamepad::getGamepadCount();
@@ -346,7 +326,7 @@ void Game::frame()
         // Perform lazy first time initialization
         initialize();
         if (_scriptTarget)
-            _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_initialize);
+            _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, initialize));
         _initialized = true;
 
         // Fire first game resize event
@@ -390,7 +370,7 @@ void Game::frame()
 
         // Run script update.
         if (_scriptTarget)
-            _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_update, elapsedTime);
+            _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, update), elapsedTime);
 
         // Audio Rendering.
         _audioController->update(elapsedTime);
@@ -400,7 +380,7 @@ void Game::frame()
 
         // Run script render.
         if (_scriptTarget)
-            _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_render, elapsedTime);
+            _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, render), elapsedTime);
 
         // Update FPS.
         ++_frameCount;
@@ -424,14 +404,14 @@ void Game::frame()
 
         // Script update.
         if (_scriptTarget)
-            _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_update, 0);
+            _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, update), 0);
 
         // Graphics Rendering.
         render(0);
 
         // Script render.
         if (_scriptTarget)
-            _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_render, 0);
+            _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, render), 0);
     }
 }
 
@@ -460,7 +440,7 @@ void Game::updateOnce()
     _aiController->update(elapsedTime);
     _audioController->update(elapsedTime);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_update, elapsedTime);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, update), elapsedTime);
 }
 
 void Game::setViewport(const Rectangle& viewport)
@@ -606,14 +586,14 @@ void Game::keyEventInternal(Keyboard::KeyEvent evt, int key)
 {
     keyEvent(evt, key);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_keyEvent, evt, key);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, keyEvent), evt, key);
 }
 
 void Game::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
     touchEvent(evt, x, y, contactIndex);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_touchEvent, evt, x, y, contactIndex);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, touchEvent), evt, x, y, contactIndex);
 }
 
 bool Game::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
@@ -622,7 +602,7 @@ bool Game::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelt
         return true;
 
     if (_scriptTarget)
-        return _scriptTarget->fireScriptEvent<bool>(SCRIPT_EVENT_mouseEvent, evt, x, y, wheelDelta);
+        return _scriptTarget->fireScriptEvent<bool>(GP_GET_SCRIPT_EVENT(GameScriptTarget, mouseEvent), evt, x, y, wheelDelta);
 
     return false;
 }
@@ -636,7 +616,7 @@ void Game::resizeEventInternal(unsigned int width, unsigned int height)
         _height = height;
         resizeEvent(width, height);
         if (_scriptTarget)
-            _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_resizeEvent, width, height);
+            _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, resizeEvent), width, height);
     }
 }
 
@@ -644,49 +624,49 @@ void Game::gestureSwipeEventInternal(int x, int y, int direction)
 {
     gestureSwipeEvent(x, y, direction);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_gestureSwipeEvent, x, y, direction);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, gestureSwipeEvent), x, y, direction);
 }
 
 void Game::gesturePinchEventInternal(int x, int y, float scale)
 {
     gesturePinchEvent(x, y, scale);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_gesturePinchEvent, x, y, scale);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, gesturePinchEvent), x, y, scale);
 }
 
 void Game::gestureTapEventInternal(int x, int y)
 {
     gestureTapEvent(x, y);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_gestureTapEvent, x, y);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, gestureTapEvent), x, y);
 }
 
 void Game::gestureLongTapEventInternal(int x, int y, float duration)
 {
     gestureLongTapEvent(x, y, duration);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_gestureLongTapevent, x, y, duration);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, gestureLongTapevent), x, y, duration);
 }
 
 void Game::gestureDragEventInternal(int x, int y)
 {
     gestureDragEvent(x, y);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_gestureDragEvent, x, y);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, gestureDragEvent), x, y);
 }
 
 void Game::gestureDropEventInternal(int x, int y)
 {
     gestureDropEvent(x, y);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_gestureDropEvent, x, y);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, gestureDropEvent), x, y);
 }
 
 void Game::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
 {
     gamepadEvent(evt, gamepad);
     if (_scriptTarget)
-        _scriptTarget->fireScriptEvent<void>(SCRIPT_EVENT_gamepadEvent, evt, gamepad);
+        _scriptTarget->fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(GameScriptTarget, gamepadEvent), evt, gamepad);
 }
 
 void Game::getArguments(int* argc, char*** argv) const
@@ -703,12 +683,7 @@ void Game::schedule(float timeOffset, TimeListener* timeListener, void* cookie)
 
 void Game::schedule(float timeOffset, const char* function)
 {
-    if (!_scriptListeners)
-        _scriptListeners = new std::vector<ScriptListener*>();
-
-    ScriptListener* listener = new ScriptListener(function);
-    _scriptListeners->push_back(listener);
-    schedule(timeOffset, listener, NULL);
+    getScriptController()->schedule(timeOffset, function);
 }
 
 void Game::clearSchedule()
@@ -734,16 +709,6 @@ void Game::fireTimeEvents(double frameTime)
     }
 }
 
-Game::ScriptListener::ScriptListener(const char* url)
-{
-    function = Game::getInstance()->getScriptController()->loadUrl(url);
-}
-
-void Game::ScriptListener::timeEvent(long timeDiff, void* cookie)
-{
-    Game::getInstance()->getScriptController()->executeFunction<void>(function.c_str(), "l", timeDiff);
-}
-
 Game::TimeEvent::TimeEvent(double time, TimeListener* timeListener, void* cookie)
     : time(time), listener(timeListener), cookie(cookie)
 {

+ 5 - 24
gameplay/src/Game.h

@@ -595,11 +595,12 @@ public:
      * Schedules a time event to be sent to the given TimeListener a given number of game milliseconds from now.
      * Game time stops while the game is paused. A time offset of zero will fire the time event in the next frame.
      * 
-     * Note: the given Lua function must take a single floating point number, which is the difference between the
-     * current game time and the target time (see TimeListener::timeEvent).
+     * The given script function must take a single floating point number, which is the difference between the
+     * current game time and the target time (see TimeListener::timeEvent). The function will be executed
+     * in the context of the script envionrment that the schedule function was called from.
      * 
      * @param timeOffset The number of game milliseconds in the future to schedule the event to be fired.
-     * @param function The Lua script function that will receive the event.
+     * @param function The script function that will receive the event.
      */
     void schedule(float timeOffset, const char* function);
 
@@ -659,7 +660,7 @@ protected:
 
     /**
      * Renders a single frame once and then swaps it to the display.
-     * This calls the given Lua function, which should take no parameters and return nothing (void).
+     * This calls the given script function, which should take no parameters and return nothing (void).
      *
      * This is useful for rendering splash screens.
      */
@@ -676,25 +677,6 @@ protected:
 
 private:
 
-    /**
-     * Allows time listener interaction from Lua scripts.
-     */
-    struct ScriptListener : public TimeListener
-    {
-        /**
-         * Constructor.
-         */
-        ScriptListener(const char* url);
-
-        /**
-         * @see TimeListener#timeEvent(long, void*)
-         */
-        void timeEvent(long timeDiff, void* cookie);
-
-        /** Holds the name of the Lua script function to call back. */
-        std::string function;
-    };
-
     struct ShutdownListener : public TimeListener
     {
         void timeEvent(long timeDiff, void* cookie);
@@ -782,7 +764,6 @@ private:
     AudioListener* _audioListener;              // The audio listener in 3D space.
     std::priority_queue<TimeEvent, std::vector<TimeEvent>, std::less<TimeEvent> >* _timeEvents;     // Contains the scheduled time events.
     ScriptController* _scriptController;            // Controls the scripting engine.
-    std::vector<ScriptListener*>* _scriptListeners; // Lua script listeners.
     ScriptTarget* _scriptTarget;                // Script target for the game
 
     // Note: Do not add STL object member variables on the stack; this will cause false memory leaks to be reported.

+ 11 - 6
gameplay/src/Node.cpp

@@ -16,11 +16,6 @@
 #define NODE_DIRTY_BOUNDS 2
 #define NODE_DIRTY_ALL (NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS)
 
-/** @script{ignore} */
-GP_SCRIPT_EVENTS();
-/** @script{ignore} */
-GP_SCRIPT_EVENT(update, "f");
-
 namespace gameplay
 {
 
@@ -452,7 +447,7 @@ void Node::update(float elapsedTime)
             node->update(elapsedTime);
     }
 
-    fireScriptEvent<void>(SCRIPT_EVENT_update, elapsedTime);
+    fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(Node, update), this, elapsedTime);
 }
 
 bool Node::isStatic() const
@@ -1284,6 +1279,16 @@ PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
 
 AIAgent* Node::getAgent() const
 {
+    // Lazily create a new Agent for this Node if we don't have one yet.
+    // Basically, all Nodes by default can have an Agent, we just won't
+    // waste the memory unless they request one.
+    if (!_agent)
+    {
+        _agent = AIAgent::create();
+        _agent->_node = const_cast<Node*>(this);
+        Game::getInstance()->getAIController()->addAgent(_agent);
+    }
+
     return _agent;
 }
 

+ 10 - 1
gameplay/src/Node.h

@@ -2,6 +2,7 @@
 #define NODE_H_
 
 #include "Transform.h"
+#include "ScriptTarget.h"
 #include "Camera.h"
 #include "Light.h"
 #include "Model.h"
@@ -37,6 +38,14 @@ class Node : public Transform, public Ref
     friend class MeshSkin;
     friend class Light;
 
+    GP_SCRIPT_EVENTS_START();
+    GP_SCRIPT_EVENT(update, "<Node>f");
+    GP_SCRIPT_EVENT(messageReceived, "<Node><AIMessage>");
+    GP_SCRIPT_EVENT(stateEnter, "<Node><AIState>");
+    GP_SCRIPT_EVENT(stateExit, "<Node><AIState>");
+    GP_SCRIPT_EVENT(stateUpdate, "<Node><AIState>f");
+    GP_SCRIPT_EVENTS_END();
+
 public:
 
     /**
@@ -828,7 +837,7 @@ protected:
     /**
      * Pointer to the AI agent attached to the Node.
      */
-    AIAgent* _agent;
+    mutable AIAgent* _agent;
 
     /**
      * World Matrix representation of the Node.

+ 45 - 7
gameplay/src/PhysicsCollisionObject.cpp

@@ -13,6 +13,8 @@
 namespace gameplay
 {
 
+extern void splitURL(const std::string& url, std::string* file, std::string* id);
+
 /**
  * Internal class used to implement the collidesWith(PhysicsCollisionObject*) function.
  * @script{ignore}
@@ -45,7 +47,7 @@ PhysicsCollisionObject::~PhysicsCollisionObject()
 
     if (_scriptListeners)
     {
-        for (unsigned int i = 0; i < _scriptListeners->size(); i++)
+        for (size_t i = 0, count = _scriptListeners->size(); i < count; ++i)
         {
             SAFE_DELETE((*_scriptListeners)[i]);
         }
@@ -144,11 +146,14 @@ void PhysicsCollisionObject::removeCollisionListener(CollisionListener* listener
 
 void PhysicsCollisionObject::addCollisionListener(const char* function, PhysicsCollisionObject* object)
 {
+    ScriptListener* listener = ScriptListener::create(function);
+    if (!listener)
+        return; // falied to load
+
     if (!_scriptListeners)
         _scriptListeners = new std::vector<ScriptListener*>();
-
-    ScriptListener* listener = new ScriptListener(function);
     _scriptListeners->push_back(listener);
+
     addCollisionListener(listener, object);
 }
 
@@ -158,7 +163,7 @@ void PhysicsCollisionObject::removeCollisionListener(const char* function, Physi
         return;
 
     std::string url = function;
-    for (unsigned int i = 0; i < _scriptListeners->size(); i++)
+    for (size_t i = 0, count = _scriptListeners->size(); i < count; ++i)
     {
         if ((*_scriptListeners)[i]->url == url)
         {
@@ -301,10 +306,43 @@ void PhysicsCollisionObject::PhysicsMotionState::setCenterOfMassOffset(const Vec
     _centerOfMassOffset.setOrigin(BV(centerOfMassOffset));
 }
 
-PhysicsCollisionObject::ScriptListener::ScriptListener(const char* url)
-    : url(url)
+PhysicsCollisionObject::ScriptListener::ScriptListener()
+    : script(NULL)
+{
+}
+
+PhysicsCollisionObject::ScriptListener::~ScriptListener()
+{
+    SAFE_RELEASE(script);
+}
+
+PhysicsCollisionObject::ScriptListener* PhysicsCollisionObject::ScriptListener::create(const char* url)
 {
-    function = Game::getInstance()->getScriptController()->loadUrl(url);
+    std::string scriptPath, func;
+    splitURL(url, &scriptPath, &func);
+    if (func.empty())
+    {
+        // Only a function was specified
+        func = scriptPath;
+        scriptPath = "";
+    }
+
+    Script* script = NULL;
+    if (!scriptPath.empty())
+    {
+        script = Game::getInstance()->getScriptController()->loadScript(scriptPath.c_str(), Script::GLOBAL);
+        if (!script)
+        {
+            // Failed to load script
+            return NULL;
+        }
+    }
+
+    ScriptListener* listener = new ScriptListener();
+    listener->url = url;
+    listener->script = script;
+    listener->function = func;
+    return listener;
 }
 
 void PhysicsCollisionObject::ScriptListener::collisionEvent(PhysicsCollisionObject::CollisionListener::EventType type,

+ 28 - 6
gameplay/src/PhysicsCollisionObject.h

@@ -1,6 +1,7 @@
 #ifndef PHYSICSCOLLISIONOBJECT_H_
 #define PHYSICSCOLLISIONOBJECT_H_
 
+#include "Script.h"
 #include "Vector3.h"
 #include "PhysicsCollisionShape.h"
 
@@ -236,9 +237,10 @@ public:
     /**
      * Adds a collision listener for this collision object.
      * 
-     * Note: the given Lua function must match the function signature of PhysicsCollisionObject::CollisionListener::collisionEvent.
+     * Note: the given script function must be global and it must match the function 
+     * signature of PhysicsCollisionObject::CollisionListener::collisionEvent.
      * 
-     * @param function The Lua script function to add as a listener callback.
+     * @param function A valid global script function to add as a listener callback.
      * @param object Optional collision object used to filter the collision event.
      */
     void addCollisionListener(const char* function, PhysicsCollisionObject* object = NULL);
@@ -246,7 +248,7 @@ public:
     /**
      * Removes a collision listener.
      *
-     * @param function The Lua function (used as a listener callback) to remove.
+     * @param function The previously added script function to remove.
      * @param object Optional collision object used to filter the collision event.
      */
     void removeCollisionListener(const char* function, PhysicsCollisionObject* object = NULL);
@@ -310,12 +312,23 @@ protected:
     /**
      * Handles collision event callbacks to Lua script functions.
      */
-    struct ScriptListener : public CollisionListener
+    class ScriptListener : public CollisionListener
     {
+    public:
+
         /**
-         * Constructor.
+         * Destructor.
          */
-        ScriptListener(const char* url);
+        ~ScriptListener();
+
+        /**
+         * Creates a ScriptListener for the given script function url.
+         *
+         * @param url The global script function, or script#function.
+         *
+         * @return The ScriptListener, or NULL if the function could not be loaded.
+         */
+        static ScriptListener* create(const char* url);
 
         /**
          * @see PhysicsCollisionObject::CollisionListener
@@ -325,8 +338,17 @@ protected:
 
         /** The URL to the Lua script function to use as the callback. */
         std::string url;
+        /** The loaded script that contains the function. */
+        Script* script;
         /** The name of the Lua script function to use as the callback. */
         std::string function;
+
+    private:
+
+        /**
+         * Constructor.
+         */
+        ScriptListener();
     };
 
     /**

+ 2 - 7
gameplay/src/PhysicsController.cpp

@@ -19,11 +19,6 @@
 // The initial capacity of the Bullet debug drawer's vertex batch.
 #define INITIAL_CAPACITY 280
 
-/** @script{ignore} */
-GP_SCRIPT_EVENTS();
-/** @script{ignore} */
-GP_SCRIPT_EVENT(statusEvent, "[PhysicsController::Listener::EventType]");
-
 namespace gameplay
 {
 
@@ -489,7 +484,7 @@ void PhysicsController::update(float elapsedTime)
     _world->stepSimulation(elapsedTime * 0.001f, 10);
 
     // If we have status listeners, then check if our status has changed.
-    if (_listeners || hasScriptListener(SCRIPT_EVENT_statusEvent))
+    if (_listeners || hasScriptListener(GP_GET_SCRIPT_EVENT(PhysicsController, statusEvent)))
     {
         Listener::EventType oldStatus = _status;
 
@@ -534,7 +529,7 @@ void PhysicsController::update(float elapsedTime)
                 }
             }
 
-            fireScriptEvent<void>(SCRIPT_EVENT_statusEvent, _status);
+            fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(PhysicsController, statusEvent), _status);
         }
     }
 

+ 4 - 0
gameplay/src/PhysicsController.h

@@ -32,6 +32,10 @@ class PhysicsController : public ScriptTarget
     friend class PhysicsCollisionObject;
     friend class PhysicsGhostObject;
 
+    GP_SCRIPT_EVENTS_START();
+    GP_SCRIPT_EVENT(statusEvent, "[PhysicsController::Listener::EventType]");
+    GP_SCRIPT_EVENTS_END();
+
 public:
 
     /**

+ 10 - 2
gameplay/src/SceneLoader.cpp

@@ -91,7 +91,8 @@ Scene* SceneLoader::loadInternal(const char* url)
         SceneNodeProperty::CAMERA |
         SceneNodeProperty::ROTATE |
         SceneNodeProperty::SCALE |
-        SceneNodeProperty::TRANSLATE);
+        SceneNodeProperty::TRANSLATE |
+        SceneNodeProperty::SCRIPT);
     applyNodeProperties(sceneProperties, SceneNodeProperty::COLLISION_OBJECT);
 
     // Apply node tags
@@ -377,7 +378,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
     }
     else
     {
-        // Handle scale, rotate and translate.
+        // Handle simple types (scale, rotate, translate, script, etc)
         switch (snp._type)
         {
         case SceneNodeProperty::TRANSLATE:
@@ -401,6 +402,9 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
                 node->scale(s);
             break;
         }
+        case SceneNodeProperty::SCRIPT:
+            node->addScript(snp._value.c_str(), Script::PRIVATE_INSTANCE);
+            break;
         default:
             GP_ERROR("Unsupported node property type (%d).", snp._type);
             break;
@@ -780,6 +784,10 @@ void SceneLoader::parseNode(Properties* ns, SceneNode* parent, const std::string
         {
             addSceneNodeProperty(sceneNode, SceneNodeProperty::SCALE, ns->getString());
         }
+        else if (strcmp(name, "script") == 0)
+        {
+            addSceneNodeProperty(sceneNode, SceneNodeProperty::SCRIPT, ns->getString());
+        }
         else
         {
             GP_ERROR("Unsupported node property: %s = %s", name, ns->getString());

+ 2 - 1
gameplay/src/SceneLoader.h

@@ -57,7 +57,8 @@ private:
             TRANSLATE = 128,
             ROTATE = 256,
             SCALE = 512,
-            URL = 1024
+            URL = 1024,
+            SCRIPT = 2048
         };
 
         SceneNodeProperty(Type type, const std::string& value, int index, bool isUrl);

+ 42 - 0
gameplay/src/Script.cpp

@@ -0,0 +1,42 @@
+#include "Script.h"
+#include "ScriptController.h"
+
+namespace gameplay
+{
+
+Script::Script() : _scope(GLOBAL), _env(0)
+{
+}
+
+Script::~Script()
+{
+    Game::getInstance()->getScriptController()->unloadScript(this);
+}
+
+const char* Script::getPath() const
+{
+    return _path.c_str();
+}
+
+Script::Scope Script::getScope() const
+{
+    return _scope;
+}
+
+bool Script::functionExists(const char* name) const
+{
+    return Game::getInstance()->getScriptController()->functionExists(name, this);
+}
+
+bool Script::reload()
+{
+    ScriptController* sc = Game::getInstance()->getScriptController();
+
+    // First unload our current script
+    sc->unloadScript(this);
+
+    // Now attempt to reload the script
+    return Game::getInstance()->getScriptController()->loadScript(this);
+}
+
+}

+ 43 - 3
gameplay/src/Script.h

@@ -67,7 +67,49 @@ public:
         PRIVATE_INSTANCE
     };
 
-protected:
+    /**
+     * Returns the path from which this Script was loaded.
+     *
+     * @return The script's path.
+     */
+    const char* getPath() const;
+
+    /**
+     * Returns the scope of this script.
+     *
+     * @return The scope of this script.
+     */
+    Scope getScope() const;
+
+    /**
+     * Determines if a function with the given name exists in the script.
+     *
+     * @param name Name of the function.
+     *
+     * @return True if the function exists, false otherwise.
+     */
+    bool functionExists(const char* name) const;
+
+    /** 
+     * Reloads this script.
+     *
+     * The code in the script will be reloaded and any functions and variables will be overwritten
+     * into the script's envrionment.
+     *
+     * If the script is GLOBAL in scope, it will simply be re-run, replacing any existing global 
+     * variables and functions. If the script has changed, any previous variables or functions that
+     * do not exist in the updated script will remain in the global environment.
+     *
+     * @return True if the script is successfully reloaded, false otherwise.
+     */
+    bool reload();
+
+private:
+
+    /**
+     * Constructor.
+     */
+    Script();
 
     /**
      * Copy constructor (hidden).
@@ -79,8 +121,6 @@ protected:
      */
     ~Script();
 
-private:
-
     std::string _path;
     Scope _scope;
     int _env;

+ 538 - 196
gameplay/src/ScriptController.cpp

@@ -44,7 +44,7 @@
 
 #define PUSH_NESTED_VARIABLE(name, defaultValue, script) \
     int top = lua_gettop(_lua); \
-    if (!getNestedVariable(_lua, name, script)) \
+    if (!getNestedVariable(_lua, name, script ? script->_env : 0)) \
     { \
         lua_settop(_lua, top); \
         return (defaultValue); \
@@ -68,18 +68,18 @@ extern void splitURL(const std::string& url, std::string* file, std::string* id)
  * @param name The name of a variable or a '.' separated list of nested tables ending with a variable name.
  *             The name value may be in the format "A.B.C.D" where A is a table and B, C are child tables.
  *             D is any type, which will be accessed by the calling function.
- * @param script Optional ID of the script environment to query the variable from (or zero for the global environment).
+ * @param env Optional script environment ID, or zero for the global script environment.
  * 
  * @return True if the tables were pushed on the stack or the variable was pushed. Returns false on error.
  */
-static bool getNestedVariable(lua_State* lua, const char* name, int script = 0)
+static bool getNestedVariable(lua_State* lua, const char* name, int env = 0)
 {
     if (strchr(name, '.') == NULL)
     {
         // Just a field name, no nested tables
-        if (script)
+        if (env)
         {
-            lua_rawgeti(lua, LUA_REGISTRYINDEX, script);
+            lua_rawgeti(lua, LUA_REGISTRYINDEX, env);
             lua_getfield(lua, -1, name);
         }
         else
@@ -104,9 +104,9 @@ static bool getNestedVariable(lua_State* lua, const char* name, int script = 0)
     ++end;
     *(end - 1) = '\0';
 
-    if (script)
+    if (env)
     {
-        lua_rawgeti(lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(lua, LUA_REGISTRYINDEX, env);
         lua_getfield(lua, -1, start);
     }
     else
@@ -157,117 +157,153 @@ Script* ScriptController::loadScript(const char* path, Script::Scope scope, bool
 {
     GP_ASSERT(path);
 
+    Script* script = NULL;
+
+    // For single-instance scripts (GLOBAL and PRIVATE_SHARED), check if a script with the same
+    // path and scope is already loaded. PRIVATE_INSTANCE scripts are always reloaded.
     if (scope == Script::GLOBAL || scope == Script::PRIVATE_SHARED)
     {
-        // Check if a script with the same path is already loaded 
+        std::map<std::string, std::vector<Script*>>::iterator itr = _scripts.find(path);
+        if (itr != _scripts.end())
+        {
+
+            for (size_t i = 0, count = itr->second.size(); i < count; ++i)
+            {
+                if (itr->second[i]->_scope == scope)
+                {
+                    // Found a script with the same path and scope that's already loaded
+                    script = itr->second[i];
+                    break;
+                }
+            }
+        }
     }
 
-    std::set<std::string>::iterator iter = _loadedScripts.find(path);
-    if (iter == _loadedScripts.end() || forceReload)
+    // If the script is already loaded and forceReload was not specified, increase its
+    // reference count and return it
+    if (script && !forceReload)
     {
-        bool success = false;
-        if (iter == _loadedScripts.end())
-            _loadedScripts.insert(path); // insert before loading script to prevent load recursion
+        script->addRef();
+        return script;
+    }
 
-#ifdef __ANDROID__
-        const char* scriptContents = FileSystem::readAll(path);
-        if (luaL_dostring(_lua, scriptContents))
-        {
-            GP_WARN("Failed to run Lua script with error: '%s'.", lua_tostring(_lua, -1));
-        }
-        else
-        {
-            success = true;
-        }
-        SAFE_DELETE_ARRAY(scriptContents);
-#else
-        std::string fullPath;
-        if (!FileSystem::isAbsolutePath(path))
-        {
-            fullPath.append(FileSystem::getResourcePath());
-        }
-        fullPath.append(path);
-        if (luaL_dofile(_lua, fullPath.c_str()))
-        {
-            GP_WARN("Failed to run Lua script with error: '%s'.", lua_tostring(_lua, -1));
-        }
-        else
-        {
-            success = true;
-        }
-#endif
-        if (!success && (iter == _loadedScripts.end()))
-        {
-            iter = _loadedScripts.find(path);
-            _loadedScripts.erase(iter);
-        }
+    // Create a new script object if neccessary
+    if (script == NULL)
+    {
+        script = new Script();
+        script->_path = path;
+        script->_scope = scope;
+    }
 
-        return success;
+    // Attempt to load the script into the given scope
+    if (!loadScript(script))
+    {
+        // Freeing the script will cause it to be removed from _scripts
+        SAFE_RELEASE(script);
     }
 
-    return true;
+    return script;
 }
 
-int ScriptController::loadScriptIsolated(const char* path)
+bool ScriptController::loadScript(Script* script)
 {
-    GP_ASSERT(path);
+    GP_ASSERT(script);
 
-    std::string fullPath;
-    if (!FileSystem::isAbsolutePath(path))
+    if (!FileSystem::fileExists(script->_path.c_str()))
     {
-        fullPath.append(FileSystem::getResourcePath());
+        GP_WARN("Failed to load script: %s. File does not exist.", script->_path.c_str());
+        return false;
     }
-    fullPath.append(path);
 
-    // Load the script chunk, but don't execute it yet [chunk]
-    if (luaL_loadfile(_lua, fullPath.c_str()))
+    // Insert an entry into _scripts before loading the script, to prevent load recursion
+    std::vector<Script*>& scripts = _scripts[script->_path];
+    scripts.push_back(script);
+
+    // Load the contents of the script, but don't execute it yet
+    const char* scriptSource = FileSystem::readAll(script->_path.c_str());
+    int ret = luaL_loadstring(_lua, scriptSource); // [chunk]
+    SAFE_DELETE_ARRAY(scriptSource);
+
+    if (ret == LUA_OK)
     {
-        GP_WARN("Failed to load script with error: '%s'.", lua_tostring(_lua, -1));
-        return -1;
-    }
+        // If the requested scope is private, create a new script env table to execute
+        // the script within, using a metatable to fallback to the global table (_G)
+        if (script->_scope != Script::GLOBAL)
+        {
+            // Create a new table as an environment for the new script
+            lua_newtable(_lua); // new ENV for script [chunk, env]
 
-    // Create a new table as an environment for the new script
-    lua_newtable(_lua); // new ENV for script [chunk, env]
+            // Store a ref to the table in the registry (this pops the table) [chunk]
+            script->_env = luaL_ref(_lua, LUA_REGISTRYINDEX);
 
-    // Store a ref to the table in the registry (this pops the table) [chunk]
-    int id = luaL_ref(_lua, LUA_REGISTRYINDEX);
+            // Put the env table back on top of the stack
+            lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env); // [chunk, env]
 
-    // Put the env table back on top of the stack
-    lua_rawgeti(_lua, LUA_REGISTRYINDEX, id); // [chunk, env]
+            // Create a metatable that forwards missed lookups to global table _G
+            lua_newtable(_lua); // metatable [chunk, env, meta]
+            lua_getglobal(_lua, "_G"); // pushes _G, which will be the __index metatable entry [chunk, env, meta, _G]
 
-    // Create a metatable that forwards missed lookups to global table _G
-    lua_newtable(_lua); // metatable [chunk, env, meta]
-    lua_getglobal(_lua, "_G"); // pushes _G, which will be the __index metatable entry [chunk, env, meta, _G]
+            // Set the __index property of the metatable to _G
+            lua_setfield(_lua, -2, "__index"); // metatable on top [chunk, env, meta]
 
-    // Set the __index property of the metatable to _G
-    lua_setfield(_lua, -2, "__index"); // metatable on top [chunk, env, meta]
+            // Set the metatable for our new environment table
+            lua_setmetatable(_lua, -2); // [chunk, env]
 
-    // Set the metatable for our new environment table
-    lua_setmetatable(_lua, -2); // [chunk, env]
+            // Set the first upvalue (_ENV) for our chunk to the new environment table
+            if (lua_setupvalue(_lua, -2, 1) == NULL) // [chunk]
+            {
+                GP_WARN("Error setting environment table for script: %s.", script->_path.c_str());
+            }
+        }
 
-    // Set the first upvalue (_ENV) for our chunk to the new environment table
-    lua_setupvalue(_lua, 1, 1); // [chunk]
+        // Execute the script
+        ret = lua_pcall(_lua, 0, 0, 0);
+    }
 
-    // Finally, execute the code for our chunk that is now in its own environment
-    if (lua_pcall(_lua, 0, LUA_MULTRET, 0))
+    if (ret != LUA_OK)
     {
-        GP_WARN("Failed to execute script with error: '%s'.", lua_tostring(_lua, -1));
-        return -1;
+        script->_env = 0; // clear _env on failure
+        GP_WARN("Failed to load script: %s. %s.", script->_path.c_str(), lua_tostring(_lua, -1));
+        return false;
     }
 
-    return id;
+    return true;
 }
 
-void ScriptController::unloadScript(int id)
+void ScriptController::unloadScript(Script* script)
 {
-    // Release the reference to the environment table
-    luaL_unref(_lua, LUA_REGISTRYINDEX, id);
+    if (script->_env != 0)
+    {
+        // Release the reference to the environment table for this non-global script
+        luaL_unref(_lua, LUA_REGISTRYINDEX, script->_env);
+        script->_env = 0;
+    }
+
+    // TODO: What else can we clean up here?
+    // Can we test this with manual GC and breaking on gameplay object constructors that were delcared in the script?
+
+    // Remove the script from our managed list
+    std::map<std::string, std::vector<Script*>>::iterator itr = _scripts.find(script->_path);
+    if (itr != _scripts.end())
+    {
+        std::vector<Script*>& scripts = itr->second;
+        for (size_t i = 0, count = scripts.size(); i < count; ++i)
+        {
+            if (scripts[i] == script)
+            {
+                scripts.erase(scripts.begin() + i);
+                break;
+            }
+        }
 
-    // TODO: What else do we need to clean up?
-    // Can we test this with manual GC and breaking on gameplay object constructors that were delcared local (even global??) to the script?
+        if (scripts.empty())
+        {
+            _scripts.erase(itr);
+        }
+    }
 }
 
-bool ScriptController::getBool(const char* name, bool defaultValue, int script)
+bool ScriptController::getBool(const char* name, bool defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     bool b = lua_isboolean(_lua, -1) ? ScriptUtil::luaCheckBool(_lua, -1) : defaultValue;
@@ -275,7 +311,7 @@ bool ScriptController::getBool(const char* name, bool defaultValue, int script)
     return b;
 }
 
-char ScriptController::getChar(const char* name, char defaultValue, int script)
+char ScriptController::getChar(const char* name, char defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     char c = lua_isnumber(_lua, -1) ?  (char)luaL_checkint(_lua, -1) : defaultValue;
@@ -283,7 +319,7 @@ char ScriptController::getChar(const char* name, char defaultValue, int script)
     return c;
 }
 
-short ScriptController::getShort(const char* name, short defaultValue, int script)
+short ScriptController::getShort(const char* name, short defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     short n = lua_isnumber(_lua, -1) ? (short)luaL_checkint(_lua, -1) : defaultValue;
@@ -291,7 +327,7 @@ short ScriptController::getShort(const char* name, short defaultValue, int scrip
     return n;
 }
 
-int ScriptController::getInt(const char* name, int defaultValue, int script)
+int ScriptController::getInt(const char* name, int defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     int n = lua_isnumber(_lua, -1) ? luaL_checkint(_lua, -1) : defaultValue;
@@ -299,7 +335,7 @@ int ScriptController::getInt(const char* name, int defaultValue, int script)
     return n;
 }
 
-long ScriptController::getLong(const char* name, long defaultValue, int script)
+long ScriptController::getLong(const char* name, long defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     long n = lua_isnumber(_lua, -1) ? luaL_checklong(_lua, -1) : defaultValue;
@@ -307,7 +343,7 @@ long ScriptController::getLong(const char* name, long defaultValue, int script)
     return n;
 }
 
-unsigned char ScriptController::getUnsignedChar(const char* name, unsigned char defaultValue, int script)
+unsigned char ScriptController::getUnsignedChar(const char* name, unsigned char defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     unsigned char c = lua_isnumber(_lua, -1) ? (unsigned char)luaL_checkunsigned(_lua, -1) : defaultValue;
@@ -315,7 +351,7 @@ unsigned char ScriptController::getUnsignedChar(const char* name, unsigned char
     return c;
 }
 
-unsigned short ScriptController::getUnsignedShort(const char* name, unsigned short defaultValue, int script)
+unsigned short ScriptController::getUnsignedShort(const char* name, unsigned short defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     unsigned short n = lua_isnumber(_lua, -1) ? (unsigned short)luaL_checkunsigned(_lua, -1) : defaultValue;
@@ -323,7 +359,7 @@ unsigned short ScriptController::getUnsignedShort(const char* name, unsigned sho
     return n;
 }
 
-unsigned int ScriptController::getUnsignedInt(const char* name, unsigned int defaultValue, int script)
+unsigned int ScriptController::getUnsignedInt(const char* name, unsigned int defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     unsigned int n = lua_isnumber(_lua, -1) ? (unsigned int)luaL_checkunsigned(_lua, -1) : defaultValue;
@@ -331,7 +367,7 @@ unsigned int ScriptController::getUnsignedInt(const char* name, unsigned int def
     return n;
 }
 
-unsigned long ScriptController::getUnsignedLong(const char* name, unsigned long defaultValue, int script)
+unsigned long ScriptController::getUnsignedLong(const char* name, unsigned long defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     unsigned long n = lua_isnumber(_lua, -1) ? (unsigned long)luaL_checkunsigned(_lua, -1) : defaultValue;
@@ -339,7 +375,7 @@ unsigned long ScriptController::getUnsignedLong(const char* name, unsigned long
     return n;
 }
 
-float ScriptController::getFloat(const char* name, float defaultValue, int script)
+float ScriptController::getFloat(const char* name, float defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     float f = lua_isnumber(_lua, -1) ? (float)luaL_checknumber(_lua, -1) : defaultValue;
@@ -347,7 +383,7 @@ float ScriptController::getFloat(const char* name, float defaultValue, int scrip
     return f;
 }
 
-double ScriptController::getDouble(const char* name, double defaultValue, int script)
+double ScriptController::getDouble(const char* name, double defaultValue, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, defaultValue, script);
     double n = lua_isnumber(_lua, -1) ? (double)luaL_checknumber(_lua, -1) : defaultValue;
@@ -355,7 +391,7 @@ double ScriptController::getDouble(const char* name, double defaultValue, int sc
     return n;
 }
 
-const char* ScriptController::getString(const char* name, int script)
+const char* ScriptController::getString(const char* name, Script* script)
 {
     PUSH_NESTED_VARIABLE(name, NULL, script);
     const char* s = lua_isstring(_lua, -1) ? luaL_checkstring(_lua, -1) : NULL;
@@ -363,15 +399,15 @@ const char* ScriptController::getString(const char* name, int script)
     return s;
 }
 
-void ScriptController::setBool(const char* name, bool v, int script)
+void ScriptController::setBool(const char* name, bool v, Script* script)
 {
     // TODO: Support setting variables in nested tables. Should just need to execute code similar to
     // that in getNestedVariable, except we only need to push the parent tables onto the stack,
     // NOT the actual field/variable (since we're going to set it).
 
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushboolean(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -382,11 +418,11 @@ void ScriptController::setBool(const char* name, bool v, int script)
     }
 }
 
-void ScriptController::setChar(const char* name, char v, int script)
+void ScriptController::setChar(const char* name, char v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushinteger(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -397,11 +433,11 @@ void ScriptController::setChar(const char* name, char v, int script)
     }
 }
 
-void ScriptController::setShort(const char* name, short v, int script)
+void ScriptController::setShort(const char* name, short v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushinteger(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -412,11 +448,11 @@ void ScriptController::setShort(const char* name, short v, int script)
     }
 }
 
-void ScriptController::setInt(const char* name, int v, int script)
+void ScriptController::setInt(const char* name, int v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushinteger(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -427,11 +463,11 @@ void ScriptController::setInt(const char* name, int v, int script)
     }
 }
 
-void ScriptController::setLong(const char* name, long v, int script)
+void ScriptController::setLong(const char* name, long v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushinteger(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -442,11 +478,11 @@ void ScriptController::setLong(const char* name, long v, int script)
     }
 }
 
-void ScriptController::setUnsignedChar(const char* name, unsigned char v, int script)
+void ScriptController::setUnsignedChar(const char* name, unsigned char v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushunsigned(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -457,11 +493,11 @@ void ScriptController::setUnsignedChar(const char* name, unsigned char v, int sc
     }
 }
 
-void ScriptController::setUnsignedShort(const char* name, unsigned short v, int script)
+void ScriptController::setUnsignedShort(const char* name, unsigned short v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushunsigned(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -472,11 +508,11 @@ void ScriptController::setUnsignedShort(const char* name, unsigned short v, int
     }
 }
 
-void ScriptController::setUnsignedInt(const char* name, unsigned int v, int script)
+void ScriptController::setUnsignedInt(const char* name, unsigned int v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushunsigned(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -487,11 +523,11 @@ void ScriptController::setUnsignedInt(const char* name, unsigned int v, int scri
     }
 }
 
-void ScriptController::setUnsignedLong(const char* name, unsigned long v, int script)
+void ScriptController::setUnsignedLong(const char* name, unsigned long v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushunsigned(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -502,11 +538,11 @@ void ScriptController::setUnsignedLong(const char* name, unsigned long v, int sc
     }
 }
 
-void ScriptController::setFloat(const char* name, float v, int script)
+void ScriptController::setFloat(const char* name, float v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushnumber(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -517,11 +553,11 @@ void ScriptController::setFloat(const char* name, float v, int script)
     }
 }
 
-void ScriptController::setDouble(const char* name, double v, int script)
+void ScriptController::setDouble(const char* name, double v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushnumber(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -532,11 +568,11 @@ void ScriptController::setDouble(const char* name, double v, int script)
     }
 }
 
-void ScriptController::setString(const char* name, const char* v, int script)
+void ScriptController::setString(const char* name, const char* v, Script* script)
 {
-    if (script)
+    if (script && script->_env)
     {
-        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script);
+        lua_rawgeti(_lua, LUA_REGISTRYINDEX, script->_env);
         lua_pushstring(_lua, v);
         lua_setfield(_lua, -2, name);
     }
@@ -547,7 +583,7 @@ void ScriptController::setString(const char* name, const char* v, int script)
     }
 }
 
-bool ScriptController::functionExists(const char* name, int script) const
+bool ScriptController::functionExists(const char* name, const Script* script) const
 {
     PUSH_NESTED_VARIABLE(name, false, script);
 
@@ -558,6 +594,11 @@ bool ScriptController::functionExists(const char* name, int script) const
     return result;
 }
 
+Script* ScriptController::getCurrentScript() const
+{
+    return _envStack.empty() ? NULL : _envStack.back();
+}
+
 void ScriptController::print(const char* str)
 {
     gameplay::print("%s", str);
@@ -673,6 +714,13 @@ void ScriptController::initialize()
 
 void ScriptController::finalize()
 {
+    // Cleanup any outstanding time listeners
+    for (std::list<ScriptTimeListener*>::iterator itr = _timeListeners.begin(); itr != _timeListeners.end(); ++itr)
+    {
+        SAFE_DELETE(*itr);
+    }
+    _timeListeners.clear();
+
     if (_lua)
 	{
         // Perform a full garbage collection cycle.
@@ -686,7 +734,7 @@ void ScriptController::finalize()
 	}
 }
 
-void ScriptController::executeFunctionHelper(int resultCount, const char* func, const char* args, va_list* list, int script)
+void ScriptController::executeFunctionHelper(int resultCount, const char* func, const char* args, va_list* list, Script* script)
 {
 	if (!_lua)
 		return; // handles calling this method after script is finalized
@@ -697,14 +745,18 @@ void ScriptController::executeFunctionHelper(int resultCount, const char* func,
         return;
     }
 
-    // If script was not specified (or is 0/global) and we are currently executing another function,
+    // If script was not specified and we are currently executing another function,
     // call this function in the previous call's environment (stored in _envStack).
     // This allows gameplay script callbacks (such as Scene.visit) to work locally when called
     // from an sandboxed script.
-    if (script == 0 && !_envStack.empty())
+    if (!script && !_envStack.empty())
+    {
+        // Execute in the currently running script's environment
         script = _envStack.back();
+    }
+    int env = script ? script->_env : 0;
 
-    if (!getNestedVariable(_lua, func, script))
+    if (!getNestedVariable(_lua, func, env))
     {
         GP_WARN("Failed to call function '%s'", func);
         return;
@@ -810,13 +862,13 @@ void ScriptController::executeFunctionHelper(int resultCount, const char* func,
         }
     }
 
-    _envStack.push_back(script);
+    pushScript(script);
 
     // Perform the function call.
     if (lua_pcall(_lua, argumentCount, resultCount, 0) != 0)
         GP_WARN("Failed to call function '%s' with error '%s'.", func, lua_tostring(_lua, -1));
 
-    _envStack.pop_back();
+    popScript();
 }
 
 int ScriptController::convert(lua_State* state)
@@ -854,27 +906,91 @@ int ScriptController::convert(lua_State* state)
     return 0;
 }
 
+void ScriptController::schedule(float timeOffset, const char* function)
+{
+    // Get the currently execute script
+    Script* script = _envStack.empty() ? NULL : _envStack.back();
+    if (script)
+    {
+        // Increase the reference count of the script while we hold it so it doesn't
+        // get destroyed while waiting for the event to fire.
+        script->addRef();
+    }
+
+    ScriptTimeListener* listener = new ScriptTimeListener(script, function);
+    _timeListeners.push_back(listener);
+
+    Game::getInstance()->schedule(timeOffset, listener, NULL);
+}
+
+void ScriptController::pushScript(Script* script)
+{
+    // Increase the reference count of the script while it's pushed,
+    // to prevent it from being destroyed during this time.
+    if (script)
+        script->addRef();
+
+    _envStack.push_back(script);
+}
+
+void ScriptController::popScript()
+{
+    GP_ASSERT(!_envStack.empty());
+
+    Script* script = _envStack.back();
+
+    _envStack.pop_back();
+
+    SAFE_RELEASE(script);
+}
+
+ScriptController::ScriptTimeListener::ScriptTimeListener(Script* script, const char* function) : script(script), function(function)
+{
+}
+
+ScriptController::ScriptTimeListener::~ScriptTimeListener()
+{
+    // Release 
+    SAFE_RELEASE(script);
+}
+
+void ScriptController::ScriptTimeListener::timeEvent(long timeDiff, void* cookie)
+{
+    // Remove ourself from the script controller's list
+    std::list<ScriptTimeListener*>& list = Game::getInstance()->getScriptController()->_timeListeners;
+    std::list<ScriptTimeListener*>::iterator itr = std::find(list.begin(), list.end(), this);
+    if (itr != list.end())
+        list.erase(itr);
+
+    // Call the script function
+    Game::getInstance()->getScriptController()->executeFunction<void>(script, function.c_str(), "l", timeDiff);
+
+    // Free ourself.
+    // IMPORTANT: Don't do anything else after this line!!
+    delete this;
+}
+
 // Helper macros.
-#define SCRIPT_EXECUTE_FUNCTION_NO_PARAM(type, checkfunc) \
+#define SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, type, checkfunc) \
     int top = lua_gettop(_lua); \
-    executeFunctionHelper(1, func, NULL, NULL); \
+    executeFunctionHelper(1, func, NULL, NULL, script); \
     type value = (type)checkfunc(_lua, -1); \
     lua_pop(_lua, -1); \
     lua_settop(_lua, top); \
     return value;
 
-#define SCRIPT_EXECUTE_FUNCTION_PARAM(type, checkfunc) \
+#define SCRIPT_EXECUTE_FUNCTION_PARAM(script, type, checkfunc) \
     int top = lua_gettop(_lua); \
     va_list list; \
     va_start(list, args); \
-    executeFunctionHelper(1, func, args, &list); \
+    executeFunctionHelper(1, func, args, &list, script); \
     type value = (type)checkfunc(_lua, -1); \
     lua_pop(_lua, -1); \
     va_end(list); \
     lua_settop(_lua, top); \
     return value;
 
-#define SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(type, checkfunc) \
+#define SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, type, checkfunc) \
     int top = lua_gettop(_lua); \
     executeFunctionHelper(1, func, args, list, script); \
     type value = (type)checkfunc(_lua, -1); \
@@ -884,69 +1000,134 @@ int ScriptController::convert(lua_State* state)
 
 template<> void ScriptController::executeFunction<void>(const char* func)
 {
-    int top = lua_gettop(_lua);
-    executeFunctionHelper(0, func, NULL, NULL);
-    lua_settop(_lua, top);
+    executeFunction<void>((Script*)NULL, func);
 }
 
 template<> bool ScriptController::executeFunction<bool>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(bool, ScriptUtil::luaCheckBool);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, bool, ScriptUtil::luaCheckBool);
 }
 
 template<> char ScriptController::executeFunction<char>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(char, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, char, luaL_checkint);
 }
 
 template<> short ScriptController::executeFunction<short>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(short, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, short, luaL_checkint);
 }
 
 template<> int ScriptController::executeFunction<int>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(int, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, int, luaL_checkint);
 }
 
 template<> long ScriptController::executeFunction<long>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(long, luaL_checklong);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, long, luaL_checklong);
 }
 
 template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(unsigned char, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, unsigned char, luaL_checkunsigned);
 }
 
 template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(unsigned short, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, unsigned short, luaL_checkunsigned);
 }
 
 template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(unsigned int, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, unsigned int, luaL_checkunsigned);
 }
 
 template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(unsigned long, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, unsigned long, luaL_checkunsigned);
 }
 
 template<> float ScriptController::executeFunction<float>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(float, luaL_checknumber);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, float, luaL_checknumber);
 }
 
 template<> double ScriptController::executeFunction<double>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(double, luaL_checknumber);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, double, luaL_checknumber);
 }
 
 template<> std::string ScriptController::executeFunction<std::string>(const char* func)
 {
-    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(std::string, luaL_checkstring);
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(NULL, std::string, luaL_checkstring);
+}
+
+template<> void ScriptController::executeFunction<void>(Script* script, const char* func)
+{
+    int top = lua_gettop(_lua);
+    executeFunctionHelper(0, func, NULL, NULL, script);
+    lua_settop(_lua, top);
+}
+
+template<> bool ScriptController::executeFunction<bool>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, bool, ScriptUtil::luaCheckBool);
+}
+
+template<> char ScriptController::executeFunction<char>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, char, luaL_checkint);
+}
+
+template<> short ScriptController::executeFunction<short>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, short, luaL_checkint);
+}
+
+template<> int ScriptController::executeFunction<int>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, int, luaL_checkint);
+}
+
+template<> long ScriptController::executeFunction<long>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, long, luaL_checklong);
+}
+
+template<> unsigned char ScriptController::executeFunction<unsigned char>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, unsigned char, luaL_checkunsigned);
+}
+
+template<> unsigned short ScriptController::executeFunction<unsigned short>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, unsigned short, luaL_checkunsigned);
+}
+
+template<> unsigned int ScriptController::executeFunction<unsigned int>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, unsigned int, luaL_checkunsigned);
+}
+
+template<> unsigned long ScriptController::executeFunction<unsigned long>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, unsigned long, luaL_checkunsigned);
+}
+
+template<> float ScriptController::executeFunction<float>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, float, luaL_checknumber);
+}
+
+template<> double ScriptController::executeFunction<double>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, double, luaL_checknumber);
+}
+
+template<> std::string ScriptController::executeFunction<std::string>(Script* script, const char* func)
+{
+    SCRIPT_EXECUTE_FUNCTION_NO_PARAM(script, std::string, luaL_checkstring);
 }
 
 /** Template specialization. */
@@ -955,7 +1136,7 @@ template<> void ScriptController::executeFunction<void>(const char* func, const
     int top = lua_gettop(_lua);
     va_list list;
     va_start(list, args);
-    executeFunctionHelper(0, func, args, &list);
+    executeFunctionHelper(0, func, args, &list, NULL);
     va_end(list);
     lua_settop(_lua, top);
 }
@@ -963,151 +1144,312 @@ template<> void ScriptController::executeFunction<void>(const char* func, const
 /** Template specialization. */
 template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(bool, ScriptUtil::luaCheckBool);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, bool, ScriptUtil::luaCheckBool);
 }
 
 /** Template specialization. */
 template<> char ScriptController::executeFunction<char>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(char, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, char, luaL_checkint);
 }
 
 /** Template specialization. */
 template<> short ScriptController::executeFunction<short>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(short, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, short, luaL_checkint);
 }
 
 /** Template specialization. */
 template<> int ScriptController::executeFunction<int>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(int, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, int, luaL_checkint);
 }
 
 /** Template specialization. */
 template<> long ScriptController::executeFunction<long>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(long, luaL_checklong);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, long, luaL_checklong);
 }
 
 /** Template specialization. */
 template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(unsigned char, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, unsigned char, luaL_checkunsigned);
 }
 
 /** Template specialization. */
 template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(unsigned short, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, unsigned short, luaL_checkunsigned);
 }
 
 /** Template specialization. */
 template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(unsigned int, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, unsigned int, luaL_checkunsigned);
 }
 
 /** Template specialization. */
 template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(unsigned long, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, unsigned long, luaL_checkunsigned);
 }
 
 /** Template specialization. */
 template<> float ScriptController::executeFunction<float>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(float, luaL_checknumber);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, float, luaL_checknumber);
 }
 
 /** Template specialization. */
 template<> double ScriptController::executeFunction<double>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(double, luaL_checknumber);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, double, luaL_checknumber);
 }
 
 /** Template specialization. */
 template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, ...)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM(std::string, luaL_checkstring);
+    SCRIPT_EXECUTE_FUNCTION_PARAM(NULL, std::string, luaL_checkstring);
+}
+
+/** Template specialization. */
+template<> void ScriptController::executeFunction<void>(Script* script, const char* func, const char* args, ...)
+{
+    int top = lua_gettop(_lua);
+    va_list list;
+    va_start(list, args);
+    executeFunctionHelper(0, func, args, &list, script);
+    va_end(list);
+    lua_settop(_lua, top);
+}
+
+/** Template specialization. */
+template<> bool ScriptController::executeFunction<bool>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, bool, ScriptUtil::luaCheckBool);
+}
+
+/** Template specialization. */
+template<> char ScriptController::executeFunction<char>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, char, luaL_checkint);
+}
+
+/** Template specialization. */
+template<> short ScriptController::executeFunction<short>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, short, luaL_checkint);
+}
+
+/** Template specialization. */
+template<> int ScriptController::executeFunction<int>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, int, luaL_checkint);
+}
+
+/** Template specialization. */
+template<> long ScriptController::executeFunction<long>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, long, luaL_checklong);
+}
+
+/** Template specialization. */
+template<> unsigned char ScriptController::executeFunction<unsigned char>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, unsigned char, luaL_checkunsigned);
+}
+
+/** Template specialization. */
+template<> unsigned short ScriptController::executeFunction<unsigned short>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, unsigned short, luaL_checkunsigned);
+}
+
+/** Template specialization. */
+template<> unsigned int ScriptController::executeFunction<unsigned int>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, unsigned int, luaL_checkunsigned);
+}
+
+/** Template specialization. */
+template<> unsigned long ScriptController::executeFunction<unsigned long>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, unsigned long, luaL_checkunsigned);
+}
+
+/** Template specialization. */
+template<> float ScriptController::executeFunction<float>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, float, luaL_checknumber);
+}
+
+/** Template specialization. */
+template<> double ScriptController::executeFunction<double>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, double, luaL_checknumber);
+}
+
+/** Template specialization. */
+template<> std::string ScriptController::executeFunction<std::string>(Script* script, const char* func, const char* args, ...)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM(script, std::string, luaL_checkstring);
+}
+
+/** Template specialization. */
+template<> void ScriptController::executeFunction<void>(const char* func, const char* args, va_list* list)
+{
+    executeFunctionHelper(0, func, args, list, NULL);
+}
+
+/** Template specialization. */
+template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, bool, ScriptUtil::luaCheckBool);
+}
+
+/** Template specialization. */
+template<> char ScriptController::executeFunction<char>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, char, luaL_checkint);
+}
+
+/** Template specialization. */
+template<> short ScriptController::executeFunction<short>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, short, luaL_checkint);
+}
+
+/** Template specialization. */
+template<> int ScriptController::executeFunction<int>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, int, luaL_checkint);
+}
+
+/** Template specialization. */
+template<> long ScriptController::executeFunction<long>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, long, luaL_checklong);
+}
+
+/** Template specialization. */
+template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, unsigned char, luaL_checkunsigned);
+}
+
+/** Template specialization. */
+template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, unsigned short, luaL_checkunsigned);
+}
+
+/** Template specialization. */
+template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, unsigned int, luaL_checkunsigned);
+}
+
+/** Template specialization. */
+template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, unsigned long, luaL_checkunsigned);
+}
+
+/** Template specialization. */
+template<> float ScriptController::executeFunction<float>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, float, luaL_checknumber);
+}
+
+/** Template specialization. */
+template<> double ScriptController::executeFunction<double>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, double, luaL_checknumber);
+}
+
+/** Template specialization. */
+template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, va_list* list)
+{
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(NULL, std::string, luaL_checkstring);
 }
 
 /** Template specialization. */
-template<> void ScriptController::executeFunction<void>(const char* func, const char* args, va_list* list, int script)
+template<> void ScriptController::executeFunction<void>(Script* script, const char* func, const char* args, va_list* list)
 {
     executeFunctionHelper(0, func, args, list, script);
 }
 
 /** Template specialization. */
-template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, va_list* list, int script)
+template<> bool ScriptController::executeFunction<bool>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(bool, ScriptUtil::luaCheckBool);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, bool, ScriptUtil::luaCheckBool);
 }
 
 /** Template specialization. */
-template<> char ScriptController::executeFunction<char>(const char* func, const char* args, va_list* list, int script)
+template<> char ScriptController::executeFunction<char>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(char, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, char, luaL_checkint);
 }
 
 /** Template specialization. */
-template<> short ScriptController::executeFunction<short>(const char* func, const char* args, va_list* list, int script)
+template<> short ScriptController::executeFunction<short>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(short, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, short, luaL_checkint);
 }
 
 /** Template specialization. */
-template<> int ScriptController::executeFunction<int>(const char* func, const char* args, va_list* list, int script)
+template<> int ScriptController::executeFunction<int>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(int, luaL_checkint);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, int, luaL_checkint);
 }
 
 /** Template specialization. */
-template<> long ScriptController::executeFunction<long>(const char* func, const char* args, va_list* list, int script)
+template<> long ScriptController::executeFunction<long>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(long, luaL_checklong);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, long, luaL_checklong);
 }
 
 /** Template specialization. */
-template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, va_list* list, int script)
+template<> unsigned char ScriptController::executeFunction<unsigned char>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned char, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, unsigned char, luaL_checkunsigned);
 }
 
 /** Template specialization. */
-template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, va_list* list, int script)
+template<> unsigned short ScriptController::executeFunction<unsigned short>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned short, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, unsigned short, luaL_checkunsigned);
 }
 
 /** Template specialization. */
-template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, va_list* list, int script)
+template<> unsigned int ScriptController::executeFunction<unsigned int>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned int, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, unsigned int, luaL_checkunsigned);
 }
 
 /** Template specialization. */
-template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, va_list* list, int script)
+template<> unsigned long ScriptController::executeFunction<unsigned long>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(unsigned long, luaL_checkunsigned);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, unsigned long, luaL_checkunsigned);
 }
 
 /** Template specialization. */
-template<> float ScriptController::executeFunction<float>(const char* func, const char* args, va_list* list, int script)
+template<> float ScriptController::executeFunction<float>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(float, luaL_checknumber);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, float, luaL_checknumber);
 }
 
 /** Template specialization. */
-template<> double ScriptController::executeFunction<double>(const char* func, const char* args, va_list* list, int script)
+template<> double ScriptController::executeFunction<double>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(double, luaL_checknumber);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, double, luaL_checknumber);
 }
 
 /** Template specialization. */
-template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, va_list* list, int script)
+template<> std::string ScriptController::executeFunction<std::string>(Script* script, const char* func, const char* args, va_list* list)
 {
-    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(std::string, luaL_checkstring);
+    SCRIPT_EXECUTE_FUNCTION_PARAM_LIST(script, std::string, luaL_checkstring);
 }
 
 void ScriptUtil::registerLibrary(const char* name, const luaL_Reg* functions)

+ 300 - 80
gameplay/src/ScriptController.h

@@ -15,7 +15,9 @@ class ScriptController
 {
     friend class Game;
     friend class Platform;
+    friend class Script;
     friend class ScriptUtil;
+    friend class ScriptTimeListener;
 
 public:
 
@@ -39,7 +41,7 @@ public:
     Script* loadScript(const char* path, Script::Scope scope = Script::GLOBAL, bool forceReload = false);
 
     /**
-     * Calls the specified no-parameter global Lua function.
+     * Calls a zero-parameter global function.
      * 
      * @param func The name of the function to call.
      * 
@@ -50,7 +52,19 @@ public:
     template<typename T> T executeFunction(const char* func);
 
     /**
-     * Calls the specified global Lua function using the given parameters.
+     * Calls a zero-parameter function.
+     * 
+     * @param script The script to execute the function on, or NULL for the global script environment.
+     * @param func The name of the function to call.
+     * 
+     * @return The return value of the executed Lua function.
+     *
+     * @script{ignore}
+     */
+    template<typename T> T executeFunction(Script* script, const char* func);
+
+    /**
+     * Calls a global function using the given parameters.
      * 
      * @param func The name of the function to call.
      * @param args The argument signature of the function. Of the form 'xxx', where each 'x' is a parameter type and must be one of:
@@ -69,7 +83,8 @@ public:
      *      - 'p' - pointer
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
-     * 
+     * @param ... Parameters to pass to the script fucntion, as specified by the args parameter.
+     *
      * @return The return value of the executed Lua function.
      *
      * @script{ignore}
@@ -77,8 +92,9 @@ public:
     template<typename T> T executeFunction(const char* func, const char* args, ...);
 
     /**
-     * Calls the specified global Lua function using the given parameters.
+     * Calls the a function from the specified script, using the given parameters.
      * 
+     * @param script The script to execute the function on, or NULL for the global script environment.
      * @param func The name of the function to call.
      * @param args The argument signature of the function. Of the form 'xxx', where each 'x' is a parameter type and must be one of:
      *      - 'b' - bool
@@ -96,157 +112,213 @@ public:
      *      - 'p' - pointer
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
-     * @param list The variable argument list containing the function's parameters.
-     * @param script Optional ID for the script environment of the function to execute, or zero for the default/global environment.
+     * @param ... Parameters to pass to the script fucntion, as specified by the args parameter.
+     * 
+     * @return The return value of the executed Lua function.
+     *
+     * @script{ignore}
+     */
+    template<typename T> T executeFunction(Script* script, const char* func, const char* args, ...);
+
+    /**
+     * Calls the specified global Lua function using the given parameters.
+     * 
+     * @param func The name of the function to call.
+     * @param args The optional argument signature of the function. Of the form 'xxx', where each 'x' is a parameter type and must be one of:
+     *      - 'b' - bool
+     *      - 'c' - char
+     *      - 'h' - short
+     *      - 'i' - int
+     *      - 'l' - long
+     *      - 'f' - float
+     *      - 'd' - double
+     *      - 'ui' - unsigned int
+     *      - 'ul' - unsigned long
+     *      - 'uc' - unsigned char
+     *      - 'uh' - unsigned short
+     *      - 's' - string
+     *      - 'p' - pointer
+     *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
+     *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
+     * @param list The variable argument list containing the function's parameters, or NULL for an empty parameter list.
      *
      * @return The return value of the executed Lua function.
      *
      * @script{ignore}
      */
-    template<typename T> T executeFunction(const char* func, const char* args, va_list* list, int script = 0);
+    template<typename T> T executeFunction(const char* func, const char* args, va_list* list);
+
+    /**
+     * Calls the specified global Lua function using the given parameters.
+     * 
+     * @param script Optional script to use, or NULL for the global script environment.
+     * @param func The name of the function to call.
+     * @param args The optional argument signature of the function. Of the form 'xxx', where each 'x' is a parameter type and must be one of:
+     *      - 'b' - bool
+     *      - 'c' - char
+     *      - 'h' - short
+     *      - 'i' - int
+     *      - 'l' - long
+     *      - 'f' - float
+     *      - 'd' - double
+     *      - 'ui' - unsigned int
+     *      - 'ul' - unsigned long
+     *      - 'uc' - unsigned char
+     *      - 'uh' - unsigned short
+     *      - 's' - string
+     *      - 'p' - pointer
+     *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
+     *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
+     * @param list The variable argument list containing the function's parameters, or NULL for an empty parameter list.
+     *
+     * @return The return value of the executed Lua function.
+     *
+     * @script{ignore}
+     */
+    template<typename T> T executeFunction(Script* script, const char* func, const char* args, va_list* list);
 
     /**
      * Gets the global boolean script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a bool.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      *
      * @return The global boolean script variable.
      * 
      * @script{ignore}
      */
-    bool getBool(const char* name, bool defaultValue = false, int script = 0);
+    bool getBool(const char* name, bool defaultValue = false, Script* script = NULL);
 
     /**
      * Gets the global char script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global char script variable.
      * 
      * @script{ignore}
      */
-    char getChar(const char* name, char defaultValue = 0, int script = 0);
+    char getChar(const char* name, char defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global short script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global short script variable.
      * 
      * @script{ignore}
      */
-    short getShort(const char* name, short defaultValue = 0, int script = 0);
+    short getShort(const char* name, short defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global int script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global int script variable.
      * 
      * @script{ignore}
      */
-    int getInt(const char* name, int defaultValue = 0, int script = 0);
+    int getInt(const char* name, int defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global long script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global long script variable.
      * 
      * @script{ignore}
      */
-    long getLong(const char* name, long defaultValue = 0, int script = 0);
+    long getLong(const char* name, long defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global unsigned char script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global unsigned char script variable.
      * 
      * @script{ignore}
      */
-    unsigned char getUnsignedChar(const char* name, unsigned char defaultValue = 0, int script = 0);
+    unsigned char getUnsignedChar(const char* name, unsigned char defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global unsigned short script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global unsigned short script variable.
      * 
      * @script{ignore}
      */
-    unsigned short getUnsignedShort(const char* name, unsigned short defaultValue = 0, int script = 0);
+    unsigned short getUnsignedShort(const char* name, unsigned short defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global unsigned int script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global unsigned int script variable.
      * 
      * @script{ignore}
      */
-    unsigned int getUnsignedInt(const char* name, unsigned int defaultValue = 0, int script = 0);
+    unsigned int getUnsignedInt(const char* name, unsigned int defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global unsigned long script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global unsigned long script variable.
      * 
      * @script{ignore}
      */
-    unsigned long getUnsignedLong(const char* name, unsigned long defaultValue = 0, int script = 0);
+    unsigned long getUnsignedLong(const char* name, unsigned long defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global float script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global float script variable.
      * 
      * @script{ignore}
      */
-    float getFloat(const char* name, float defaultValue = 0, int script = 0);
+    float getFloat(const char* name, float defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global double script variable with the given name.
      * 
      * @param name The name of the variable.
      * @param defaultValue The default value to return if the variable is not a number.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The global double script variable.
      * 
      * @script{ignore}
      */
-    double getDouble(const char* name, double defaultValue = 0, int script = 0);
+    double getDouble(const char* name, double defaultValue = 0, Script* script = NULL);
 
     /**
      * Gets the global string variable with the given name.
@@ -256,13 +328,13 @@ public:
      * required, it should be copied into another string for storage.
      *
      * @param name The name of the variable.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @return The string variable or NULL if the variable is not a string.
      * 
      * @script{ignore}
      */
-    const char* getString(const char* name, int script = 0);
+    const char* getString(const char* name, Script* script = NULL);
 
     /**
      * Gets the global pointer script variable of the given type with the given name.
@@ -281,132 +353,132 @@ public:
      * 
      * @param name The name of the script variable.
      * @param v The boolean value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setBool(const char* name, bool v, int script = 0);
+    void setBool(const char* name, bool v, Script* script = NULL);
 
     /**
      * Sets the global char script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The char value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setChar(const char* name, char v, int script = 0);
+    void setChar(const char* name, char v, Script* script = NULL);
 
     /**
      * Sets the global short script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The short value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setShort(const char* name, short v, int script = 0);
+    void setShort(const char* name, short v, Script* script = NULL);
 
     /**
      * Sets the global int script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The int value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setInt(const char* name, int v, int script = 0);
+    void setInt(const char* name, int v, Script* script = NULL);
 
     /**
      * Sets the global long script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The long value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setLong(const char* name, long v, int script = 0);
+    void setLong(const char* name, long v, Script* script = NULL);
 
     /**
      * Gets the global unsigned char script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The unsigned char value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setUnsignedChar(const char* name, unsigned char v, int script = 0);
+    void setUnsignedChar(const char* name, unsigned char v, Script* script = NULL);
 
     /**
      * Sets the global unsigned short script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The unsigned short value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setUnsignedShort(const char* name, unsigned short v, int script = 0);
+    void setUnsignedShort(const char* name, unsigned short v, Script* script = NULL);
 
     /**
      * Sets the global unsigned int script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The unsigned int value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setUnsignedInt(const char* name, unsigned int v, int script = 0);
+    void setUnsignedInt(const char* name, unsigned int v, Script* script = NULL);
 
     /**
      * Sets the global unsigned long script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The unsigned long value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setUnsignedLong(const char* name, unsigned long v, int script = 0);
+    void setUnsignedLong(const char* name, unsigned long v, Script* script = NULL);
 
     /**
      * Sets the global float script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The float value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setFloat(const char* name, float v, int script = 0);
+    void setFloat(const char* name, float v, Script* script = NULL);
 
     /**
      * Sets the global double script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The double value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setDouble(const char* name, double v, int script = 0);
+    void setDouble(const char* name, double v, Script* script = NULL);
 
     /**
      * Sets the global string script variable with the given name to the given value.
      * 
      * @param name The name of the script variable.
      * @param v The string value.
-     * @param script Optional ID for the script environment to use, or zero for the default/global environment.
+     * @param script Optional script to use, or zero for the global script environment.
      * 
      * @script{ignore}
      */
-    void setString(const char* name, const char* v, int script = 0);
+    void setString(const char* name, const char* v, Script* script = NULL);
 
     /**
      * Sets the global pointer script variable of the given type with the given name to the given value.
@@ -423,11 +495,23 @@ public:
      * Determines if there exists a function with the specified name in the given script environment.
      *
      * @param name The name of the function to check.
-     * @param script Optional ID of the script environment to inspect, or zero to inspect the global environment.
+     * @param script Optional script to inspect, or NULL to inspect the global script environment.
      *
      * @return True if the specified function exists, false otherwise.
      */
-    bool functionExists(const char* name, int script = 0) const;
+    bool functionExists(const char* name, const Script* script = NULL) const;
+
+    /**
+     * Returns the currently executing script.
+     *
+     * Note that this function returns the currently executing Script object,
+     * which is not guaranteed to be valid unless the returned script's
+     * reference count is increased while the caller holds onto it.
+     *
+     * @return The currently executing script, or NULL if either there is no currently
+     *      executing script or the global script environment is current.
+     */
+    Script* getCurrentScript() const;
 
     /**
      * Prints the string to the platform's output stream or log file.
@@ -448,6 +532,32 @@ public:
 
 private:
 
+    /**
+     * Allows time listener interaction from Lua scripts.
+     */
+    struct ScriptTimeListener : public TimeListener
+    {
+        /**
+         * Constructor.
+         */
+        ScriptTimeListener(Script* script, const char* function);
+
+        /**
+         * Destructor.
+         */
+        ~ScriptTimeListener();
+
+        /**
+         * @see TimeListener#timeEvent(long, void*)
+         */
+        void timeEvent(long timeDiff, void* cookie);
+
+        /** Holds the script to execute the function within. */
+        Script* script;
+        /** Holds the name of the Lua script function to call back. */
+        std::string function;
+    };
+
     /**
      * Constructor.
      */
@@ -474,7 +584,19 @@ private:
     void finalize();
 
     /**
-     * Attempts to unload a script with the given ID.
+     * Internal loadScript variant that supports loading into an existing Script object
+     * for reloading purposes.
+     *
+     * @param script A Script object containing a valid path and scope to load.
+     *
+     * @return True if the script is successfully loaded, false otherwise.
+     *
+     * @see loadScript(const char*, Script::scope, bool)
+     */
+    bool loadScript(Script* script);
+
+    /**
+     * Attempts to unload the specified script.
      *
      * Unloading a script causes the non-global data within the script to be
      * released such that a reference is no longer held to it. It will then
@@ -482,16 +604,19 @@ private:
      * any data in the global environment or if any other code still references
      * data from the script, that data will not be freed.
      *
-     * @param id The ID of the script environment.
+     * Global scripts cannot be explicitly unloaded and this function will do
+     * nothing for such scripts.
+     *
+     * @param script The script to be unloaded.
      */
-    void unloadScript(int id);
+    void unloadScript(Script* script);
 
     /**
      * Calls the specified Lua function using the given parameters.
      * 
      * @param resultCount The expected number of returned values.
      * @param func The name of the function to call.
-     * @param args The argument signature of the function, as a string of the form
+     * @param args The optional argument signature of the function, as a string of the form
      *      'xxx', where each 'x' is a parameter type and must be one of:
      *      - 'b' - bool
      *      - 'c' - char
@@ -509,9 +634,9 @@ private:
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
      * @param list The variable argument list.
-     * @param script Optional ID for the script environment of the function to execute, or zero for the default/global environment.
+     * @param script Optional script to execute the function in, or NULL for to execute it in the global environment.
      */
-    void executeFunctionHelper(int resultCount, const char* func, const char* args, va_list* list, int script = 0);
+    void executeFunctionHelper(int resultCount, const char* func, const char* args, va_list* list, Script* script = NULL);
 
     /**
      * Converts a Gameplay userdata value to the type with the given class name.
@@ -539,12 +664,26 @@ private:
      */
     static int convert(lua_State* state);
 
+    /**
+     * Schedules a script function to execute after the given time interval.
+     *
+     * This function is executed in the environment of the script that calls this function.
+     *
+     * @param timeOffset The number of game milliseconds in the future to schedule the event to be fired.
+     * @param function The Lua script function that will receive the event.
+     */
+    void schedule(float timeOffset, const char* function);
+
+    void pushScript(Script* script);
+
+    void popScript();
+
     lua_State* _lua;
     unsigned int _returnCount;
-    std::map<std::string, std::vector<std::string> > _hierarchy;
-    std::set<std::string> _loadedScripts;
-    std::map<int, std::string> _environments;
-    std::vector<int> _envStack;
+    std::map<std::string, std::vector<std::string>> _hierarchy;
+    std::map<std::string, std::vector<Script*>> _scripts;
+    std::vector<Script*> _envStack;
+    std::list<ScriptTimeListener*> _timeListeners;
 };
 
 /** Template specialization. */
@@ -574,6 +713,33 @@ template<> double ScriptController::executeFunction<double>(const char* func);
 /** Template specialization. */
 template<> std::string ScriptController::executeFunction<std::string>(const char* func);
 
+/** Template specialization. */
+template<> void ScriptController::executeFunction<void>(Script* script, const char* func);
+/** Template specialization. */
+template<> bool ScriptController::executeFunction<bool>(Script* script, const char* func);
+/** Template specialization. */
+template<> char ScriptController::executeFunction<char>(Script* script, const char* func);
+/** Template specialization. */
+template<> short ScriptController::executeFunction<short>(Script* script, const char* func);
+/** Template specialization. */
+template<> int ScriptController::executeFunction<int>(Script* script, const char* func);
+/** Template specialization. */
+template<> long ScriptController::executeFunction<long>(Script* script, const char* func);
+/** Template specialization. */
+template<> unsigned char ScriptController::executeFunction<unsigned char>(Script* script, const char* func);
+/** Template specialization. */
+template<> unsigned short ScriptController::executeFunction<unsigned short>(Script* script, const char* func);
+/** Template specialization. */
+template<> unsigned int ScriptController::executeFunction<unsigned int>(Script* script, const char* func);
+/** Template specialization. */
+template<> unsigned long ScriptController::executeFunction<unsigned long>(Script* script, const char* func);
+/** Template specialization. */
+template<> float ScriptController::executeFunction<float>(Script* script, const char* func);
+/** Template specialization. */
+template<> double ScriptController::executeFunction<double>(Script* script, const char* func);
+/** Template specialization. */
+template<> std::string ScriptController::executeFunction<std::string>(Script* script, const char* func);
+
 /** Template specialization. */
 template<> void ScriptController::executeFunction<void>(const char* func, const char* args, ...);
 /** Template specialization. */
@@ -602,31 +768,85 @@ template<> double ScriptController::executeFunction<double>(const char* func, co
 template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, ...);
 
 /** Template specialization. */
-template<> void ScriptController::executeFunction<void>(const char* func, const char* args, va_list* list, int script);
+template<> void ScriptController::executeFunction<void>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> bool ScriptController::executeFunction<bool>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> char ScriptController::executeFunction<char>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> short ScriptController::executeFunction<short>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> int ScriptController::executeFunction<int>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> long ScriptController::executeFunction<long>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> unsigned char ScriptController::executeFunction<unsigned char>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> unsigned short ScriptController::executeFunction<unsigned short>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> unsigned int ScriptController::executeFunction<unsigned int>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> unsigned long ScriptController::executeFunction<unsigned long>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> float ScriptController::executeFunction<float>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> double ScriptController::executeFunction<double>(Script* script, const char* func, const char* args, ...);
+/** Template specialization. */
+template<> std::string ScriptController::executeFunction<std::string>(Script* script, const char* func, const char* args, ...);
+
+/** Template specialization. */
+template<> void ScriptController::executeFunction<void>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> char ScriptController::executeFunction<char>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> short ScriptController::executeFunction<short>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> int ScriptController::executeFunction<int>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> long ScriptController::executeFunction<long>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> float ScriptController::executeFunction<float>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> double ScriptController::executeFunction<double>(const char* func, const char* args, va_list* list);
+/** Template specialization. */
+template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, va_list* list);
+
+/** Template specialization. */
+template<> void ScriptController::executeFunction<void>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> bool ScriptController::executeFunction<bool>(const char* func, const char* args, va_list* list, int script);
+template<> bool ScriptController::executeFunction<bool>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> char ScriptController::executeFunction<char>(const char* func, const char* args, va_list* list, int script);
+template<> char ScriptController::executeFunction<char>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> short ScriptController::executeFunction<short>(const char* func, const char* args, va_list* list, int script);
+template<> short ScriptController::executeFunction<short>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> int ScriptController::executeFunction<int>(const char* func, const char* args, va_list* list, int script);
+template<> int ScriptController::executeFunction<int>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> long ScriptController::executeFunction<long>(const char* func, const char* args, va_list* list, int script);
+template<> long ScriptController::executeFunction<long>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> unsigned char ScriptController::executeFunction<unsigned char>(const char* func, const char* args, va_list* list, int script);
+template<> unsigned char ScriptController::executeFunction<unsigned char>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> unsigned short ScriptController::executeFunction<unsigned short>(const char* func, const char* args, va_list* list, int script);
+template<> unsigned short ScriptController::executeFunction<unsigned short>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> unsigned int ScriptController::executeFunction<unsigned int>(const char* func, const char* args, va_list* list, int script);
+template<> unsigned int ScriptController::executeFunction<unsigned int>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> unsigned long ScriptController::executeFunction<unsigned long>(const char* func, const char* args, va_list* list, int script);
+template<> unsigned long ScriptController::executeFunction<unsigned long>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> float ScriptController::executeFunction<float>(const char* func, const char* args, va_list* list, int script);
+template<> float ScriptController::executeFunction<float>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> double ScriptController::executeFunction<double>(const char* func, const char* args, va_list* list, int script);
+template<> double ScriptController::executeFunction<double>(Script* script, const char* func, const char* args, va_list* list);
 /** Template specialization. */
-template<> std::string ScriptController::executeFunction<std::string>(const char* func, const char* args, va_list* list, int script);
+template<> std::string ScriptController::executeFunction<std::string>(Script* script, const char* func, const char* args, va_list* list);
 
 /**
  * Functions and structures used by the generated Lua script bindings.

+ 21 - 5
gameplay/src/ScriptController.inl

@@ -272,7 +272,12 @@ ScriptUtil::LuaArray<T> ScriptUtil::getObjectPointer(int index, const char* type
 
 template<typename T> T ScriptController::executeFunction(const char* func)
 {
-    executeFunctionHelper(1, func, NULL, NULL);
+    return executeFunction<T>((Script*)NULL, func);
+}
+
+template<typename T> T ScriptController::executeFunction(Script* script, const char* func)
+{
+    executeFunctionHelper(1, func, NULL, NULL, script);
     T value = (T)((ScriptUtil::LuaObject*)lua_touserdata(_lua, -1))->instance;
     lua_pop(_lua, -1);
     return value;
@@ -282,15 +287,26 @@ template<typename T> T ScriptController::executeFunction(const char* func, const
 {
     va_list list;
     va_start(list, args);
-    executeFunctionHelper(1, func, args, &list);
+    T value = executeFunction<T>((Script*)NULL, func, args, list);
+    va_end(list);
+    return value;
+}
 
-    T value = (T)((ScriptUtil::LuaObject*)lua_touserdata(_lua, -1))->instance;
-    lua_pop(_lua, -1);
+template<typename T> T ScriptController::executeFunction(Script* script, const char* func, const char* args, ...)
+{
+    va_list list;
+    va_start(list, args);
+    T value = executeFunction<T>(script, func, args, list);
     va_end(list);
     return value;
 }
 
-template<typename T> T ScriptController::executeFunction(const char* func, const char* args, va_list* list, int script)
+template<typename T> T ScriptController::executeFunction(const char* func, const char* args, va_list* list)
+{
+    return executeFunctionHelper((Script*)NULL, func, args, list);
+}
+
+template<typename T> T ScriptController::executeFunction(Script* script, const char* func, const char* args, va_list* list)
 {
     executeFunctionHelper(1, func, args, list, script);
 

+ 316 - 139
gameplay/src/ScriptTarget.cpp

@@ -11,6 +11,16 @@ namespace gameplay
 
 extern void splitURL(const std::string& url, std::string* file, std::string* id);
 
+const char* ScriptTarget::Event::getName() const
+{
+    return name.c_str();
+}
+
+const char* ScriptTarget::Event::getArgs() const
+{
+    return args.c_str();
+}
+
 ScriptTarget::EventRegistry::EventRegistry()
 {
 }
@@ -23,14 +33,13 @@ ScriptTarget::EventRegistry::~EventRegistry()
     }
 }
 
-const ScriptTarget::EventRegistry::Event* ScriptTarget::EventRegistry::addEvent(const char* name, const char* args)
+const ScriptTarget::Event* ScriptTarget::EventRegistry::addEvent(const char* name, const char* args)
 {
     GP_ASSERT(name);
 
     Event* evt = new Event;
     evt->name = name;
     evt->args = args ? args : "";
-    evt->registry = this;
 
     _events.push_back(evt);
 
@@ -42,158 +51,332 @@ unsigned int ScriptTarget::EventRegistry::getEventCount() const
     return _events.size();
 }
 
-const ScriptTarget::EventRegistry::Event* ScriptTarget::EventRegistry::getEvent(unsigned int index) const
+const ScriptTarget::Event* ScriptTarget::EventRegistry::getEvent(unsigned int index) const
 {
     GP_ASSERT(index < _events.size());
 
     return _events[index];
 }
 
-ScriptTarget::ScriptTarget() : _scripts(NULL), _events(NULL)
+const ScriptTarget::Event* ScriptTarget::EventRegistry::getEvent(const char* name) const
+{
+    GP_ASSERT(name);
+
+    for (size_t i = 0, count = _events.size(); i < count; ++i)
+    {
+        if (_events[i]->name == name)
+            return _events[i];
+    }
+
+    return NULL;
+}
+
+ScriptTarget::ScriptTarget() : _scriptRegistries(NULL), _scripts(NULL), _scriptCallbacks(NULL)
 {
 }
 
 ScriptTarget::~ScriptTarget()
 {
+    // Free callbacks
+    SAFE_DELETE(_scriptCallbacks);
+
     // Free scripts
-    Script* script = _scripts;
-    while (script)
+    ScriptEntry* se = _scripts;
+    while (se)
     {
-        // The Game class is itself a ScriptTarget, so we need to protect against
-        // this destructor being called after the Game's destructor, when the
-        // ScriptController has already been destroyed.
-        Game* game = Game::getInstance();
-        if (game)
-        {
-            ScriptController* sc = game->getScriptController();
-            sc->unloadScript(script->id);
-        }
-        script->id = 0;
-        Script* tmp = script;
-        script = script->next;
-        SAFE_DELETE(script);
+        ScriptEntry* tmp = se;
+        se = se->next;
+
+        SAFE_RELEASE(tmp->script);
+        SAFE_DELETE(tmp);
     }
 
-    // Free events (we don't own the EventRegistry pointers, so don't free them)
-    SAFE_DELETE(_events);
+    // Free registry entries
+    RegistryEntry* re = _scriptRegistries;
+    while (re)
+    {
+        RegistryEntry* tmp = re;
+        re = re->next;
+
+        // Don't delete the actual EventRegistry, since it's shared by all
+        // ScriptTargets of the same type
+        SAFE_DELETE(re);
+    }
 }
 
 void ScriptTarget::registerEvents(EventRegistry* registry)
 {
     GP_ASSERT(registry);
 
-    if (!_events)
-        _events = new std::vector<EventRegistry*>();
-
-    _events->push_back(registry);
+    // Attach the registry
+    RegistryEntry* re = new RegistryEntry(registry);
+    if (_scriptRegistries)
+    {
+        RegistryEntry* last = _scriptRegistries;
+        while (last->next)
+            last = last->next;
+        last->next = re;
+        re->prev = last;
+    }
+    else
+    {
+        _scriptRegistries = re;
+    }
 }
 
-void ScriptTarget::addScript(const char* path, Script::Scope scope)
+Script* ScriptTarget::addScript(const char* path, Script::Scope scope)
 {
-    // Load the script into an isolated environment
     ScriptController* sc = Game::getInstance()->getScriptController();
-    int id = sc->loadScriptIsolated(path);
-    if (id <= 0)
-        return id;
+
+    // Load the script
+    Script* script = sc->loadScript(path, scope);
+    if (!script)
+        return NULL;
 
     // Attach the script
-    Script* script = new Script;
-    script->id = id;
-    script->path = path;
+    ScriptEntry* se = new ScriptEntry(script);
     if (_scripts)
     {
-        Script* last = _scripts;
+        ScriptEntry* last = _scripts;
         while (last->next)
             last = last->next;
-        last->next = script;
-        script->prev = last;
+        last->next = se;
+        se->prev = last;
     }
     else
     {
-        _scripts = script;
+        _scripts = se;
     }
 
-    // Inspect the loaded script for supported event functions.
+    // Inspect the loaded script for event functions that are supported by this ScriptTarget.
     // TODO: We'll need to re-load eventCallbacks when EventRegistries change for this ScriptObject.
-    if (_events)
+    RegistryEntry* re = _scriptRegistries;
+    while (re)
     {
-        for (size_t i = 0, registryCount = _events->size(); i < registryCount; ++i)
+        std::vector<Event*>& events = re->registry->_events;
+        for (size_t i = 0, count = events.size(); i < count; ++i)
         {
-            std::vector<EventRegistry::Event*>& events = (*_events)[i]->_events;
-            for (size_t j = 0, eventCount = events.size(); j < eventCount; ++j)
+            const Event* event = events[i];
+            if (sc->functionExists(event->name.c_str(), script))
             {
-                EventRegistry::Event* event = events[j];
-                if (sc->functionExists(event->name.c_str(), id))
-                {
-                    script->eventCallbacks.push_back(event);
-                }
+                if (!_scriptCallbacks)
+                    _scriptCallbacks = new std::map<const Event*, std::vector<CallbackFunction>>();
+                (*_scriptCallbacks)[event].push_back(CallbackFunction(script, event->name.c_str()));
             }
         }
+        re = re->next;
     }
 
-    return script->id;
+    return script;
 }
 
-bool ScriptTarget::removeScript(const char* path)
+bool ScriptTarget::removeScript(const char* path, Script::Scope scope)
 {
-    Script* script = _scripts;
-    while (script)
+    GP_ASSERT(path);
+
+    ScriptEntry* se = _scripts;
+    while (se)
     {
-        if (script->path == path)
+        if (strcmp(se->script->getPath(), path) == 0 && scope == se->script->getScope())
         {
-            removeScript(script);
-
+            removeScript(se);
             return true;
         }
-        script = script->next;
+        se = se->next;
     }
 
     return false;
 }
 
-void ScriptTarget::removeScript(Script* script)
+void ScriptTarget::removeScript(ScriptEntry* se)
 {
-    GP_ASSERT(script);
+    GP_ASSERT(se);
 
-    // Link out this script
-    Script* next = script->next;
-    if (script->prev)
-        script->prev->next = script->next;
-    if (script->next)
-        script->next->prev = script->prev;
+    // Link out this ScriptEntry
+    if (se->prev)
+        se->prev->next = se->next;
+    if (se->next)
+        se->next->prev = se->prev;
+    if (_scripts == se)
+        _scripts = se->next;
 
-    // Unload the script
-    Game::getInstance()->getScriptController()->unloadScript(script->id);
+    Script* script = se->script;
 
-    // Free the script object
-    SAFE_DELETE(script);
+    // Delete the ScriptEntry
+    SAFE_DELETE(se);
 
-    // TODO: Remove callbacks
-}
+    // Erase any callback functions registered for this script
+    if (_scriptCallbacks)
+    {
+        std::map<const Event*, std::vector<CallbackFunction>>::iterator itr = _scriptCallbacks->begin();
+        for ( ; itr != _scriptCallbacks->end(); ++itr)
+        {
+            std::vector<CallbackFunction>& callbacks = itr->second;
+            std::vector<CallbackFunction>::iterator itr2 = callbacks.begin();
+            while (itr2 != callbacks.end())
+            {
+                if (itr2->script == script)
+                    itr2 = callbacks.erase(itr2);
+                else
+                    ++itr2;
+            }
+        }
+    }
 
+    // Free the script
+    SAFE_RELEASE(script);
+}
 
 void ScriptTarget::addScriptCallback(const char* eventName, const char* function)
 {
-    std::string script, func;
-    splitURL(function, &script, &func);
+    GP_ASSERT(eventName);
+    GP_ASSERT(function);
+
+    // Lookup the specified event
+    const Event* event = NULL;
+    RegistryEntry* re = _scriptRegistries;
+    while (re)
+    {
+        if ((event = re->registry->getEvent(eventName)) != NULL)
+            break;
+        re = re->next;
+    }
+
+    if (event == NULL)
+    {
+        GP_WARN("No event named '%s' found for script target while registering function: %s", eventName, function);
+        return;
+    }
+
+    // Parse the script name (if it exists) and function out
+    std::string scriptPath, func;
+    splitURL(function, &scriptPath, &func);
     if (func.length() == 0)
     {
         // The url doesn't reference a script, only a function
-        func = script;
-        script = "";
+        func = scriptPath;
+        scriptPath = "";
+    }
+
+    // Have we already loaded this global script?
+    bool loaded = true;
+    Script* script = NULL;
+    if (!scriptPath.empty())
+    {
+        loaded = false;
+        ScriptEntry* se = _scripts;
+        while (se)
+        {
+            if (scriptPath == se->script->getPath() && se->script->getScope() == Script::GLOBAL)
+            {
+                // Script is already loaded
+                script = se->script;
+                loaded = true;
+                break;
+            }
+            se = se->next;
+        }
+    }
+
+    if (!loaded)
+    {
+        // The specified global script is not yet loaded, so do so
+        script = Game::getInstance()->getScriptController()->loadScript(scriptPath.c_str(), Script::GLOBAL);
+        if (script)
+        {
+            loaded = true;
+            ScriptEntry* se = new ScriptEntry(script);
+            if (_scripts)
+            {
+                ScriptEntry* last = _scripts;
+                while (last->next)
+                    last = last->next;
+                last->next = se;
+                se->prev = last;
+            }
+            else
+            {
+                _scripts = se;
+            }
+        }
+        else
+        {
+            GP_WARN("Failed to load script '%s' for script target while registering for function: %s", scriptPath.c_str(), function);
+        }
     }
 
-    // Ensure the script is loaded
-    if (script.length() > 0)
+    if (loaded)
     {
-        if (!Game::getInstance()->getScriptController()->loadScript(script.c_str()))
-            return "";
+        // Store the callback
+        if (!_scriptCallbacks)
+            _scriptCallbacks = new std::map<const Event*, std::vector<CallbackFunction>>();
+        (*_scriptCallbacks)[event].push_back(CallbackFunction(script, func.c_str()));
     }
 }
 
 void ScriptTarget::removeScriptCallback(const char* eventName, const char* function)
 {
-    // TODO
+    // Parse the script name (if it exists) and function out
+    std::string scriptPath, func;
+    splitURL(function, &scriptPath, &func);
+    if (func.length() == 0)
+    {
+        // The url doesn't reference a script, only a function
+        func = scriptPath;
+        scriptPath = "";
+    }
+
+    // Find the script entry for this callback
+    ScriptEntry* scriptEntry = NULL;
+    if (!scriptPath.empty())
+    {
+        ScriptEntry* se = _scripts;
+        while (se)
+        {
+            if (scriptPath == se->script->getPath() && se->script->getScope() == Script::GLOBAL)
+            {
+                scriptEntry = se;
+                break;
+            }
+            se = se->next;
+        }
+    }
+    Script* script = scriptEntry ? scriptEntry->script : NULL;
+
+    // Remove any registered callback functions that match the specified one
+    int removedCallbacks = 0;
+    int totalCallbacks = 0;
+    if (_scriptCallbacks)
+    {
+        std::map<const Event*, std::vector<CallbackFunction>>::iterator itr = _scriptCallbacks->begin();
+        for (; itr != _scriptCallbacks->end(); ++itr)
+        {
+            // Erase matching callback functions for this event
+            bool forEvent = itr->first->name == eventName;
+            std::vector<CallbackFunction>& callbacks = itr->second;
+            std::vector<CallbackFunction>::iterator itr2 = callbacks.begin();
+            while (itr2 != callbacks.end())
+            {
+                if (itr2->script == script)
+                {
+                    ++totalCallbacks; // sum total number of callbacks found for this script
+                    if (forEvent && itr2->function == func)
+                    {
+                        itr2 = callbacks.erase(itr2);
+                        ++removedCallbacks; // sum number of callbacks removed
+                    }
+                    else
+                        ++itr2;
+                }
+            }
+        }
+    }
+
+    // Cleanup the script if there are no remaining callbacks for it
+    if (scriptEntry && (totalCallbacks - removedCallbacks) <= 0)
+    {
+        removeScript(scriptEntry);
+    }
 }
 
 void ScriptTarget::clearScripts()
@@ -204,103 +387,97 @@ void ScriptTarget::clearScripts()
     }
 }
 
-bool ScriptTarget::hasScriptListener(const EventRegistry::Event* evt) const
+bool ScriptTarget::hasScriptListener(const char* eventName) const
 {
-    Script* script = _scripts;
-    while (script)
+    GP_ASSERT(eventName);
+
+    // Lookup the event for this name
+    const Event* event = NULL;
+    RegistryEntry* re = _scriptRegistries;
+    while (re)
     {
-        // Does this script have a callback implemented for the given event?
-        std::vector<const EventRegistry::Event*>& callbacks = script->eventCallbacks;
-        for (size_t i = 0, count = callbacks.size(); i < count; ++i)
+        if ((event = re->registry->getEvent(eventName)) != NULL)
+            break;
+        re = re->next;
+    }
+
+    if (event == NULL)
+        return false;
+
+    return hasScriptListener(event);
+}
+
+bool ScriptTarget::hasScriptListener(const Event* event) const
+{
+    GP_ASSERT(event);
+
+    if (_scriptCallbacks)
+    {
+        std::map<const Event*, std::vector<CallbackFunction>>::iterator itr = _scriptCallbacks->find(event);
+        if (itr != _scriptCallbacks->end())
         {
-            if (callbacks[i] == evt)
-                return true;
+            return !itr->second.empty();
         }
-        //std::vector<std::string>::iterator itr = std::find(callbacks.begin(), callbacks.end(), evt->name);
-        //if (itr != callbacks.end())
-            //return true;
-        script = script->next;
     }
 
     return false;
 }
 
-template<> void ScriptTarget::fireScriptEvent<void>(const EventRegistry::Event* evt, ...)
+template<> void ScriptTarget::fireScriptEvent<void>(const Event* event, ...)
 {
-    GP_ASSERT(evt);
+    GP_ASSERT(event);
+
+    if (!_scriptCallbacks)
+        return; // no registered callbacks
 
     va_list list;
-    va_start(list, evt);
+    va_start(list, event);
 
-    // Fire this event for all scripts that support it
-    Script* script = _scripts;
-    while (script)
+    // Lookup registered callbacks for this event and fire them
+    std::map<const Event*, std::vector<CallbackFunction>>::iterator itr = _scriptCallbacks->find(event);
+    if (itr != _scriptCallbacks->end())
     {
-        // Is there a callback in this script for this event?
-        std::vector<const EventRegistry::Event*>& callbacks = script->eventCallbacks;
+        ScriptController* sc = Game::getInstance()->getScriptController();
+        std::vector<CallbackFunction>& callbacks = itr->second;
         for (size_t i = 0, count = callbacks.size(); i < count; ++i)
         {
-            if (callbacks[i] == evt)
-            {
-                Game::getInstance()->getScriptController()->executeFunction<void>(evt->name.c_str(), evt->args.c_str(), &list, script->id);
-            }
-        }
-        /*
-        std::vector<std::string>& callbacks = script->eventCallbacks;
-        std::vector<std::string>::iterator itr = std::find(callbacks.begin(), callbacks.end(), evt->name);
-        if (itr != callbacks.end())
-        {
-            Game::getInstance()->getScriptController()->executeFunction<void>(itr->c_str(), evt->args.c_str(), &list, script->id);
+            CallbackFunction& cb = callbacks[i];
+            sc->executeFunction<void>(cb.script, cb.function.c_str(), event->args.c_str(), &list);
         }
-        */
-
-        script = script->next;
     }
 
     va_end(list);
 }
 
-template<> bool ScriptTarget::fireScriptEvent<bool>(const EventRegistry::Event* evt, ...)
+template<> bool ScriptTarget::fireScriptEvent<bool>(const Event* event, ...)
 {
+    GP_ASSERT(event);
+
+    if (!_scriptCallbacks)
+        return false; // no registered callbacks
+
     va_list list;
-    va_start(list, evt);
+    va_start(list, event);
 
-    // Fire this event for all scripts that support it
-    Script* script = _scripts;
-    while (script)
+    // Lookup registered callbacks for this event and fire them
+    std::map<const Event*, std::vector<CallbackFunction>>::iterator itr = _scriptCallbacks->find(event);
+    if (itr != _scriptCallbacks->end())
     {
-        // Is there a callback in this script for this event?
-        std::vector<const EventRegistry::Event*>& callbacks = script->eventCallbacks;
+        ScriptController* sc = Game::getInstance()->getScriptController();
+        std::vector<CallbackFunction>& callbacks = itr->second;
         for (size_t i = 0, count = callbacks.size(); i < count; ++i)
         {
-            if (callbacks[i] == evt)
-            {
-                // Call the script function
-                if (Game::getInstance()->getScriptController()->executeFunction<bool>(evt->name.c_str(), evt->args.c_str(), &list, script->id))
-                {
-                    va_end(list);
-                    return true;
-                }
-            }
-        }
-        /*
-        std::vector<std::string>& callbacks = script->eventCallbacks;
-        std::vector<std::string>::iterator itr = std::find(callbacks.begin(), callbacks.end(), evt->name);
-        if (itr != callbacks.end())
-        {
-            // Call the script function
-            if (Game::getInstance()->getScriptController()->executeFunction<bool>(itr->c_str(), evt->args.c_str(), &list, script->id))
+            CallbackFunction& cb = callbacks[i];
+            if (sc->executeFunction<bool>(cb.script, cb.function.c_str(), event->args.c_str(), &list))
             {
                 va_end(list);
                 return true;
             }
         }
-        */
-
-        script = script->next;
     }
 
     va_end(list);
+
     return false;
 }
 

+ 183 - 89
gameplay/src/ScriptTarget.h

@@ -1,56 +1,96 @@
 #ifndef SCRIPTTARGET_H_
 #define SCRIPTTARGET_H_
 
-#include "Base.h"
+#include "Script.h"
 
 namespace gameplay
 {
 
 /**
- * Signals the start of script event declarations for a ScriptTarget implementation.
+ * Macro to indidate the start of script event definitions for a class.
  *
- * This macro should be followed by one or more calls to GP_SCRIPT_EVENT.
- *
- * It is recommended that these macros be used at the top of the source file that
- * contains the implemtation of a ScriptTarget child class.
+ * This macro should be used at the top of a class declaration. The class
+ * should extend ScriptTarget and the lines immediately following this
+ * macro should be one or more GP_SCRIPT_EVENT macros, followed by
+ * exactly one GP_SCRIPT_EVENTS_END macro.
  *
  * @script{ignore}
  */
-#define GP_SCRIPT_EVENTS() \
-    static gameplay::ScriptTarget::EventRegistry __eventRegistry
+#define GP_SCRIPT_EVENTS_START() \
+public: \
+    class ScriptEvents { \
+    public: \
+        static ScriptEvents* getInstance() \
+        { \
+            static ScriptEvents instance; \
+            return &instance; \
+        } \
+        ScriptTarget::EventRegistry* getRegistry() \
+        { \
+            static ScriptTarget::EventRegistry registry; \
+            return &registry; \
+        }
 
 /**
- * Defines a script event of the given name and adds it to the event registry for
- * the current scope.
- *
- * A call to GP_SCRIPT_EVENT_START must exist before any calls to GP_SCRIPT_EVENT
- * are made. This macro will define a constant in the current code scope that is
- * named SCRIPT_EVENT_eventName, which should be used when calling 
- * ScriptTarget::fireScriptEvent from a ScriptTarget child class.  For this reason,
- * these macros should exist outside the definition of the class, preferably at
- * the top of the source file.
+ * Macro to define a single supported script event for a class.
  *
- * @param eventName Name of the event (no quotes).
- * @param eventArgs Parmeters for this script event.
+ * This macro should follow exactly one prior GP_SCRIPT_EVENTS_START macro
+ * and zero or more other GP_SCRIPT_EVENT macros.
  *
- * @see ScriptController::executeFunction
+ * @param eventName The name of the script event.
+ * @param eventArgs A string of arguments to be passed to the script event, using
+ *      the format specified in ScriptController::executeFunction.
  *
  * @script{ignore}
  */
 #define GP_SCRIPT_EVENT(eventName, eventArgs) \
-    static const gameplay::ScriptTarget::EventRegistry::Event* SCRIPT_EVENT_ ## eventName = __eventRegistry.addEvent(#eventName, eventArgs)
+        struct SCRIPT_EVENT_ ## eventName \
+        { \
+            SCRIPT_EVENT_ ## eventName() \
+            { \
+                getEvent(); \
+            } \
+            static const ScriptTarget::Event* getEvent() \
+            { \
+                static const ScriptTarget::Event* event = ScriptEvents::getInstance()->getRegistry()->addEvent(#eventName, eventArgs); \
+                return event; \
+            } \
+        }; \
+        SCRIPT_EVENT_ ## eventName eventName;
+
+/**
+ * Macro to indiate the end of a series of script event defintions.
+ *
+ * @script{ignore}
+ */
+#define GP_SCRIPT_EVENTS_END() \
+    private: \
+        ScriptEvents() { } \
+    };
+
+/**
+ * Macro used to retrieve a script event object the given class name.
+ *
+ * @param eventClass The C++ class that contains the specified script event.
+ * @param eventName The name of the registered script event to retrieve.
+ *
+ * @script{ignore}
+ */
+#define GP_GET_SCRIPT_EVENT(eventClass, eventName) \
+    eventClass ## ::ScriptEvents::getInstance()-> ## eventName ## .getEvent()
+
 
 /**
  * Registers the defined script events for a ScriptTarget.
  *
- * This macro should be called in the constructor of a ScriptTarget
- * child class implementation. It requires that GP_SCRIPT_EVENT
- * macros be defined (normally at the top of the compilation unit).
+ * This macro should be called at the beginning of all constructors of a
+ * ScriptTarget child class that contains one or more script event 
+ * declarations (via the GP_SCRIPT_EVENT macro).
  *
  * @script{ignore}
  */
 #define GP_REGISTER_SCRIPT_EVENTS() \
-    ScriptTarget::registerEvents(&__eventRegistry)
+    ScriptTarget::registerEvents(ScriptEvents::getInstance()->getRegistry())
 
 /**
  * Defines an interface for supporting script callbacks.
@@ -61,43 +101,56 @@ class ScriptTarget
 
 public:
 
+    /**
+     * Defines a single script event.
+     */
+    class Event
+    {
+        friend class ScriptTarget;
+
+    public:
+
+        /**
+         * Returns the name of this event.
+         *
+         * @return The event name.
+         */
+        const char* getName() const;
+
+        /**
+         * Returns the argument string for this event.
+         *
+         * @return The argument string.
+         */
+        const char* getArgs() const;
+
+    private:
+
+        /**
+         * The event name.
+         */
+        std::string name;
+
+        /**
+         * The event arguments.
+         *
+         * @see ScriptController::executeFunction
+         */
+        std::string args;
+
+    };
+
     /**
      * Script event registry that defines the supported script events
      * for a ScriptTarget.
      *
      * This class should generally only be used via the GP_REGISTER_SCRIPT_EVENTS macro.
-     *
-     * @script{ignore}
      */
     class EventRegistry
     {
         friend class ScriptTarget;
-    public:
 
-        /**
-         * Defines a single script event.
-         *
-         * @script{ignore}
-         */
-        struct Event
-        {
-            /**
-             * The event name.
-             */
-            std::string name;
-
-            /**
-             * The event arguments.
-             *
-             * @see ScriptController::executeFunction
-             */
-            std::string args;
-
-            /**
-             * The EventRegistry this event belongs to.
-             */
-            EventRegistry* registry;
-        };
+    public:
 
         /**
          * Creates an empty event registry.
@@ -137,6 +190,15 @@ public:
          */
         const Event* getEvent(unsigned int index) const;
 
+        /**
+         * Returns the event that matches the given name.
+         *
+         * @param name The name of the event to search for.
+         *
+         * @return The matching event, or NULL if no such event exists.
+         */
+        const Event* getEvent(const char* name) const;
+
     private:
 
         std::vector<Event*> _events;
@@ -146,17 +208,21 @@ public:
      * Attaches a script to this object.
      *
      * @param path Path to the script.
+     * @param scope The scope for the script.
+     *
      * @return A pointer to the successfully loaded script, or NULL if unsuccessful.
      */
-    Script* addScript(const char* path);
+    Script* addScript(const char* path, Script::Scope scope);
 
     /**
      * Removes a previously attached script from this object.
      *
-     * @param path The same path that was used to load the script.
+     * @param path The same path that was used to load the script being removed.
+     * @param scope The same scope that was used to load the script being removed.
+     *
      * @return True if a script is successfully removed, false otherwise.
      */
-    bool removeScript(const char* path);
+    bool removeScript(const char* path, Script::Scope scope);
 
     /**
      * Adds the given global script function as a callback for the given event.
@@ -185,35 +251,75 @@ public:
      * Determines if there is a script installed that is listening for the given script
      * event (i.e. has a function callback defined for the given event).
      *
-     * @param evt The script event to check.
+     * @param eventName The script event to check.
+     *
+     * @return True if there is a listener for the specified event, false otherwise.
+     */
+    bool hasScriptListener(const char* eventName) const;
+
+    /**
+     * Determines if there is a script installed that is listening for the given script
+     * event (i.e. has a function callback defined for the given event).
+     *
+     * @param event The script event to check.
      *
      * @return True if there is a listener for the specified event, false otherwise.
+     */
+    bool hasScriptListener(const Event* event) const;
+
+    /**
+     * Fires the specified script event, passing the specified arguments.
+     *
+     * The only supported return types are void and boolean. When a boolean
+     * return type is used and there are multiple scripts registered for the
+     * given script event, event delegation will stop at the first script
+     * that returns a value of true.
+     * 
+     * @param event The script event to fire, which was returned from EventRegistry::addEvent.
+     * @param ... Optional list of arguments to pass to the script event (should match the
+     *      script event argument definition).
      *
      * @script{ignore}
      */
-    bool hasScriptListener(const EventRegistry::Event* evt) const;
+    template<typename T> T fireScriptEvent(const Event* event, ...);
 
 protected:
 
     /**
-     * Stores a registered script callback.
+     * Stores an EventRegistry entry for a ScriptTarget.
      */
-    struct Callback
+    struct RegistryEntry
+    {
+        EventRegistry* registry;
+        RegistryEntry* next;
+        RegistryEntry* prev;
+
+        RegistryEntry(EventRegistry* registry) : registry(registry), next(NULL), prev(NULL) { }
+    };
+
+    /**
+     * Stores a Script that is registered for a ScriptTarget.
+     */
+    struct ScriptEntry
     {
-        // The script the callback belongs to
+        Script* script;
+        ScriptEntry* next;
+        ScriptEntry* prev;
+        ScriptEntry(Script* script) : script(script), next(NULL), prev(NULL) { }
+    };
+
+    /**
+     * Stores a single registered script callback function.
+     */
+    struct CallbackFunction
+    {
+        // The script the callback belongs to (or NULL if the callback is a global function)
         Script* script;
 
         // The function within the script to call
         std::string function;
 
-        // The script event this callback is for
-        const EventRegistry::Event* event;
-
-        // Linked list info
-        Callback* next;
-        Callback* prev;
-
-        Callback() : script(NULL), event(NULL), next(NULL), prev(NULL) { }
+        CallbackFunction(Script* script, const char* function) : script(script), function(function) { }
     };
 
     /**
@@ -229,7 +335,7 @@ protected:
     /**
      * Removes the specified script.
      */
-    void removeScript(Script* script);
+    void removeScript(ScriptEntry* se);
 
     /**
      * Registers a set of supported script events and event arguments for this ScriptTarget. 
@@ -246,35 +352,23 @@ protected:
      */
     void registerEvents(EventRegistry* registry);
 
-    /**
-     * Fires the specified script event, passing the specified arguments.
-     *
-     * The only supported return types are void and boolean. When a boolean
-     * return type is used and there are multiple scripts registered for the
-     * given script event, event delegation will stop at the first script
-     * that returns a value of true.
-     * 
-     * @param evt The script event to fire, which was returned from EventRegistry::addEvent.
-     * @param ... Optional list of arguments to pass to the script event (should match the
-     *      script event argument definition).
-     */
-    template<typename T> T fireScriptEvent(const EventRegistry::Event* evt, ...);
-
-    /** Holds the registered events for this script target. */
-    std::vector<EventRegistry*>* _events;
+    /** Holds the event registries for this script target. */
+    RegistryEntry* _scriptRegistries;
     /** Holds the list of scripts referenced by this ScriptTarget. */
-    Script* _scripts;
+    ScriptEntry* _scripts;
+    /** Holds the list of callback functions registered for this ScriptTarget. */
+    std::map<const Event*, std::vector<CallbackFunction>>* _scriptCallbacks;
 };
 
-template<typename T> T ScriptTarget::fireScriptEvent(const EventRegistry::Event* evt, ...)
+template<typename T> T ScriptTarget::fireScriptEvent(const Event* evt, ...)
 {
     GP_ERROR("Unsupported return type for template function ScriptTarget::fireScriptEvent.");
 }
 
 /** Template specialization. */
-template<> void ScriptTarget::fireScriptEvent<void>(const EventRegistry::Event* evt, ...);
+template<> void ScriptTarget::fireScriptEvent<void>(const Event* event, ...);
 /** Template specialization. */
-template<> bool ScriptTarget::fireScriptEvent<bool>(const EventRegistry::Event* evt, ...);
+template<> bool ScriptTarget::fireScriptEvent<bool>(const Event* event, ...);
 
 }
 

+ 1 - 6
gameplay/src/Transform.cpp

@@ -3,11 +3,6 @@
 #include "Game.h"
 #include "Node.h"
 
-/** @script{ignore} */
-GP_SCRIPT_EVENTS();
-/** @script{ignore} */
-GP_SCRIPT_EVENT(transformChanged, "<Transform>");
-
 namespace gameplay
 {
 
@@ -1000,7 +995,7 @@ void Transform::transformChanged()
             l.listener->transformChanged(this, l.cookie);
         }
     }
-    fireScriptEvent<void>(SCRIPT_EVENT_transformChanged, this);
+    fireScriptEvent<void>(GP_GET_SCRIPT_EVENT(Transform, transformChanged), this);
 }
 
 void Transform::cloneInto(Transform* transform, NodeCloneContext &context) const

+ 5 - 2
gameplay/src/Transform.h

@@ -1,12 +1,11 @@
 #ifndef TRANSFORM_H_
 #define TRANSFORM_H_
 
-#include "Ref.h"
+#include "ScriptTarget.h"
 #include "Vector3.h"
 #include "Quaternion.h"
 #include "Matrix.h"
 #include "AnimationTarget.h"
-#include "ScriptTarget.h"
 
 namespace gameplay
 {
@@ -31,6 +30,10 @@ class ScriptListener;
  */
 class Transform : public AnimationTarget, public ScriptTarget
 {
+    GP_SCRIPT_EVENTS_START();
+    GP_SCRIPT_EVENT(transformChanged, "<Transform>");
+    GP_SCRIPT_EVENTS_END();
+
 public:
 
     /**

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

@@ -6,8 +6,6 @@
 #include "Game.h"
 #include "Node.h"
 #include "Ref.h"
-#include "ScriptController.h"
-#include "ScriptTarget.h"
 
 namespace gameplay
 {
@@ -17,15 +15,12 @@ void luaRegister_AIAgent()
     const luaL_Reg lua_members[] = 
     {
         {"addRef", lua_AIAgent_addRef},
-        {"addScript", lua_AIAgent_addScript},
-        {"clearScripts", lua_AIAgent_clearScripts},
         {"getId", lua_AIAgent_getId},
         {"getNode", lua_AIAgent_getNode},
         {"getRefCount", lua_AIAgent_getRefCount},
         {"getStateMachine", lua_AIAgent_getStateMachine},
         {"isEnabled", lua_AIAgent_isEnabled},
         {"release", lua_AIAgent_release},
-        {"removeScript", lua_AIAgent_removeScript},
         {"setEnabled", lua_AIAgent_setEnabled},
         {"setListener", lua_AIAgent_setListener},
         {NULL, NULL}
@@ -117,77 +112,6 @@ int lua_AIAgent_addRef(lua_State* state)
     return 0;
 }
 
-int lua_AIAgent_addScript(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 = gameplay::ScriptUtil::getString(2, false);
-
-                AIAgent* instance = getInstance(state);
-                int result = instance->addScript(param1);
-
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
-
-                return 1;
-            }
-
-            lua_pushstring(state, "lua_AIAgent_addScript - 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_clearScripts(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->clearScripts();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_AIAgent_clearScripts - 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.
@@ -413,45 +337,6 @@ int lua_AIAgent_release(lua_State* state)
     return 0;
 }
 
-int lua_AIAgent_removeScript(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 = gameplay::ScriptUtil::getString(2, false);
-
-                AIAgent* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
-
-                // Push the return value onto the stack.
-                lua_pushboolean(state, result);
-
-                return 1;
-            }
-
-            lua_pushstring(state, "lua_AIAgent_removeScript - 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_setEnabled(lua_State* state)
 {
     // Get the number of parameters.

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

@@ -7,15 +7,12 @@ namespace gameplay
 // Lua bindings for AIAgent.
 int lua_AIAgent__gc(lua_State* state);
 int lua_AIAgent_addRef(lua_State* state);
-int lua_AIAgent_addScript(lua_State* state);
-int lua_AIAgent_clearScripts(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_removeScript(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);

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

@@ -6,8 +6,6 @@
 #include "Game.h"
 #include "Node.h"
 #include "Ref.h"
-#include "ScriptController.h"
-#include "ScriptTarget.h"
 
 namespace gameplay
 {

+ 2 - 115
gameplay/src/lua/lua_AIState.cpp

@@ -1,13 +1,13 @@
 #include "Base.h"
 #include "ScriptController.h"
 #include "lua_AIState.h"
+#include "AIAgent.h"
 #include "AIState.h"
 #include "AIStateMachine.h"
 #include "Base.h"
 #include "Game.h"
+#include "Node.h"
 #include "Ref.h"
-#include "ScriptController.h"
-#include "ScriptTarget.h"
 
 namespace gameplay
 {
@@ -17,12 +17,9 @@ void luaRegister_AIState()
     const luaL_Reg lua_members[] = 
     {
         {"addRef", lua_AIState_addRef},
-        {"addScript", lua_AIState_addScript},
-        {"clearScripts", lua_AIState_clearScripts},
         {"getId", lua_AIState_getId},
         {"getRefCount", lua_AIState_getRefCount},
         {"release", lua_AIState_release},
-        {"removeScript", lua_AIState_removeScript},
         {"setListener", lua_AIState_setListener},
         {NULL, NULL}
     };
@@ -113,77 +110,6 @@ int lua_AIState_addRef(lua_State* state)
     return 0;
 }
 
-int lua_AIState_addScript(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 = gameplay::ScriptUtil::getString(2, false);
-
-                AIState* instance = getInstance(state);
-                int result = instance->addScript(param1);
-
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
-
-                return 1;
-            }
-
-            lua_pushstring(state, "lua_AIState_addScript - 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_clearScripts(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->clearScripts();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_AIState_clearScripts - 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.
@@ -286,45 +212,6 @@ int lua_AIState_release(lua_State* state)
     return 0;
 }
 
-int lua_AIState_removeScript(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 = gameplay::ScriptUtil::getString(2, false);
-
-                AIState* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
-
-                // Push the return value onto the stack.
-                lua_pushboolean(state, result);
-
-                return 1;
-            }
-
-            lua_pushstring(state, "lua_AIState_removeScript - 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_setListener(lua_State* state)
 {
     // Get the number of parameters.

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

@@ -7,12 +7,9 @@ namespace gameplay
 // Lua bindings for AIState.
 int lua_AIState__gc(lua_State* state);
 int lua_AIState_addRef(lua_State* state);
-int lua_AIState_addScript(lua_State* state);
-int lua_AIState_clearScripts(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_removeScript(lua_State* state);
 int lua_AIState_setListener(lua_State* state);
 int lua_AIState_static_create(lua_State* state);
 

+ 2 - 2
gameplay/src/lua/lua_AIStateListener.cpp

@@ -1,13 +1,13 @@
 #include "Base.h"
 #include "ScriptController.h"
 #include "lua_AIStateListener.h"
+#include "AIAgent.h"
 #include "AIState.h"
 #include "AIStateMachine.h"
 #include "Base.h"
 #include "Game.h"
+#include "Node.h"
 #include "Ref.h"
-#include "ScriptController.h"
-#include "ScriptTarget.h"
 
 namespace gameplay
 {

+ 359 - 180
gameplay/src/lua/lua_AnimationClip.cpp

@@ -9,6 +9,7 @@
 #include "Quaternion.h"
 #include "Ref.h"
 #include "ScriptController.h"
+#include "ScriptTarget.h"
 
 namespace gameplay
 {
@@ -21,6 +22,9 @@ void luaRegister_AnimationClip()
         {"addEndListener", lua_AnimationClip_addEndListener},
         {"addListener", lua_AnimationClip_addListener},
         {"addRef", lua_AnimationClip_addRef},
+        {"addScript", lua_AnimationClip_addScript},
+        {"addScriptCallback", lua_AnimationClip_addScriptCallback},
+        {"clearScripts", lua_AnimationClip_clearScripts},
         {"crossFade", lua_AnimationClip_crossFade},
         {"getActiveDuration", lua_AnimationClip_getActiveDuration},
         {"getAnimation", lua_AnimationClip_getAnimation},
@@ -34,6 +38,7 @@ void luaRegister_AnimationClip()
         {"getRepeatCount", lua_AnimationClip_getRepeatCount},
         {"getSpeed", lua_AnimationClip_getSpeed},
         {"getStartTime", lua_AnimationClip_getStartTime},
+        {"hasScriptListener", lua_AnimationClip_hasScriptListener},
         {"isPlaying", lua_AnimationClip_isPlaying},
         {"pause", lua_AnimationClip_pause},
         {"play", lua_AnimationClip_play},
@@ -41,6 +46,8 @@ void luaRegister_AnimationClip()
         {"removeBeginListener", lua_AnimationClip_removeBeginListener},
         {"removeEndListener", lua_AnimationClip_removeEndListener},
         {"removeListener", lua_AnimationClip_removeListener},
+        {"removeScript", lua_AnimationClip_removeScript},
+        {"removeScriptCallback", lua_AnimationClip_removeScriptCallback},
         {"setActiveDuration", lua_AnimationClip_setActiveDuration},
         {"setBlendWeight", lua_AnimationClip_setBlendWeight},
         {"setLoopBlendTime", lua_AnimationClip_setLoopBlendTime},
@@ -114,38 +121,23 @@ int lua_AnimationClip_addBeginListener(lua_State* state)
     {
         case 2:
         {
-            do
+            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))
             {
-                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.
+                bool param1Valid;
+                gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
+                if (!param1Valid)
                 {
-                    // Get parameter 1 off the stack.
-                    bool param1Valid;
-                    gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
-                    if (!param1Valid)
-                        break;
-
-                    AnimationClip* instance = getInstance(state);
-                    instance->addBeginListener(param1);
-                    
-                    return 0;
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'AnimationClip::Listener'.");
+                    lua_error(state);
                 }
-            } while (0);
 
-            do
-            {
-                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 = gameplay::ScriptUtil::getString(2, false);
-
-                    AnimationClip* instance = getInstance(state);
-                    instance->addBeginListener(param1);
-                    
-                    return 0;
-                }
-            } while (0);
+                AnimationClip* instance = getInstance(state);
+                instance->addBeginListener(param1);
+                
+                return 0;
+            }
 
             lua_pushstring(state, "lua_AnimationClip_addBeginListener - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
@@ -171,38 +163,23 @@ int lua_AnimationClip_addEndListener(lua_State* state)
     {
         case 2:
         {
-            do
+            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))
             {
-                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.
+                bool param1Valid;
+                gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
+                if (!param1Valid)
                 {
-                    // Get parameter 1 off the stack.
-                    bool param1Valid;
-                    gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
-                    if (!param1Valid)
-                        break;
-
-                    AnimationClip* instance = getInstance(state);
-                    instance->addEndListener(param1);
-                    
-                    return 0;
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'AnimationClip::Listener'.");
+                    lua_error(state);
                 }
-            } while (0);
 
-            do
-            {
-                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 = gameplay::ScriptUtil::getString(2, false);
-
-                    AnimationClip* instance = getInstance(state);
-                    instance->addEndListener(param1);
-                    
-                    return 0;
-                }
-            } while (0);
+                AnimationClip* instance = getInstance(state);
+                instance->addEndListener(param1);
+                
+                return 0;
+            }
 
             lua_pushstring(state, "lua_AnimationClip_addEndListener - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
@@ -228,46 +205,27 @@ int lua_AnimationClip_addListener(lua_State* state)
     {
         case 3:
         {
-            do
+            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)
             {
-                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.
+                bool param1Valid;
+                gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
+                if (!param1Valid)
                 {
-                    // Get parameter 1 off the stack.
-                    bool param1Valid;
-                    gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
-                    if (!param1Valid)
-                        break;
-
-                    // Get parameter 2 off the stack.
-                    unsigned long param2 = (unsigned long)luaL_checkunsigned(state, 3);
-
-                    AnimationClip* instance = getInstance(state);
-                    instance->addListener(param1, param2);
-                    
-                    return 0;
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'AnimationClip::Listener'.");
+                    lua_error(state);
                 }
-            } while (0);
 
-            do
-            {
-                if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                    (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
-                    lua_type(state, 3) == LUA_TNUMBER)
-                {
-                    // Get parameter 1 off the stack.
-                    const char* param1 = gameplay::ScriptUtil::getString(2, false);
-
-                    // Get parameter 2 off the stack.
-                    unsigned long param2 = (unsigned long)luaL_checkunsigned(state, 3);
+                // Get parameter 2 off the stack.
+                unsigned long param2 = (unsigned long)luaL_checkunsigned(state, 3);
 
-                    AnimationClip* instance = getInstance(state);
-                    instance->addListener(param1, param2);
-                    
-                    return 0;
-                }
-            } while (0);
+                AnimationClip* instance = getInstance(state);
+                instance->addListener(param1, param2);
+                
+                return 0;
+            }
 
             lua_pushstring(state, "lua_AnimationClip_addListener - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
@@ -315,6 +273,130 @@ int lua_AnimationClip_addRef(lua_State* state)
     return 0;
 }
 
+int lua_AnimationClip_addScript(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
+                AnimationClip* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_AnimationClip_addScript - 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_AnimationClip_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                AnimationClip* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_AnimationClip_addScriptCallback - 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_AnimationClip_clearScripts(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))
+            {
+                AnimationClip* instance = getInstance(state);
+                instance->clearScripts();
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_AnimationClip_clearScripts - 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_AnimationClip_crossFade(lua_State* state)
 {
     // Get the number of parameters.
@@ -790,6 +872,69 @@ int lua_AnimationClip_getStartTime(lua_State* state)
     return 0;
 }
 
+int lua_AnimationClip_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    AnimationClip* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    AnimationClip* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_AnimationClip_hasScriptListener - 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_AnimationClip_isPlaying(lua_State* state)
 {
     // Get the number of parameters.
@@ -931,38 +1076,23 @@ int lua_AnimationClip_removeBeginListener(lua_State* state)
     {
         case 2:
         {
-            do
+            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))
             {
-                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.
+                bool param1Valid;
+                gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
+                if (!param1Valid)
                 {
-                    // Get parameter 1 off the stack.
-                    bool param1Valid;
-                    gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
-                    if (!param1Valid)
-                        break;
-
-                    AnimationClip* instance = getInstance(state);
-                    instance->removeBeginListener(param1);
-                    
-                    return 0;
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'AnimationClip::Listener'.");
+                    lua_error(state);
                 }
-            } while (0);
-
-            do
-            {
-                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 = gameplay::ScriptUtil::getString(2, false);
 
-                    AnimationClip* instance = getInstance(state);
-                    instance->removeBeginListener(param1);
-                    
-                    return 0;
-                }
-            } while (0);
+                AnimationClip* instance = getInstance(state);
+                instance->removeBeginListener(param1);
+                
+                return 0;
+            }
 
             lua_pushstring(state, "lua_AnimationClip_removeBeginListener - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
@@ -988,38 +1118,23 @@ int lua_AnimationClip_removeEndListener(lua_State* state)
     {
         case 2:
         {
-            do
+            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))
             {
-                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.
+                bool param1Valid;
+                gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
+                if (!param1Valid)
                 {
-                    // Get parameter 1 off the stack.
-                    bool param1Valid;
-                    gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
-                    if (!param1Valid)
-                        break;
-
-                    AnimationClip* instance = getInstance(state);
-                    instance->removeEndListener(param1);
-                    
-                    return 0;
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'AnimationClip::Listener'.");
+                    lua_error(state);
                 }
-            } while (0);
 
-            do
-            {
-                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 = gameplay::ScriptUtil::getString(2, false);
-
-                    AnimationClip* instance = getInstance(state);
-                    instance->removeEndListener(param1);
-                    
-                    return 0;
-                }
-            } while (0);
+                AnimationClip* instance = getInstance(state);
+                instance->removeEndListener(param1);
+                
+                return 0;
+            }
 
             lua_pushstring(state, "lua_AnimationClip_removeEndListener - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
@@ -1045,48 +1160,112 @@ int lua_AnimationClip_removeListener(lua_State* state)
     {
         case 3:
         {
-            do
+            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)
             {
-                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.
+                bool param1Valid;
+                gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
+                if (!param1Valid)
                 {
-                    // Get parameter 1 off the stack.
-                    bool param1Valid;
-                    gameplay::ScriptUtil::LuaArray<AnimationClip::Listener> param1 = gameplay::ScriptUtil::getObjectPointer<AnimationClip::Listener>(2, "AnimationClipListener", false, &param1Valid);
-                    if (!param1Valid)
-                        break;
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'AnimationClip::Listener'.");
+                    lua_error(state);
+                }
 
-                    // Get parameter 2 off the stack.
-                    unsigned long param2 = (unsigned long)luaL_checkunsigned(state, 3);
+                // Get parameter 2 off the stack.
+                unsigned long param2 = (unsigned long)luaL_checkunsigned(state, 3);
 
-                    AnimationClip* instance = getInstance(state);
-                    instance->removeListener(param1, param2);
-                    
-                    return 0;
-                }
-            } while (0);
+                AnimationClip* instance = getInstance(state);
+                instance->removeListener(param1, param2);
+                
+                return 0;
+            }
 
-            do
+            lua_pushstring(state, "lua_AnimationClip_removeListener - 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_AnimationClip_removeScript(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
-                if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                    (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
-                    lua_type(state, 3) == LUA_TNUMBER)
-                {
-                    // Get parameter 1 off the stack.
-                    const char* param1 = gameplay::ScriptUtil::getString(2, false);
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                    // Get parameter 2 off the stack.
-                    unsigned long param2 = (unsigned long)luaL_checkunsigned(state, 3);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                    AnimationClip* instance = getInstance(state);
-                    instance->removeListener(param1, param2);
-                    
-                    return 0;
-                }
-            } while (0);
+                AnimationClip* instance = getInstance(state);
+                bool result = instance->removeScript(param1, param2);
 
-            lua_pushstring(state, "lua_AnimationClip_removeListener - Failed to match the given parameters to a valid function signature.");
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_AnimationClip_removeScript - 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_AnimationClip_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                AnimationClip* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_AnimationClip_removeScriptCallback - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
             break;
         }

+ 6 - 0
gameplay/src/lua/lua_AnimationClip.h

@@ -10,6 +10,9 @@ int lua_AnimationClip_addBeginListener(lua_State* state);
 int lua_AnimationClip_addEndListener(lua_State* state);
 int lua_AnimationClip_addListener(lua_State* state);
 int lua_AnimationClip_addRef(lua_State* state);
+int lua_AnimationClip_addScript(lua_State* state);
+int lua_AnimationClip_addScriptCallback(lua_State* state);
+int lua_AnimationClip_clearScripts(lua_State* state);
 int lua_AnimationClip_crossFade(lua_State* state);
 int lua_AnimationClip_getActiveDuration(lua_State* state);
 int lua_AnimationClip_getAnimation(lua_State* state);
@@ -23,6 +26,7 @@ int lua_AnimationClip_getRefCount(lua_State* state);
 int lua_AnimationClip_getRepeatCount(lua_State* state);
 int lua_AnimationClip_getSpeed(lua_State* state);
 int lua_AnimationClip_getStartTime(lua_State* state);
+int lua_AnimationClip_hasScriptListener(lua_State* state);
 int lua_AnimationClip_isPlaying(lua_State* state);
 int lua_AnimationClip_pause(lua_State* state);
 int lua_AnimationClip_play(lua_State* state);
@@ -30,6 +34,8 @@ int lua_AnimationClip_release(lua_State* state);
 int lua_AnimationClip_removeBeginListener(lua_State* state);
 int lua_AnimationClip_removeEndListener(lua_State* state);
 int lua_AnimationClip_removeListener(lua_State* state);
+int lua_AnimationClip_removeScript(lua_State* state);
+int lua_AnimationClip_removeScriptCallback(lua_State* state);
 int lua_AnimationClip_setActiveDuration(lua_State* state);
 int lua_AnimationClip_setBlendWeight(lua_State* state);
 int lua_AnimationClip_setLoopBlendTime(lua_State* state);

+ 1 - 0
gameplay/src/lua/lua_AnimationClipListener.cpp

@@ -9,6 +9,7 @@
 #include "Quaternion.h"
 #include "Ref.h"
 #include "ScriptController.h"
+#include "ScriptTarget.h"
 
 namespace gameplay
 {

+ 174 - 11
gameplay/src/lua/lua_Button.cpp

@@ -26,6 +26,7 @@ void luaRegister_Button()
         {"addListener", lua_Button_addListener},
         {"addRef", lua_Button_addRef},
         {"addScript", lua_Button_addScript},
+        {"addScriptCallback", lua_Button_addScriptCallback},
         {"canFocus", lua_Button_canFocus},
         {"clearScripts", lua_Button_clearScripts},
         {"createAnimation", lua_Button_createAnimation},
@@ -74,6 +75,7 @@ void luaRegister_Button()
         {"getY", lua_Button_getY},
         {"getZIndex", lua_Button_getZIndex},
         {"hasFocus", lua_Button_hasFocus},
+        {"hasScriptListener", lua_Button_hasScriptListener},
         {"isChild", lua_Button_isChild},
         {"isContainer", lua_Button_isContainer},
         {"isEnabled", lua_Button_isEnabled},
@@ -87,6 +89,7 @@ void luaRegister_Button()
         {"release", lua_Button_release},
         {"removeListener", lua_Button_removeListener},
         {"removeScript", lua_Button_removeScript},
+        {"removeScriptCallback", lua_Button_removeScriptCallback},
         {"setAlignment", lua_Button_setAlignment},
         {"setAnimationPropertyValue", lua_Button_setAnimationPropertyValue},
         {"setAutoSize", lua_Button_setAutoSize},
@@ -272,19 +275,32 @@ int lua_Button_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Button* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Button* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -295,7 +311,47 @@ int lua_Button_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Button_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Button* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Button_addScriptCallback - 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;
         }
@@ -2742,6 +2798,69 @@ int lua_Button_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_Button_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Button* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Button* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Button_hasScriptListener - 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_Button_isChild(lua_State* state)
 {
     // Get the number of parameters.
@@ -3184,16 +3303,20 @@ int lua_Button_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Button* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3207,7 +3330,47 @@ int lua_Button_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Button_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Button* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Button_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_Button.h

@@ -9,6 +9,7 @@ int lua_Button__gc(lua_State* state);
 int lua_Button_addListener(lua_State* state);
 int lua_Button_addRef(lua_State* state);
 int lua_Button_addScript(lua_State* state);
+int lua_Button_addScriptCallback(lua_State* state);
 int lua_Button_canFocus(lua_State* state);
 int lua_Button_clearScripts(lua_State* state);
 int lua_Button_createAnimation(lua_State* state);
@@ -57,6 +58,7 @@ int lua_Button_getX(lua_State* state);
 int lua_Button_getY(lua_State* state);
 int lua_Button_getZIndex(lua_State* state);
 int lua_Button_hasFocus(lua_State* state);
+int lua_Button_hasScriptListener(lua_State* state);
 int lua_Button_isChild(lua_State* state);
 int lua_Button_isContainer(lua_State* state);
 int lua_Button_isEnabled(lua_State* state);
@@ -70,6 +72,7 @@ int lua_Button_isYPercentage(lua_State* state);
 int lua_Button_release(lua_State* state);
 int lua_Button_removeListener(lua_State* state);
 int lua_Button_removeScript(lua_State* state);
+int lua_Button_removeScriptCallback(lua_State* state);
 int lua_Button_setAlignment(lua_State* state);
 int lua_Button_setAnimationPropertyValue(lua_State* state);
 int lua_Button_setAutoSize(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_CheckBox.cpp

@@ -27,6 +27,7 @@ void luaRegister_CheckBox()
         {"addListener", lua_CheckBox_addListener},
         {"addRef", lua_CheckBox_addRef},
         {"addScript", lua_CheckBox_addScript},
+        {"addScriptCallback", lua_CheckBox_addScriptCallback},
         {"canFocus", lua_CheckBox_canFocus},
         {"clearScripts", lua_CheckBox_clearScripts},
         {"createAnimation", lua_CheckBox_createAnimation},
@@ -76,6 +77,7 @@ void luaRegister_CheckBox()
         {"getY", lua_CheckBox_getY},
         {"getZIndex", lua_CheckBox_getZIndex},
         {"hasFocus", lua_CheckBox_hasFocus},
+        {"hasScriptListener", lua_CheckBox_hasScriptListener},
         {"isChecked", lua_CheckBox_isChecked},
         {"isChild", lua_CheckBox_isChild},
         {"isContainer", lua_CheckBox_isContainer},
@@ -90,6 +92,7 @@ void luaRegister_CheckBox()
         {"release", lua_CheckBox_release},
         {"removeListener", lua_CheckBox_removeListener},
         {"removeScript", lua_CheckBox_removeScript},
+        {"removeScriptCallback", lua_CheckBox_removeScriptCallback},
         {"setAlignment", lua_CheckBox_setAlignment},
         {"setAnimationPropertyValue", lua_CheckBox_setAnimationPropertyValue},
         {"setAutoSize", lua_CheckBox_setAutoSize},
@@ -276,19 +279,32 @@ int lua_CheckBox_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                CheckBox* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                CheckBox* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -299,7 +315,47 @@ int lua_CheckBox_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_CheckBox_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                CheckBox* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_CheckBox_addScriptCallback - 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;
         }
@@ -2781,6 +2837,69 @@ int lua_CheckBox_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_CheckBox_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    CheckBox* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    CheckBox* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_CheckBox_hasScriptListener - 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_CheckBox_isChecked(lua_State* state)
 {
     // Get the number of parameters.
@@ -3258,16 +3377,20 @@ int lua_CheckBox_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 CheckBox* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3281,7 +3404,47 @@ int lua_CheckBox_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_CheckBox_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                CheckBox* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_CheckBox_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_CheckBox.h

@@ -9,6 +9,7 @@ int lua_CheckBox__gc(lua_State* state);
 int lua_CheckBox_addListener(lua_State* state);
 int lua_CheckBox_addRef(lua_State* state);
 int lua_CheckBox_addScript(lua_State* state);
+int lua_CheckBox_addScriptCallback(lua_State* state);
 int lua_CheckBox_canFocus(lua_State* state);
 int lua_CheckBox_clearScripts(lua_State* state);
 int lua_CheckBox_createAnimation(lua_State* state);
@@ -58,6 +59,7 @@ int lua_CheckBox_getX(lua_State* state);
 int lua_CheckBox_getY(lua_State* state);
 int lua_CheckBox_getZIndex(lua_State* state);
 int lua_CheckBox_hasFocus(lua_State* state);
+int lua_CheckBox_hasScriptListener(lua_State* state);
 int lua_CheckBox_isChecked(lua_State* state);
 int lua_CheckBox_isChild(lua_State* state);
 int lua_CheckBox_isContainer(lua_State* state);
@@ -72,6 +74,7 @@ int lua_CheckBox_isYPercentage(lua_State* state);
 int lua_CheckBox_release(lua_State* state);
 int lua_CheckBox_removeListener(lua_State* state);
 int lua_CheckBox_removeScript(lua_State* state);
+int lua_CheckBox_removeScriptCallback(lua_State* state);
 int lua_CheckBox_setAlignment(lua_State* state);
 int lua_CheckBox_setAnimationPropertyValue(lua_State* state);
 int lua_CheckBox_setAutoSize(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_Container.cpp

@@ -38,6 +38,7 @@ void luaRegister_Container()
         {"addListener", lua_Container_addListener},
         {"addRef", lua_Container_addRef},
         {"addScript", lua_Container_addScript},
+        {"addScriptCallback", lua_Container_addScriptCallback},
         {"canFocus", lua_Container_canFocus},
         {"clearScripts", lua_Container_clearScripts},
         {"createAnimation", lua_Container_createAnimation},
@@ -95,6 +96,7 @@ void luaRegister_Container()
         {"getY", lua_Container_getY},
         {"getZIndex", lua_Container_getZIndex},
         {"hasFocus", lua_Container_hasFocus},
+        {"hasScriptListener", lua_Container_hasScriptListener},
         {"insertControl", lua_Container_insertControl},
         {"isChild", lua_Container_isChild},
         {"isContainer", lua_Container_isContainer},
@@ -114,6 +116,7 @@ void luaRegister_Container()
         {"removeControl", lua_Container_removeControl},
         {"removeListener", lua_Container_removeListener},
         {"removeScript", lua_Container_removeScript},
+        {"removeScriptCallback", lua_Container_removeScriptCallback},
         {"setActiveControl", lua_Container_setActiveControl},
         {"setAlignment", lua_Container_setAlignment},
         {"setAnimationPropertyValue", lua_Container_setAnimationPropertyValue},
@@ -353,19 +356,32 @@ int lua_Container_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Container* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Container* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -376,7 +392,47 @@ int lua_Container_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Container_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Container* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Container_addScriptCallback - 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;
         }
@@ -3208,6 +3264,69 @@ int lua_Container_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_Container_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Container* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Container* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Container_hasScriptListener - 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_Container_insertControl(lua_State* state)
 {
     // Get the number of parameters.
@@ -3912,16 +4031,20 @@ int lua_Container_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Container* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3935,7 +4058,47 @@ int lua_Container_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Container_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Container* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Container_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_Container.h

@@ -10,6 +10,7 @@ int lua_Container_addControl(lua_State* state);
 int lua_Container_addListener(lua_State* state);
 int lua_Container_addRef(lua_State* state);
 int lua_Container_addScript(lua_State* state);
+int lua_Container_addScriptCallback(lua_State* state);
 int lua_Container_canFocus(lua_State* state);
 int lua_Container_clearScripts(lua_State* state);
 int lua_Container_createAnimation(lua_State* state);
@@ -67,6 +68,7 @@ int lua_Container_getX(lua_State* state);
 int lua_Container_getY(lua_State* state);
 int lua_Container_getZIndex(lua_State* state);
 int lua_Container_hasFocus(lua_State* state);
+int lua_Container_hasScriptListener(lua_State* state);
 int lua_Container_insertControl(lua_State* state);
 int lua_Container_isChild(lua_State* state);
 int lua_Container_isContainer(lua_State* state);
@@ -86,6 +88,7 @@ int lua_Container_release(lua_State* state);
 int lua_Container_removeControl(lua_State* state);
 int lua_Container_removeListener(lua_State* state);
 int lua_Container_removeScript(lua_State* state);
+int lua_Container_removeScriptCallback(lua_State* state);
 int lua_Container_setActiveControl(lua_State* state);
 int lua_Container_setAlignment(lua_State* state);
 int lua_Container_setAnimationPropertyValue(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_Control.cpp

@@ -23,6 +23,7 @@ void luaRegister_Control()
         {"addListener", lua_Control_addListener},
         {"addRef", lua_Control_addRef},
         {"addScript", lua_Control_addScript},
+        {"addScriptCallback", lua_Control_addScriptCallback},
         {"canFocus", lua_Control_canFocus},
         {"clearScripts", lua_Control_clearScripts},
         {"createAnimation", lua_Control_createAnimation},
@@ -71,6 +72,7 @@ void luaRegister_Control()
         {"getY", lua_Control_getY},
         {"getZIndex", lua_Control_getZIndex},
         {"hasFocus", lua_Control_hasFocus},
+        {"hasScriptListener", lua_Control_hasScriptListener},
         {"isChild", lua_Control_isChild},
         {"isContainer", lua_Control_isContainer},
         {"isEnabled", lua_Control_isEnabled},
@@ -84,6 +86,7 @@ void luaRegister_Control()
         {"release", lua_Control_release},
         {"removeListener", lua_Control_removeListener},
         {"removeScript", lua_Control_removeScript},
+        {"removeScriptCallback", lua_Control_removeScriptCallback},
         {"setAlignment", lua_Control_setAlignment},
         {"setAnimationPropertyValue", lua_Control_setAnimationPropertyValue},
         {"setAutoSize", lua_Control_setAutoSize},
@@ -267,19 +270,32 @@ int lua_Control_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Control* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Control* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -290,7 +306,47 @@ int lua_Control_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Control_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Control* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Control_addScriptCallback - 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;
         }
@@ -2737,6 +2793,69 @@ int lua_Control_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_Control_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Control* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Control* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Control_hasScriptListener - 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_Control_isChild(lua_State* state)
 {
     // Get the number of parameters.
@@ -3179,16 +3298,20 @@ int lua_Control_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Control* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3202,7 +3325,47 @@ int lua_Control_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Control_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Control* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Control_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_Control.h

@@ -9,6 +9,7 @@ int lua_Control__gc(lua_State* state);
 int lua_Control_addListener(lua_State* state);
 int lua_Control_addRef(lua_State* state);
 int lua_Control_addScript(lua_State* state);
+int lua_Control_addScriptCallback(lua_State* state);
 int lua_Control_canFocus(lua_State* state);
 int lua_Control_clearScripts(lua_State* state);
 int lua_Control_createAnimation(lua_State* state);
@@ -57,6 +58,7 @@ int lua_Control_getX(lua_State* state);
 int lua_Control_getY(lua_State* state);
 int lua_Control_getZIndex(lua_State* state);
 int lua_Control_hasFocus(lua_State* state);
+int lua_Control_hasScriptListener(lua_State* state);
 int lua_Control_isChild(lua_State* state);
 int lua_Control_isContainer(lua_State* state);
 int lua_Control_isEnabled(lua_State* state);
@@ -70,6 +72,7 @@ int lua_Control_isYPercentage(lua_State* state);
 int lua_Control_release(lua_State* state);
 int lua_Control_removeListener(lua_State* state);
 int lua_Control_removeScript(lua_State* state);
+int lua_Control_removeScriptCallback(lua_State* state);
 int lua_Control_setAlignment(lua_State* state);
 int lua_Control_setAnimationPropertyValue(lua_State* state);
 int lua_Control_setAutoSize(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_Form.cpp

@@ -39,6 +39,7 @@ void luaRegister_Form()
         {"addListener", lua_Form_addListener},
         {"addRef", lua_Form_addRef},
         {"addScript", lua_Form_addScript},
+        {"addScriptCallback", lua_Form_addScriptCallback},
         {"canFocus", lua_Form_canFocus},
         {"clearScripts", lua_Form_clearScripts},
         {"createAnimation", lua_Form_createAnimation},
@@ -97,6 +98,7 @@ void luaRegister_Form()
         {"getY", lua_Form_getY},
         {"getZIndex", lua_Form_getZIndex},
         {"hasFocus", lua_Form_hasFocus},
+        {"hasScriptListener", lua_Form_hasScriptListener},
         {"insertControl", lua_Form_insertControl},
         {"isBatchingEnabled", lua_Form_isBatchingEnabled},
         {"isChild", lua_Form_isChild},
@@ -117,6 +119,7 @@ void luaRegister_Form()
         {"removeControl", lua_Form_removeControl},
         {"removeListener", lua_Form_removeListener},
         {"removeScript", lua_Form_removeScript},
+        {"removeScriptCallback", lua_Form_removeScriptCallback},
         {"setActiveControl", lua_Form_setActiveControl},
         {"setAlignment", lua_Form_setAlignment},
         {"setAnimationPropertyValue", lua_Form_setAnimationPropertyValue},
@@ -363,19 +366,32 @@ int lua_Form_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Form* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Form* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -386,7 +402,47 @@ int lua_Form_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Form_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Form* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Form_addScriptCallback - 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;
         }
@@ -3253,6 +3309,69 @@ int lua_Form_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_Form_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Form* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Form* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Form_hasScriptListener - 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_Form_insertControl(lua_State* state)
 {
     // Get the number of parameters.
@@ -3992,16 +4111,20 @@ int lua_Form_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Form* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -4015,7 +4138,47 @@ int lua_Form_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Form_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Form* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Form_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_Form.h

@@ -10,6 +10,7 @@ int lua_Form_addControl(lua_State* state);
 int lua_Form_addListener(lua_State* state);
 int lua_Form_addRef(lua_State* state);
 int lua_Form_addScript(lua_State* state);
+int lua_Form_addScriptCallback(lua_State* state);
 int lua_Form_canFocus(lua_State* state);
 int lua_Form_clearScripts(lua_State* state);
 int lua_Form_createAnimation(lua_State* state);
@@ -68,6 +69,7 @@ int lua_Form_getX(lua_State* state);
 int lua_Form_getY(lua_State* state);
 int lua_Form_getZIndex(lua_State* state);
 int lua_Form_hasFocus(lua_State* state);
+int lua_Form_hasScriptListener(lua_State* state);
 int lua_Form_insertControl(lua_State* state);
 int lua_Form_isBatchingEnabled(lua_State* state);
 int lua_Form_isChild(lua_State* state);
@@ -88,6 +90,7 @@ int lua_Form_release(lua_State* state);
 int lua_Form_removeControl(lua_State* state);
 int lua_Form_removeListener(lua_State* state);
 int lua_Form_removeScript(lua_State* state);
+int lua_Form_removeScriptCallback(lua_State* state);
 int lua_Form_setActiveControl(lua_State* state);
 int lua_Form_setAlignment(lua_State* state);
 int lua_Form_setAnimationPropertyValue(lua_State* state);

+ 38 - 1
gameplay/src/lua/lua_Game.cpp

@@ -86,7 +86,7 @@ void luaRegister_Game()
     };
     std::vector<std::string> scopePath;
 
-    gameplay::ScriptUtil::registerClass("Game", lua_members, NULL, lua_Game__gc, lua_statics, scopePath);
+    gameplay::ScriptUtil::registerClass("Game", lua_members, lua_Game__init, lua_Game__gc, lua_statics, scopePath);
 }
 
 static Game* getInstance(lua_State* state)
@@ -134,6 +134,43 @@ int lua_Game__gc(lua_State* state)
     return 0;
 }
 
+int lua_Game__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 Game();
+            if (returnPtr)
+            {
+                gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                object->instance = returnPtr;
+                object->owns = true;
+                luaL_getmetatable(state, "Game");
+                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_Game_canExit(lua_State* state)
 {
     // Get the number of parameters.

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

@@ -6,6 +6,7 @@ namespace gameplay
 
 // Lua bindings for Game.
 int lua_Game__gc(lua_State* state);
+int lua_Game__init(lua_State* state);
 int lua_Game_canExit(lua_State* state);
 int lua_Game_clear(lua_State* state);
 int lua_Game_clearSchedule(lua_State* state);

+ 12 - 2
gameplay/src/lua/lua_Global.cpp

@@ -26,6 +26,7 @@
 #include "PhysicsController.h"
 #include "Properties.h"
 #include "RenderState.h"
+#include "Script.h"
 #include "Terrain.h"
 #include "TextBox.h"
 #include "Texture.h"
@@ -131,6 +132,7 @@ void luaRegister_lua_Global()
     gameplay::ScriptUtil::setGlobalHierarchyPair("Ref", "RenderState::StateBlock");
     gameplay::ScriptUtil::setGlobalHierarchyPair("Ref", "RenderTarget");
     gameplay::ScriptUtil::setGlobalHierarchyPair("Ref", "Scene");
+    gameplay::ScriptUtil::setGlobalHierarchyPair("Ref", "Script");
     gameplay::ScriptUtil::setGlobalHierarchyPair("Ref", "Slider");
     gameplay::ScriptUtil::setGlobalHierarchyPair("Ref", "Technique");
     gameplay::ScriptUtil::setGlobalHierarchyPair("Ref", "Terrain");
@@ -144,8 +146,7 @@ void luaRegister_lua_Global()
     gameplay::ScriptUtil::setGlobalHierarchyPair("RenderState", "Material");
     gameplay::ScriptUtil::setGlobalHierarchyPair("RenderState", "Pass");
     gameplay::ScriptUtil::setGlobalHierarchyPair("RenderState", "Technique");
-    gameplay::ScriptUtil::setGlobalHierarchyPair("ScriptTarget", "AIAgent");
-    gameplay::ScriptUtil::setGlobalHierarchyPair("ScriptTarget", "AIState");
+    gameplay::ScriptUtil::setGlobalHierarchyPair("ScriptTarget", "AnimationClip");
     gameplay::ScriptUtil::setGlobalHierarchyPair("ScriptTarget", "Button");
     gameplay::ScriptUtil::setGlobalHierarchyPair("ScriptTarget", "CheckBox");
     gameplay::ScriptUtil::setGlobalHierarchyPair("ScriptTarget", "Container");
@@ -875,6 +876,15 @@ void luaRegister_lua_Global()
         gameplay::ScriptUtil::registerEnumValue(RenderState::STENCIL_OP_DECR_WRAP, "STENCIL_OP_DECR_WRAP", scopePath);
     }
 
+    // Register enumeration Script::Scope.
+    {
+        std::vector<std::string> scopePath;
+        scopePath.push_back("Script");
+        gameplay::ScriptUtil::registerEnumValue(Script::GLOBAL, "GLOBAL", scopePath);
+        gameplay::ScriptUtil::registerEnumValue(Script::PRIVATE_SHARED, "PRIVATE_SHARED", scopePath);
+        gameplay::ScriptUtil::registerEnumValue(Script::PRIVATE_INSTANCE, "PRIVATE_INSTANCE", scopePath);
+    }
+
     // Register enumeration Terrain::Flags.
     {
         std::vector<std::string> scopePath;

+ 174 - 11
gameplay/src/lua/lua_ImageControl.cpp

@@ -24,6 +24,7 @@ void luaRegister_ImageControl()
         {"addListener", lua_ImageControl_addListener},
         {"addRef", lua_ImageControl_addRef},
         {"addScript", lua_ImageControl_addScript},
+        {"addScriptCallback", lua_ImageControl_addScriptCallback},
         {"canFocus", lua_ImageControl_canFocus},
         {"clearScripts", lua_ImageControl_clearScripts},
         {"createAnimation", lua_ImageControl_createAnimation},
@@ -74,6 +75,7 @@ void luaRegister_ImageControl()
         {"getY", lua_ImageControl_getY},
         {"getZIndex", lua_ImageControl_getZIndex},
         {"hasFocus", lua_ImageControl_hasFocus},
+        {"hasScriptListener", lua_ImageControl_hasScriptListener},
         {"isChild", lua_ImageControl_isChild},
         {"isContainer", lua_ImageControl_isContainer},
         {"isEnabled", lua_ImageControl_isEnabled},
@@ -87,6 +89,7 @@ void luaRegister_ImageControl()
         {"release", lua_ImageControl_release},
         {"removeListener", lua_ImageControl_removeListener},
         {"removeScript", lua_ImageControl_removeScript},
+        {"removeScriptCallback", lua_ImageControl_removeScriptCallback},
         {"setAlignment", lua_ImageControl_setAlignment},
         {"setAnimationPropertyValue", lua_ImageControl_setAnimationPropertyValue},
         {"setAutoSize", lua_ImageControl_setAutoSize},
@@ -274,19 +277,32 @@ int lua_ImageControl_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                ImageControl* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                ImageControl* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -297,7 +313,47 @@ int lua_ImageControl_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_ImageControl_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                ImageControl* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_ImageControl_addScriptCallback - 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;
         }
@@ -2832,6 +2888,69 @@ int lua_ImageControl_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_ImageControl_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    ImageControl* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    ImageControl* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_ImageControl_hasScriptListener - 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_ImageControl_isChild(lua_State* state)
 {
     // Get the number of parameters.
@@ -3274,16 +3393,20 @@ int lua_ImageControl_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 ImageControl* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3297,7 +3420,47 @@ int lua_ImageControl_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_ImageControl_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                ImageControl* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_ImageControl_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_ImageControl.h

@@ -9,6 +9,7 @@ int lua_ImageControl__gc(lua_State* state);
 int lua_ImageControl_addListener(lua_State* state);
 int lua_ImageControl_addRef(lua_State* state);
 int lua_ImageControl_addScript(lua_State* state);
+int lua_ImageControl_addScriptCallback(lua_State* state);
 int lua_ImageControl_canFocus(lua_State* state);
 int lua_ImageControl_clearScripts(lua_State* state);
 int lua_ImageControl_createAnimation(lua_State* state);
@@ -59,6 +60,7 @@ int lua_ImageControl_getX(lua_State* state);
 int lua_ImageControl_getY(lua_State* state);
 int lua_ImageControl_getZIndex(lua_State* state);
 int lua_ImageControl_hasFocus(lua_State* state);
+int lua_ImageControl_hasScriptListener(lua_State* state);
 int lua_ImageControl_isChild(lua_State* state);
 int lua_ImageControl_isContainer(lua_State* state);
 int lua_ImageControl_isEnabled(lua_State* state);
@@ -72,6 +74,7 @@ int lua_ImageControl_isYPercentage(lua_State* state);
 int lua_ImageControl_release(lua_State* state);
 int lua_ImageControl_removeListener(lua_State* state);
 int lua_ImageControl_removeScript(lua_State* state);
+int lua_ImageControl_removeScriptCallback(lua_State* state);
 int lua_ImageControl_setAlignment(lua_State* state);
 int lua_ImageControl_setAnimationPropertyValue(lua_State* state);
 int lua_ImageControl_setAutoSize(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_Joint.cpp

@@ -32,6 +32,7 @@ void luaRegister_Joint()
         {"addListener", lua_Joint_addListener},
         {"addRef", lua_Joint_addRef},
         {"addScript", lua_Joint_addScript},
+        {"addScriptCallback", lua_Joint_addScriptCallback},
         {"clearScripts", lua_Joint_clearScripts},
         {"clone", lua_Joint_clone},
         {"createAnimation", lua_Joint_createAnimation},
@@ -98,6 +99,7 @@ void luaRegister_Joint()
         {"getWorldMatrix", lua_Joint_getWorldMatrix},
         {"getWorldViewMatrix", lua_Joint_getWorldViewMatrix},
         {"getWorldViewProjectionMatrix", lua_Joint_getWorldViewProjectionMatrix},
+        {"hasScriptListener", lua_Joint_hasScriptListener},
         {"hasTag", lua_Joint_hasTag},
         {"isActive", lua_Joint_isActive},
         {"isActiveInHierarchy", lua_Joint_isActiveInHierarchy},
@@ -107,6 +109,7 @@ void luaRegister_Joint()
         {"removeChild", lua_Joint_removeChild},
         {"removeListener", lua_Joint_removeListener},
         {"removeScript", lua_Joint_removeScript},
+        {"removeScriptCallback", lua_Joint_removeScriptCallback},
         {"rotate", lua_Joint_rotate},
         {"rotateX", lua_Joint_rotateX},
         {"rotateY", lua_Joint_rotateY},
@@ -375,19 +378,32 @@ int lua_Joint_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Joint* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Joint* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -398,7 +414,47 @@ int lua_Joint_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Joint_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Joint* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Joint_addScriptCallback - 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;
         }
@@ -3801,6 +3857,69 @@ int lua_Joint_getWorldViewProjectionMatrix(lua_State* state)
     return 0;
 }
 
+int lua_Joint_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Joint* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Joint* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Joint_hasScriptListener - 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_hasTag(lua_State* state)
 {
     // Get the number of parameters.
@@ -4101,16 +4220,20 @@ int lua_Joint_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Joint* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -4124,7 +4247,47 @@ int lua_Joint_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Joint_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Joint* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Joint_removeScriptCallback - 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;
         }

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

@@ -10,6 +10,7 @@ int lua_Joint_addChild(lua_State* state);
 int lua_Joint_addListener(lua_State* state);
 int lua_Joint_addRef(lua_State* state);
 int lua_Joint_addScript(lua_State* state);
+int lua_Joint_addScriptCallback(lua_State* state);
 int lua_Joint_clearScripts(lua_State* state);
 int lua_Joint_clone(lua_State* state);
 int lua_Joint_createAnimation(lua_State* state);
@@ -76,6 +77,7 @@ int lua_Joint_getViewProjectionMatrix(lua_State* state);
 int lua_Joint_getWorldMatrix(lua_State* state);
 int lua_Joint_getWorldViewMatrix(lua_State* state);
 int lua_Joint_getWorldViewProjectionMatrix(lua_State* state);
+int lua_Joint_hasScriptListener(lua_State* state);
 int lua_Joint_hasTag(lua_State* state);
 int lua_Joint_isActive(lua_State* state);
 int lua_Joint_isActiveInHierarchy(lua_State* state);
@@ -85,6 +87,7 @@ int lua_Joint_removeAllChildren(lua_State* state);
 int lua_Joint_removeChild(lua_State* state);
 int lua_Joint_removeListener(lua_State* state);
 int lua_Joint_removeScript(lua_State* state);
+int lua_Joint_removeScriptCallback(lua_State* state);
 int lua_Joint_rotate(lua_State* state);
 int lua_Joint_rotateX(lua_State* state);
 int lua_Joint_rotateY(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_JoystickControl.cpp

@@ -24,6 +24,7 @@ void luaRegister_JoystickControl()
         {"addListener", lua_JoystickControl_addListener},
         {"addRef", lua_JoystickControl_addRef},
         {"addScript", lua_JoystickControl_addScript},
+        {"addScriptCallback", lua_JoystickControl_addScriptCallback},
         {"canFocus", lua_JoystickControl_canFocus},
         {"clearScripts", lua_JoystickControl_clearScripts},
         {"createAnimation", lua_JoystickControl_createAnimation},
@@ -76,6 +77,7 @@ void luaRegister_JoystickControl()
         {"getY", lua_JoystickControl_getY},
         {"getZIndex", lua_JoystickControl_getZIndex},
         {"hasFocus", lua_JoystickControl_hasFocus},
+        {"hasScriptListener", lua_JoystickControl_hasScriptListener},
         {"isChild", lua_JoystickControl_isChild},
         {"isContainer", lua_JoystickControl_isContainer},
         {"isEnabled", lua_JoystickControl_isEnabled},
@@ -90,6 +92,7 @@ void luaRegister_JoystickControl()
         {"release", lua_JoystickControl_release},
         {"removeListener", lua_JoystickControl_removeListener},
         {"removeScript", lua_JoystickControl_removeScript},
+        {"removeScriptCallback", lua_JoystickControl_removeScriptCallback},
         {"setAlignment", lua_JoystickControl_setAlignment},
         {"setAnimationPropertyValue", lua_JoystickControl_setAnimationPropertyValue},
         {"setAutoSize", lua_JoystickControl_setAutoSize},
@@ -277,19 +280,32 @@ int lua_JoystickControl_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                JoystickControl* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                JoystickControl* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -300,7 +316,47 @@ int lua_JoystickControl_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_JoystickControl_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                JoystickControl* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_JoystickControl_addScriptCallback - 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;
         }
@@ -2914,6 +2970,69 @@ int lua_JoystickControl_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_JoystickControl_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    JoystickControl* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    JoystickControl* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_JoystickControl_hasScriptListener - 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_JoystickControl_isChild(lua_State* state)
 {
     // Get the number of parameters.
@@ -3391,16 +3510,20 @@ int lua_JoystickControl_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 JoystickControl* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3414,7 +3537,47 @@ int lua_JoystickControl_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_JoystickControl_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                JoystickControl* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_JoystickControl_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_JoystickControl.h

@@ -9,6 +9,7 @@ int lua_JoystickControl__gc(lua_State* state);
 int lua_JoystickControl_addListener(lua_State* state);
 int lua_JoystickControl_addRef(lua_State* state);
 int lua_JoystickControl_addScript(lua_State* state);
+int lua_JoystickControl_addScriptCallback(lua_State* state);
 int lua_JoystickControl_canFocus(lua_State* state);
 int lua_JoystickControl_clearScripts(lua_State* state);
 int lua_JoystickControl_createAnimation(lua_State* state);
@@ -61,6 +62,7 @@ int lua_JoystickControl_getX(lua_State* state);
 int lua_JoystickControl_getY(lua_State* state);
 int lua_JoystickControl_getZIndex(lua_State* state);
 int lua_JoystickControl_hasFocus(lua_State* state);
+int lua_JoystickControl_hasScriptListener(lua_State* state);
 int lua_JoystickControl_isChild(lua_State* state);
 int lua_JoystickControl_isContainer(lua_State* state);
 int lua_JoystickControl_isEnabled(lua_State* state);
@@ -75,6 +77,7 @@ int lua_JoystickControl_isYPercentage(lua_State* state);
 int lua_JoystickControl_release(lua_State* state);
 int lua_JoystickControl_removeListener(lua_State* state);
 int lua_JoystickControl_removeScript(lua_State* state);
+int lua_JoystickControl_removeScriptCallback(lua_State* state);
 int lua_JoystickControl_setAlignment(lua_State* state);
 int lua_JoystickControl_setAnimationPropertyValue(lua_State* state);
 int lua_JoystickControl_setAutoSize(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_Label.cpp

@@ -24,6 +24,7 @@ void luaRegister_Label()
         {"addListener", lua_Label_addListener},
         {"addRef", lua_Label_addRef},
         {"addScript", lua_Label_addScript},
+        {"addScriptCallback", lua_Label_addScriptCallback},
         {"canFocus", lua_Label_canFocus},
         {"clearScripts", lua_Label_clearScripts},
         {"createAnimation", lua_Label_createAnimation},
@@ -73,6 +74,7 @@ void luaRegister_Label()
         {"getY", lua_Label_getY},
         {"getZIndex", lua_Label_getZIndex},
         {"hasFocus", lua_Label_hasFocus},
+        {"hasScriptListener", lua_Label_hasScriptListener},
         {"isChild", lua_Label_isChild},
         {"isContainer", lua_Label_isContainer},
         {"isEnabled", lua_Label_isEnabled},
@@ -86,6 +88,7 @@ void luaRegister_Label()
         {"release", lua_Label_release},
         {"removeListener", lua_Label_removeListener},
         {"removeScript", lua_Label_removeScript},
+        {"removeScriptCallback", lua_Label_removeScriptCallback},
         {"setAlignment", lua_Label_setAlignment},
         {"setAnimationPropertyValue", lua_Label_setAnimationPropertyValue},
         {"setAutoSize", lua_Label_setAutoSize},
@@ -271,19 +274,32 @@ int lua_Label_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Label* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Label* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -294,7 +310,47 @@ int lua_Label_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Label_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Label* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Label_addScriptCallback - 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;
         }
@@ -2776,6 +2832,69 @@ int lua_Label_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_Label_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Label* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Label* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Label_hasScriptListener - 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_Label_isChild(lua_State* state)
 {
     // Get the number of parameters.
@@ -3218,16 +3337,20 @@ int lua_Label_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Label* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3241,7 +3364,47 @@ int lua_Label_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Label_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Label* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Label_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_Label.h

@@ -9,6 +9,7 @@ int lua_Label__gc(lua_State* state);
 int lua_Label_addListener(lua_State* state);
 int lua_Label_addRef(lua_State* state);
 int lua_Label_addScript(lua_State* state);
+int lua_Label_addScriptCallback(lua_State* state);
 int lua_Label_canFocus(lua_State* state);
 int lua_Label_clearScripts(lua_State* state);
 int lua_Label_createAnimation(lua_State* state);
@@ -58,6 +59,7 @@ int lua_Label_getX(lua_State* state);
 int lua_Label_getY(lua_State* state);
 int lua_Label_getZIndex(lua_State* state);
 int lua_Label_hasFocus(lua_State* state);
+int lua_Label_hasScriptListener(lua_State* state);
 int lua_Label_isChild(lua_State* state);
 int lua_Label_isContainer(lua_State* state);
 int lua_Label_isEnabled(lua_State* state);
@@ -71,6 +73,7 @@ int lua_Label_isYPercentage(lua_State* state);
 int lua_Label_release(lua_State* state);
 int lua_Label_removeListener(lua_State* state);
 int lua_Label_removeScript(lua_State* state);
+int lua_Label_removeScriptCallback(lua_State* state);
 int lua_Label_setAlignment(lua_State* state);
 int lua_Label_setAnimationPropertyValue(lua_State* state);
 int lua_Label_setAutoSize(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_Node.cpp

@@ -31,6 +31,7 @@ void luaRegister_Node()
         {"addListener", lua_Node_addListener},
         {"addRef", lua_Node_addRef},
         {"addScript", lua_Node_addScript},
+        {"addScriptCallback", lua_Node_addScriptCallback},
         {"clearScripts", lua_Node_clearScripts},
         {"clone", lua_Node_clone},
         {"createAnimation", lua_Node_createAnimation},
@@ -96,6 +97,7 @@ void luaRegister_Node()
         {"getWorldMatrix", lua_Node_getWorldMatrix},
         {"getWorldViewMatrix", lua_Node_getWorldViewMatrix},
         {"getWorldViewProjectionMatrix", lua_Node_getWorldViewProjectionMatrix},
+        {"hasScriptListener", lua_Node_hasScriptListener},
         {"hasTag", lua_Node_hasTag},
         {"isActive", lua_Node_isActive},
         {"isActiveInHierarchy", lua_Node_isActiveInHierarchy},
@@ -105,6 +107,7 @@ void luaRegister_Node()
         {"removeChild", lua_Node_removeChild},
         {"removeListener", lua_Node_removeListener},
         {"removeScript", lua_Node_removeScript},
+        {"removeScriptCallback", lua_Node_removeScriptCallback},
         {"rotate", lua_Node_rotate},
         {"rotateX", lua_Node_rotateX},
         {"rotateY", lua_Node_rotateY},
@@ -374,19 +377,32 @@ int lua_Node_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Node* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Node* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -397,7 +413,47 @@ int lua_Node_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Node_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Node* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Node_addScriptCallback - 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;
         }
@@ -3756,6 +3812,69 @@ int lua_Node_getWorldViewProjectionMatrix(lua_State* state)
     return 0;
 }
 
+int lua_Node_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Node* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Node* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Node_hasScriptListener - 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_hasTag(lua_State* state)
 {
     // Get the number of parameters.
@@ -4056,16 +4175,20 @@ int lua_Node_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Node* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -4079,7 +4202,47 @@ int lua_Node_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Node_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Node* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Node_removeScriptCallback - 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;
         }

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

@@ -10,6 +10,7 @@ int lua_Node_addChild(lua_State* state);
 int lua_Node_addListener(lua_State* state);
 int lua_Node_addRef(lua_State* state);
 int lua_Node_addScript(lua_State* state);
+int lua_Node_addScriptCallback(lua_State* state);
 int lua_Node_clearScripts(lua_State* state);
 int lua_Node_clone(lua_State* state);
 int lua_Node_createAnimation(lua_State* state);
@@ -75,6 +76,7 @@ int lua_Node_getViewProjectionMatrix(lua_State* state);
 int lua_Node_getWorldMatrix(lua_State* state);
 int lua_Node_getWorldViewMatrix(lua_State* state);
 int lua_Node_getWorldViewProjectionMatrix(lua_State* state);
+int lua_Node_hasScriptListener(lua_State* state);
 int lua_Node_hasTag(lua_State* state);
 int lua_Node_isActive(lua_State* state);
 int lua_Node_isActiveInHierarchy(lua_State* state);
@@ -84,6 +86,7 @@ int lua_Node_removeAllChildren(lua_State* state);
 int lua_Node_removeChild(lua_State* state);
 int lua_Node_removeListener(lua_State* state);
 int lua_Node_removeScript(lua_State* state);
+int lua_Node_removeScriptCallback(lua_State* state);
 int lua_Node_rotate(lua_State* state);
 int lua_Node_rotateX(lua_State* state);
 int lua_Node_rotateY(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_PhysicsController.cpp

@@ -20,6 +20,7 @@ void luaRegister_PhysicsController()
     const luaL_Reg lua_members[] = 
     {
         {"addScript", lua_PhysicsController_addScript},
+        {"addScriptCallback", lua_PhysicsController_addScriptCallback},
         {"addStatusListener", lua_PhysicsController_addStatusListener},
         {"clearScripts", lua_PhysicsController_clearScripts},
         {"createFixedConstraint", lua_PhysicsController_createFixedConstraint},
@@ -29,8 +30,10 @@ void luaRegister_PhysicsController()
         {"createSpringConstraint", lua_PhysicsController_createSpringConstraint},
         {"drawDebug", lua_PhysicsController_drawDebug},
         {"getGravity", lua_PhysicsController_getGravity},
+        {"hasScriptListener", lua_PhysicsController_hasScriptListener},
         {"rayTest", lua_PhysicsController_rayTest},
         {"removeScript", lua_PhysicsController_removeScript},
+        {"removeScriptCallback", lua_PhysicsController_removeScriptCallback},
         {"removeStatusListener", lua_PhysicsController_removeStatusListener},
         {"setGravity", lua_PhysicsController_setGravity},
         {"sweepTest", lua_PhysicsController_sweepTest},
@@ -57,19 +60,32 @@ int lua_PhysicsController_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                PhysicsController* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                PhysicsController* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -80,7 +96,47 @@ int lua_PhysicsController_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_PhysicsController_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                PhysicsController* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_PhysicsController_addScriptCallback - 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;
         }
@@ -1362,6 +1418,69 @@ int lua_PhysicsController_getGravity(lua_State* state)
     return 0;
 }
 
+int lua_PhysicsController_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    PhysicsController* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    PhysicsController* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_PhysicsController_hasScriptListener - 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_PhysicsController_rayTest(lua_State* state)
 {
     // Get the number of parameters.
@@ -1511,16 +1630,20 @@ int lua_PhysicsController_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 PhysicsController* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -1534,7 +1657,47 @@ int lua_PhysicsController_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_PhysicsController_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                PhysicsController* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_PhysicsController_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_PhysicsController.h

@@ -6,6 +6,7 @@ namespace gameplay
 
 // Lua bindings for PhysicsController.
 int lua_PhysicsController_addScript(lua_State* state);
+int lua_PhysicsController_addScriptCallback(lua_State* state);
 int lua_PhysicsController_addStatusListener(lua_State* state);
 int lua_PhysicsController_clearScripts(lua_State* state);
 int lua_PhysicsController_createFixedConstraint(lua_State* state);
@@ -15,8 +16,10 @@ int lua_PhysicsController_createSocketConstraint(lua_State* state);
 int lua_PhysicsController_createSpringConstraint(lua_State* state);
 int lua_PhysicsController_drawDebug(lua_State* state);
 int lua_PhysicsController_getGravity(lua_State* state);
+int lua_PhysicsController_hasScriptListener(lua_State* state);
 int lua_PhysicsController_rayTest(lua_State* state);
 int lua_PhysicsController_removeScript(lua_State* state);
+int lua_PhysicsController_removeScriptCallback(lua_State* state);
 int lua_PhysicsController_removeStatusListener(lua_State* state);
 int lua_PhysicsController_setGravity(lua_State* state);
 int lua_PhysicsController_sweepTest(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_RadioButton.cpp

@@ -27,6 +27,7 @@ void luaRegister_RadioButton()
         {"addListener", lua_RadioButton_addListener},
         {"addRef", lua_RadioButton_addRef},
         {"addScript", lua_RadioButton_addScript},
+        {"addScriptCallback", lua_RadioButton_addScriptCallback},
         {"canFocus", lua_RadioButton_canFocus},
         {"clearScripts", lua_RadioButton_clearScripts},
         {"createAnimation", lua_RadioButton_createAnimation},
@@ -77,6 +78,7 @@ void luaRegister_RadioButton()
         {"getY", lua_RadioButton_getY},
         {"getZIndex", lua_RadioButton_getZIndex},
         {"hasFocus", lua_RadioButton_hasFocus},
+        {"hasScriptListener", lua_RadioButton_hasScriptListener},
         {"isChild", lua_RadioButton_isChild},
         {"isContainer", lua_RadioButton_isContainer},
         {"isEnabled", lua_RadioButton_isEnabled},
@@ -91,6 +93,7 @@ void luaRegister_RadioButton()
         {"release", lua_RadioButton_release},
         {"removeListener", lua_RadioButton_removeListener},
         {"removeScript", lua_RadioButton_removeScript},
+        {"removeScriptCallback", lua_RadioButton_removeScriptCallback},
         {"setAlignment", lua_RadioButton_setAlignment},
         {"setAnimationPropertyValue", lua_RadioButton_setAnimationPropertyValue},
         {"setAutoSize", lua_RadioButton_setAutoSize},
@@ -278,19 +281,32 @@ int lua_RadioButton_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                RadioButton* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                RadioButton* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -301,7 +317,47 @@ int lua_RadioButton_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_RadioButton_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                RadioButton* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_RadioButton_addScriptCallback - 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;
         }
@@ -2818,6 +2874,69 @@ int lua_RadioButton_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_RadioButton_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    RadioButton* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    RadioButton* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_RadioButton_hasScriptListener - 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_RadioButton_isChild(lua_State* state)
 {
     // Get the number of parameters.
@@ -3295,16 +3414,20 @@ int lua_RadioButton_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 RadioButton* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3318,7 +3441,47 @@ int lua_RadioButton_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_RadioButton_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                RadioButton* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_RadioButton_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_RadioButton.h

@@ -9,6 +9,7 @@ int lua_RadioButton__gc(lua_State* state);
 int lua_RadioButton_addListener(lua_State* state);
 int lua_RadioButton_addRef(lua_State* state);
 int lua_RadioButton_addScript(lua_State* state);
+int lua_RadioButton_addScriptCallback(lua_State* state);
 int lua_RadioButton_canFocus(lua_State* state);
 int lua_RadioButton_clearScripts(lua_State* state);
 int lua_RadioButton_createAnimation(lua_State* state);
@@ -59,6 +60,7 @@ int lua_RadioButton_getX(lua_State* state);
 int lua_RadioButton_getY(lua_State* state);
 int lua_RadioButton_getZIndex(lua_State* state);
 int lua_RadioButton_hasFocus(lua_State* state);
+int lua_RadioButton_hasScriptListener(lua_State* state);
 int lua_RadioButton_isChild(lua_State* state);
 int lua_RadioButton_isContainer(lua_State* state);
 int lua_RadioButton_isEnabled(lua_State* state);
@@ -73,6 +75,7 @@ int lua_RadioButton_isYPercentage(lua_State* state);
 int lua_RadioButton_release(lua_State* state);
 int lua_RadioButton_removeListener(lua_State* state);
 int lua_RadioButton_removeScript(lua_State* state);
+int lua_RadioButton_removeScriptCallback(lua_State* state);
 int lua_RadioButton_setAlignment(lua_State* state);
 int lua_RadioButton_setAnimationPropertyValue(lua_State* state);
 int lua_RadioButton_setAutoSize(lua_State* state);

+ 320 - 0
gameplay/src/lua/lua_Script.cpp

@@ -0,0 +1,320 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_Script.h"
+#include "Base.h"
+#include "Game.h"
+#include "Ref.h"
+#include "Script.h"
+#include "ScriptController.h"
+
+namespace gameplay
+{
+
+void luaRegister_Script()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"addRef", lua_Script_addRef},
+        {"functionExists", lua_Script_functionExists},
+        {"getPath", lua_Script_getPath},
+        {"getRefCount", lua_Script_getRefCount},
+        {"getScope", lua_Script_getScope},
+        {"release", lua_Script_release},
+        {"reload", lua_Script_reload},
+        {NULL, NULL}
+    };
+    const luaL_Reg* lua_statics = NULL;
+    std::vector<std::string> scopePath;
+
+    gameplay::ScriptUtil::registerClass("Script", lua_members, NULL, lua_Script__gc, lua_statics, scopePath);
+}
+
+static Script* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "Script");
+    luaL_argcheck(state, userdata != NULL, 1, "'Script' expected.");
+    return (Script*)((gameplay::ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_Script__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, "Script");
+                luaL_argcheck(state, userdata != NULL, 1, "'Script' expected.");
+                gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)userdata;
+                if (object->owns)
+                {
+                    Script* instance = (Script*)object->instance;
+                    SAFE_RELEASE(instance);
+                }
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Script__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_Script_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))
+            {
+                Script* instance = getInstance(state);
+                instance->addRef();
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Script_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_Script_functionExists(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 = gameplay::ScriptUtil::getString(2, false);
+
+                Script* instance = getInstance(state);
+                bool result = instance->functionExists(param1);
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_Script_functionExists - 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_Script_getPath(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))
+            {
+                Script* instance = getInstance(state);
+                const char* result = instance->getPath();
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_Script_getPath - 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_Script_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))
+            {
+                Script* instance = getInstance(state);
+                unsigned int result = instance->getRefCount();
+
+                // Push the return value onto the stack.
+                lua_pushunsigned(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_Script_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_Script_getScope(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))
+            {
+                Script* instance = getInstance(state);
+                Script::Scope result = instance->getScope();
+
+                // Push the return value onto the stack.
+                lua_pushnumber(state, (int)result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_Script_getScope - 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_Script_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))
+            {
+                Script* instance = getInstance(state);
+                instance->release();
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Script_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_Script_reload(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))
+            {
+                Script* instance = getInstance(state);
+                bool result = instance->reload();
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_Script_reload - 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;
+}
+
+}

+ 21 - 0
gameplay/src/lua/lua_Script.h

@@ -0,0 +1,21 @@
+#ifndef LUA_SCRIPT_H_
+#define LUA_SCRIPT_H_
+
+namespace gameplay
+{
+
+// Lua bindings for Script.
+int lua_Script__gc(lua_State* state);
+int lua_Script_addRef(lua_State* state);
+int lua_Script_functionExists(lua_State* state);
+int lua_Script_getPath(lua_State* state);
+int lua_Script_getRefCount(lua_State* state);
+int lua_Script_getScope(lua_State* state);
+int lua_Script_release(lua_State* state);
+int lua_Script_reload(lua_State* state);
+
+void luaRegister_Script();
+
+}
+
+#endif

+ 84 - 119
gameplay/src/lua/lua_ScriptController.cpp

@@ -13,10 +13,8 @@ void luaRegister_ScriptController()
     const luaL_Reg lua_members[] = 
     {
         {"functionExists", lua_ScriptController_functionExists},
+        {"getCurrentScript", lua_ScriptController_getCurrentScript},
         {"loadScript", lua_ScriptController_loadScript},
-        {"loadScriptIsolated", lua_ScriptController_loadScriptIsolated},
-        {"loadUrl", lua_ScriptController_loadUrl},
-        {"unloadScript", lua_ScriptController_unloadScript},
         {NULL, NULL}
     };
     const luaL_Reg lua_statics[] = 
@@ -69,13 +67,19 @@ int lua_ScriptController_functionExists(lua_State* state)
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
                 (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
-                lua_type(state, 3) == LUA_TNUMBER)
+                (lua_type(state, 3) == LUA_TUSERDATA || lua_type(state, 3) == LUA_TTABLE || lua_type(state, 3) == LUA_TNIL))
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
                 // Get parameter 2 off the stack.
-                int param2 = (int)luaL_checkint(state, 3);
+                bool param2Valid;
+                gameplay::ScriptUtil::LuaArray<Script> param2 = gameplay::ScriptUtil::getObjectPointer<Script>(3, "Script", false, &param2Valid);
+                if (!param2Valid)
+                {
+                    lua_pushstring(state, "Failed to convert parameter 2 to type 'Script'.");
+                    lua_error(state);
+                }
 
                 ScriptController* instance = getInstance(state);
                 bool result = instance->functionExists(param1, param2);
@@ -100,7 +104,7 @@ int lua_ScriptController_functionExists(lua_State* state)
     return 0;
 }
 
-int lua_ScriptController_loadScript(lua_State* state)
+int lua_ScriptController_getCurrentScript(lua_State* state)
 {
     // Get the number of parameters.
     int paramCount = lua_gettop(state);
@@ -108,55 +112,35 @@ int lua_ScriptController_loadScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 1:
         {
-            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
             {
-                // Get parameter 1 off the stack.
-                const char* param1 = gameplay::ScriptUtil::getString(2, false);
-
                 ScriptController* instance = getInstance(state);
-                bool result = instance->loadScript(param1);
-
-                // Push the return value onto the stack.
-                lua_pushboolean(state, result);
-
-                return 1;
-            }
-
-            lua_pushstring(state, "lua_ScriptController_loadScript - 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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
-                lua_type(state, 3) == LUA_TBOOLEAN)
-            {
-                // Get parameter 1 off the stack.
-                const char* param1 = gameplay::ScriptUtil::getString(2, false);
-
-                // Get parameter 2 off the stack.
-                bool param2 = gameplay::ScriptUtil::luaCheckBool(state, 3);
-
-                ScriptController* instance = getInstance(state);
-                bool result = instance->loadScript(param1, param2);
-
-                // Push the return value onto the stack.
-                lua_pushboolean(state, result);
+                void* returnPtr = (void*)instance->getCurrentScript();
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
 
-            lua_pushstring(state, "lua_ScriptController_loadScript - Failed to match the given parameters to a valid function signature.");
+            lua_pushstring(state, "lua_ScriptController_getCurrentScript - 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_pushstring(state, "Invalid number of parameters (expected 1).");
             lua_error(state);
             break;
         }
@@ -164,7 +148,7 @@ int lua_ScriptController_loadScript(lua_State* state)
     return 0;
 }
 
-int lua_ScriptController_loadScriptIsolated(lua_State* state)
+int lua_ScriptController_loadScript(lua_State* state)
 {
     // Get the number of parameters.
     int paramCount = lua_gettop(state);
@@ -181,85 +165,102 @@ int lua_ScriptController_loadScriptIsolated(lua_State* state)
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
                 ScriptController* instance = getInstance(state);
-                int result = instance->loadScriptIsolated(param1);
-
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                void* returnPtr = (void*)instance->loadScript(param1);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
 
-            lua_pushstring(state, "lua_ScriptController_loadScriptIsolated - 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_pushstring(state, "lua_ScriptController_loadScript - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
             break;
         }
-    }
-    return 0;
-}
-
-int lua_ScriptController_loadUrl(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:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                ScriptController* instance = getInstance(state);
-                std::string result = instance->loadUrl(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushstring(state, result.c_str());
+                ScriptController* instance = getInstance(state);
+                void* returnPtr = (void*)instance->loadScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
 
-            lua_pushstring(state, "lua_ScriptController_loadUrl - Failed to match the given parameters to a valid function signature.");
+            lua_pushstring(state, "lua_ScriptController_loadScript - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
             break;
         }
-        case 3:
+        case 4:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
                 (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
-                (lua_type(state, 3) == LUA_TTABLE || lua_type(state, 3) == LUA_TLIGHTUSERDATA))
+                lua_type(state, 3) == LUA_TNUMBER &&
+                lua_type(state, 4) == LUA_TBOOLEAN)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
                 // Get parameter 2 off the stack.
-                gameplay::ScriptUtil::LuaArray<int> param2 = gameplay::ScriptUtil::getIntPointer(3);
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                ScriptController* instance = getInstance(state);
-                std::string result = instance->loadUrl(param1, param2);
+                // Get parameter 3 off the stack.
+                bool param3 = gameplay::ScriptUtil::luaCheckBool(state, 4);
 
-                // Push the return value onto the stack.
-                lua_pushstring(state, result.c_str());
+                ScriptController* instance = getInstance(state);
+                void* returnPtr = (void*)instance->loadScript(param1, param2, param3);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
 
-            lua_pushstring(state, "lua_ScriptController_loadUrl - Failed to match the given parameters to a valid function signature.");
+            lua_pushstring(state, "lua_ScriptController_loadScript - 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_pushstring(state, "Invalid number of parameters (expected 2, 3 or 4).");
             lua_error(state);
             break;
         }
@@ -327,40 +328,4 @@ int lua_ScriptController_static_print(lua_State* state)
     return 0;
 }
 
-int lua_ScriptController_unloadScript(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.
-                int param1 = (int)luaL_checkint(state, 2);
-
-                ScriptController* instance = getInstance(state);
-                instance->unloadScript(param1);
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_ScriptController_unloadScript - 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;
-}
-
 }

+ 1 - 3
gameplay/src/lua/lua_ScriptController.h

@@ -6,11 +6,9 @@ namespace gameplay
 
 // Lua bindings for ScriptController.
 int lua_ScriptController_functionExists(lua_State* state);
+int lua_ScriptController_getCurrentScript(lua_State* state);
 int lua_ScriptController_loadScript(lua_State* state);
-int lua_ScriptController_loadScriptIsolated(lua_State* state);
-int lua_ScriptController_loadUrl(lua_State* state);
 int lua_ScriptController_static_print(lua_State* state);
-int lua_ScriptController_unloadScript(lua_State* state);
 
 void luaRegister_ScriptController();
 

+ 174 - 11
gameplay/src/lua/lua_ScriptTarget.cpp

@@ -13,8 +13,11 @@ void luaRegister_ScriptTarget()
     const luaL_Reg lua_members[] = 
     {
         {"addScript", lua_ScriptTarget_addScript},
+        {"addScriptCallback", lua_ScriptTarget_addScriptCallback},
         {"clearScripts", lua_ScriptTarget_clearScripts},
+        {"hasScriptListener", lua_ScriptTarget_hasScriptListener},
         {"removeScript", lua_ScriptTarget_removeScript},
+        {"removeScriptCallback", lua_ScriptTarget_removeScriptCallback},
         {NULL, NULL}
     };
     const luaL_Reg* lua_statics = NULL;
@@ -38,19 +41,32 @@ int lua_ScriptTarget_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                ScriptTarget* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                ScriptTarget* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -61,7 +77,47 @@ int lua_ScriptTarget_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_ScriptTarget_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                ScriptTarget* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_ScriptTarget_addScriptCallback - 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;
         }
@@ -101,7 +157,7 @@ int lua_ScriptTarget_clearScripts(lua_State* state)
     return 0;
 }
 
-int lua_ScriptTarget_removeScript(lua_State* state)
+int lua_ScriptTarget_hasScriptListener(lua_State* state)
 {
     // Get the number of parameters.
     int paramCount = lua_gettop(state);
@@ -110,15 +166,82 @@ int lua_ScriptTarget_removeScript(lua_State* state)
     switch (paramCount)
     {
         case 2:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    ScriptTarget* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    ScriptTarget* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_ScriptTarget_hasScriptListener - 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_ScriptTarget_removeScript(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_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 ScriptTarget* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -132,7 +255,47 @@ int lua_ScriptTarget_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_ScriptTarget_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                ScriptTarget* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_ScriptTarget_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_ScriptTarget.h

@@ -6,8 +6,11 @@ namespace gameplay
 
 // Lua bindings for ScriptTarget.
 int lua_ScriptTarget_addScript(lua_State* state);
+int lua_ScriptTarget_addScriptCallback(lua_State* state);
 int lua_ScriptTarget_clearScripts(lua_State* state);
+int lua_ScriptTarget_hasScriptListener(lua_State* state);
 int lua_ScriptTarget_removeScript(lua_State* state);
+int lua_ScriptTarget_removeScriptCallback(lua_State* state);
 
 void luaRegister_ScriptTarget();
 

+ 178 - 0
gameplay/src/lua/lua_ScriptTargetEvent.cpp

@@ -0,0 +1,178 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_ScriptTargetEvent.h"
+#include "Base.h"
+#include "ScriptController.h"
+#include "ScriptTarget.h"
+
+namespace gameplay
+{
+
+void luaRegister_ScriptTargetEvent()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"getArgs", lua_ScriptTargetEvent_getArgs},
+        {"getName", lua_ScriptTargetEvent_getName},
+        {NULL, NULL}
+    };
+    const luaL_Reg* lua_statics = NULL;
+    std::vector<std::string> scopePath;
+    scopePath.push_back("ScriptTarget");
+
+    gameplay::ScriptUtil::registerClass("ScriptTargetEvent", lua_members, lua_ScriptTargetEvent__init, lua_ScriptTargetEvent__gc, lua_statics, scopePath);
+}
+
+static ScriptTarget::Event* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "ScriptTargetEvent");
+    luaL_argcheck(state, userdata != NULL, 1, "'ScriptTargetEvent' expected.");
+    return (ScriptTarget::Event*)((gameplay::ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_ScriptTargetEvent__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, "ScriptTargetEvent");
+                luaL_argcheck(state, userdata != NULL, 1, "'ScriptTargetEvent' expected.");
+                gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)userdata;
+                if (object->owns)
+                {
+                    ScriptTarget::Event* instance = (ScriptTarget::Event*)object->instance;
+                    SAFE_DELETE(instance);
+                }
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_ScriptTargetEvent__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_ScriptTargetEvent__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 ScriptTarget::Event();
+            if (returnPtr)
+            {
+                gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                object->instance = returnPtr;
+                object->owns = true;
+                luaL_getmetatable(state, "ScriptTargetEvent");
+                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_ScriptTargetEvent_getArgs(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))
+            {
+                ScriptTarget::Event* instance = getInstance(state);
+                const char* result = instance->getArgs();
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_ScriptTargetEvent_getArgs - 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_ScriptTargetEvent_getName(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))
+            {
+                ScriptTarget::Event* instance = getInstance(state);
+                const char* result = instance->getName();
+
+                // Push the return value onto the stack.
+                lua_pushstring(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_ScriptTargetEvent_getName - 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;
+}
+
+}

+ 17 - 0
gameplay/src/lua/lua_ScriptTargetEvent.h

@@ -0,0 +1,17 @@
+#ifndef LUA_SCRIPTTARGETEVENT_H_
+#define LUA_SCRIPTTARGETEVENT_H_
+
+namespace gameplay
+{
+
+// Lua bindings for ScriptTarget::Event.
+int lua_ScriptTargetEvent__gc(lua_State* state);
+int lua_ScriptTargetEvent__init(lua_State* state);
+int lua_ScriptTargetEvent_getArgs(lua_State* state);
+int lua_ScriptTargetEvent_getName(lua_State* state);
+
+void luaRegister_ScriptTargetEvent();
+
+}
+
+#endif

+ 304 - 0
gameplay/src/lua/lua_ScriptTargetEventRegistry.cpp

@@ -0,0 +1,304 @@
+#include "Base.h"
+#include "ScriptController.h"
+#include "lua_ScriptTargetEventRegistry.h"
+#include "Base.h"
+#include "ScriptController.h"
+#include "ScriptTarget.h"
+
+namespace gameplay
+{
+
+void luaRegister_ScriptTargetEventRegistry()
+{
+    const luaL_Reg lua_members[] = 
+    {
+        {"addEvent", lua_ScriptTargetEventRegistry_addEvent},
+        {"getEvent", lua_ScriptTargetEventRegistry_getEvent},
+        {"getEventCount", lua_ScriptTargetEventRegistry_getEventCount},
+        {NULL, NULL}
+    };
+    const luaL_Reg* lua_statics = NULL;
+    std::vector<std::string> scopePath;
+    scopePath.push_back("ScriptTarget");
+
+    gameplay::ScriptUtil::registerClass("ScriptTargetEventRegistry", lua_members, lua_ScriptTargetEventRegistry__init, lua_ScriptTargetEventRegistry__gc, lua_statics, scopePath);
+}
+
+static ScriptTarget::EventRegistry* getInstance(lua_State* state)
+{
+    void* userdata = luaL_checkudata(state, 1, "ScriptTargetEventRegistry");
+    luaL_argcheck(state, userdata != NULL, 1, "'ScriptTargetEventRegistry' expected.");
+    return (ScriptTarget::EventRegistry*)((gameplay::ScriptUtil::LuaObject*)userdata)->instance;
+}
+
+int lua_ScriptTargetEventRegistry__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, "ScriptTargetEventRegistry");
+                luaL_argcheck(state, userdata != NULL, 1, "'ScriptTargetEventRegistry' expected.");
+                gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)userdata;
+                if (object->owns)
+                {
+                    ScriptTarget::EventRegistry* instance = (ScriptTarget::EventRegistry*)object->instance;
+                    SAFE_DELETE(instance);
+                }
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_ScriptTargetEventRegistry__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_ScriptTargetEventRegistry__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 ScriptTarget::EventRegistry();
+            if (returnPtr)
+            {
+                gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                object->instance = returnPtr;
+                object->owns = true;
+                luaL_getmetatable(state, "ScriptTargetEventRegistry");
+                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_ScriptTargetEventRegistry_addEvent(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 = gameplay::ScriptUtil::getString(2, false);
+
+                ScriptTarget::EventRegistry* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addEvent(param1);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "ScriptTargetEvent");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_ScriptTargetEventRegistry_addEvent - 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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                ScriptTarget::EventRegistry* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addEvent(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "ScriptTargetEvent");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_ScriptTargetEventRegistry_addEvent - 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;
+}
+
+int lua_ScriptTargetEventRegistry_getEvent(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:
+        {
+            do
+            {
+                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);
+
+                    ScriptTarget::EventRegistry* instance = getInstance(state);
+                    void* returnPtr = (void*)instance->getEvent(param1);
+                    if (returnPtr)
+                    {
+                        gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                        object->instance = returnPtr;
+                        object->owns = false;
+                        luaL_getmetatable(state, "ScriptTargetEvent");
+                        lua_setmetatable(state, -2);
+                    }
+                    else
+                    {
+                        lua_pushnil(state);
+                    }
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    ScriptTarget::EventRegistry* instance = getInstance(state);
+                    void* returnPtr = (void*)instance->getEvent(param1);
+                    if (returnPtr)
+                    {
+                        gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                        object->instance = returnPtr;
+                        object->owns = false;
+                        luaL_getmetatable(state, "ScriptTargetEvent");
+                        lua_setmetatable(state, -2);
+                    }
+                    else
+                    {
+                        lua_pushnil(state);
+                    }
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_ScriptTargetEventRegistry_getEvent - 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_ScriptTargetEventRegistry_getEventCount(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))
+            {
+                ScriptTarget::EventRegistry* instance = getInstance(state);
+                unsigned int result = instance->getEventCount();
+
+                // Push the return value onto the stack.
+                lua_pushunsigned(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_ScriptTargetEventRegistry_getEventCount - 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;
+}
+
+}

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

@@ -0,0 +1,18 @@
+#ifndef LUA_SCRIPTTARGETEVENTREGISTRY_H_
+#define LUA_SCRIPTTARGETEVENTREGISTRY_H_
+
+namespace gameplay
+{
+
+// Lua bindings for ScriptTarget::EventRegistry.
+int lua_ScriptTargetEventRegistry__gc(lua_State* state);
+int lua_ScriptTargetEventRegistry__init(lua_State* state);
+int lua_ScriptTargetEventRegistry_addEvent(lua_State* state);
+int lua_ScriptTargetEventRegistry_getEvent(lua_State* state);
+int lua_ScriptTargetEventRegistry_getEventCount(lua_State* state);
+
+void luaRegister_ScriptTargetEventRegistry();
+
+}
+
+#endif

+ 174 - 11
gameplay/src/lua/lua_Slider.cpp

@@ -25,6 +25,7 @@ void luaRegister_Slider()
         {"addListener", lua_Slider_addListener},
         {"addRef", lua_Slider_addRef},
         {"addScript", lua_Slider_addScript},
+        {"addScriptCallback", lua_Slider_addScriptCallback},
         {"canFocus", lua_Slider_canFocus},
         {"clearScripts", lua_Slider_clearScripts},
         {"createAnimation", lua_Slider_createAnimation},
@@ -80,6 +81,7 @@ void luaRegister_Slider()
         {"getY", lua_Slider_getY},
         {"getZIndex", lua_Slider_getZIndex},
         {"hasFocus", lua_Slider_hasFocus},
+        {"hasScriptListener", lua_Slider_hasScriptListener},
         {"isChild", lua_Slider_isChild},
         {"isContainer", lua_Slider_isContainer},
         {"isEnabled", lua_Slider_isEnabled},
@@ -94,6 +96,7 @@ void luaRegister_Slider()
         {"release", lua_Slider_release},
         {"removeListener", lua_Slider_removeListener},
         {"removeScript", lua_Slider_removeScript},
+        {"removeScriptCallback", lua_Slider_removeScriptCallback},
         {"setAlignment", lua_Slider_setAlignment},
         {"setAnimationPropertyValue", lua_Slider_setAnimationPropertyValue},
         {"setAutoSize", lua_Slider_setAutoSize},
@@ -286,19 +289,32 @@ int lua_Slider_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Slider* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Slider* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -309,7 +325,47 @@ int lua_Slider_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Slider_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Slider* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Slider_addScriptCallback - 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;
         }
@@ -3001,6 +3057,69 @@ int lua_Slider_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_Slider_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Slider* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Slider* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Slider_hasScriptListener - 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_Slider_isChild(lua_State* state)
 {
     // Get the number of parameters.
@@ -3478,16 +3597,20 @@ int lua_Slider_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Slider* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3501,7 +3624,47 @@ int lua_Slider_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Slider_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Slider* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Slider_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_Slider.h

@@ -9,6 +9,7 @@ int lua_Slider__gc(lua_State* state);
 int lua_Slider_addListener(lua_State* state);
 int lua_Slider_addRef(lua_State* state);
 int lua_Slider_addScript(lua_State* state);
+int lua_Slider_addScriptCallback(lua_State* state);
 int lua_Slider_canFocus(lua_State* state);
 int lua_Slider_clearScripts(lua_State* state);
 int lua_Slider_createAnimation(lua_State* state);
@@ -64,6 +65,7 @@ int lua_Slider_getX(lua_State* state);
 int lua_Slider_getY(lua_State* state);
 int lua_Slider_getZIndex(lua_State* state);
 int lua_Slider_hasFocus(lua_State* state);
+int lua_Slider_hasScriptListener(lua_State* state);
 int lua_Slider_isChild(lua_State* state);
 int lua_Slider_isContainer(lua_State* state);
 int lua_Slider_isEnabled(lua_State* state);
@@ -78,6 +80,7 @@ int lua_Slider_isYPercentage(lua_State* state);
 int lua_Slider_release(lua_State* state);
 int lua_Slider_removeListener(lua_State* state);
 int lua_Slider_removeScript(lua_State* state);
+int lua_Slider_removeScriptCallback(lua_State* state);
 int lua_Slider_setAlignment(lua_State* state);
 int lua_Slider_setAnimationPropertyValue(lua_State* state);
 int lua_Slider_setAutoSize(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_TextBox.cpp

@@ -25,6 +25,7 @@ void luaRegister_TextBox()
         {"addListener", lua_TextBox_addListener},
         {"addRef", lua_TextBox_addRef},
         {"addScript", lua_TextBox_addScript},
+        {"addScriptCallback", lua_TextBox_addScriptCallback},
         {"canFocus", lua_TextBox_canFocus},
         {"clearScripts", lua_TextBox_clearScripts},
         {"createAnimation", lua_TextBox_createAnimation},
@@ -78,6 +79,7 @@ void luaRegister_TextBox()
         {"getY", lua_TextBox_getY},
         {"getZIndex", lua_TextBox_getZIndex},
         {"hasFocus", lua_TextBox_hasFocus},
+        {"hasScriptListener", lua_TextBox_hasScriptListener},
         {"isChild", lua_TextBox_isChild},
         {"isContainer", lua_TextBox_isContainer},
         {"isEnabled", lua_TextBox_isEnabled},
@@ -91,6 +93,7 @@ void luaRegister_TextBox()
         {"release", lua_TextBox_release},
         {"removeListener", lua_TextBox_removeListener},
         {"removeScript", lua_TextBox_removeScript},
+        {"removeScriptCallback", lua_TextBox_removeScriptCallback},
         {"setAlignment", lua_TextBox_setAlignment},
         {"setAnimationPropertyValue", lua_TextBox_setAnimationPropertyValue},
         {"setAutoSize", lua_TextBox_setAutoSize},
@@ -279,19 +282,32 @@ int lua_TextBox_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                TextBox* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                TextBox* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -302,7 +318,47 @@ int lua_TextBox_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_TextBox_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                TextBox* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_TextBox_addScriptCallback - 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;
         }
@@ -2924,6 +2980,69 @@ int lua_TextBox_hasFocus(lua_State* state)
     return 0;
 }
 
+int lua_TextBox_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    TextBox* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    TextBox* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_TextBox_hasScriptListener - 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_TextBox_isChild(lua_State* state)
 {
     // Get the number of parameters.
@@ -3366,16 +3485,20 @@ int lua_TextBox_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 TextBox* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -3389,7 +3512,47 @@ int lua_TextBox_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_TextBox_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                TextBox* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_TextBox_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_TextBox.h

@@ -9,6 +9,7 @@ int lua_TextBox__gc(lua_State* state);
 int lua_TextBox_addListener(lua_State* state);
 int lua_TextBox_addRef(lua_State* state);
 int lua_TextBox_addScript(lua_State* state);
+int lua_TextBox_addScriptCallback(lua_State* state);
 int lua_TextBox_canFocus(lua_State* state);
 int lua_TextBox_clearScripts(lua_State* state);
 int lua_TextBox_createAnimation(lua_State* state);
@@ -62,6 +63,7 @@ int lua_TextBox_getX(lua_State* state);
 int lua_TextBox_getY(lua_State* state);
 int lua_TextBox_getZIndex(lua_State* state);
 int lua_TextBox_hasFocus(lua_State* state);
+int lua_TextBox_hasScriptListener(lua_State* state);
 int lua_TextBox_isChild(lua_State* state);
 int lua_TextBox_isContainer(lua_State* state);
 int lua_TextBox_isEnabled(lua_State* state);
@@ -75,6 +77,7 @@ int lua_TextBox_isYPercentage(lua_State* state);
 int lua_TextBox_release(lua_State* state);
 int lua_TextBox_removeListener(lua_State* state);
 int lua_TextBox_removeScript(lua_State* state);
+int lua_TextBox_removeScriptCallback(lua_State* state);
 int lua_TextBox_setAlignment(lua_State* state);
 int lua_TextBox_setAnimationPropertyValue(lua_State* state);
 int lua_TextBox_setAutoSize(lua_State* state);

+ 174 - 11
gameplay/src/lua/lua_Transform.cpp

@@ -19,6 +19,7 @@ void luaRegister_Transform()
     {
         {"addListener", lua_Transform_addListener},
         {"addScript", lua_Transform_addScript},
+        {"addScriptCallback", lua_Transform_addScriptCallback},
         {"clearScripts", lua_Transform_clearScripts},
         {"createAnimation", lua_Transform_createAnimation},
         {"createAnimationFromBy", lua_Transform_createAnimationFromBy},
@@ -43,9 +44,11 @@ void luaRegister_Transform()
         {"getTranslationY", lua_Transform_getTranslationY},
         {"getTranslationZ", lua_Transform_getTranslationZ},
         {"getUpVector", lua_Transform_getUpVector},
+        {"hasScriptListener", lua_Transform_hasScriptListener},
         {"isStatic", lua_Transform_isStatic},
         {"removeListener", lua_Transform_removeListener},
         {"removeScript", lua_Transform_removeScript},
+        {"removeScriptCallback", lua_Transform_removeScriptCallback},
         {"rotate", lua_Transform_rotate},
         {"rotateX", lua_Transform_rotateX},
         {"rotateY", lua_Transform_rotateY},
@@ -388,19 +391,32 @@ int lua_Transform_addScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
-                Transform* instance = getInstance(state);
-                int result = instance->addScript(param1);
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
 
-                // Push the return value onto the stack.
-                lua_pushinteger(state, result);
+                Transform* instance = getInstance(state);
+                void* returnPtr = (void*)instance->addScript(param1, param2);
+                if (returnPtr)
+                {
+                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                    object->instance = returnPtr;
+                    object->owns = false;
+                    luaL_getmetatable(state, "Script");
+                    lua_setmetatable(state, -2);
+                }
+                else
+                {
+                    lua_pushnil(state);
+                }
 
                 return 1;
             }
@@ -411,7 +427,47 @@ int lua_Transform_addScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Transform_addScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Transform* instance = getInstance(state);
+                instance->addScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Transform_addScriptCallback - 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;
         }
@@ -1931,6 +1987,69 @@ int lua_Transform_getUpVector(lua_State* state)
     return 0;
 }
 
+int lua_Transform_hasScriptListener(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:
+        {
+            do
+            {
+                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 = gameplay::ScriptUtil::getString(2, false);
+
+                    Transform* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            do
+            {
+                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.
+                    bool param1Valid;
+                    gameplay::ScriptUtil::LuaArray<ScriptTarget::Event> param1 = gameplay::ScriptUtil::getObjectPointer<ScriptTarget::Event>(2, "ScriptTargetEvent", false, &param1Valid);
+                    if (!param1Valid)
+                        break;
+
+                    Transform* instance = getInstance(state);
+                    bool result = instance->hasScriptListener(param1);
+
+                    // Push the return value onto the stack.
+                    lua_pushboolean(state, result);
+
+                    return 1;
+                }
+            } while (0);
+
+            lua_pushstring(state, "lua_Transform_hasScriptListener - 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_Transform_isStatic(lua_State* state)
 {
     // Get the number of parameters.
@@ -2016,16 +2135,20 @@ int lua_Transform_removeScript(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 2:
+        case 3:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
-                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL))
+                (lua_type(state, 2) == LUA_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 const char* param1 = gameplay::ScriptUtil::getString(2, false);
 
+                // Get parameter 2 off the stack.
+                Script::Scope param2 = (Script::Scope)luaL_checkint(state, 3);
+
                 Transform* instance = getInstance(state);
-                bool result = instance->removeScript(param1);
+                bool result = instance->removeScript(param1, param2);
 
                 // Push the return value onto the stack.
                 lua_pushboolean(state, result);
@@ -2039,7 +2162,47 @@ int lua_Transform_removeScript(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_pushstring(state, "Invalid number of parameters (expected 3).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
+int lua_Transform_removeScriptCallback(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_TSTRING || lua_type(state, 2) == LUA_TNIL) &&
+                (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                const char* param1 = gameplay::ScriptUtil::getString(2, false);
+
+                // Get parameter 2 off the stack.
+                const char* param2 = gameplay::ScriptUtil::getString(3, false);
+
+                Transform* instance = getInstance(state);
+                instance->removeScriptCallback(param1, param2);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Transform_removeScriptCallback - 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;
         }

+ 3 - 0
gameplay/src/lua/lua_Transform.h

@@ -9,6 +9,7 @@ int lua_Transform__gc(lua_State* state);
 int lua_Transform__init(lua_State* state);
 int lua_Transform_addListener(lua_State* state);
 int lua_Transform_addScript(lua_State* state);
+int lua_Transform_addScriptCallback(lua_State* state);
 int lua_Transform_clearScripts(lua_State* state);
 int lua_Transform_createAnimation(lua_State* state);
 int lua_Transform_createAnimationFromBy(lua_State* state);
@@ -33,9 +34,11 @@ int lua_Transform_getTranslationX(lua_State* state);
 int lua_Transform_getTranslationY(lua_State* state);
 int lua_Transform_getTranslationZ(lua_State* state);
 int lua_Transform_getUpVector(lua_State* state);
+int lua_Transform_hasScriptListener(lua_State* state);
 int lua_Transform_isStatic(lua_State* state);
 int lua_Transform_removeListener(lua_State* state);
 int lua_Transform_removeScript(lua_State* state);
+int lua_Transform_removeScriptCallback(lua_State* state);
 int lua_Transform_rotate(lua_State* state);
 int lua_Transform_rotateX(lua_State* state);
 int lua_Transform_rotateY(lua_State* state);

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

@@ -105,8 +105,11 @@ void lua_RegisterAllBindings()
     luaRegister_RenderTarget();
     luaRegister_Scene();
     luaRegister_ScreenDisplayer();
+    luaRegister_Script();
     luaRegister_ScriptController();
     luaRegister_ScriptTarget();
+    luaRegister_ScriptTargetEvent();
+    luaRegister_ScriptTargetEventRegistry();
     luaRegister_Slider();
     luaRegister_SpriteBatch();
     luaRegister_Technique();

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

@@ -100,8 +100,11 @@
 #include "lua_RenderTarget.h"
 #include "lua_Scene.h"
 #include "lua_ScreenDisplayer.h"
+#include "lua_Script.h"
 #include "lua_ScriptController.h"
 #include "lua_ScriptTarget.h"
+#include "lua_ScriptTargetEvent.h"
+#include "lua_ScriptTargetEventRegistry.h"
 #include "lua_Slider.h"
 #include "lua_SpriteBatch.h"
 #include "lua_Technique.h"