Browse Source

Merge pull request #7 from evolutional/docs/gdnet-articles

docs: added tutorial articles
Greg Douglas 4 years ago
parent
commit
91dba617b3
72 changed files with 7259 additions and 0 deletions
  1. 1930 0
      gmsrc/doc/tutorial/1-intro/intro-to-gamemonkey.md
  2. 2 0
      gmsrc/doc/tutorial/1-intro/scripts/export_test.gm
  3. 23 0
      gmsrc/doc/tutorial/1-intro/scripts/expressions_1.gm
  4. 10 0
      gmsrc/doc/tutorial/1-intro/scripts/function_test.gm
  5. 6 0
      gmsrc/doc/tutorial/1-intro/scripts/functions_1.gm
  6. 2 0
      gmsrc/doc/tutorial/1-intro/scripts/hello.gm
  7. 5 0
      gmsrc/doc/tutorial/1-intro/scripts/loops_1.gm
  8. 8 0
      gmsrc/doc/tutorial/1-intro/scripts/loops_2.gm
  9. 15 0
      gmsrc/doc/tutorial/1-intro/scripts/scoping_1.gm
  10. 15 0
      gmsrc/doc/tutorial/1-intro/scripts/scoping_2.gm
  11. 13 0
      gmsrc/doc/tutorial/1-intro/scripts/scoping_3.gm
  12. 13 0
      gmsrc/doc/tutorial/1-intro/scripts/scoping_4.gm
  13. 14 0
      gmsrc/doc/tutorial/1-intro/scripts/scoping_5.gm
  14. 72 0
      gmsrc/doc/tutorial/1-intro/scripts/scoping_6.gm
  15. 8 0
      gmsrc/doc/tutorial/1-intro/scripts/tables_1.gm
  16. 10 0
      gmsrc/doc/tutorial/1-intro/scripts/tables_2.gm
  17. 7 0
      gmsrc/doc/tutorial/1-intro/scripts/tables_3.gm
  18. 8 0
      gmsrc/doc/tutorial/1-intro/scripts/tables_4.gm
  19. 8 0
      gmsrc/doc/tutorial/1-intro/scripts/tables_5.gm
  20. 9 0
      gmsrc/doc/tutorial/1-intro/scripts/tables_6.gm
  21. 14 0
      gmsrc/doc/tutorial/1-intro/scripts/tables_7.gm
  22. 9 0
      gmsrc/doc/tutorial/1-intro/src/basic_1.cpp
  23. 11 0
      gmsrc/doc/tutorial/1-intro/src/basic_2.cpp
  24. 13 0
      gmsrc/doc/tutorial/1-intro/src/basic_3.cpp
  25. 34 0
      gmsrc/doc/tutorial/1-intro/src/error_handling.cpp
  26. 63 0
      gmsrc/doc/tutorial/1-intro/src/execute_function_1.cpp
  27. 76 0
      gmsrc/doc/tutorial/1-intro/src/execute_function_2.cpp
  28. 57 0
      gmsrc/doc/tutorial/1-intro/src/execute_function_3.cpp
  29. 20 0
      gmsrc/doc/tutorial/1-intro/src/execution_1.cpp
  30. 66 0
      gmsrc/doc/tutorial/1-intro/src/export_function_1.cpp
  31. 50 0
      gmsrc/doc/tutorial/1-intro/src/export_function_2.cpp
  32. 29 0
      gmsrc/doc/tutorial/1-intro/src/loading_scripts_1.cpp
  33. 29 0
      gmsrc/doc/tutorial/1-intro/src/variables_1.cpp
  34. 46 0
      gmsrc/doc/tutorial/1-intro/src/variables_2.cpp
  35. 57 0
      gmsrc/doc/tutorial/1-intro/src/vector_1.cpp
  36. 112 0
      gmsrc/doc/tutorial/1-intro/src/vector_2.cpp
  37. 140 0
      gmsrc/doc/tutorial/1-intro/src/vector_2a.cpp
  38. 204 0
      gmsrc/doc/tutorial/1-intro/src/vector_3.cpp
  39. 230 0
      gmsrc/doc/tutorial/1-intro/src/vector_4.cpp
  40. BIN
      gmsrc/doc/tutorial/2-continuing/blocksigstates.GIF
  41. 2121 0
      gmsrc/doc/tutorial/2-continuing/continuing-gamemonkey.md
  42. 44 0
      gmsrc/doc/tutorial/2-continuing/cpp/blocking_01.cpp
  43. 369 0
      gmsrc/doc/tutorial/2-continuing/cpp/blocking_02.cpp
  44. 48 0
      gmsrc/doc/tutorial/2-continuing/cpp/blocking_02.gm
  45. 254 0
      gmsrc/doc/tutorial/2-continuing/cpp/ext_01.cpp
  46. 257 0
      gmsrc/doc/tutorial/2-continuing/cpp/ext_02.cpp
  47. 29 0
      gmsrc/doc/tutorial/2-continuing/cpp/functioncall_01.cpp
  48. 26 0
      gmsrc/doc/tutorial/2-continuing/cpp/functioncall_02.cpp
  49. 50 0
      gmsrc/doc/tutorial/2-continuing/cpp/signals_01.cpp
  50. 68 0
      gmsrc/doc/tutorial/2-continuing/cpp/signals_02.cpp
  51. 47 0
      gmsrc/doc/tutorial/2-continuing/cpp/this_01.cpp
  52. 27 0
      gmsrc/doc/tutorial/2-continuing/cpp/threads_01a.cpp
  53. 27 0
      gmsrc/doc/tutorial/2-continuing/cpp/threads_01b.cpp
  54. 22 0
      gmsrc/doc/tutorial/2-continuing/cpp/threads_02.cpp
  55. 26 0
      gmsrc/doc/tutorial/2-continuing/cpp/threads_03.cpp
  56. BIN
      gmsrc/doc/tutorial/2-continuing/guardstates.GIF
  57. 25 0
      gmsrc/doc/tutorial/2-continuing/scripts/blocking_01.gm
  58. 18 0
      gmsrc/doc/tutorial/2-continuing/scripts/blocking_02.gm
  59. 29 0
      gmsrc/doc/tutorial/2-continuing/scripts/blocking_03.gm
  60. 25 0
      gmsrc/doc/tutorial/2-continuing/scripts/blocking_04.gm
  61. 27 0
      gmsrc/doc/tutorial/2-continuing/scripts/blocking_05.gm
  62. 25 0
      gmsrc/doc/tutorial/2-continuing/scripts/states_01.gm
  63. 51 0
      gmsrc/doc/tutorial/2-continuing/scripts/states_02.gm
  64. 31 0
      gmsrc/doc/tutorial/2-continuing/scripts/states_03.gm
  65. 30 0
      gmsrc/doc/tutorial/2-continuing/scripts/states_04.gm
  66. 15 0
      gmsrc/doc/tutorial/2-continuing/scripts/threads_01.gm
  67. 16 0
      gmsrc/doc/tutorial/2-continuing/scripts/threads_02.gm
  68. 17 0
      gmsrc/doc/tutorial/2-continuing/scripts/threads_03.gm
  69. 17 0
      gmsrc/doc/tutorial/2-continuing/scripts/threads_04.gm
  70. 20 0
      gmsrc/doc/tutorial/2-continuing/scripts/threads_this_01.gm
  71. 24 0
      gmsrc/doc/tutorial/2-continuing/scripts/threads_this_02.gm
  72. 36 0
      gmsrc/doc/tutorial/2-continuing/scripts/threads_this_03.gm

+ 1930 - 0
gmsrc/doc/tutorial/1-intro/intro-to-gamemonkey.md

@@ -0,0 +1,1930 @@
+# Introduction to GameMonkey Script
+
+## Foreword
+
+This article is the revised version of the two-part series originally published in 2006 on GameDev.net. Its content reflects the author's version of the combined and [revised article](https://www.gamedev.net/tutorials/_/technical/apis-and-tools/introduction-to-gamemonkey-script-r3297/). There are several aspects that are out of date; such as the version numbers and comparison to Lua. The article has been left in its original form for preservation and posterity.
+
+## Introduction
+
+This article will introduce you to the GameMonkey Script (abbreviated to
+*GM Script* or simply *GM*) language and API and how it can be used in
+your own games. It begins with a short introduction to the language and
+how it compares to Lua, the most similar language to GM Script and a
+popular choice in game development. The article will then show you the
+basic features of the script language itself and teach you how to bind
+the virtual machine with your game applications. This article does not
+intend to be a comprehensive tutorial on using GameMonkey Script, nor
+will it cover the advanced topics and techniques that can be employed
+when scripting, however it will be enough to *whet your appetite* for GM
+Script and provide you with enough information to explore the language
+on your own. You can follow along with the examples in the code by
+experimenting with the *gme.exe* program that ships with standard
+GameMonkey distributions and running the example scripts that are
+supplied with this article.
+
+## Prerequisites
+
+In order to get the most of this article and indeed GameMonkey script,
+it is assumed that:-
+
+1. You have a working **C++** compiler environment (an IDE or command-line, it doesn't matter)
+2. You are able to program to an average level in C++
+3. You are able to understand languages with a similar syntax to C/C++
+4. You have an interest or requirement in embedding scripting languages
+
+If you fail any of these prerequisites, then by all means correct them
+before you continue reading as you will probably not get much from this
+article.
+
+## What Is GameMonkey Script?
+
+Scripting in games has long been an important technique for developers
+to employ. Scripting allows you to separate your game logic from your
+hardcore engine code and gives you the ability to tweak your content
+without time-consuming rebuilds of the entire engine. Some games, for
+example *Unreal,* have vastly complicated scripting environments in
+place which allow you to create graphical effects and perform almost
+every action imaginable in your game. In the past it was popular for
+game developers to 'roll their own' scripting language that was tied
+directly into their game systems, however language parsing and virtual
+machine design is a complex subject meaning that many developers are
+choosing to adopt a third party scripting language.
+
+Influenced by the popular embedded scripting language, Matthew Riek and
+Greg Douglas set about creating their very own language for a game
+project whilst employment at *Auran Software*; and thus GameMonkey
+Script was born. Created specifically for game scripting, GM Script is
+written with speed and simplicity in mind. The original version of GM
+Script has been used in several commercial ventures, from PC games to
+console games, and is growing in popularity amongst hobby game
+developers.
+
+## Comparison to Lua
+
+As GameMonkey script was originally inspired by Lua, it is useful to
+highlight the differences between the two environments.
+
+Feature | GameMonkey Script | Lua
+---|---|---
+Script Syntax | C-like | C/BASIC hybrid
+Source Language          |C++                     |C
+Numbers                  |int, float              |double
+Array Start Index        |0                       |1
+Default Scope            |local                   |global
+Multi-tasking            |Coroutines (called threads)    | Coroutines
+Garbage Collection       |Incremental Mark & Sweep |Incremental ark & Sweep
+Parser                   |Flex/Bison              |Custom Parser
+Data Access method       |Global table / function call params |Stack access
+Statement terminator     |Semi-colon              |Optional emi-colon
+Ease of host binding:- with 3rd party tool   |Moderate                |Difficult
+Ease of host binding:- with 3rd party tool  |Simple/Moderate         |Simple
+Community size           |Small                   |Large
+Availability of documentation/example code         |Low                     |High
+Latest version           |1.25j                   |5.1.3
+License                  |MIT                     |MIT
+
+Lua has been used successfully in many commercial and amateur game
+projects, however it can be difficult to use without a third party
+binding library as its stack-access method can be confusing for people
+new to scripting. GameMonkey Script aims to address the complexities of
+Lua whilst still maintaining its inherent power through flexibility.
+
+## Introduction to the Language
+
+In the following section I will introduce you to the GameMonkey Script
+language. You will learn how to manipulate variables, how to create and
+call functions and how to use the powerful GM Script 'table' object.
+This section is intended to be a primer to the language and it is
+assumed that you have some programming knowledge of C, C++, Java or
+other similar syntax styles. You can follow the simple examples I
+present here and experiment yourself using the *gme* executable that
+comes with standard GameMonkey Script distributions.
+
+### Syntax Overview
+
+This following section will give you an overview of the syntax used by
+the GameMonkey Script language. You will have noticed from the previous
+examples that the basic syntax of GM Script is very much akin to that of
+C. GM Script features the common elements of most programming
+languages:-
+
+- Variables
+- Comments
+- Expressions
+- Comparison Statements (if / else)
+- Loops (for, while, foreach)
+- Functions
+
+GameMonkey Script also features an in-built threading and state system,
+allowing you to create multiple threads within the virtual machine to
+run several parallel tasks at once. However, I will not venture into
+that territory in this introductory article.
+
+### GameMonkey Scripts: Defined
+
+A 'script' in GameMonkey is usually a plain-text ASCII file that
+contains a collection of functions, variable declarations and
+expressions. Scripts are usually loaded in from disk and compiled into a
+form that the GM environment can work with, namely *bytecode*. There is
+no standard form to a GameMonkey Script; you do not have to import
+'modules' like in Python, nor do you have to adhere to any indentation
+formatting (again, like Python). GameMonkey script does not have a
+native version of the *'include'* directive, so usually a script is
+self-contained (although you can load and execute multiple scripts on
+the same machine). The only requirement in GameMonkey Script is that
+function variables are declared before you try and call them; the
+ordering of such statements is important as there is no pre-processor.
+
+### GameMonkey Variables
+
+Unlike C/C++, GM Script is a *dynamically typed* language; variables do
+not have to be declared before use and can hold *any* type of value,
+even *functions*. The in-built basic types of GameMonkey Script are that
+of the number (integers or floats), the string, the function and the
+'table'. Here's some simple variables in use:
+
+```
+    myNull = null;
+    myNum = 50;
+    myString = "Hello!";
+    myFloat = 3.14;
+    print( myNum );
+    print( myString );
+    print( myFloat );
+```
+
+As you will see, a variable declaration is as simple as assigning a
+value. You will notice that every line is terminated by a semi-colon.
+This denotes the end of a statement and unlike Lua, is non-optional in
+GameMonkey Script. To C/C++ developers this will come naturally and so
+shouldn't cause too many problems.
+
+### Comments
+
+Comments in GM Script are exactly like those in C++; you can choose
+between C++ style line-comments or C-style block comments:-
+
+```
+    x = 5; // This is a line comment
+
+    /*
+        This is a block comment
+    */
+```
+
+### Expression and Conditional Syntax
+
+GameMonkey Script can evaluate common expressions using the standard
+C-style expression syntax and as such, anyone familiar with C or C++
+will feel comfortable using GameMonkey Script expressions.
+
+```
+    x = 5; // Assign a value to x
+    print( x );
+
+    y = (x * 10) + 56; // Assign a value to y
+    print( y );
+
+    if (x == 10) // Comparison (equality)
+    {
+        print( "x is equal to 10" );
+    }
+
+    if (x != 10) // Comparison (inequality)
+    {
+        print( "x is not equal to 10" );
+    }
+
+    if (x < 10) // Comparison (less than)
+    {
+        print( "x is less than 10" );
+    }
+
+    if (x > 10) // Comparison (greater than)
+    {
+        print( "x is greater than 10" );
+    }
+```
+
+GM Script also features bitwise operations, such as *or* ('\|'), *and*
+('&') and *not* ('!') which can be used in assignment or comparison
+expressions.
+
+One can employ conditional logic in GameMonkey script by using the 'if'
+comparison.
+
+```
+    if ( <condition expression> )
+    {
+        // Do something if true
+    }
+    else if ( <second condition> )
+    {
+        // Do if 2nd condition passes
+    }
+    else
+    {
+        // Do if all are false
+    }
+```
+
+Unlike C/C++, GM Script does not contain a 'switch' or 'case' statement
+so one must emulate the functionality by using blocks of if / else if
+tests.
+
+### Loops and iterations
+
+GameMonkey script has several methods of executing a loop. The first is
+the familiar '*for*' statement:-
+
+```
+    for (<statement>; <condition>; <statement>)
+    {
+        // repeated statement
+    }
+```
+
+A simple example to iterate a variable and print the number it contains
+would be:-
+
+```
+    for (it = 0; it <= 10; it = it + 1)
+    {
+        print( "it = ", it );
+    }
+```
+
+The output will be the numbers from 0 to 10 printed on separate lines in
+the output console.
+
+The '*while'* statement is used in situations where the conditions
+around the loop aren't as certain; the most common use of the while loop
+is to loop until a particular flag is set.
+
+```
+    while ( <condition> )
+    {
+        // repeated statement
+    }
+```
+
+For example, to repeat until the user has pressed the 'quit' button:-
+
+```
+    while ( !quitButtonPressed )
+    {
+        // do something in the game
+        quitButtonPressed = host_check_for_quit();
+    }
+```
+
+Note that the *'host_check_for_quit'* function is a hypothetical
+application-bound function. Similarly, an approximation of the 'for'
+loop you saw previously would be:-
+
+```
+    it = 0;
+    while (it <= 10)
+    {
+        print( "it = ", it );
+        it = it + 1;
+    }
+```
+
+The *'foreach'* loop allows you to iterate over the contents and keys of
+a table. I will cover this in more detail in the table section of this
+article.
+
+That was a brief overview of the various statements, expressions and
+symbols used in the GM Script language; however it is far from
+exhaustive. For a full list of expressions and iterators along with
+their syntax you are advised to consult the
+*'GameMonkeyScriptReference'* which comes with the official GameMonkey
+Script releases.
+
+### Scripted Functions
+
+The GameMonkey Script machine has two forms of functions. The first is
+the scripted function, a function that is created and coded in script. A
+scripted function is specified in the same way as a normal variable:-
+
+```
+    myMultiply = function( x, y ) { return x * y; };
+```
+
+As functions are created and specified as variables, it is extremely
+important to remember the terminating semi-colon at the end of the
+function declaration. Calling a function is as you'd expect from a
+C-style syntax:-
+
+```
+    a = myMultiply( 100, 2 );
+    print( a );
+```
+
+The second type of function is that of the host-declared function. An
+example of a native function is the '*print*' command which is contained
+within gmMachineLib and bound to every gmMachine you create. Only 'C'
+style functions or static class methods can be bound to the GameMonkey
+machine, but there are workarounds to this. I will cover the binding of
+native functions further on in this article.
+
+## GameMonkey Script Tables
+
+The table is an important and powerful structure within GameMonkey
+script. At its most basic, it allows you to specify arrays of data, it
+its most complex, you can begin to create organised structures of data
+and functions for use in your games.
+
+### Tables as Arrays
+
+A table can be used as a simple array which contains any type of data.
+
+Initialisation Example:
+
+```
+    myArray = table( 1, 2, 3.14, 4, 5, "dog", "cat", 100 );
+```
+
+Much like C/C++ arrays, you need to use indices to access the data
+within the table. All indices are zero-based when a table is initialised
+in this manner. Lua programmers should note this difference, as in Lua
+initialised tables begin at index 1.
+
+Accessing the data:
+
+```
+    myArray[0] = 50;
+    print( myArray[1] );
+
+    myArray[100] = "dog_100"; // new item added
+    print( myArray[100] );
+```
+
+### Tables as Associative Arrays
+
+A table can also be used as an associative array, much like the 'map'
+structure in the C++ STL. An associative array can be indexed using a
+non-numeric key, allowing for 'named' data lookups. Again, the data
+items in an associative array can be of any type.
+
+Initialisation:
+
+```
+    myData = table( Name = "Test", Weight = 60 );
+```
+
+Accessing the data is as simple as the first example:
+
+```
+    print( myData[ "Name" ] );
+    print( myData[ "Weight" ] );
+
+    myData["Name"] = "Albert";
+    myData["Test"] = "Some Text Here";
+
+    print( myData[ "Name" ] );
+    print( myData[ "Test" ] );
+```
+
+You will have noticed that we can assign new keys and indexes at any
+time as the tables have no defined bounds.
+
+### Tables as Mixed Arrays
+
+You can use the table as a 'mixed array', an array that contains both
+indexed data and keyed data (as in an associative array). This makes the
+table structure very flexible:-
+
+```
+    myTest = table( 1, 4, Test = "Text!", 7, 8 );
+    print( myTest[0] );
+    print( myTest[3] );
+    print( myTest["Test"] );
+```
+
+In the example above, the second print statement prints the number 7 and
+not as you may expect, the word "Text!". The reason for this is because
+GM Script keeps indexes and keys separate from each other within the
+table.
+
+### Iterating Table Data -- 'foreach'
+
+The *'foreach'* statement allows you to iterate over the contents of a
+table in a loop. The most basic form of the foreach statement is to
+examine just the values within the table:
+
+```
+    foreach ( <value> in <table> ) { // statements }
+```
+
+An example of this follows:
+
+```
+    fruits = table ( "apple", "pear", "orange" );
+    foreach ( frt in fruits )
+    {
+        print(frt);
+    }
+```
+
+Will print the contents of the table to the console in no particular
+order. However, you may have noticed that the table key is often as
+important as the value it references and may wish to capture that data
+too:-
+
+```
+    foreach ( <key> and <value> in <table> { // statements }
+```
+
+An example:-
+
+```
+    fruits = table ( "apple", "pear", Juicy = "orange" );
+    foreach ( k and f in fruits )
+    {
+        print( "The value at key '", k, "' is '", f, "'" );
+    }
+```
+
+Will print something similar to:-
+
+```
+    The value at key '0' is 'apple'
+    The value at key 'Juicy' is 'orange'
+    The value at key '1' is 'pear'
+```
+
+### Simulation of 'structs' and simple classes with Tables
+
+The final use of the table structure is to simulate C/C++ structs and
+classes. If you recall what I mentioned before, the GM Script table
+object can store *any* type of data, including functions. Because of
+this, you can assign a scripted function to an index or key within a
+table.
+
+```
+    myStruct = table(
+        SayHello = function() { print( "Hello, world!" ); }
+    );
+
+    myStruct.SayHello(); // Call table-bound function
+```
+
+As you see in the example, you can access keyed table data using the
+period (dot) operator. This allows us to treat the table as a simple
+class structure, accessing the named elements in a familiar fashion.
+
+```
+    myAlien = table(
+        Name = "Alien",
+        AttackPower = 20,
+        Strength = 50,
+        OnAttack = function( entity ) {
+            entity.Damage( this.AttackPower );
+        }
+    );
+```
+
+The slightly more complex example shows how simply a generic alien
+scripted object can be created using the in-built GameMonkey Script
+types and how it is centred primarily around the use of the table
+object.
+
+Unlike C++ classes, it is important to note that the GM Script table
+object has no constructor/destructor, cannot be inherited from and does
+not allow for custom operator overriding. However, you can achieve such
+behaviour through creating your own bound types (covered in the next
+instalment of this article). It should also be noted that GM tables have
+no concept of public, private and protected scoping as C++ presents for
+structs and classes. All table members are declared as being in the
+public scope and so can be accessed from anywhere. I will continue the
+scoping discussion in the next section.
+
+### Scoping
+
+GameMonkey script has a range of scopes for variables (and hence
+functions). If you wish your functions or methods to be accessible from
+outside of the script (for example, to be read directly by the host
+application) you must declare them as being in the *global* scope. The
+global scope is accessible everywhere in the script; even within other
+functions. Without this declaration, the objects are implicitly within
+*local* scope, which means they're only accessible to within the current
+scope or lower.
+
+```
+    // Create a variable in the global scope
+    global myvar = 100;
+
+    // parameter 'a_param' is in function local scope
+    myfunc = function( a_param ) {
+        // variable myvar is in local scope
+        myvar = a_param;
+        print( myvar );
+    };
+    print( myvar );
+
+    myfunc( 50 );
+    print( myvar );
+```
+
+Hold up a minute; you will notice that I've created 2 variables called
+myvar, one in the function and the other in global scope. If you run
+this script you will notice that the value of the global *myvar* is
+unchanged, even though you set the value of *myvar* in the function. The
+reason for this is simple; they exist in different scopes! GameMonkey
+allows you to set global variables from within functions by explicitly
+specifying the scope of the variable. In this case, I add the *global*
+keyword to the *myvar* declaration in *myfunc.*
+
+```
+    // Create a variable in the global scope
+    global myvar = 100;
+
+    // parameter 'a_param' is in function local scope
+    myfunc = function( a_param ) {
+            // Access variable myvar in global scope
+            global myvar = a_param;
+            print( myvar );
+    };
+    print( myvar );
+
+    myfunc( 50 );
+    print( myvar );
+```
+
+Things can begin to become tricky, however, when using tables and the
+'*this*' operator. Whenever a variable is part of a table or
+user-defined object, it exists in the *member* scope of the parent
+object, or *this.* This concept will be familiar to you if you've done
+any work in C++, so I will not dwell on it. Let's have a look at the
+member scoping in use:-
+
+```
+    global mytable = table(
+        myMember = 50,
+        setMember = function( a_value ){
+            myMember = a_value;
+        }
+    );
+    print( mytable.myMember );
+
+    mytable.setMember( 100 );
+    print( mytable.myMember );
+```
+
+The script above behaves similarly to the local scoping example; the
+*myMember* method isn't altered. However, when you include the *member*
+scoping keyword you will see a different result.
+
+```
+    global mytable = table(
+        myMember = 50,
+        setMember = function( a_value ) {
+            member myMember = a_value;
+        }
+    );
+    print( mytable.myMember );
+
+    mytable.setMember( 100 );
+    print( mytable.myMember );
+```
+
+The 'this' scoping is fairly complicated, but at the same time is very
+powerful. Using 'this' scoping you can create generic delegates that can
+access the data of the object that is passed as 'this'. Confused? Take a
+look at the following example:-
+
+```
+    myTable = table(
+        myMember = 50
+    );
+
+    setMember = function( a_param ) {
+        this.myMember = a_param;
+    };
+    print( myTable.myMember );
+
+    myTable:setMember( 100 );
+    print( myTable.myMember );
+```
+
+In this example the function 'setMember' is completely external to the
+'myTable' object but is able to access its data and methods. The reason
+it is able to do this is though use of passing the *myTable* object as
+*this* when calling the setMember function. The body of setMember
+explicitly states that it will alter the data belonging to *this*
+without actually belonging to *this* at compile time. This allows you to
+create very powerful scripted functions which can exist in the global
+scope and be called from objects as if they were a member of that object
+itself. An abbreviation for typing 'this' is to simply type a single
+period '.'. For a more complex example of 'this' in action, please refer
+to *scoping_6.gm* which is included with this article.
+
+## Embedding GameMonkey Script
+
+Now that you have an understanding of the language syntax and have
+experimented with its use, you will want to want to do something with it
+in your games or applications. To do this, the GameMonkey Script library
+needs to be *embedded* in your own code. In order to do this, I will
+first introduce you to the concept of embedding and then provide some
+information in order to guide you in doing it yourself.
+
+GameMonkey Script runs as a *Virtual Machine* environment that requires
+binding manually to your host application. A virtual machine is, as its
+name implies, a piece of software that behaves as if it were a computer
+itself (Wikipedia, 2005). Typically, a virtual machine will execute
+programs by interpreting its own 'bytecode' which is similar to the
+machine code used by the CPU on the machine I'm using to write this
+document. The game (or application) that uses the virtual machine must
+interact with its interface. You cannot simply call a scripted function
+or access data directly from your compiler environment - you must access
+the correct API functions to do so. Typically, the virtual machine has a
+very basic set of functions and data types; it is up to your game to
+*export* an interface of its own to the script environment. As you do
+this, the game and scripting environment become bound in a symbiotic
+relationship; in this state, the game is often referred to as the
+'native' (as in non-interpreted), or 'host application' in which the
+scripted machine is 'embedded' (Varanese, 2003).
+
+### Setting up your Compiler Environment
+
+Compiler environments can vary quite wildly and so this section is by no
+means a comprehensive tutorial on setting up GameMonkey Script for your
+compiler. At this stage you will have downloaded the latest GameMonkey
+Script release zip file, unpacked it and be presented with the C++
+source code for the library. To embed GameMonkey script, you can either
+compile a static library from the source code or compile the source
+along with your host application. For the sake of convenience, I will go
+the static-library route and describe the basic method of compiling a
+static library of the GM Script sources using a typical IDE.
+
+1. Create an empty 'static library' C++ project
+2. Locate your relevant platform configuration file(*) and copy it to your *gm/src* directory of the standard GM Script distribution
+3. Import the **.cpp* and **.h* source files from the *gm/src* folder excluding the *gmDebugger.cpp and gmDebugger.h* files
+4. Set your compiler settings, altering the optimisation, runtime library and debug settings appropriately
+5. Compile the static library and store in an accessible location
+
+Once you have the static library, you can link it to your application
+like a normal library and compile programs using the GM Script API
+(assuming, of course, that you tell your compiler where to find the
+headers).
+
+You will notice that step **b** has an asterisk next to it. The
+configuration file *gmConfig_p.h* is where all platform-specific defines
+and settings are kept. You can use it to specify the endian-ness of
+native CPU, the size of common types or even set specific compiler
+settings. Choosing your platform configuration is relatively simple for
+common Windows and Linux platforms (both MSVC and GCC), but you may need
+to edit your configuration file if you're using an exotic compiler
+and/or platform.
+
+### Creating the GM Virtual Machine
+
+Before you can use GameMonkey Script in any way you must embed it in
+your application. To do so, you must create an instance of the virtual
+machine, which is embodied by the *gmMachine* class provided by the
+GameMonkey API.
+
+```
+    #include "gmThread.h"
+
+    int main()
+    {
+        // Create the GM Machine
+        gmMachine gm;
+        return 0;
+    }
+```
+
+**Example: basic_1.cpp**
+
+Compiling and linking should proceed without a problem provided that you
+a) include the directory containing your GM headers in your project or
+global search path and b) link to the static library you created
+earlier. If you run this program you will see nothing special; but it's
+there. The GameMonkey VM is embedded in your application!
+
+### Executing a String as a Script
+
+An embedded virtual machine is next to useless without a script to run
+on it, so this next section will cover the most basic way you can
+execute a script on the GameMonkey VM. The *gmMachine* object you
+created earlier has a member function called *ExecuteString* which
+provides you with a method to execute a text string as a script on the
+GM Machine. Let's see a simple example of this in action:-
+
+```
+    #include "gmThread.h"
+
+    int main()
+    {
+        gmMachine gm;
+
+        // Execute a simple script
+        gm.ExecuteString( "print( \"Hello, world!\" );" );
+        return 0;
+    }
+```
+
+**Example: basic_2.cpp**
+
+Compiling and running this program should display the immortal words
+*"Hello, world!"* in your console window. There are two ways of using
+string literals within GameMonkey Script; the first is to use the
+familiar double quotes to denote the beginning and end of the string.
+For example:-
+
+```
+    gm.ExecuteString( "print( \"Hello, world!\" );" );
+```
+
+The second way is to use the back quote character:-
+
+```
+    gm.ExecuteString( "print( \`Hello, world!\` );" );
+```
+
+These both perform the same function but it should be noted that the two
+styles cannot be mixed within the same string:-
+
+```
+    gm.ExecuteString( "print( \"Hello, world!\` );" ); //ERROR
+```
+
+Providing GameMonkey Script with a script string containing
+double-quoted string literals poses us a problem as we're using C++ and
+we will need to escape these elements in order to compile our program.
+
+In the following code snippet, I will store my script in a *const
+char** string and pass the data to GM for execution:-
+
+```
+    #include "gmThread.h"
+
+    int main()
+    {
+        const char *myScript = "fruits = table ( \"apple\", \"pear\", \"orange\" ); foreach ( frt in fruits ) { print(frt); } ";
+
+        gmMachine gm;
+
+        // Execute the script
+        gm.ExecuteString( myScript );
+        return 0;
+    }
+```
+
+**Example: basic_3.cpp**
+
+As you can see, hard coding scripts as text strings can quickly become
+messy and it actually defeats the need for a scripting language in the
+first place; your strings are still compiled along with the application
+and any changes to them forces a recompile! In the following section I
+will talk about loading scripts from a file.
+
+### Executing a Script from File
+
+In order to overcome the need for hard-coded scripts, it is beneficial
+to load the scripted data from a file. However, you may notice that the
+gmMachine object has no member function for loading scripts from a file
+resource. To some, this omission may seem to be a startling oversight,
+but it becomes understandable when you appreciate the context that the
+GameMonkey Script environment is intended for - games! Games often have
+many weird and wonderful methods of loading file resources; some choose
+straight file IO, others use a zip-like format, others have encryption
+and some even use a network layer to receive the game content. In this
+context, a single 'LoadScript' member function is fairly pointless as
+the majority of games embedding GM would have little use for it.
+
+The basic method of loading a script from file is as follows:-
+
+1. Locate the file resource
+2. Open the file resource
+3. Obtain the size of the data to load
+4. Allocate enough memory to load the data plus one byte for the zero terminator
+5. Load the data from file into the allocated memory
+6. Close the file
+7. Compile the script from the loaded data
+8. Free up the allocated memory containing the script
+
+It is worth bearing in mind that steps 3, 4 and 5 can be combined into a
+single step because we can use *ifstream* and *string* from the C++
+standard library, however I have chosen to separate out the steps should
+you be using a non-C++ library such as PhysicsFS or the legacy C FILE
+functions. With this in mind, it is simple to write our own simple
+implementation based on the C++ standard library.
+
+```
+    #include <fstream>
+    #include <string>
+    #include <iterator>
+
+    int gmLoadAndExecuteScript( gmMachine &a_machine, const char *a_filename )
+    {
+        std::ifstream file(a_filename);
+
+        if (!file)
+            return GM_EXCEPTION;
+
+        std::string fileString = std::string(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
+        file.close();
+        return a_machine.ExecuteString(fileString.c_str());
+    }
+```
+
+**Example: loading_scripts_1.cpp**
+
+If you now integrate this code with the simple example code shown
+previously, you should now be able to load and execute scripts from a
+text file. GameMonkey scripts usually have a *.gm, extension, but this
+is obviously not required.
+
+```
+    #include "gmThread.h"
+
+    int main()
+    {
+        gmMachine gm;
+        // Execute a simple script file
+        gmLoadAndExecuteScript ( gm, "scripts/hello.gm" );
+        return 0;
+    }
+```
+
+### Basic Error Checking
+
+Now that your scripts are getting more complex you may begin to
+experience accidental syntax errors which would cause the script
+compilation to fail. It is extremely important that you handle at least
+the basic errors that come from bad script compilation. The gmMachine
+object maintains an internal log of the last errors in the compilation
+process which will help you catch these errors should they occur.
+
+The basic way of checking an error is to catch the return from the
+*ExecuteString* member function. If the value is zero, there is no error
+and you can proceed as normal. However if the value is non-zero you have
+an error and should handle it somehow. Simply knowing that there's an
+error is useless in helping you track it down, so GameMonkey gives you
+access to the error log for your own use. You can access the compilation
+log using the *GetLog* member function of the gmMachine object. From the
+retrieved gmLog object you can access the *GetEntry* function, which
+allows you to iterate through the errors the log contains, popping them
+from the list when you're done.
+
+```
+    #include "gmThread.h"
+    void handleErrors( gmMachine &a_machine )
+    {
+        gmLog &log = a_machine.GetLog();
+
+        // Get the first error
+        bool firstError = true;
+        const char *err = log.GetEntry( firstError );
+
+        while ( err )
+        {
+            std::cout << "Compilation error: -" << err << std::endl;
+            err = log.GetEntry( firstError );
+        }
+    }
+```
+
+**Example: error_handling.cpp**
+
+In the code above you will notice the use of the *firstError* variable;
+this is used internally by GM Script to control the one-way iteration
+over the log entries. You must be set the variable to true for the first
+call to the function; it will be set to false on subsequent calls.
+
+```
+int main()
+{
+    const char *myScript = "fruits = table ( \"apple\", \"pear\", \"orange\" ); foreach ( frt in fruits ) { print(frt); } ";
+
+    gmMachine gm;
+
+    // Execute a simple script
+    int ret = gm.ExecuteString( myScript );
+    if ( ret != 0 )
+    {
+        // There were errors in the script, exit gracefully
+        handleErrors( gm );
+        return 1;
+    }
+    return 0;
+}
+```
+
+**Example: error_handling.cpp**
+
+Now that you know how to handle script compilation errors I will set you
+the task of updating the *gmLoadAndExecuteScript* function and adding
+better error handling and reporting compilation errors to the user.
+
+### More on Script Execution
+
+All of the examples we've looked at so far have assumed that you want
+to execute a script immediately; this can often not be the case in games
+where data and scripts need to be loaded and compiled at a specific
+time, usually while a loading screen is presented. GameMonkey has two
+ways of preventing a compiled script from immediate execution; the first
+is to set the optional *a_now* parameter of the
+*gmMachine::ExecuteString* member function to *false* when you call it.
+This will compile the string but not execute it until you call the
+*Execute* member function on the gmMachine object. An example of this
+follows:
+
+```
+    #include "gmThread.h"
+
+    int main()
+    {
+        gmMachine gm;
+
+        // Compile a simple script without running it
+        gm.ExecuteString( "print( \"Hello, world!\" );", 0, false );
+
+        // The text wasn't printed!
+        // Wait for a key press
+        getchar();
+
+        // The script will now execute!
+        gm.Execute( 0 );
+        return 0;
+    }
+```
+
+**Example: execution_1.cpp**
+
+A task for you, the reader, is to create an enhanced version of the
+*gmLoadAndExecuteScript* function which allows you to specify when the
+code is actually executed by specifying the *a_now* parameter
+appropriately.
+
+The second method of controlling when a script is executed involves
+compiling it down to raw bytecode and executing the stream as a library.
+This method is useful in games as the script is converted into a form
+that isn't as easily readable as a script stored in a text file. One
+common use for scripting in games is to execute a script within a game
+level when the a certain event is triggered; by using a bytecode version
+of your scripts you can easily include compiled script code within your
+game level file. This is beyond the scope of this article and will not
+be explored further, however if you wish to explore this on your own,
+you should refer to the functions *CompileStringToLib* and *ExecuteLib*
+which are members of gmMachine. Like using text files, you are
+responsible for writing your own loading and saving routines for the
+*gmStream* objects that contain the compiled scripts.
+
+In the example code *execution_1.cpp* you were introduced to a new
+member function of the gmMachine object, namely *Execute.* This function
+effectively tells the machine to execute all active threads in turn. As
+you can appreciate, it is extremely powerful when it comes to running
+scripted threads, as you can now update the GameMonkey virtual machine
+along with the rest of your game logic. Using scripted threads, or
+*co-routines*, is out of this article's scope but I will introduce you
+to the basic concept of how they work.
+
+Everything within the GameMonkey virtual machine runs in a *gmThread*
+object, which has its own executable bytecode, stack and scope. The
+virtual machine can hold many of these threads in memory at any one
+time, preserving the states of them until the threads are next
+'ticked' by the machine. What happens behind the scenes of the
+*ExecuteString* function is that GameMonkey will spawn a new GM Script
+thread, compile the script into the thread and populate its internal
+structures with references to the functions and variables contained
+within this script. If *a_now* is true, the thread will execute
+immediately on the gmMachine, causing the bytecode to be interpreted
+until there is no more code or the thread yields control back to the
+virtual machine. If *a_now* is false, the thread will be pushed into the
+queue along with the other threads and will only be updated on an
+*Execute* cycle, again executing until there is no more code or the
+thread yields.
+
+## The GM Script Objects
+
+If you look back to the first article you will recall that I said
+GameMonkey Script has several built-in types, namely integers, floats,
+strings, functions, tables and null. All variables within GMScript are
+held and accessed initially by *gmVariable* objects, which is a
+'catch-all' type and will be explained fully in the next section.
+Because GameMonkey Script objects are 'reference types' we must allocate
+them reference through the virtual machine; this rule applies to all but
+the three basic types -- integers, floats and the null type. Therefore,
+if you need to create a function, string, Table or a user-data type you
+must use request them from the gmMachine in the form of the
+*gmFunctionObject*, *gmStringObject*, *gmTableObject* and *gmUserObject*
+C++ objects.
+
+I am not going to detail exactly how to use these types because you can
+glean this information from the GM API docs, but I will say that *every*
+time you need GM to handle any of these types you *must* allocate them
+via the gmMachine object. For example, if you need to pass a string as a
+function parameter you cannot just pass the literal or a pointer to the
+null-terminated string data. Instead, you must allocate a new
+gmStringObject using *gmMachine::AllocStringObject* and populate the
+data accordingly. Likewise, if you are creating a bound type which needs
+to reference a native structure you must allocate a gmUserObject and set
+its data as your native pointer. You will see examples of these
+operations in the following section.
+
+### gmVariable Object
+
+The gmVariable type is important in many areas when accessing the VM
+API. Instead of having to provide multiple API functions to handle every
+conceivable object type GM has provided the *gmVariable*. The gmVariable
+is used in everything from function parameters and return data to table
+data objects; this object is a 'catch-all' class which holds the
+variable data that can pass to and from the VM as it holds information
+about the *type* of data as well as the data itself. The GM machine will
+read off the variable *type* before deciding how to proceed with
+handling the data it contains so it is vitally important that you set
+the appropriate type when manipulating your variables. Let's have a
+look at how you can create and manipulate a new variable:
+
+```
+    int main()
+    {
+        gmMachine gm;
+
+        // Allocate a string from the machine and set it as a variable
+        gmVariable stringVar( gm.AllocStringObject("Hello, World") );
+
+        // Allocate a variable containing an int and a float
+        // note it doesn't need to be created from the machine
+        gmVariable intVar( 100 );
+        gmVariable floatVar( 1.5f );
+
+        // Create a variable with a newly created table
+        gmVariable tableVar( gm.AllocTableObject() );
+
+        // Reset table var as an int, losing the table data it contained
+        tableVar.SetInt( 200 );
+
+        // Variable copying
+        intVar = floatVar;
+
+        // Make 'null'
+        stringVar.Nullify();
+
+        return 0;
+    }
+```
+
+**Example: variables_1.cpp**
+
+As mentioned previously, you need to allocate String and Table objects
+from the gmMachine object, but because floats and integers are native
+types, you are not required to perform any extra allocation to hold the
+data they contain. The variables created in the example don't actually
+do anything, but they are all ready to be pushed as a function parameter
+or set in a table. As you can see above, like in GMScript itself, you
+are free to assign variables, reset variables with new data or even
+completely nullify them.
+
+Sometimes you will be presented with a gmVariable from the machine; it
+may be come as a function parameter or as the result of a 'Get' on a
+gmTableObject. In these situations you will need to know how to retrieve
+the data. If you look in the *gmVariable.h* header you will see the
+following code in the gmVariable class.
+
+```
+    gmType m_type;
+    union
+    {
+        int m_int;
+        float m_float;
+        gmptr m_ref;
+    } m_value;
+```
+
+This should give you a hint in how to retrieve the data. Before you can
+do *anything* else you must check the *m_type* member. This holds the
+appropriate enumeration and will be either *GM_NULL*, *GM_INT, GM_FLOAT,
+GM_STRING, GM_FUNCTION, GM_TABLE* or an integer for your own types which
+increment from *GM_USER*. Once you have ascertained the type you can
+retrieve the value from the *m_value* union; in the case of integers and
+floats this is as simple as accessing *m_int* and *m_float*
+respectively, but what happens for other types? The answer should be
+obvious -- you need to cast the *m_ref* pointer to your appropriate
+type. It should be noted, however, that there are no runtime checks to
+ensure you're casting to the correct type; it is for this precise
+reason that you should *always* check the type before you attempt to
+cast. In a dynamically typed environment such as GameMonkey Script there
+are no guarantees about the type of data you will receive, so you must
+place it upon yourself to check before you access the data in the
+variable. The following example will highlight how to check for the type
+and access the data accordingly. As an exercise, try experimenting by
+changing the value you place in the *var* gmVariable and examine the
+results you get back.
+
+```
+    using namespace std;
+
+    int main()
+    {
+        gmMachine gm;
+
+        // Try setting your own variable here
+        gmVariable var( gm.AllocStringObject("Hello, World") );
+        switch (var.m_type)
+        {
+            case GM_NULL:
+                cout << "Variable is NULL type" << endl;
+                break;
+            case GM_INT:
+                cout << "Variable is INT type" << endl;
+                cout << "Value:" << var.m_value.m_int << endl;
+                break;
+            case GM_FLOAT:
+                cout << "Variable is FLOAT type" << endl;
+                cout << "Value:" << var.m_value.m_float << endl;
+                break;
+            case GM_STRING:
+                cout << "Variable is STRING type" << endl;
+                cout << "Value:" << reinterpret_cast<gmStringObject>(var.m_value.m_ref)->GetString() << endl;
+                break;
+            case GM_TABLE:
+                cout << "Variable is TABLE type" << endl;
+                cout << "Items:" << reinterpret_cast<gmTableObject>(var.m_value.m_ref)->Count() << endl;
+                break;
+            case GM_FUNCTION:
+                cout << "Variable is FUNCTION type" << endl;
+                break;
+            default:
+                cout << "Variable is USER type" << endl;
+                // retrieve native pointer from user object
+                void *ptr = reinterpret_cast<gmUserObject>(var.m_value.m_ref)->m_user;
+                break;
+        };
+
+        return 0;
+    }
+```
+
+**Example: variables_2.cpp**
+
+A final word of caution about gmVariables; numeric data can be stored
+with either the *GM_INT* or the *GM_FLOAT* type depending on whether it
+has a decimal or not. For example, imagine a script which uses a loop to
+count from 0 to 10 in increments of 0.5f. The variable will initially
+hold data of *int* type (zero is an int), and alternating between float
+and int on every second iteration. Because of this, it is important that
+any function that expects numeric float data performs a check to see if
+the variable is either a *GM_INT* or a *GM_FLOAT.*
+
+### Calling a Scripted Function
+
+There will often be times that you would like to call a known scripted
+function from your application; perhaps you specify that your game will
+need to call an *InitialiseGame* scripted function, or perhaps the
+*Attack* function in *scoping_6.gm* that was originally presented in
+part one's scripts. In GameMonkey Script there are currently two ways
+to call a scripted function from native code; the 'manual' way which
+uses the raw API to push variables and prepare the stack, and the
+'simple' way which uses a utility call *gmCall*. I will take you
+through calling a scripted function using gmCall, since that is the
+simplest and most common way you'll need to call a function. For
+purists, I have included some example source that doesn't use gmCall
+with this article, but for most purposes I advise using gmCall.
+
+### Using *gmCall*
+
+The authors of GameMonkey Script realised that the 'manual' way of
+calling functions can be long-winded and prone to error and so have
+thoughtfully provided *gmCall* to vastly simplify the calling of
+scripted functions.
+
+1. Create the gmCall object
+2. Call the BeginGlobalFunction / BeginTableFunction member function to initialise
+3. Push the parameters
+4. 'End' the call
+5. Get return values, if required
+
+Here is an example that calls a scripted function '*myMultiply*' which
+takes two numbers as parameters and returns their sum.
+
+```
+    int main()
+    {
+        gmMachine gm;
+
+        // Execute a simple script file
+        gmLoadAndExecuteScript ( gm, "scripts/function_test.gm" );
+        
+        gmCall call;
+        if ( call.BeginGlobalFunction( &gm, "myMultiply" ) )
+        {
+            // Push the parameters
+            call.AddParamInt( 10 );
+            // Example showing a variable can be used
+            gmVariable var( 2 );
+            call.AddParam( var );
+            // Execute the call
+            call.End();
+            // Handle the return value
+            int myReturn = 0;
+            if (call.GetReturnedInt( myReturn ) )
+            {
+                std::cout << "myMultiply returned " << myReturn << std::endl;
+            }
+            else
+            {
+                std::cout << "myMultiply returned an incorrect value" <<
+                std::endl;
+            }
+        }
+        else
+        {
+            std::cout << "Error calling 'myMultiply'" << std::endl;
+        }
+        return 0;
+    }
+```
+
+The gmCall *AddParam** functions allow you add parameters without
+having to deal with gmVariable objects (although it is entirely possible
+to pass your own gmVariables). Any required allocations and validations
+are performed automatically for you, allowing you to quickly access the
+scripted functions you need.
+
+### Creating a host-bound function
+
+Now that you know how to call a scripted function from native code, you
+may be wondering how you export your own functions to GameMonkey Script.
+The reasons for wanting to do so are understandable; some people may
+want the speed of native code (although GM is fast, it's still slower
+than native code), others may want to expose aspects of their game or
+engine to the script. Whatever your reasons, you need to know how to
+export your own functions.
+
+Unlike some scripting languages (for example AngelScript), functions
+must be 'wrapped' for use by the VM. The GM Script VM doesn't have
+the ability to translate the parameters from the script into a form
+understandable by your native compiled code -- one reason being that
+function calls and their parameters aren't known until runtime, unlike
+in C++ where everything is checked during compilation. The process
+within the wrapped a function usually involves the following steps:
+
+1. Parsing the parameters passed from the scripting VM
+2. Converting them into a usable form for C++ code
+3. Performing the main action of the function
+4. Converting any return values to a suitable format for the VM
+5. Returning control back to script
+
+Here's the code I will be examining for a simple 'native' version of
+*myMultiply*:-
+
+```
+    int GM_CDECL gm_myMultiply( gmThread *a_thread )
+    {
+        // Check the number of parameters passed is correct
+        if (a_thread->GetNumParams() != 2 )
+            return GM_EXCEPTION;
+
+        // Local vars to hold data from params
+        int a_x = 0;
+        int a_y = 0;
+
+        // Check params are valid types
+        if (a_thread->ParamType(0) != GM_INT)
+            return GM_EXCEPTION;
+
+        if (a_thread->ParamType(1) != GM_INT)
+            return GM_EXCEPTION;
+
+        // Get data from params
+        a_x = a_thread->Param(0).m_value.m_int;
+        a_x = a_thread->Param(1).m_value.m_int;
+
+        // perform calculation
+        int ret = a_x * a_y;
+
+        // return value
+        a_thread->PushInt( ret );
+
+        return GM_OK;
+    }
+```
+
+Like its scripted counterpart, this function takes two parameters and
+returns the sum of their values. The 'wrapped' function first checks
+that the number of parameters it has been passed is correct; if not we
+return a scripted exception, next it checks to see that the parameters
+are the correct type (in this case, *int*). It then reads the values of
+these parameters from the thread - you will notice that the parameters
+are held again in the *gmVariable* structure. After the parameter data
+has been collected and converted you can now perform the main body of
+the function; in this example it is a simple multiplication but in your
+games it is likely that you will call another function in your engine.
+
+You will notice that a lot of the code to check parameters is repetitive
+and can be cumbersome to write. Fortunately for us, the GameMonkey
+authors have provided several macros to aid our task.
+
+```
+    int GM_CDECL gm_myMultiply( gmThread *a_thread )
+    {
+        GM_CHECK_NUM_PARAMS(2);
+        GM_CHECK_INT_PARAM( a_x, 0 );
+        GM_CHECK_INT_PARAM( a_y, 1 );
+
+        int ret = a_x * a_y;
+        a_thread->PushInt( ret );
+        return GM_OK;
+    }
+```
+
+The *GM_CHECK_NUM_PARAMS* macro is fairly self-explanatory; it checks
+the number of parameters from the thread. The *GM_CHECK\_*\_PARAM*
+macros are similar, but they also declare the variables and fill them
+for you. These macros make the code much simpler to read while still
+performing the same function.
+
+## Creating a simple type
+
+Many game developers will want to expose their own types to a scripting
+system, and GameMonkey Script is no exception. Imagine a simple class
+that is in most 3d applications, the *Vector* class. This can be as
+simple as a structure composed of 3 floats for *x, y* and *z* or can be
+as complex as a class which holds member functions to perform operations
+and calculations on the vector data. Sometimes it is possible to use the
+integral *table* object for custom-bound objects, but in some situations
+you require the application to have more control over the object --
+perhaps by providing extra validation, data conversion or updating
+another object in your game when the data is changed on the object. With
+a simple *table* this sort of control is impossible, hence the need for
+user-defined types.
+
+### Choosing what to bind
+
+When choosing to bind your type you must consider how it will be used in
+script. For example, the simple *Vector* type could be easily
+represented as a fixed array of 3 floats, it could have the constituent
+items stored in named members (such as x, y and z), or it could be
+comprised of both.
+
+For example:
+
+```
+    v = Vector( 10, 20, 50 ); // Create vector
+
+    // Vector could be represented using 3 floats
+    v[0] = 20;
+    v[2] = v[1];
+
+    // Access vector using named members
+    v.X = 20; // Set X member to 20
+    v.Z = v.Y;
+```
+
+You could choose to provide the exact same interface as your engine's
+vector class, you could simplify it somewhat, or you could even provide
+an entirely different interface. For example, some people may wish to
+access vector maths functions using the *dot* operator, whereas others
+may wish to keep the vector type as data-only and provide specialist
+functions to manipulate the data.
+
+For example:
+
+```
+    v = Vector( 10, 20, 50 ); // Create vector
+    v.Normalise(); // Call normalise using dot operator
+    NormaliseVector( v ); // Normalise using a specialist function
+```
+
+Many game developers seem to think they need to expose their entire C++
+class to the scripting environment. While this is possible, it is often
+unnecessary; there could be many member functions that are useless in a
+scripting context so it makes little sense to include them. Even more
+so, there may be member functions and data that you do not want your
+script to be able to access so exposing the full C++ class would be
+undesirable. Unfortunately, the decisions about what to bind are
+entirely context dependant and will change for every game project, game
+system or even game class you wish to bind to a scripting language. In
+my personal experience, I have found it useful to provide a simplified
+and refactored interface to the scripting environment. The more
+complicated it is to use the scripted interface the more likely it is to
+confuse people and create problems for them whilst using it. If the
+interface is simple, you can also spend less time documenting it and
+writing code to debug it.
+
+## Binding a simple Vector type
+
+The discussion around type binding will continue by expanding the Vector
+example examined previously. I will outline a *simple* 3d vector class
+and create a type binding for the GameMonkey Script environment.
+
+Imagine a typical game engine's vector type (simplified):
+
+```
+    class Vector
+    {
+    public:
+        Vector() : x(0), y(0), z(0) { }
+        Vector( float a_x, float a_y, float a_z ) : x(a_x), y(a_y), z(a_z) { }
+        float x, y, z;
+    };
+```
+
+There are three constructors; one default constructor, one taking the
+values to initialise the vector with and a copy constructor. The first
+thing to do to bind this vector type to GM Script is to specify the
+basic type library. The 'library' is nothing more than a global
+function declared within the machine global context and an instruction
+to the gmMachine to register this function with a specified type name.
+This global function effectively becomes the type's constructor and is
+the ideal place to begin creating our bound type.
+
+The constructor entry point is specified in a *gmFunctionEntry* table as
+such:
+
+```
+    namespace gmVector
+    {
+        // Declare a type ID
+        gmType Type = GM_NULL;
+
+        int GM_CDECL libentry( gmThread *a_thread )
+        {
+            Vector *p = new Vector();
+            a_thread->PushNewUser( p, Type );
+            return GM_EXCEPTION;
+        }
+
+        gmFunctionEntry lib[] =
+        {
+            { "Vector", libentry } // type name, entry point
+        };
+
+    }; // end of namespace gmVector
+```
+
+**Example: vector_1.cpp**
+
+You will notice the global declaration of a gmType variable named
+*Type*; this is to hold the GM type Id once the type is registered with
+the gmMachine. You are free to name the constructor whatever you want,
+but for organisational reasons I have named it *libentry* and placed it
+within the *gmVector* namespace. The *libentry* function is where the
+first step of the binding is done; we create an instance of the native
+class object and return it to GM by pushing it onto the thread as a new
+*gmUserObject* but with the type id stored within our library.
+
+Now that the initial structure of the library is laid out we can
+register it with the gmMachine. Initialisation is done with 2 simple
+function calls:
+
+```
+    namespace gmVector
+    {
+        void BindLib( gmMachine *a_machine )
+        {
+            // Register one function (the entry point)
+            a_machine->RegisterLibrary( lib, 1 );
+            Type = a_machine->CreateUserType( lib[0].m_name );
+        }
+    }; // end of namespace gmVector
+```
+
+**Example: vector_1.cpp**
+
+Just like function binding, you need to register the library with the
+machine. After doing so you create your type and store it away for use
+in the rest of the library. The *CreateUserType* member function simply
+takes the name of a type to register; in this case I've retrieved it
+directly from the library constructor's name as you should ensure that
+it corresponds with the function you just registered as the constructor.
+
+### Constructor with Parameters
+
+At present, this type is pretty useless as there is no way of accessing
+the data the Vector contains. The decision about how to access the data
+is an important one; shall we allow the user to access it via named
+properties (e.g.: x, y, z members) or via an array of floats. I shall
+answer this question shortly, but first we need a way of initialising
+the data on construction of the type. As in the C++ class, we want to
+allow the user to specify a constructor with several parameters to
+initialise the data in the vector as well as providing a default
+constructor.
+
+```
+    namespace gmVector
+    {
+        int GM_CDECL default_constructor( gmThread *a_thread )
+        {
+            // Create a native object with default params
+            Vector *p = new Vector();
+            a_thread->PushNewUser( p, Type );
+            return GM_OK;
+        }
+
+        /// This is the constructor for passed data items
+        int GM_CDECL data_constructor( gmThread *a_thread )
+        {
+            // Check for a valid number of parameters
+            if (a_thread->GetNumParams() != 3 )
+                return GM_EXCEPTION;
+
+            // Loop through and grab the params, checking their types
+            float v[3];
+            for (int i = 0; i < 3; ++i)
+            {
+                switch (a_thread->Param(i).m_type)
+                {
+                case GM_INT:
+                    v[i] = a_thread->Param(i).m_value.m_int;
+                    break;
+                case GM_FLOAT:
+                    v[i] = a_thread->Param(i).m_value.m_float;
+                    break;
+                default:
+                    a_thread->GetMachine()->GetLog().LogEntry( "Vector: Param %d error -
+                    expected int or float", i );
+                    return GM_EXCEPTION;
+                }
+            }
+
+            // Create a native object with default params
+            Vector *p = new Vector( v[0], v[1], v[2] );
+            // Return to GM
+            a_thread->PushNewUser( p, Type );
+            return GM_OK;
+        }
+
+        /// Entry point for the library; this is effectively the constructor
+        int GM_CDECL libentry( gmThread *a_thread )
+        {
+            // Delegate the appropriate call based on the arg count
+            switch (a_thread->GetNumParams())
+            {
+            case 0:
+                return default_constructor( a_thread );
+            case 3:
+                return data_constructor( a_thread );
+            };
+
+            // Not handled, log an error and return an exception
+            a_thread->GetMachine()->GetLog().LogEntry( "Vector: Bad number of
+            parameters passed" );
+            return GM_EXCEPTION;
+        }
+
+    }; // end namespace gmVector
+```
+
+**Example: vector_2.cpp**
+
+I have adjusted the *libentry* function to delegate the actual
+constructor operation based on the number of parameters passed. The
+*default_constructor* function is the same as the previous libentry
+function, but in *data_constructor* you can see that I engage in an
+operation to retrieve the parameters from the thread. This is exactly
+the same as if you were binding a regular function, so I won't dwell on
+how it works. The new constructor validates that the parameters are
+either *integers* or *floats* and stores them for passing to the native
+*Vector* class' constructor.
+
+The data constructor could be extended to allow for copy construction of
+objects, allowing you to pass a variable of your Vector type and use it
+to create a copy of itself. This is important to remember as GameMonkey
+Script user-bound variables are *reference types*; if you assign a
+variable with another they will reference each other and any changes
+made to one will be visible in the other. As a learning exercise, I will
+leave the addition of the copy constructor as an extension for you to
+pursue on your own - you should be able to code it yourself with the
+information I've given you so far. If you get stuck you may refer to
+example *vector_2a.cpp* for my implementation.
+
+Now that there's some actual data in the vector object you need to
+allow scripts to retrieve it for use in other operations. It is at this
+point that we must decide the data access method; I have chosen to
+provide the members *x, y z* as this is familiar to many people and I
+feel best represents how I will use the vector in script. As I said
+previously, the decision is entirely yours and the methods I will
+describe can be adapted to use the *indexed* access method if you
+choose.
+
+### Operator Overrides
+
+If you have ever overridden a class operator in C++ you will know how
+powerful this feature is -- operator overriding allows you to specify a
+function to control the behaviour of a type when certain script
+operators are used. The operators you can override for a type in GM
+Script are:
+
+**Operator**|**Example**|**Purpose**
+---|---|---
+Dot Set   | v.x = 50;   | Setting of 'members'
+Dot Get   | a = v.y;    | Getting of 'members'
+Index Set | v[0] = 100; | Setting of indexed items
+Index Get | a = v[3];   | Getting of indexed items
+Add       | a = v + v2; | Addition of type variable with another variable
+Sub       | a = v -- v2;| Subtraction of type variable with another variable
+Mul       | a = v * v2; | Multiplication of type variable with another variable
+Div       | a = v / v2; | Division of type variable with another variable
+
+In this simple example I will only override the dot operators to provide
+access to the simulated 'member' access method of the Vector data.
+Operator overriding follows the same structure for each operator so it
+is simple to adapt my example to use the index operators.
+
+Operator functions all have the same signature:-
+
+```
+    void GM_CDECL operator_func(gmThread * a_thread, gmVariable *a_operands);
+```
+
+### GetDot Operator
+
+The operands passed to the operators vary on the type of operator. For
+the GetDot operator the operands are as follows:
+
+**Operand** | **Purpose**
+---|---
+0                    | The variable being operated upon and the return variable on exit (e.g.: 'v' in *a = v.x;* )
+1                    | The 'member' being accessed (as a gmStringObject) (e.g.: 'x' in *a = v.x;* )
+2                    | Data passed for assigning with the value from the object (e.g.: 'a' in *a = v.x;* )
+
+The following code details the GetDot function we will be using:
+
+```
+    void GM_CDECL OpGetDot(gmThread * a_thread, gmVariable * a_operands)
+    {
+        GM_ASSERT(a_operands[0].m_type == Type);
+
+        Vector* thisVec = reinterpret_cast<Vector*>(reinterpret_cast<gmUserObject*>(GM_OBJECT(a_operands[0].m_value.m_ref))->m_user);
+
+        GM_ASSERT(a_operands[1].m_type == GM_STRING);
+
+        gmStringObject* stringObj = reinterpret_cast<gmStringObject*>(GM_OBJECT(a_operands[1].m_value.m_ref));
+        const char* propName = stringObj->GetString();
+
+        // Resolve the member name
+        if(::stricmp(propName, "x") == 0)
+        {
+            a_operands[0].SetFloat(thisVec->x);
+        }
+        else if(::stricmp(propName, "y") == 0)
+        {
+            a_operands[0].SetFloat(thisVec->y);
+        }
+        else if(::stricmp(propName, "z") == 0)
+        {
+            a_operands[0].SetFloat(thisVec->z);
+        }
+        else
+        {
+            a_operands[0].Nullify();
+        }
+    }
+```
+
+**Example: vector_3.cpp**
+
+The process is simple; first we check that the type of the variable
+being operated on matches that of the newly bound Vector type.
+Afterwards, the string name of the member is retrieved and checked
+against the members we wish to 'export'. Confusingly operand zero is
+also the return variable, so it must be set with the relevant value from
+the bound class. This is as simple as copying the value from the
+'real' member in our class to the variable represented by operand
+zero. If there is a problem, you should nullify the return variable,
+which returns *null* to GameMonkey Script.
+
+With the Get Dot operator function created, it's time to add its
+registration to the *BindLib* function we looked as earlier. This is as
+simple as calling the *RegisterTypeOperator* on the newly bound type,
+passing the relevant operator and function handler as parameters:
+
+a_machine->RegisterTypeOperator(Type, O_GETDOT, NULL, OpGetDot);
+
+### SetDot Operator
+
+If you experiment with some scripts on the new Vector type, you will
+notice that you can read data from it but not alter the data in any way
+outside of actual construction of the variable. We will now provide a
+*SetDot* operator override to handle the setting of the member data. The
+operands are similar to that of *GetDot:*
+
+**Operand**c| **Purpose**
+---|---
+0 | The variable being operated upon and the return variable on exit (e.g.: 'v' in *v.x = a;* )
+1 | The data passed for assignment (e.g.: 'a' in *v.x = a;* )
+2 | The 'member' being accessed (as a gmStringObject) (e.g.: 'x' in *v.x = a;* )
+
+A function to handle the Set Dot operator for our vector class is as
+follows:
+
+```
+    void GM_CDECL OpSetDot(gmThread * a_thread, gmVariable * a_operands)
+    {
+        GM_ASSERT(a_operands[0].m_type == Type);
+
+        Vector* thisVec = reinterpret_cast<Vector*>(reinterpret_cast<gmUserObject*>(GM_OBJECT(a_operands[0].m_value.m_ref))->m_user);
+
+        GM_ASSERT(a_operands[2].m_type == GM_STRING);
+
+        gmStringObject* stringObj = reinterpret_cast<gmStringObject*>(GM_OBJECT(a_operands[2].m_value.m_ref));
+
+        const char* propname = stringObj->GetString();
+
+        // Create a variable to hold the data to assign
+        // handle both ints and floats
+        float newFloat = 0.0f;
+
+        if(a_operands[1].m_type == GM_FLOAT)
+        {
+            newFloat = a_operands[1].m_value.m_float;
+        }
+        else if(a_operands[1].m_type == GM_INT)
+        {
+            newFloat = (float)a_operands[1].m_value.m_int;
+        }
+
+        // Assign the data
+        if(::stricmp( propname, "x") == 0)
+        {
+            thisVec->x = newFloat;
+        }
+        else if(::stricmp( propname, "y") == 0)
+        {
+            thisVec->y = newFloat;
+        }
+        else if(::stricmp( propname, "z") == 0)
+        {
+            thisVec->z = newFloat;
+        }
+    }
+```
+
+**Example: vector_3.cpp**
+
+As you can see, it follows a similar progression from the previous
+example, except this time we need to retrieve the value passed to the
+function by the script (operand #1). As before, the member is compared
+to the exported members and the assignment made accordingly. Adding the
+following line to the *BindLib* function will complete the simple type.
+
+```
+    a_machine->RegisterTypeOperator(Type, O_SETDOT, NULL, OpSetDot);
+```
+
+I mentioned previously that GameMonkey Script user variables are
+reference types; this becomes evident now that you have working dot
+operators. For example, if one were to write a script such as:
+
+```
+    a = Vector( 20, 20, 30 );
+    b = a;
+    b.x = 10;
+    print(a.x);
+    print(b.x);
+```
+
+You would see that updating the value of *b.x* would also update the
+value of *a.x* as they both reference the same data. The solution to
+this would be to implement a copy constructor for the Vector type (or
+add a 'Copy' function to the type) which would be used as such:
+
+```
+    a = Vector( 20, 20, 30 );
+    b = Vector( a );
+    b.x = 10;
+    print(a.x);
+    print(b.x);
+```
+
+In this case you would notice that the data is copied and the two
+variables retain their own data.
+
+And there we have it; an *almost complete* simple vector type for you to
+use in your scripts. It is almost complete because we have not yet
+touched on the subject of Garbage Collection, which plays an important
+role in any bound type you create.
+
+## Garbage Collection
+
+GameMonkey Script, like many other scripting languages, has an in-built
+garbage collector (GC). A garbage collector will periodically examine
+the data within the machine and determine whether an object is being
+referenced or not -- if an object is deemed to have no referencing
+objects, the machine can assume it is no longer in use and will delete
+it to free memory. The GameMonkey machine uses an *incremental mark &
+sweep* garbage collector which has two main phases of operation. The
+first stage will examine all of the objects in the machine and 'mark'
+the unreferenced objects for deletion. Once this phase is complete, the
+'sweep' stage is executed which calls the destructors (or more
+correctly *finalizers*) on all the marked objects and removed them from
+the machine. The GC is said to be incremental as it performs a little
+work on each execution cycle to reduce the amount of time the script
+execution cycle of the machine is 'paused' for a full collection
+sweep.
+
+Garbage collection is important when binding your own types as you can
+often create a memory leak if an object is garbage collected without
+cleaning up any native objects it creates. Even more dangerously, if
+your object references other objects internally the GM machine may
+delete them and leave you with a bad pointer which could cause your game
+to crash. Both of these scenarios are undesirable so you need to make
+the garbage collector aware of your new object and tell it how to handle
+it.
+
+In order to handle the garbage collection on your bound type you must
+provide two things to the GameMonkey machine; a '*trace*' callback and
+a '*destruct*' callback. The trace callback is used during the *mark*
+phase of the GC and is used to tell the garbage collector which objects
+your native type is referencing. If you examine the code for the
+*gmTableObject* you will notice that its trace method will trace each of
+the objects the table holds; without doing this, the GC may remove some
+of the items from the machine erroneously. The *destruct* callback is
+used when the sweep stage is operational; it is used to free up any
+memory used by your bound type.
+
+I will complete my simple *Vector type* example by providing it with
+full garbage collection callbacks:
+
+```
+    /// Effectively the destructor for the object
+    void GM_CDECL gc_destruct(gmMachine * a_machine, gmUserObject* a_object)
+    {
+        std::cout << "Vector: destructing\n";
+
+        GM_ASSERT(a_object->m_userType == Type);
+        Vector* object = reinterpret_cast<Vector*>(a_object->m_user);
+        delete object;
+    }
+
+    // Trace the object in the mark phase
+    bool gc_trace( gmMachine * a_machine, gmUserObject* a_object, gmGarbageCollector* a_gc, const int a_workLeftToGo, int& a_workDone )
+    {
+        // Make sure this is the correct type
+        GM_ASSERT(a_object->m_userType == m_gmType);
+
+        // If your object immediately references other gmObjects, you should
+        call GetNextObject for each member here
+
+        // mark 'me' as done
+        a_workDone++;
+
+        return true;
+    }
+```
+
+**Example: vector_4.cpp**
+
+The *gc_destruct* destructor is simple; it merely calls delete on the
+memory we allocated in the constructor. The trace callback, *gc_trace*,
+is also simple for this particular type, but can get complicated as your
+type begins to reference more objects. Each immediate member object your
+type references should be pointed to using the GC method
+*GetNextObject*, which will allow GM to build the tree of referenced
+objects. You should also update the a_workDone parameter reference to
+indicate how many objects you are currently holding a reference to; this
+allows the incremental GC to effectively govern its own workload.
+Finally, we must register these callbacks in the *BindLib* function:
+
+a_machine->RegisterUserCallbacks(Type, gc_trace, gc_destruct, NULL);
+
+In this call we tell the gmMachine to register both a trace and destruct
+callback for this type. If you don't need them you can always pass
+NULL, but in the majority of times you will need to specify these
+callbacks.
+
+## Further Exploration
+
+This article has provided you with enough information to begin exploring
+GameMonkey Script on your own. I have tried to cover as much of the
+important information as possible without getting too complicated or in
+depth and so there will invariably be areas that some people wish to
+expand upon. The topic of binding, for example, can fill many more pages
+and is a subject that many people will wish to explore. If you are such
+a person, I will set you the task of building on the simple vector
+example I provided here. Some example experiments may be:
+
+- Adding copy constructor behaviour to types (Simple)
+- Adding *Indexed* access operators (Simple)
+- Handling additional operators on the vector class (Simple)
+- Adding extra methods to the class, such as *Normalise* (Moderate)
+- Create a function which takes Vector as a parameter (Moderate)
+- Create a simple library and type to bind simple C File I/O to GameMonkey (Moderate)
+- Create more complex types which are bound to your game engine (Advanced)
+
+You are urged to experiment further with the examples I have provided
+for you and begin looking further into what GameMonkey has to offer.
+Your game may wish to take advantage of scripted threads to remove many
+asynchronous operations, a subject which is useful but has not been
+covered here in this introductory article.
+
+## 
+
+## References
+
+Code::Blocks IDE. [URL: http://www.codeblocks.org]
+
+Douglas, G. & Riek, M. (2003). *GameMonkey Script Reference*. Included
+with all official GameMonkey Script distributions. [URL: http://www.somedude.net/gamemonkey]
+
+Lua Website. [URL: http://www.lua.org]
+Varanese, A., (2003). *Game Scripting Mastery.* Premier Press, Ohio,USA.
+
+Wikipedia (2005). Wikipedia: *Virtual Machines.* [URL: http://en.wikipedia.org/Virtual_machine].

+ 2 - 0
gmsrc/doc/tutorial/1-intro/scripts/export_test.gm

@@ -0,0 +1,2 @@
+print( myMultiply( 10, 2 ) );
+

+ 23 - 0
gmsrc/doc/tutorial/1-intro/scripts/expressions_1.gm

@@ -0,0 +1,23 @@
+x = 5;			// Assign a value to x
+print( x );
+
+y = (x * 10) + 56;	// Assign a value to y
+print( y );
+
+if (x == 10)		// Comparison (equality)
+{
+	print( "x is equal to 10" );
+}
+if (x != 10)		// Comparison (inequality)
+{
+	print( "x is not equal to 10" );
+}
+if (x < 10)			// Comparison (less than)
+{
+	print( "x is less than 10" );
+}
+if (x > 10)			// Comparison (greater than)
+{
+	print( "x is greater than 10" );
+}
+

+ 10 - 0
gmsrc/doc/tutorial/1-intro/scripts/function_test.gm

@@ -0,0 +1,10 @@
+global sayHello = function()
+{
+	print( "Hello, World!");
+};
+
+global myMultiply = function( a_x, a_y )
+{
+	return a_x * a_y;
+};
+

+ 6 - 0
gmsrc/doc/tutorial/1-intro/scripts/functions_1.gm

@@ -0,0 +1,6 @@
+
+myMultiply = function( x, y )	{ return x * y; };
+
+a = myMultiply( 100, 2 );
+print( a );
+

+ 2 - 0
gmsrc/doc/tutorial/1-intro/scripts/hello.gm

@@ -0,0 +1,2 @@
+print("Hello, World!");
+

+ 5 - 0
gmsrc/doc/tutorial/1-intro/scripts/loops_1.gm

@@ -0,0 +1,5 @@
+for (it = 0; it <= 10; it = it + 1)
+{
+	print( "it = ", it );
+}
+

+ 8 - 0
gmsrc/doc/tutorial/1-intro/scripts/loops_2.gm

@@ -0,0 +1,8 @@
+it = 0;
+
+while (it <= 10)
+{
+	print( "it = ", it );
+	it = it + 1;
+}
+

+ 15 - 0
gmsrc/doc/tutorial/1-intro/scripts/scoping_1.gm

@@ -0,0 +1,15 @@
+// Create a variable in the global scope
+global myvar = 100;
+
+// parameter 'a_param' is in function local scope
+myfunc = function( a_param )
+{
+	// variable myvar is in local scope
+	myvar = a_param;
+	print( myvar );
+};
+
+print( myvar );
+myfunc( 50 );
+print( myvar );
+

+ 15 - 0
gmsrc/doc/tutorial/1-intro/scripts/scoping_2.gm

@@ -0,0 +1,15 @@
+// Create a variable in the global scope
+global myvar = 100;
+
+// parameter 'a_param' is in function local scope
+myfunc = function( a_param )
+{
+	// Access variable myvar in global scope
+	global myvar = a_param;
+	print( myvar );
+};
+
+print( myvar );
+myfunc( 50 );
+print( myvar );
+

+ 13 - 0
gmsrc/doc/tutorial/1-intro/scripts/scoping_3.gm

@@ -0,0 +1,13 @@
+global mytable = table(
+
+	myMember = 50,
+	setMember = function( a_value )
+	{
+		myMember = a_value;
+	}
+);
+
+print( mytable.myMember );
+mytable.setMember( 100 );
+print( mytable.myMember );
+

+ 13 - 0
gmsrc/doc/tutorial/1-intro/scripts/scoping_4.gm

@@ -0,0 +1,13 @@
+global mytable = table(
+
+	myMember = 50,
+	setMember = function( a_value )
+	{
+		member myMember = a_value;
+	}
+);
+
+print( mytable.myMember );
+mytable.setMember( 100 );
+print( mytable.myMember );
+

+ 14 - 0
gmsrc/doc/tutorial/1-intro/scripts/scoping_5.gm

@@ -0,0 +1,14 @@
+
+myTable = table(
+	myMember = 50
+);
+
+setMember = function( a_param )
+{
+	this.myMember = a_param;
+};
+
+print( myTable.myMember );
+myTable:setMember( 100 );
+print( myTable.myMember );
+

+ 72 - 0
gmsrc/doc/tutorial/1-intro/scripts/scoping_6.gm

@@ -0,0 +1,72 @@
+/*
+	Scoping example to show 'this' scoping in action
+*/
+
+bigAlien = table(
+	myName = "Big Alien"
+	,myPower = 100
+	,myHealth = 100
+	,isDead = false
+);
+
+smallAlien = table(
+	myName = "Small Alien"
+	,myPower = 10
+	,myHealth = 10
+	,isDead = false
+);
+
+player = table(
+
+	myName = "Player"
+	,myPower = 20
+	,myHealth = 20
+	,isDead = false
+);
+
+Attack = function( a_target )
+{
+	print( a_target.myName, "was attacked by", .myName );
+	// Attack
+	a_target.myHealth -= .myPower;
+
+	if (a_target.myHealth < 0 )
+	{
+		a_target.myHealth = 0;
+	}
+
+	if (a_target.myHealth == 0)
+	{
+		a_target.isDead = true;
+		print( a_target.myName, "died" );
+	}
+};
+
+ShowStats = function()
+{
+	print( "Stats for **", .myName, "**" );
+	print( "Health", .myHealth );
+	print( "Power", .myPower );
+	print( "Dead?", .isDead );
+	print( "-----------------\n" );
+};
+
+// Show stats before attacks commence
+player:ShowStats();
+smallAlien:ShowStats();
+bigAlien:ShowStats();
+
+print( "Commencing attacks!\n" );
+
+smallAlien:Attack( player );
+player:Attack( smallAlien );
+bigAlien:Attack( player );
+
+print( "Attacks over!\n" );
+
+player:ShowStats();
+smallAlien:ShowStats();
+bigAlien:ShowStats();
+
+
+

+ 8 - 0
gmsrc/doc/tutorial/1-intro/scripts/tables_1.gm

@@ -0,0 +1,8 @@
+
+myArray = table( 1, 2, 3.14, 4, 5, "dog", "cat", 100 );
+
+myArray[0] = 50;
+print( myArray[1] );
+myArray[100] = "dog_100";	// new item added
+print( myArray[100] );
+

+ 10 - 0
gmsrc/doc/tutorial/1-intro/scripts/tables_2.gm

@@ -0,0 +1,10 @@
+
+myData = table( Name = "Test", Weight = 60 );
+
+print( myData[ "Name" ] );
+print( myData[ "Weight" ] );
+myData["Name"] = "Albert";
+myData["Test"] = "Some Text Here";
+print( myData[ "Name" ] );
+print( myData[ "Test" ] );
+

+ 7 - 0
gmsrc/doc/tutorial/1-intro/scripts/tables_3.gm

@@ -0,0 +1,7 @@
+
+myTest = table( 1, 4, Test = "Text!", 7, 8 );
+print( myTest[0] );
+print( myTest[3] );
+print( myTest["Test"] );
+
+

+ 8 - 0
gmsrc/doc/tutorial/1-intro/scripts/tables_4.gm

@@ -0,0 +1,8 @@
+
+fruits = table ( "apple", "pear", "orange" );
+foreach ( frt in fruits )
+{
+	print(frt);
+}
+
+

+ 8 - 0
gmsrc/doc/tutorial/1-intro/scripts/tables_5.gm

@@ -0,0 +1,8 @@
+
+fruits = table ( "apple", "pear", Juicy = "orange" );
+foreach ( k and f in fruits )
+{
+	print( "The value at key '", k, "' is '", f, "'" );
+}
+
+

+ 9 - 0
gmsrc/doc/tutorial/1-intro/scripts/tables_6.gm

@@ -0,0 +1,9 @@
+
+myStruct = table(
+	SayHello = function() { print( "Hello, world!" ); }
+);
+
+myStruct.SayHello();	// Call table-bound function
+
+
+

+ 14 - 0
gmsrc/doc/tutorial/1-intro/scripts/tables_7.gm

@@ -0,0 +1,14 @@
+
+myAlien = table(
+	Name = "Alien",
+	AttackPower = 20,
+	Strength = 50,
+	OnAttack = function( entity )
+		{
+			entity.Damage( this.AttackPower );
+			
+		}
+);
+
+
+

+ 9 - 0
gmsrc/doc/tutorial/1-intro/src/basic_1.cpp

@@ -0,0 +1,9 @@
+#include "gmThread.h"
+
+int main()
+{
+	// Create the GM Machine object on the stack
+	gmMachine gm;
+
+	return 0;
+} 

+ 11 - 0
gmsrc/doc/tutorial/1-intro/src/basic_2.cpp

@@ -0,0 +1,11 @@
+#include "gmThread.h"
+
+int main()
+{
+	gmMachine gm;
+
+	// Execute a simple script
+	gm.ExecuteString( "print( \"Hello, world!\" );" );
+
+	return 0;
+} 

+ 13 - 0
gmsrc/doc/tutorial/1-intro/src/basic_3.cpp

@@ -0,0 +1,13 @@
+#include "gmThread.h"
+
+int main()
+{
+    const char *myScript = "fruits = table ( \"apple\", \"pear\", \"orange\" );	foreach ( frt in fruits ) { print(frt);	} ";
+
+	gmMachine gm;
+
+	// Execute a simple script
+	gm.ExecuteString( myScript );
+
+	return 0;
+} 

+ 34 - 0
gmsrc/doc/tutorial/1-intro/src/error_handling.cpp

@@ -0,0 +1,34 @@
+#include <iostream>
+#include "gmThread.h"
+
+void handleErrors( gmMachine &a_machine )
+{
+	gmLog &log = a_machine.GetLog();
+    // Get the first error
+    bool firstError = true;
+	const char *err = log.GetEntry( firstError );
+	while ( err )
+	{
+		std::cout << "Compilation error: -" << err << std::endl;
+		err = log.GetEntry( firstError );
+	}
+}
+
+int main()
+{
+    const char *myScript = "fruits = table ( \"apple\", \"pear\", \"orange\" );	foreach ( frt in fruits ) { print(frt);	} ";
+
+	gmMachine gm;
+
+	// Execute a simple script
+	int ret = gm.ExecuteString( myScript );
+    if ( ret )
+    {
+        // There were errors in the script, exit gracefully
+        handleErrors( gm );
+        return 1;
+    } 
+
+	return 0;
+}
+

+ 63 - 0
gmsrc/doc/tutorial/1-intro/src/execute_function_1.cpp

@@ -0,0 +1,63 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <iterator>
+#include "gmThread.h"
+#include "gmCall.h"
+
+int gmLoadAndExecuteScript( gmMachine &a_machine, const char *a_filename )
+{
+    std::ifstream file(a_filename);
+    if (!file)
+        return GM_EXCEPTION;
+	
+	std::string fileString = std::string(std::istreambuf_iterator<char>(file),
+                                         std::istreambuf_iterator<char>());
+	file.close();
+	return a_machine.ExecuteString(fileString.c_str());
+}
+
+
+int main()
+{
+	gmMachine gm;
+
+	// Execute a simple script file
+	gmLoadAndExecuteScript ( &gm, "scripts/function_test.gm" );
+
+    
+    gmVariable funcName, funcFound;
+    funcName.SetString( gm.AllocStringObject("sayHello") );
+    // find in global table
+    funcFound = gm.GetGlobals()->Get(funcName);
+
+    if ( funcFound.m_type != GM_FUNCTION )
+    {
+    	std::cout << "Failed to find 'sayHello'";
+    	return 0;
+    }
+    
+    // Get function object from variable
+    gmFunctionObject *func = (gmFunctionObject *)funcFound.m_value.m_ref;
+    
+    gmThread *thread = gm.CreateThread();
+    // Push empty 'this' value
+    thread->Push( gmVariable::s_null );
+    thread->PushFunction( func );
+    
+    // No params needed
+    
+    // Get a blank variable to grab the return
+    gmVariable returnVar;
+    
+    // execute the thread
+    int state = thread->PushStackFrame( 0 );
+    if (state != gmThread::KILLED )
+    {
+        state = thread->Sys_Execute( &returnVar );
+    }
+    
+
+	return 0;
+} 
+

+ 76 - 0
gmsrc/doc/tutorial/1-intro/src/execute_function_2.cpp

@@ -0,0 +1,76 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <iterator>
+#include "gmThread.h"
+#include "gmCall.h"
+
+int gmLoadAndExecuteScript( gmMachine &a_machine, const char *a_filename )
+{
+    std::ifstream file(a_filename);
+    if (!file)
+        return GM_EXCEPTION;
+	
+	std::string fileString = std::string(std::istreambuf_iterator<char>(file),
+                                         std::istreambuf_iterator<char>());
+	file.close();
+	return a_machine.ExecuteString(fileString.c_str());
+}
+
+
+int main()
+{
+	gmMachine gm;
+
+	// Execute a simple script file
+	gmLoadAndExecuteScript ( gm, "scripts/function_test.gm" );
+
+    
+    gmVariable funcName, funcFound;
+    funcName.SetString( gm.AllocStringObject("myMultiply") );
+    // find in global table
+    funcFound = gm.GetGlobals()->Get(funcName);
+
+    if ( funcFound.m_type != GM_FUNCTION )
+    {
+    	std::cout << "Failed to find 'myMultiply'";
+    	return 0;
+    }
+    
+    // Get function object from variable
+    gmFunctionObject *func = reinterpret_cast<gmFunctionObject *>(funcFound.m_value.m_ref);
+    
+    gmThread *thread = gm.CreateThread();
+    // Push empty 'this' value
+    thread->Push( gmVariable::s_null );
+    thread->PushFunction( func );
+    
+    // Push two parameters, one holding 10 and the other 2 (both integers)
+    // This effectivley calls: myMutliply( 10, 2 )
+    thread->PushInt( 10 );
+    thread->PushInt( 2 );
+    
+    // Get a blank variable to grab the return
+    gmVariable returnVar;
+    
+    // execute the thread
+    int state = thread->PushStackFrame( 2 );    // NOTE! 2 parameters passed!
+    if (state != gmThread::KILLED )
+    {
+        state = thread->Sys_Execute( &returnVar );
+    }
+    
+    // Check the return
+    if (returnVar.m_type != GM_INT)
+    {
+    	std::cout << "There was a problem; non-int returned from myMultiply!";
+        return 0;
+    }
+    
+    int myReturn = returnVar.m_value.m_int;
+    
+    std::cout << "myMultiply returned " << myReturn << std::endl;
+
+	return 0;
+} 
+

+ 57 - 0
gmsrc/doc/tutorial/1-intro/src/execute_function_3.cpp

@@ -0,0 +1,57 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <iterator>
+#include "gmThread.h"
+#include "gmCall.h"
+
+int gmLoadAndExecuteScript( gmMachine &a_machine, const char *a_filename )
+{
+    std::ifstream file(a_filename);
+    if (!file)
+        return GM_EXCEPTION;
+	
+	std::string fileString = std::string(std::istreambuf_iterator<char>(file),
+                                         std::istreambuf_iterator<char>());
+	file.close();
+	return a_machine.ExecuteString(fileString.c_str());
+}
+
+
+int main()
+{
+	gmMachine gm;
+
+	// Execute a simple script file
+	gmLoadAndExecuteScript ( gm, "scripts/function_test.gm" );
+
+    gmCall  call;
+    if ( call.BeginGlobalFunction( &gm, "myMultiply" ) )
+    {
+        // Push the parameters
+    	call.AddParamInt( 10 );
+    	// Example showing a variable can be used
+    	gmVariable var( 2 );
+    	call.AddParam( var );
+
+    	// Execute the call
+    	call.End();
+    	// Handle the return value
+    	int myReturn = 0;
+    	if (call.GetReturnedInt( myReturn ) )
+    	{
+    		std::cout << "myMultiply returned " << myReturn << std::endl;
+    	}
+    	else
+    	{
+    		std::cout << "myMultiply returned an incorrect value" << std::endl;
+    	}
+    }
+    else
+    {
+        std::cout << "Error: Could execute function 'myMultiply'" << std::endl;
+    }
+    
+	return 0;
+} 
+

+ 20 - 0
gmsrc/doc/tutorial/1-intro/src/execution_1.cpp

@@ -0,0 +1,20 @@
+#include <cstdlib>
+#include "gmThread.h"
+
+int main()
+{
+	gmMachine gm;
+
+	// Compile a simple script without running it
+	gm.ExecuteString( "print( `Hello, world!` );", 0, false );
+
+	// The text wasn't printed!
+
+	// Wait for a keypress
+    getchar();
+    
+	// The script will now execute!
+    gm.Execute( 0 );
+
+	return 0;
+} 

+ 66 - 0
gmsrc/doc/tutorial/1-intro/src/export_function_1.cpp

@@ -0,0 +1,66 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <iterator>
+#include "gmThread.h"
+#include "gmCall.h"
+
+int gmLoadAndExecuteScript( gmMachine &a_machine, const char *a_filename )
+{
+    std::ifstream file(a_filename);
+    if (!file)
+        return GM_EXCEPTION;
+	
+	std::string fileString = std::string(std::istreambuf_iterator<char>(file),
+                                         std::istreambuf_iterator<char>());
+	file.close();
+	return a_machine.ExecuteString(fileString.c_str());
+}
+
+int GM_CDECL gm_myMultiply( gmThread *a_thread )
+{
+	// Check the number of parameters passed is correct
+	if (a_thread->GetNumParams() != 2 )
+        return GM_EXCEPTION;
+        
+    // Local vars to hold data from params
+	int a_x = 0;
+	int a_y = 0;
+	
+	// Check params are valid types
+	if (a_thread->ParamType(0) != GM_INT)
+        return GM_EXCEPTION;
+    if (a_thread->ParamType(1) != GM_INT)
+        return GM_EXCEPTION;
+	
+	// Get data from params
+	a_x = a_thread->Param(0).m_value.m_int;
+	a_x = a_thread->Param(1).m_value.m_int;
+	
+	// perform calculation
+	int ret = a_x * a_y;
+	
+	// return value
+	a_thread->PushInt( ret );
+	
+	return GM_OK;
+}
+
+gmFunctionEntry s_myLibrary [] =
+{
+	{ "myMultiply", gm_myMultiply }
+};
+
+int main()
+{
+	gmMachine gm;
+
+    // Bind the function to GameMonkey
+    gm.RegisterLibrary( s_myLibrary, sizeof(s_myLibrary) / sizeof(s_myLibrary[1]), 0 );
+    
+    	// Execute a simple script file
+	gmLoadAndExecuteScript ( gm, "scripts/export_test.gm" );
+    
+	return 0;
+} 
+

+ 50 - 0
gmsrc/doc/tutorial/1-intro/src/export_function_2.cpp

@@ -0,0 +1,50 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <iterator>
+#include "gmThread.h"
+#include "gmCall.h"
+
+int gmLoadAndExecuteScript( gmMachine &a_machine, const char *a_filename )
+{
+    std::ifstream file(a_filename);
+    if (!file)
+        return GM_EXCEPTION;
+	
+	std::string fileString = std::string(std::istreambuf_iterator<char>(file),
+                                         std::istreambuf_iterator<char>());
+	file.close();
+	return a_machine.ExecuteString(fileString.c_str());
+}
+
+int GM_CDECL gm_myMultiply( gmThread *a_thread )
+{
+	GM_CHECK_NUM_PARAMS(2);
+	GM_CHECK_INT_PARAM( a_x, 0 );
+	GM_CHECK_INT_PARAM( a_y, 1 );
+	
+	int ret = a_x * a_y;
+	
+	a_thread->PushInt( ret );
+	
+	return GM_OK;
+}
+
+gmFunctionEntry s_myLibrary [] =
+{
+	{ "myMultiply", gm_myMultiply }
+};
+
+int main()
+{
+	gmMachine gm;
+
+    // Bind the function to GameMonkey
+    gm.RegisterLibrary( s_myLibrary, sizeof(s_myLibrary) / sizeof(s_myLibrary[1]), 0 );
+    
+    	// Execute a simple script file
+	gmLoadAndExecuteScript ( gm, "scripts/export_test.gm" );
+    
+	return 0;
+} 
+

+ 29 - 0
gmsrc/doc/tutorial/1-intro/src/loading_scripts_1.cpp

@@ -0,0 +1,29 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <iterator>
+#include "gmThread.h"
+
+int gmLoadAndExecuteScript( gmMachine &a_machine, const char *a_filename )
+{
+    std::ifstream file(a_filename);
+    if (!file)
+        return GM_EXCEPTION;
+	
+	std::string fileString = std::string(std::istreambuf_iterator<char>(file),
+                                         std::istreambuf_iterator<char>());
+	file.close();
+	return a_machine.ExecuteString(fileString.c_str());
+}
+
+
+int main()
+{
+	gmMachine gm;
+
+	// Execute a simple script file
+	gmLoadAndExecuteScript ( gm, "scripts/hello.gm" );
+
+	return 0;
+} 
+

+ 29 - 0
gmsrc/doc/tutorial/1-intro/src/variables_1.cpp

@@ -0,0 +1,29 @@
+#include <iostream>
+#include "gmThread.h"
+
+int main()
+{
+	gmMachine gm;
+
+    // Allocate a string from the machine and set it as a variable
+    gmVariable stringVar( gm.AllocStringObject("Hello, World") );
+    // Allocate a variable containing an int and a float
+    // note it doesn't need to be created from the machine
+    gmVariable intVar( 100 );
+    gmVariable floatVar( 1.5f );
+    
+    // Create a variable with a newly created table
+    gmVariable tableVar( gm.AllocTableObject() );
+    
+    // Reset table var as an int, losing the table data it contained
+    tableVar.SetInt( 200 );
+    
+    // Variable copying
+    intVar = floatVar;
+    
+    // Make 'null'
+    stringVar.Nullify();
+    
+	return 0;
+} 
+

+ 46 - 0
gmsrc/doc/tutorial/1-intro/src/variables_2.cpp

@@ -0,0 +1,46 @@
+#include <iostream>
+#include "gmThread.h"
+
+using namespace std;
+
+int main()
+{
+	gmMachine gm;
+
+    // Try setting your own variable here
+    gmVariable var( gm.AllocStringObject("Hello, World") );
+
+    switch (var.m_type)
+    {
+    case GM_NULL:
+        cout << "Variable is NULL type" << endl;
+        break;
+    case GM_INT:
+        cout << "Variable is INT type" << endl;
+        cout << "Value:" << var.m_value.m_int << endl;
+        break;
+    case GM_FLOAT:
+        cout << "Variable is FLOAT type" << endl;
+        cout << "Value:" << var.m_value.m_float << endl;
+        break;
+    case GM_STRING:
+        cout << "Variable is STRING type" << endl;
+        cout << "Value:" << reinterpret_cast<gmStringObject *>(var.m_value.m_ref)->GetString() << endl;
+        break;
+    case GM_TABLE:
+        cout << "Variable is TABLE type" << endl;
+        cout << "Items:" << reinterpret_cast<gmTableObject *>(var.m_value.m_ref)->Count() << endl;
+        break;
+    case GM_FUNCTION:
+        cout << "Variable is FUNCTION type" << endl;
+        break;
+    default:
+        cout << "Variable is USER type" << endl;
+        // retrieve native pointer from user object
+        void *ptr = reinterpret_cast<gmUserObject *>(var.m_value.m_ref)->m_user;
+        
+    };
+    
+	return 0;
+} 
+

+ 57 - 0
gmsrc/doc/tutorial/1-intro/src/vector_1.cpp

@@ -0,0 +1,57 @@
+#include <iostream>
+#include "gmThread.h"
+
+class Vector
+{
+public:
+    Vector() : x(0), y(0), z(0) { }
+    Vector( float a_x, float a_y, float a_z ) : x(a_x), y(a_y), z(a_z) { }
+
+    float x, y, z;
+};
+
+namespace gmVector
+{
+
+// Declare a type ID
+gmType   Type   = GM_NULL;
+				
+/// Entry point for the library; this is effectively the constructor 
+int GM_CDECL libentry( gmThread *a_thread )
+{
+	std::cout << "Vector:: libentry called from script\n";
+    Vector *p = new Vector();
+    a_thread->PushNewUser( p, Type );
+    return GM_EXCEPTION;
+}
+		
+// Library entry point; this defines the constructor of the type
+gmFunctionEntry lib[] =
+{
+	{ "Vector", libentry }
+};
+
+
+void BindLib( gmMachine *a_machine )
+{
+	// Register one function (the entry point)
+    a_machine->RegisterLibrary( lib, 1 );
+    Type = a_machine->CreateUserType( lib[0].m_name );
+}
+
+
+};      // end namespace gmVector
+
+int main()
+{
+	gmMachine gm;
+
+    // Bind the type
+    gmVector::BindLib( &gm );
+
+    // A simple test
+    gm.ExecuteString("v = Vector();" );
+    
+	return 0;
+} 
+

+ 112 - 0
gmsrc/doc/tutorial/1-intro/src/vector_2.cpp

@@ -0,0 +1,112 @@
+#include <iostream>
+#include "gmThread.h"
+
+class Vector
+{
+public:
+    Vector() : x(0), y(0), z(0) { }
+    Vector( float a_x, float a_y, float a_z ) : x(a_x), y(a_y), z(a_z) { }
+
+    float x, y, z;
+    
+};
+
+namespace gmVector
+{
+
+// Declare a type ID
+gmType   Type   = GM_NULL;
+		
+int GM_CDECL default_constructor( gmThread *a_thread )
+{
+	// Create a native object with default params
+    Vector *p = new Vector();
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+
+/// This is the constructor for passed data items
+int GM_CDECL data_constructor( gmThread *a_thread )
+{ 
+	// Check for a valid number of parameters
+    if (a_thread->GetNumParams() != 3 )
+        return GM_EXCEPTION;
+	
+    // Loop through and grab the params, checking their types
+    float v[3];
+    for (int i = 0; i < 3; ++i)
+    {
+        switch (a_thread->Param(i).m_type)
+        {
+        case GM_INT:
+            v[i] = a_thread->Param(i).m_value.m_int;
+            break;
+        case GM_FLOAT:
+            v[i] = a_thread->Param(i).m_value.m_float;
+            break;
+        default:
+            a_thread->GetMachine()->GetLog().LogEntry( "Vector: Param %d error - expected int or float", i );
+            return GM_EXCEPTION;
+        }
+    }
+    // Create a native object with default params    
+    Vector *p = new Vector( v[0], v[1], v[2] );
+ 
+    // Return to GM
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+			
+/// Entry point for the library; this is effectively the constructor 
+int GM_CDECL libentry( gmThread *a_thread )
+{
+    // Delegate the appropriate call based on the arg count
+    switch (a_thread->GetNumParams())
+    {
+    case 0:
+        return default_constructor( a_thread );
+    case 3:
+        return data_constructor( a_thread );
+    };
+    
+    // Not handled, log an error and return an exception
+    a_thread->GetMachine()->GetLog().LogEntry( "Vector: Bad number of parameters passed" );
+    return GM_EXCEPTION;
+}
+		
+
+// Library entry point; this defines the constructor of the type
+gmFunctionEntry lib[] =
+{
+	{ "Vector", libentry }
+};
+
+// Type lib; these functions become members of the type
+gmFunctionEntry typeLib[] = 
+{
+	{ 0, 0 }
+};
+
+
+void BindLib( gmMachine *a_machine )
+{
+	// Register one function (the entry point)
+    a_machine->RegisterLibrary( lib, 1 );
+    Type = a_machine->CreateUserType( lib[0].m_name );
+}
+
+
+};      // end namespace gmVector
+
+int main()
+{
+	gmMachine gm;
+
+    // Bind the type
+    gmVector::BindLib( &gm );
+
+    gm.ExecuteString("v = Vector( 30, 40, 60.5 );" );
+    
+	return 0;
+} 
+

+ 140 - 0
gmsrc/doc/tutorial/1-intro/src/vector_2a.cpp

@@ -0,0 +1,140 @@
+#include <iostream>
+#include "gmThread.h"
+
+class Vector
+{
+public:
+    Vector() : x(0), y(0), z(0) { }
+    Vector( float a_x, float a_y, float a_z ) : x(a_x), y(a_y), z(a_z) { }
+
+    float x, y, z;
+    
+};
+
+namespace gmVector
+{
+
+// Declare a type ID
+gmType   Type   = GM_NULL;
+		
+int GM_CDECL default_constructor( gmThread *a_thread )
+{
+	// Create a native object with default params
+    Vector *p = new Vector();
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+
+/// This is the constructor for passed data items
+int GM_CDECL data_constructor( gmThread *a_thread )
+{ 
+	// Check for a valid number of parameters
+    if (a_thread->GetNumParams() != 3 )
+        return GM_EXCEPTION;
+	
+    // Loop through and grab the params, checking their types
+    float v[3];
+    for (int i = 0; i < 3; ++i)
+    {
+        switch (a_thread->Param(i).m_type)
+        {
+        case GM_INT:
+            v[i] = a_thread->Param(i).m_value.m_int;
+            break;
+        case GM_FLOAT:
+            v[i] = a_thread->Param(i).m_value.m_float;
+            break;
+        default:
+            a_thread->GetMachine()->GetLog().LogEntry( "Vector: Param %d error - expected int or float", i );
+            return GM_EXCEPTION;
+        }
+    }
+    // Create a native object with default params    
+    Vector *p = new Vector( v[0], v[1], v[2] );
+ 
+    // Return to GM
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+
+/// This is the constructor for a passed Vector type
+int GM_CDECL copy_constructor( gmThread *a_thread )
+{ 
+	// Check for a valid number of parameters
+    if (a_thread->GetNumParams() != 1 )
+        return GM_EXCEPTION;
+	
+    // Check if the type is the same as the Vector type registered
+    if (a_thread->Param(0).m_type != Type)
+        return GM_EXCEPTION;
+
+    gmUserObject *usr = reinterpret_cast<gmUserObject*>(a_thread->Param(0).m_value.m_ref);
+    Vector *cpy = reinterpret_cast<Vector*>(usr->m_user);  
+
+    // Null pointer returned
+    if (cpy == 0)
+        return GM_EXCEPTION;
+
+    // Create a native object using the default copy constructor
+    Vector *p = new Vector( *cpy );
+ 
+    // Return to GM
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+			
+/// Entry point for the library; this is effectively the constructor 
+int GM_CDECL libentry( gmThread *a_thread )
+{
+    // Delegate the appropriate call based on the arg count
+    switch (a_thread->GetNumParams())
+    {
+    case 0:
+        return default_constructor( a_thread );
+    case 1:
+        return copy_constructor( a_thread );
+    case 3:
+        return data_constructor( a_thread );
+    };
+    
+    // Not handled, log an error and return an exception
+    a_thread->GetMachine()->GetLog().LogEntry( "Vector: Bad number of parameters passed" );
+    return GM_EXCEPTION;
+}
+		
+
+// Library entry point; this defines the constructor of the type
+gmFunctionEntry lib[] =
+{
+	{ "Vector", libentry }
+};
+
+// Type lib; these functions become members of the type
+gmFunctionEntry typeLib[] = 
+{
+	{ 0, 0 }
+};
+
+
+void BindLib( gmMachine *a_machine )
+{
+	// Register one function (the entry point)
+    a_machine->RegisterLibrary( lib, 1 );
+    Type = a_machine->CreateUserType( lib[0].m_name );
+}
+
+
+};      // end namespace gmVector
+
+int main()
+{
+	gmMachine gm;
+
+    // Bind the type
+    gmVector::BindLib( &gm );
+
+    gm.ExecuteString("v = Vector( 30, 40, 60.5 ); v2 = Vector(v);" );
+    
+	return 0;
+} 
+

+ 204 - 0
gmsrc/doc/tutorial/1-intro/src/vector_3.cpp

@@ -0,0 +1,204 @@
+#include <iostream>
+#include "gmThread.h"
+
+class Vector
+{
+public:
+    Vector() : x(0), y(0), z(0) { }
+    Vector( float a_x, float a_y, float a_z ) : x(a_x), y(a_y), z(a_z) { }
+
+    float x, y, z;
+    
+};
+
+namespace gmVector
+{
+
+// Declare a type ID
+gmType   Type   = GM_NULL;
+		
+int GM_CDECL default_constructor( gmThread *a_thread )
+{
+	// Create a native object with default params
+    Vector *p = new Vector();
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+
+/// This is the constructor for passed data items
+int GM_CDECL data_constructor( gmThread *a_thread )
+{ 
+    // Loop through and grab the params, checking their types
+    float v[3];
+    for (int i = 0; i < 3; ++i)
+    {
+    	switch (a_thread->Param(i).m_type)
+    	{
+        case GM_INT:
+    		v[i] = a_thread->Param(i).m_value.m_int;
+    		break;
+    	case GM_FLOAT:
+    		v[i] = a_thread->Param(i).m_value.m_float;
+    		break;
+        default:
+            a_thread->GetMachine()->GetLog().LogEntry( "Vector: Param %d error - expected int or float", i );
+            return GM_EXCEPTION;
+    	}
+    }
+
+    // Create a native object with default params
+    Vector *p = new Vector( v[0], v[1], v[2] );
+    // Return to GM
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+			
+/// This is the constructor for a passed Vector type
+int GM_CDECL copy_constructor( gmThread *a_thread )
+{ 
+	// Check for a valid number of parameters
+    if (a_thread->GetNumParams() != 1 )
+        return GM_EXCEPTION;
+	
+    // Check if the type is the same as the Vector type registered
+    if (a_thread->Param(0).m_type != Type)
+        return GM_EXCEPTION;
+
+    gmUserObject *usr = reinterpret_cast<gmUserObject*>(a_thread->Param(0).m_value.m_ref);
+    Vector *cpy = reinterpret_cast<Vector*>(usr->m_user);  
+
+    // Null pointer returned
+    if (cpy == 0)
+        return GM_EXCEPTION;
+
+    // Create a native object using the default copy constructor
+    Vector *p = new Vector( *cpy );
+ 
+    // Return to GM
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+			
+/// Entry point for the library; this is effectively the constructor 
+int GM_CDECL libentry( gmThread *a_thread )
+{
+    // Delegate the appropriate call based on the arg count
+    switch (a_thread->GetNumParams())
+    {
+    case 0:
+        return default_constructor( a_thread );
+    case 1:
+        return copy_constructor( a_thread );
+    case 3:
+        return data_constructor( a_thread );
+    };
+    
+    // Not handled, log an error and return an exception
+    a_thread->GetMachine()->GetLog().LogEntry( "Vector: Bad number of parameters passed" );
+    return GM_EXCEPTION;
+}
+
+
+void GM_CDECL OpGetDot(gmThread * a_thread, gmVariable * a_operands)
+{
+	GM_ASSERT(a_operands[0].m_type == Type);
+    Vector* thisVec = reinterpret_cast<Vector*>(reinterpret_cast<gmUserObject*>(GM_OBJECT(a_operands[0].m_value.m_ref))->m_user);
+
+    GM_ASSERT(a_operands[1].m_type == GM_STRING);
+    gmStringObject* stringObj = reinterpret_cast<gmStringObject*>(GM_OBJECT(a_operands[1].m_value.m_ref));
+    const char* propName = stringObj->GetString();
+
+    // Resolve the member name
+    if(::stricmp(propName, "x") == 0)
+    {
+      a_operands[0].SetFloat(thisVec->x);
+    }
+    else if(::stricmp(propName, "y") == 0)
+    {
+      a_operands[0].SetFloat(thisVec->y);
+    }
+    else if(::stricmp(propName, "z") == 0)
+    {
+      a_operands[0].SetFloat(thisVec->z);
+    }
+    else
+    {
+      a_operands[0].Nullify();
+    }
+}
+
+void GM_CDECL OpSetDot(gmThread * a_thread, gmVariable * a_operands)
+{
+    GM_ASSERT(a_operands[0].m_type == Type);
+    Vector* thisVec = reinterpret_cast<Vector*>(reinterpret_cast<gmUserObject*>(GM_OBJECT(a_operands[0].m_value.m_ref))->m_user);
+    
+    GM_ASSERT(a_operands[2].m_type == GM_STRING);
+    gmStringObject* stringObj = reinterpret_cast<gmStringObject*>(GM_OBJECT(a_operands[2].m_value.m_ref));
+    const char* propname = stringObj->GetString();
+    
+    // Create a variable to hold the data t assign
+    // handle both ints and floats
+    float newFloat = 0.0f;
+    if(a_operands[1].m_type == GM_FLOAT)
+    {
+      newFloat = a_operands[1].m_value.m_float;
+    }
+    else if(a_operands[1].m_type == GM_INT)
+    {
+      newFloat = (float)a_operands[1].m_value.m_int;
+    }
+    
+    // Assign the data
+    if(::stricmp( propname, "x") == 0)
+    {
+      thisVec->x = newFloat;
+    }
+    else if(::stricmp( propname, "y") == 0)
+    {
+      thisVec->y = newFloat;
+    }
+    else if(::stricmp( propname, "z") == 0)
+    {
+      thisVec->z = newFloat;
+    }
+}
+
+// Library entry point; this defines the constructor of the type
+gmFunctionEntry lib[] =
+{
+	{ "Vector", libentry }
+};
+
+// Type lib; these functions become members of the type
+gmFunctionEntry typeLib[] = 
+{
+	{ 0, 0 }
+};
+
+
+void BindLib( gmMachine *a_machine )
+{
+	// Register one function (the entry point)
+    a_machine->RegisterLibrary( lib, 1 );
+    Type = a_machine->CreateUserType( lib[0].m_name );
+    
+    // Register the 'Get Dot' operator
+    a_machine->RegisterTypeOperator(Type, O_GETDOT, NULL, OpGetDot);
+    a_machine->RegisterTypeOperator(Type, O_SETDOT, NULL, OpSetDot);
+}
+
+
+};      // end namespace gmVector
+
+int main()
+{
+	gmMachine gm;
+
+    // Bind the type
+    gmVector::BindLib( &gm );
+
+    gm.ExecuteString("v = Vector( 30, 40, 60.5 ); v.y = v.x * 2; print( v.y );" );
+    
+	return 0;
+} 
+

+ 230 - 0
gmsrc/doc/tutorial/1-intro/src/vector_4.cpp

@@ -0,0 +1,230 @@
+#include <iostream>
+#include "gmThread.h"
+
+class Vector
+{
+public:
+    Vector() : x(0), y(0), z(0) { }
+    Vector( float a_x, float a_y, float a_z ) : x(a_x), y(a_y), z(a_z) { }
+
+    float x, y, z;
+    
+};
+
+namespace gmVector
+{
+
+// Declare a type ID
+gmType   Type   = GM_NULL;
+		
+int GM_CDECL default_constructor( gmThread *a_thread )
+{
+	// Create a native object with default params
+    Vector *p = new Vector();
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+
+/// This is the constructor for passed data items
+int GM_CDECL data_constructor( gmThread *a_thread )
+{ 
+    // Loop through and grab the params, checking their types
+    float v[3];
+    for (int i = 0; i < 3; ++i)
+    {
+    	switch (a_thread->Param(i).m_type)
+    	{
+        case GM_INT:
+    		v[i] = a_thread->Param(i).m_value.m_int;
+    		break;
+    	case GM_FLOAT:
+    		v[i] = a_thread->Param(i).m_value.m_float;
+    		break;
+        default:
+            a_thread->GetMachine()->GetLog().LogEntry( "Vector: Param %d error - expected int or float", i );
+            return GM_EXCEPTION;
+    	}
+    }
+
+    // Create a native object with default params
+    Vector *p = new Vector( v[0], v[1], v[2] );
+    // Return to GM
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+
+
+int GM_CDECL copy_constructor( gmThread *a_thread )
+{ 
+	// Check for a valid number of parameters
+    if (a_thread->GetNumParams() != 1 )
+        return GM_EXCEPTION;
+	
+    // Check if the type is the same as the Vector type registered
+    if (a_thread->Param(0).m_type != Type)
+        return GM_EXCEPTION;
+
+    gmUserObject *usr = reinterpret_cast<gmUserObject*>(a_thread->Param(0).m_value.m_ref);
+    Vector *cpy = reinterpret_cast<Vector*>(usr->m_user);  
+
+    // Null pointer returned
+    if (cpy == 0)
+        return GM_EXCEPTION;
+
+    // Create a native object using the default copy constructor
+    Vector *p = new Vector( *cpy );
+ 
+    // Return to GM
+    a_thread->PushNewUser( p, Type );
+	return GM_OK;	
+}
+			
+/// Entry point for the library; this is effectively the constructor 
+int GM_CDECL libentry( gmThread *a_thread )
+{
+    // Delegate the appropriate call based on the arg count
+    switch (a_thread->GetNumParams())
+    {
+    case 0:
+        return default_constructor( a_thread );
+    case 1:
+        return copy_constructor( a_thread );
+    case 3:
+        return data_constructor( a_thread );
+    };
+    
+    // Not handled, log an error and return an exception
+    a_thread->GetMachine()->GetLog().LogEntry( "Vector: Bad number of parameters passed" );
+    return GM_EXCEPTION;
+}
+
+
+/// Effectively the destructor for the object
+void GM_CDECL gc_destruct(gmMachine * a_machine, gmUserObject* a_object)
+{
+	std::cout << "Vector: destructing\n";
+	GM_ASSERT(a_object->m_userType == Type);
+    Vector* object = reinterpret_cast<Vector*>(a_object->m_user);
+    delete object;
+}
+
+// Trace the objct in the mark phase
+bool gc_trace( gmMachine * a_machine, gmUserObject* a_object, gmGarbageCollector* a_gc, const int a_workLeftToGo, int& a_workDone )
+{
+    // Make sure this is the correct type
+    GM_ASSERT(a_object->m_userType == m_gmType);
+
+    // If your object references other gmObjects, you should call GetNextObject for each one here
+
+    // mark 'me' as done
+    a_workDone++;
+    return true;
+}
+
+
+void GM_CDECL OpGetDot(gmThread * a_thread, gmVariable * a_operands)
+{
+	GM_ASSERT(a_operands[0].m_type == Type);
+    Vector* thisVec = reinterpret_cast<Vector*>(reinterpret_cast<gmUserObject*>(GM_OBJECT(a_operands[0].m_value.m_ref))->m_user);
+
+    GM_ASSERT(a_operands[1].m_type == GM_STRING);
+    gmStringObject* stringObj = reinterpret_cast<gmStringObject*>(GM_OBJECT(a_operands[1].m_value.m_ref));
+    const char* propName = stringObj->GetString();
+
+    // Resolve the member name
+    if(::stricmp(propName, "x") == 0)
+    {
+      a_operands[0].SetFloat(thisVec->x);
+    }
+    else if(::stricmp(propName, "y") == 0)
+    {
+      a_operands[0].SetFloat(thisVec->y);
+    }
+    else if(::stricmp(propName, "z") == 0)
+    {
+      a_operands[0].SetFloat(thisVec->z);
+    }
+    else
+    {
+      a_operands[0].Nullify();
+    }
+}
+
+void GM_CDECL OpSetDot(gmThread * a_thread, gmVariable * a_operands)
+{
+    GM_ASSERT(a_operands[0].m_type == Type);
+    Vector* thisVec = reinterpret_cast<Vector*>(reinterpret_cast<gmUserObject*>(GM_OBJECT(a_operands[0].m_value.m_ref))->m_user);
+    
+    GM_ASSERT(a_operands[2].m_type == GM_STRING);
+    gmStringObject* stringObj = reinterpret_cast<gmStringObject*>(GM_OBJECT(a_operands[2].m_value.m_ref));
+    const char* propname = stringObj->GetString();
+    
+    // Create a variable to hold the data t assign
+    // handle both ints and floats
+    float newFloat = 0.0f;
+    if(a_operands[1].m_type == GM_FLOAT)
+    {
+      newFloat = a_operands[1].m_value.m_float;
+    }
+    else if(a_operands[1].m_type == GM_INT)
+    {
+      newFloat = (float)a_operands[1].m_value.m_int;
+    }
+    
+    // Assign the data
+    if(::stricmp( propname, "x") == 0)
+    {
+      thisVec->x = newFloat;
+    }
+    else if(::stricmp( propname, "y") == 0)
+    {
+      thisVec->y = newFloat;
+    }
+    else if(::stricmp( propname, "z") == 0)
+    {
+      thisVec->z = newFloat;
+    }
+}
+
+// Library entry point; this defines the constructor of the type
+gmFunctionEntry lib[] =
+{
+	{ "Vector", libentry }
+};
+
+// Type lib; these functions become members of the type
+gmFunctionEntry typeLib[] = 
+{
+	{ 0, 0 }
+};
+
+
+void BindLib( gmMachine *a_machine )
+{
+	// Register one function (the entry point)
+    a_machine->RegisterLibrary( lib, 1 );
+    Type = a_machine->CreateUserType( lib[0].m_name );
+    
+    // Register the 'Get Dot' operator
+    a_machine->RegisterTypeOperator(Type, O_GETDOT, NULL, OpGetDot);
+    a_machine->RegisterTypeOperator(Type, O_SETDOT, NULL, OpSetDot);
+    
+    // Register GC callbacks
+    a_machine->RegisterUserCallbacks(Type, gc_trace, gc_destruct, NULL); 
+}
+
+
+};      // end namespace gmVector
+
+int main()
+{
+	gmMachine gm;
+
+    // Bind the type
+    gmVector::BindLib( &gm );
+
+    gm.ExecuteString("v = Vector( 30, 40, 60.5 ); v.y = v.x * 2; print( v.y );" );
+    
+	return 0;
+} 
+

BIN
gmsrc/doc/tutorial/2-continuing/blocksigstates.GIF


+ 2121 - 0
gmsrc/doc/tutorial/2-continuing/continuing-gamemonkey.md

@@ -0,0 +1,2121 @@
+# Continuting GameMonkey Script: Advanced Use
+
+## Foreword
+
+This article is the revised version of that [originally published in 2009 on GameDev.net](https://www.gamedev.net/tutorials/_/technical/game-programming/continuing-gamemonkey-script-advanced-use-r2666/). There are several aspects that are out of date, however the article has been left in its original form for preservation and posterity.
+
+## Introduction
+
+By reading my *Introduction to GameMonkey Script* articles you have been
+introduced to the basic features of the *GameMonkey Script* (GM Script
+or simply 'GM' herein) language and how to embed it into your game or
+application. This article will teach you some of the more advanced
+aspects of the GM language and the virtual machine API. I will begin by
+describing the functionality and provide examples in GameMonkey Script
+code itself as this allows simple and quick demonstration of the
+features. I will then continue this discussion with examples in C++ code
+to demonstrate how to access this functionality from within your game
+engine itself.
+
+In order to follow this article you are assumed to have read, understood
+and implemented the ideas and examples presented in the introductory
+articles. It is also expected that you are familiar with concepts such
+as simple messaging systems and event handlers so that you can follow
+some of the sample code without issue.
+
+This article covers the following topics:
+
+- Cooperative Threads
+- Blocking / Signalling
+- Threads and 'this'
+- Thread States
+- The Structure of a Thread
+- Creating Script-Extensible Entities
+- Best practices for using GameMonkey
+
+## Scripting Cooperative Threads
+
+Every script running within the GM virtual machine is executed within
+its own "thread". A "thread" is standalone in that it has its own
+executable bytecode and stack but it runs within the overall context of
+the GameMonkey machine so can access data and functions from other
+threads. Unlike your operating system's definition of a "thread", the GM
+virtual machine is based around a co-operative threading model, so that
+upon every execution of the gmMachine::Execute() method each thread must
+either complete (terminate) or *yield* to the machine to allow other
+threads a chance to execute.
+
+When a thread runs, it executes a *function*, a sequence of bytecode
+that is contained within its own *stackframe*. Whenever you execute a
+script in GameMonkey the bytecode is compiled into a function and is
+actually created within a thread to be executed. As a result, any
+explicit creation of your own threads will need a function to actually
+execute. This concept will be covered in more detail in a later section
+of this article.
+
+### Creating Threads from Script
+
+There are two ways of creating a thread in GM; the first is via the
+scripting language itself -- there is an in-built function called
+thread() that takes the thread function and the values to be passed to
+this function as arguments. The following example demonstrates how to
+create a new thread from script:
+
+```
+  global thread_1 = function( a_count ) {
+    print( "[1] Starting..." );
+    for (i = 0; i < a_count; i = i + 1)
+    {
+      print( "[1] iteration: " + i );
+    };
+
+    print( "[1] Finishing..." );
+  };
+
+  print( "[0] Ready to execute..." );
+  thread( thread_1, 100 );
+  sleep(1);
+  print( "[0] Thread created..." );
+```
+
+**Example: threads_01.gm**
+
+```
+  [0] Ready to execute...
+  [1] Starting...
+  [1] Iteration 0
+  ...
+  [1] Iteration 99
+  [1] Finishing...
+  [0] Thread Created...
+```
+
+**Output: threads_01.gm**
+
+In this example, a new thread is created within the machine which
+executes a function to count from 0 to 99. It will continue until the
+function is completed, hogging the machine's runtime until it is done.
+In this example, the sleep() function is called to yield control from
+the main thread and into the new thread we create. Use of sleep will be
+discussed later on in this article.
+
+### Yielding Thread Execution
+
+Now that you are able to spawn a new scripted thread you can begin to
+run processes co-operatively. As mentioned before, GM is **not** based
+upon a pre-emptive threading environment so each thread needs to *yield*
+to others after it has finished a portion of work; it is up to the
+script writer to define what a portion of 'work' for a thread and should
+be.
+
+In the following example we create two threads, each counting from 0 to
+a specified number. This example does not use yield() -- what do you
+think will happen when you run it?
+
+```
+  global thread_func = function( a_name, a_count ) {
+    print( "["+a_name+"] Starting..." );
+    for (i = 0; i < a_count; i = i + 1)
+    {
+      print( "["+a_name+"] iteration: " + i );
+    };
+
+    print( "["+a_name+"] Finishing..." );
+  };
+
+  print( "[0] Ready to execute..." );
+  thread( thread_func, 1, 100 );
+  thread( thread_func, 2, 100 );
+  sleep(1);
+  print( "[0] Thread created..." );
+```
+
+**Example: threads_02.gm**
+
+```
+  [0] Ready to execute...
+  [1] Starting...
+  [1] Iteration 0
+  ...
+  [1] Iteration 99
+  [1] Finishing...
+  [2] Starting...
+  [2] Iteration 0
+  ...
+  [2] Iteration 99
+  [2] Finishing...
+  [0] Thread Created...
+```
+
+**Output: threads_02.gm**
+
+As you see from the output of the script, the two threads ran
+consecutively and not concurrently as you might have expected. The
+reason for this is that although two threads were created, the first was
+executed which blocked the second thread until it had completed. Once
+complete, the second thread was free to run until completion. If you
+intended to run a single cycle of each thread in turn you need to tell
+the GM machine when to yield execution to other threads. In order to
+tell a thread to yield, you simply call the scripted function yield()
+with no parameters.
+
+The following example is the same script but with a yield() in the loop
+of each function.
+
+```
+  global thread_func = function( a_name, a_count ) {
+    print( "["+a_name+"] Starting..." );
+
+    for (i = 0; i < a_count; i = i + 1)
+    {
+      print( "["+a_name+"] iteration: " + i );
+      yield();
+    };
+
+    print( "["+a_name+"] Finishing..." );
+  };
+
+  print( "[0] Ready to execute..." );
+  thread( thread_func, 1, 100 );
+  thread( thread_func, 2, 100 );
+  sleep(1);
+  print( "[0] Thread created..." );
+```
+
+**Example: threads_03.gm**
+
+```
+  [0] Ready to execute...
+  [1] Starting...
+  [1] Iteration 0
+  [2] Starting...
+  [2] Iteration 0
+  ...
+  [1] Iteration 99
+  [2] Iteration 99
+  [1] Finishing...
+  [2] Finishing...
+  [0] Thread Created...
+```
+
+**Output: threads_03.gm**
+
+After running the above script, you will see that instead of running
+consecutively as witnessed in the first example the two threads appeared
+to run concurrently. Internally, the GM machine ran only one thread at a
+time but the yield() command instructed the virtual machine to switch
+contexts and execute the next thread.
+
+Sometimes you may want to pause a thread for a specific length of time,
+for example if you had an NPC that needed to wait for 10 seconds at a
+waypoint before moving on. This can be achieved using the script command
+sleep(), which takes a numeric parameter of how many seconds the thread
+needs to sleep for. A sleeping thread yields until the sleep duration
+has passed, after which it resumes execution of the next command. Try
+experimenting with the samples above and replace a yield() with sleep to
+see the effects it has on execution.
+
+### Blocking and Signalling
+
+In the real world context of a game you will not be using long loops and
+yield() very often; instead thread execution and context switching can
+be controlled by the more powerful blocking and signalling mechanism
+provided by GameMonkey. In games you would use a scripted thread to act
+as the 'brain' of an entity which would 'think' on every game cycle and
+perform an action based on an event or stimulus; the majority of the
+time it may be sitting waiting for that trigger, potentially by checking
+a loop. The following example demonstrates the traditional and extremely
+inefficient way of doing this:
+
+```
+  global WakeUp = false;
+
+  global thread_1 = function( a_count ) {
+
+    while (WakeUp == false)
+    {
+      // Snooze
+      print("zzz");
+      yield();
+    }
+    print("I just woke up, boy was I tired!");
+  };
+
+  // Launch thread
+  thread( thread_1 );
+
+  // Sleep for 1 secs then set the wakeup variable
+  sleep(1);
+  WakeUp = true;
+```
+
+**Example: blocking_01.gm**
+
+When running the script, you will see a screen full of *"zzz"'s* before
+the thread 'wakes up'. The thread is actually still running here, taking
+up CPU cycles and waiting for the *WakeUp* call. GM presents a much more
+efficient way of handling this scenario via its *blocking* and
+*signalling* mechanism.
+
+A thread can block itself until a specific signal (or one of several
+signals) is received. Blocking effectively takes a thread out of the
+active thread pool, yielding until a signal wakes it up. A simple
+example is demonstrated below:
+
+```
+  global thread_1 = function() {
+    block("WAKEUP");
+    print("I just woke up, boy was I tired!");
+  };
+
+  // Launch thread
+  thread( thread_1 );
+
+  // Sleep for 1 secs then set the wakeup variable
+  sleep(1);
+  signal("WAKEUP");
+```
+
+**Example: blocking_02.gm**
+
+The thread will block until it receives a signal string of *"WAKEUP"*,
+which is sent to it after 1 second. This is more efficient as it's not
+taking up interpreted script cycles checking for a scripted variable,
+we're literally waiting upon a message from the GameMonkey machine to
+continue. It is important to remember that a thread can block or signal
+on any gmVariable and not specifically strings, which I have used here
+as the most intuitive way to demonstrate the functionality.
+
+Let's take a look a more complicated example involving two threads. Each
+thread will be created consecutively and will block on a different
+signal. The first signal will be thrown after the *sleep* command, which
+in turn will signal the other thread.
+
+```
+  global thread_1 = function() {
+    block("WAKEUP");
+    print("I just woke up, boy was I tired! You should wake up too!");
+    signal("YOUTOO");
+  };
+
+  global thread_2 = function() {
+    block("YOUTOO");
+    print("What did you wake me up for?");
+  };
+
+  // Launch thread
+  thread( thread_2 );
+  thread( thread_1 );
+
+  // Sleep for 1 secs then set the wakeup variable
+  sleep(1);
+  signal("WAKEUP");
+```
+
+**Example: blocking_03.gm**
+
+```
+  I just woke up, boy as I tired! You should wake up too!
+  What did you wake me up for?
+```
+
+**Output: blocking_03.gm**
+
+Often it is desirable for a thread to be able to block until it receives
+one of a selection signals - for example, you may want your scripted
+entity to walk to an area and then wait there until it receives a
+command to move to another point, attack an entity or indeed simply
+defend itself. The block and signal mechanism offers support for this by
+allowing you to block on multiple signals. The signal which resumes the
+thread is returned from the block command allowing you to act in
+appropriate manner.
+
+```
+  global blockfunc = function() {
+    print( "Waiting for instruction, sir!" );
+    signal_received = block("attack", "move", "defend");
+    if(signal_received == "attack")
+    {
+      print("Attacking!");
+    }
+    else if (signal_received == "move")
+    {
+      print("Moving to position!");
+    }
+    else if (signal_received == "defend")
+    {
+      print("Defending til the death!");
+    }
+  };
+
+  thread( blockfunc );
+  sleep(1);
+  signal("attack");
+```
+
+**Example: blocking_04.gm**
+
+```
+  Waiting for instruction, sir!
+  Attacking!
+```
+
+**Output: blocking_04.gm**
+
+In the example above, the thread will block upon 3 signals, *attack,
+move* or *defend*. The signal received will determine what the thread
+then proceeds to do -- in this case the attack signal is received so the
+entity attacks.
+
+Each of the signalling examples presented until now have relied upon the
+signal being global, meaning that if two threads were waiting on the
+same signal, they would both be activated together. In games this would
+mean that all of your game units waiting for a wakeup call will spring
+into action at once. You will be relieved to know that it is possible to
+send a signal to a single thread rather than globally. To achieve this
+you must know the *Thread Id* of the thread you're signalling, this is
+returned by the normal thread function when you first create the thread.
+The following example is adapted to demonstrate the same block function
+being used with multiple threads.
+
+```
+  global blockfunc = function(name) {
+    print( name + ", waiting for instruction, sir!" );
+    signal_received = block("attack", "move", "defend");
+
+    if (signal_received == "attack")
+    {
+      print(name + " is attacking!");
+    }
+    else if (signal_received == "move")
+    {
+      print(name + " is moving to position!");
+    }
+    else if (signal_received == "defend")
+    {
+      print(name + " is defending til the death!");
+    }
+  };
+
+  thread_1 = thread( blockfunc, "woob" );
+  thread_2 = thread( blockfunc, "foo" );
+
+  sleep(1);
+
+  signal("attack", thread_1);
+  signal("defend", thread_2);
+```
+
+**Example: blocking_05.gm**
+
+```
+  woob, waiting for instruction, sir!
+  foo, waiting for instruction, sir!
+  woob is attacking!
+  foo is defending til the death!
+```
+
+**Output: blocking_05.gm**
+
+As you have seen, the blocking and signalling mechanism in GameMonkey
+Script allows you to create multiple threads within the virtual machine
+and have them remain dormant and taking up no execution cycles until a
+signal is received to call it back into action. This allows you to
+design complex behaviours within your entities that respond to the
+signals that are sent back and forth between objects.
+
+### Script Threads and 'this'
+
+Now that you've explored the topics of GameMonkey's threading model,
+using block to pause them and signal to resume execution, it's time to
+look at how we can use the concept of this with threads to open up a lot
+of power for scripting in your game.
+
+Each thread has a special gmVariable associated with it - the this
+variable. The concept of this allows you to effectively run a thread
+against an object and always have that object in scope. If you recall in
+the introductory article, I demonstrated how you could use this to
+reference specific objects in function calls. In GameMonkey's threading
+system, this can be used in exactly the same way, except that it can be
+accessed in every function. See the example that follows:
+
+```
+  global my_entity = {
+    x = 50, y = 100, name = "test"
+  };
+
+  global move_ent_left = function() {
+    print( "Starting thread - this.name = " + .name );
+
+    while( this.x > 0 )
+    {
+      this.x = this.x - 10;
+      print( this.name + " - x = " + this.x );
+      yield();
+    }
+
+    print( "Ending thread - this.name = " + .name );
+  };
+
+  my_entity:thread( move_ent_left );
+  sleep(1);
+```
+
+**Example: threads_this_01.gm**
+
+```
+  Starting thread -- this.name = test
+  test -- x = 40
+  test -- x = 30
+  ...
+  Ending thread -- this.name = test
+```
+
+**Output: threads_this_01.gm**
+
+The code demonstrated above creates a simple table called *my_entity*,
+which has members *x*, *y* and *name*. The function *move_ent_left* will
+simply decrement the x position of this by 10 units, is created in the
+global scope and accepts no parameters, so we can't 'cheat' by passing
+an object instance to the function.
+
+The thread itself is created as normal using the thread() function, but
+with one key difference -- the my_entity table is passed as this via the
+syntax my_entity:thread( func );
+
+The next example will show the move_ent_left function being used for
+multiple objects and on multiple threads.
+
+```
+  global robot = {
+    x = 50, y = 100, name = "robot"
+  };
+
+  global player = {
+    x = 150, y = 200, name = "player"
+  };
+
+  global move_ent_left = function() {
+    print( "Starting thread - this.name = " + .name );
+
+    while( this.x > 0 )
+    {
+      this.x = this.x - 10;
+      print( this.name + " - x = " + this.x );
+      yield();
+    }
+
+    print( "Ending thread - this.name = " + .name );
+  };
+
+  robot:thread( move_ent_left );
+  player:thread( move_ent_left );
+  sleep(1);
+```
+
+**Example: threads_this_02.gm**
+
+```
+  Starting thread -- this.name = robot
+  robot -- x = 40
+  Starting thread -- this.name = player
+  player -- x = 140
+  ...
+  Ending thread -- this.name = robot
+  player -- x = 90
+  player -- x = 80
+  ...
+  Ending thread -- this.name = player
+```
+
+**Output: threads_this_02.gm**
+
+Clever use of threads and this is an extremely useful way of giving
+different entities different behaviours, even if they have the same
+properties; all you would need to do is pass different functions on the
+thread. In the example that follows, we define 5 "robots" that each
+posses a different behaviour -- this behaviour is executed at runtime.
+
+```
+  global create_robot = function(x, y, name) {
+    return { x = x, y = y, name = name, id, class="robot" };
+  };
+
+  global behaviour_stupid = function() {
+    print( .name + " is acting stupidly" );
+  };
+
+  global behaviour_seek = function() {
+    print( .name + " is seeking resources" );
+  };
+
+  global behaviour_rest = function() {
+    print( .name + " is resting" );
+  };
+
+  global robot_def = {
+    {"tom", behaviour_seek},
+    {"mike", behaviour_rest},
+    {"jane", behaviour_stupid},
+    {"bob", behaviour_stupid},
+    {"sarah", behaviour_seek}
+  };
+
+  for(id = 0; id < 5; id = id + 1)
+  {
+    robot = create_robot(1 * id, 10 * id, robot_def[id][0]);
+    robot:thread(robot_def[id][1]);
+  }
+
+  sleep(1);
+```
+
+**Example: threads_this_03.gm**
+
+```
+  tom is seeking resources
+  mike is resting
+  jane is acting stupidly
+  bob is acting stupidly
+  sarah is seeking resources
+```
+
+**Output: threads_this_03.gm**
+
+If the *robot* were your normal game entity that is displayed on screen,
+I'm sure you could appreciate how being able to script them in this way
+is extremely powerful.
+
+### Thread States
+
+Games often utilise finite state machines to control the behaviour and
+state of an object. State machines are often used in game entity
+artificial intelligence scripts which may want to act upon a specific
+stimulus and then return to their previous state. Consider the PacMan
+ghosts who change into to a 'panic' state when the PacMan eats a
+power-up and then revert back to 'roaming' once the power-up has worn
+off; or the patrolling unit in an RTS game that encounters an enemy,
+intercepts to attack it and then resumes its patrol once the threat has
+passed.
+
+I have demonstrated how you can effectively use different functions to
+interact with a scripted object through the use of threads and this. As
+you have seen, GameMonkey Script threads execute a function - the state
+binding allows you to change the function that is running on a thread.
+The thread will keep the same Thread Id, but will lose any locally
+defined variables in the change of execution context. The following code
+will demonstrate how to initiate a state and change to another:
+
+```
+  global awake = function() {
+    print("I'm awake!");
+  };
+
+  global resting = function() {
+    print("I am resting");
+    sig = block("wakeup");
+    if (sig == "wakeup")
+    {
+      stateSet( awake );
+    }
+  };
+
+  global init_state = function() {
+    // Set a state on the thread
+    // we're now using states
+    stateSet( resting );
+  };
+
+  thread( init_state );
+  sleep(1);
+  signal("wakeup");
+```
+
+**Example: states_01.gm**
+
+```
+I am resting
+I'm awake!
+```
+
+**Output: states_01.gm**
+
+The state of a thread is set by the first call to the in-built global
+function stateSet() that accepts the new state function and any
+additionally required parameters. You will notice that this behaves
+almost exactly how you created the thread in the first place, except
+this time you are still using the current thread and just changing the
+function that is being executed. If you want to pass this to the new
+state, you must explicitly do so when calling stateSet().Once you have
+set a thread state you can transition to a new state at any time by a
+subsequent call to stateSet().
+
+Any subsequent changes in state allow you to query the current state
+function by calling stateGet() or the previous state by calling
+stateGetLast(). This is useful as GameMonkey allows you to do
+comparisons on functions, letting you react according to the previous
+state or simply just resume the previous behaviour by switching the
+state back to what it was before. If stateGet() returns null, the thread
+isn't engaged in state behaviour; likewise if stateGetLast() returns
+null the thread hasn't had a previous state.
+
+The example that follows will demonstrate an object that is created,
+blocks until a condition is met, performs an action and then resumes the
+previous action. In one object, it will start as *asleep*, stir and then
+go back to *sleep* -- another will start *asleep*, get panicked at a
+loud noise and then cause all sorts of chaos for the player.
+
+```
+  global ent_state_panic = function() {
+    print(.name + " is panicking, firing off alarms and attracting attention to you");
+  };
+
+  global ent_state_awake = function() {
+    print(.name + " is waking up");
+    this:stateSet( stateGetLast() ); // revert to previous state
+  };
+
+  global ent_state_sleeping = function() {
+    print(.name + " is sleeping");
+    sig = block("quiet_noise", "loud_bang", "kill");
+
+    if (sig == "quiet_noise")
+    {
+      this:stateSet( ent_state_awake );
+    }
+    else if (sig == "loud_bang")
+    {
+      this:stateSet( ent_state_panic );
+    }
+    else
+    {
+      print( .name + " killed" );
+    }
+  };
+
+  /// Initialise the state on the entity
+  global ent_state_init = function(func) {
+    print( .name, " state initialised");
+    this:stateSet(func);
+  };
+
+  global ent_1 = { name = "roboguard 1000" };
+  global ent_2 = { name = "old ticker" };
+
+  // Create two threads, one for each entity and initialise them in the sleeping state
+  ent_1.threadid = ent_1:thread( ent_state_init, ent_state_sleeping );
+  ent_2.threadid = ent_2:thread( ent_state_init, ent_state_sleeping );
+
+  sleep(1);
+  print("You stand on a twig");
+  signal("quiet_noise");
+  sleep(1);
+
+  print("You fire a gun at " + ent_1.name + " causing a loud noise");
+  signal("loud_bang", ent_1.threadid);
+
+  // Tell the entity to die
+  signal("kill", ent_2.threadid);
+```
+
+**Example: states_02.gm**
+
+```
+  roboguard 1000 state initialised
+  roboguard 1000 is sleeping
+  old ticker state initialised
+  old ticker is sleeping
+  You stand on a twig
+  old ticker is waking up
+  old ticker is sleeping
+  roboguard 1000 is waking up
+  roboguard 1000 is sleeping
+  You fire a gun at roboguard 1000 causing a loud noise
+  roboguard 1000 is panicking, firing off alarms and attracting attention to you
+  old ticker killed
+```
+
+**Output: states_02.gm**
+
+The state transitions involved above are described in this diagram:
+
+![blocksigstates](blocksigstates.GIF)
+
+**Image: blocksigstates.gif**
+
+Sometimes it's useful to know about a state change before it happens to
+allow you to run cleanup code or trigger another behaviour. To achieve
+this you can call the function stateSetExitFunction() and pass a
+function object. The function you pass will be called just before the
+state of the thread changes, allowing you to run whatever code you need
+to. When the function completes the state will transition as expected;
+you could use this to play a sound effect before the real event happens,
+for example.
+
+```
+  global awake = function() {
+    print("I'm awake!");
+  };
+
+  global waking = function() {
+    print("I am stirring...");
+  };
+
+  global resting = function() {
+    print("I am resting");
+
+    sig = block("wakeup");
+    if (sig == "wakeup")
+    {
+      stateSetExitFunction( waking );
+      stateSet( awake );
+    }
+  };
+
+  global init_func = function() {
+    // set state on thread
+    stateSet( resting );
+  };
+
+  thread( init_func );
+  sleep(1);
+  signal("wakeup");
+```
+
+**Example: states_03.gm**
+
+```
+  I am resting
+  I am stirring...
+  I'm awake!
+```
+
+**Output: states_03.gm**
+
+All state changes happen on the currently operating thread, but
+sometimes it would be useful to change the state of another thread in
+the machine. Imagine you have a thread blocking on a signal for the
+player to move out of cover; if the cover explodes, you may want to
+force the players taking cover into a different state, such as the one
+that decides the next action. The stateSetOnThread() function allows you
+to do just this and requires a thread id and a state function.
+
+```
+  global state_advance = function() {
+    print("Leaving cover and advancing");
+  };
+
+  global state_decide_action = function() {
+    print("I have to decide on a next action");
+  };
+
+  global state_hiding = function() {
+    print("Behind cover, waiting to advance");
+    sig = block("advance");
+    if (sig == "advance")
+    {
+      stateSet( awake );
+    }
+  };
+
+  global init_state = function() {
+    stateSet( state_hiding );
+  };
+
+  tid = thread( init_state );
+  sleep(1);
+
+  // Signal isn't thrown, tell this thread to change state
+  print("Cover explodes!");
+
+  stateSetOnThread( tid, state_decide_action );
+```
+
+**Example: states_04.gm**
+
+```
+  Behind cover, waiting to advance
+  Cover explodes!
+  I have to decide on a next action
+```
+
+**Example: states_04.gm**
+
+As you have seen, the threading functionality built into GameMonkey
+Script provides a useful toolset to control behaviours of your entities
+and offers flexible solutions to achieve your scripting needs.
+
+## Integrating GameMonkey with your Game
+
+GameMonkey Script offers a lot of advanced
+functionality to script your game entities which can become quite
+complex for your script writers. In a real-world usage scenario you may
+wish to simplify your scripting interface and use many of GameMonkey
+Script's threading features invisibly. For example, if you create an NPC
+entity that has an update routine it is often more intuitive for a
+script writer to simply write a script such as:
+
+```
+  npcupdatefunc = function() { ... do stuff... };
+  npc = createNPC(npcupdatefunction);
+```
+
+Rather than:
+
+```
+  npcupdatefunc = function() { ... do stuff... };
+  npc = createNPC();
+  npc:thread(npcupdatefunction);
+```
+
+Your game may also feature asynchronous events such as dialog boxes or
+entity movement instructions that use the blocking functionality.
+
+This section will describe how to work with the GameMonkey Script API to
+take advantage of the threading functionality and offer some simple
+methods by which you can simplify the interface you provide to your
+script writers without compromising on the flexibility offered by the
+scripting language.
+
+### Creation of gmThreads
+
+A new thread can be created at *any* time in the virtual machine by
+calling the gmMachine::CreateThread() method. The result of this action
+is that a new gmThread object is created and a unique thread id is
+returned. You can call this method passing a gmVariable to act as this
+and importantly, a gmVariable containing the gmFunctionObject that the
+thread needs to execute. The following code demonstrates the creation of
+a simple thread via the API that calls an existing function within
+script -- for simplicity's sake this script is embedded in the
+application.
+
+```
+  #include <iostream>
+  #include "gmThread.h"
+
+  int main(int argc, char* argv[])
+  {
+
+    // Create gm virtual machine
+    gmMachine gm;
+
+    // A test script which creates the function we're testing
+    const char *testscript = "global threadfunc = function() { print(\"Hello, threads!\"); };";
+
+    // Execute the script to create the function in the VM
+    if (gm.ExecuteString( testscript, NULL, true ))
+    {
+      bool first = true;
+      std::cout << gm.GetLog().GetEntry(first);
+      return 1;
+    }
+
+    int new_threadId = 0;
+
+    // Allocate a thread within the machine
+    gm.CreateThread( gmVariable::s_null, gm.GetGlobals()->Get(&gm, "threadfunc"), &new_threadId );
+
+    // Execute the machine
+    gm.Execute(1);
+    return 0;
+  }
+```
+
+**Example: threads_01a.cpp**
+
+The code is simple; a script is executed to create the scripted function
+(a global named *threadfunc*) and a new thread is created using the
+reference to the script function obtained by reading from the global
+table. One thing to note is that as we've created a *scripted* function
+using script, we need to call gmMachine::Execute() to run the thread
+because the original ExecuteString() call actually created a thread to
+run in and it is still seen as the active thread in the machine.
+
+To demonstrate the passing of this to a thread upon creation we simply
+pass an actual variable installed of gmVariable::s_null (the static null
+value variable). An example of this follows, you will notice that the
+string I pass as this is available in the script function we call.
+
+```
+  #include <iostream>
+  #include "gmThread.h"
+
+  int main(int argc, char* argv[])
+  {
+    // Create gm virtual machine
+    gmMachine gm;
+
+    // A test script which creates the function we're testing
+    const char *testscript = "global threadfunc = function() { print(\"'this' passed as - \", this); };";
+
+    // Execute the script to create the function in the VM
+    if (gm.ExecuteString( testscript, NULL, true ))
+    {
+      bool first = true;
+      std::cout << gm.GetLog().GetEntry(first);
+      return 1;
+    }
+
+    int new_threadId = 0;
+
+    // Allocate a thread within the machine
+    gm.CreateThread( gmVariable(gm.AllocStringObject("Hello, this!")), gm.GetGlobals()->Get(&gm, "threadfunc"), &new_threadId );
+
+    // Execute the machine
+    gm.Execute(1);
+
+    return 0;
+  }
+```
+
+**Example: threads_01b.cpp**
+
+As you expect, it's entirely possible to execute a native function as
+the thread function, you simply bind the function as normal and use the
+gmFunctionObject pointer wrapped up by a gmVariable. The following code
+demonstrates the same result as the first, this time binding a function
+and calling that.
+
+```
+  int GM_CDECL gmMyThreadFunc(gmThread *a_thread)
+  {
+    std::cout << "Hello, threads!" << std::endl;
+    return GM_OK;
+  }
+
+  int main(int argc, char* argv[])
+  {
+    // Create gm virtual machine
+    gmMachine gm;
+
+    // Bind the function to use by creating a gmFunctionObject
+    gmFunctionObject *threadfunc = gm.AllocFunctionObject( gmMyThreadFunc );
+
+    int new_threadId = 0;
+
+    // Allocate a thread within the machine
+    gm.CreateThread( gmVariable::s_null, gmVariable(threadfunc), &new_threadId );
+
+    return 0;
+  }
+```
+
+**Example: threads_02.cpp**
+
+Any object can be passed to the thread as this if it has been registered
+within the gmMachine as a gmType and wrapped in a gmVariable. The
+following example shows how you can access this in the callback via the
+gmThread::GetThis() method. In this case I expect it to be a string
+type, but in your code you'd most likely use your own entity types.
+
+```
+  int GM_CDECL gmMyThreadFunc(gmThread *a_thread)
+  {
+    GM_ASSERT( a_thread->GetThis()->m_type == GM_STRING );
+
+    gmStringObject *thisstr = reinterpret_cast<gmStringObject*>(a_thread->GetThis()->m_value.m_ref);
+
+    std::cout << "'this' passed as " << thisstr->GetString() <<
+    std::endl;
+    return GM_OK;
+  }
+
+  int main(int argc, char* argv[])
+  {
+    // Create gm virtual machine
+    gmMachine gm;
+
+    // Bind the function to use by creating a gmFunctionObject
+    gmFunctionObject *threadfunc = gm.AllocFunctionObject( gmMyThreadFunc );
+
+    // Add function to the global table so scripts can access it
+    gm.GetGlobals()->Set(&gm, "threadfunc", gmVariable(threadfunc) );
+
+    // Call script to make callback, pass a variable containing "hello" as this
+    const char *script = "text = \"hello\"; text:thread( threadfunc );";
+
+    gm.ExecuteString( script );
+    return 0;
+  }
+```
+
+**Example: threads_03.cpp**
+
+### Working with 'this'
+
+So far, most of the C++ binding examples we've been using have relied on
+us passing the objects to work on as a parameter to the callback
+functions. However you're more likely to want to pass this to functions
+explicitly or implicitly by binding them to an instance of a type --
+this is how we've been doing it in many of the actual scripts you've
+seen. This next section will demonstrate how to access and use this in
+your native callbacks and continue to provide a simple example of some
+code to extend your bound types.
+
+As you have seen previously, every gmThread has a stack slot allocated
+for the this variable. This can be accessed in raw gmVariable form by
+calling gmThread::GetThis(). The main difference between GetThis() and
+Param() is that GetThis() returns the gmVariable via a const pointer and
+not by value like the Param() functions. In the previous example
+(threads_03.cpp), you were accessing a string variable passed as this.
+It is often required that you validate the type of this variable -- the
+gmThread.h file defines a series of useful macros for checking function
+parameters, there are also a few for checking the type of this, such as
+GM_CHECK_THIS_STRING, which will return a thread exception if this is
+passed as anything other than a string type.
+
+Like the Param() functions, there are several helpers for automatically
+and safely converting this back to the various native types associated
+with the GameMonkey type. So, for example ThisString() returns as a
+const char* and ThisInt() returns an int.
+
+```
+  int GM_CDECL gmThisTest(gmThread *a_thread)
+  {
+
+    GM_CHECK_THIS_STRING;
+
+    std::cout << "'this' passed as " << a_thread->ThisString() <<
+    std::endl;
+    return GM_OK;
+  }
+```
+
+**Example: this_01.cpp**
+
+There are three methods for returning your user types, ThisUser()
+returns a void* and the gmType of the object it holds;
+ThisUserCheckType() will only return a non-NULL pointer to the object if
+the type you pass in matches the object type and finally
+ThisUser_NoChecks() passes you just the pointer to the data held in the
+user object. Of course, these are simply common conversions -- you are
+encouraged to create your own routines should you require anything else,
+such as converting back and forth to your entity type automatically.
+
+### Script-Extensible Objects
+
+The use of this becomes incredibly important when it comes to working
+with your own user types and binding functions and data to them. The
+rest of this section will demonstrate a highly simplified game entity
+class that allows you to extend it with scripted properties.
+
+The first thing we do is define our game entity. In this example we
+declare it to have the following attributes:
+
+
+**Variable** | **Read/Write?** | **Description**
+---|---|---
+Id | Read        | Guid of the entity
+X  | Read, Write | X position of the entity
+Y  | Read, Write | Y position of the entity
+
+If you think back to the simple Vector binding I demonstrated in the
+original articles, you will remember that we used the raw Vector*
+pointer as the data tied to GameMonkey and bound the Dot/Ind operators
+to allow modification of the underlying data. This time along we want to
+take advantage of the flexibility of GameMonkey and effectively allow
+additional properties to be added to the object -- for example, allowing
+the script writer to add a "name" property to the object.
+
+```
+  struct Entity
+  {
+    Entity() : Id(0), X(0), Y(0) { }
+    Entity(int id) : Id(id), X(0), Y(0) { }
+    int Id, X, Y;
+  };
+```
+
+**Example: ext_01.cpp**
+
+The first step to achieving this goal is to create a proxy object that
+holds both the raw Entity data and a gmTableObject that will be used to
+hold our additional properties; this proxy is represented by a
+ScriptEntity class. We have a choice to make at this stage; do we want
+to be invasive to the Entity class and allow it to hold a pointer to the
+ScriptEntity or do we want the ScriptEntity to wrap the Entity object? I
+have chosen to add a pointer to the ScriptEntity into the Entity class;
+this enables any other consumers of the Entity class to be aware of the
+additional properties and create their own or read any existing ones --
+this allows for some nice data-driven entities to be created as you will
+see shortly.
+
+```
+  struct ScriptEntity
+  {
+    ScriptEntity(Entity &ent) : EntityObject(ent), ScriptProperties(NULL) {}
+    Entity &EntityObject;
+    gmTableObject *ScriptProperties;
+  };
+```
+
+**Example: ext_01.cpp**
+
+Once the basic objects have been defined the type is bound as normal. I
+have bound a global function createEntity() to the script environment
+which will allocate a new Entity from the EntityManager and also
+allocate a new ScriptObject and gmTableObject for it.
+
+```
+  int GM_CDECL gmCreateEntity(gmThread *a_thread)
+  {
+    // Create an entity from the manager
+    int entityId = 0;
+
+    Entity &ent = s_EntityManager.CreateEntity(entityId);
+
+    // Allocate a script entity & construct it
+    ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(s_scriptents.Alloc());
+
+    GM_PLACEMENT_NEW( ScriptEntity(ent), sent );
+
+    // Tie back to entity
+    ent.ScriptObject = sent;
+
+    // Create a property table
+    sent->ScriptProperties = a_thread->GetMachine()->AllocTableObject();
+
+    // Tell GM how much memory we're using
+    int memadjust = sizeof(gmTableObject) + sizeof(Entity) + sizeof(ScriptEntity);
+    a_thread->GetMachine()->AdjustKnownMemoryUsed(memadjust);
+
+    // return to client
+    a_thread->PushNewUser( sent, s_entitytype );
+    return GM_OK;
+  }
+```
+
+**Example: ext_01.cpp**
+
+I've chosen to use some of the in-built GameMonkey memory allocation
+routines for the ScriptEntity creation (gmMemFixed); this is a fairly
+simple fixed memory allocator which uses a freelist for reallocations.
+You are free to use the normal new and delete operators or to rely on
+memory allocation routines from your own engine.
+
+Once this function is bound, you can create entities in script -- but
+they're not much use until you bind the operators. In this case I will
+bind the GetDot and SetDot operators only. They will both work in
+similar ways; the object is retrieved from the relevant operand and the
+text of the property is resolved from the gmStringObject it is passed
+as. If the property is resolved to either *X, Y* or *Id* (the properties
+of the Entity class), we simply access the relevant property on the
+Entity. Any other property accesses will go straight to the
+gmTableObject we created on the ScriptEntity, thus allowing us to get
+and set properties that didn't exist on the base class. The SetDot
+operator code is shown below as an example.
+
+```
+  void GM_CDECL gmOpSetDot(gmThread *a_thread, gmVariable *a_operands)
+  {
+    if (a_operands[0].m_type != s_entitytype)
+    {
+      a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid type passed" );
+      a_operands[0] = gmVariable::s_null;
+      return;
+    }
+
+    // Get scriptentity back
+    ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_operands[0].GetUserSafe(s_entitytype));
+
+    // Get name of 'get' prop
+    std::string propname = a_operands[2].GetCStringSafe();
+
+    // Test for our known properties and return their values back immediately
+
+    if (propname == "X")
+    {
+      sent->EntityObject.X = a_operands[1].GetIntSafe();
+    }
+    else if (propname == "Y")
+    {
+      sent->EntityObject.Y = a_operands[1].GetIntSafe();
+    }
+    else if (propname == "Id")
+    {
+      a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot cannot set Id" );
+      a_operands[0] = gmVariable::s_null;
+    }
+    else
+    {
+      // Otherwise, store a value in the table
+      sent->ScriptProperties->Set(a_thread->GetMachine(), propname.c_str(), a_operands[1]);
+    }
+  }
+```
+
+**Example: ext_01.cpp**
+
+When you bear in mind that GameMonkey Script functions can also be
+stored as variables, you will see that you can start adding scripted
+functions to the base entity class with ease -- be it from the C++ API
+or from script itself. All functions invoked on the object have this
+implicitly passed, so code such as the following is possible:
+
+```
+  ent = createEntity();
+  ent.name = "somebody";
+  ent.sayname = function() {
+    print( "My name is: ", this.name );
+  };
+
+  ent.sayname();
+```
+
+By using the C++ API and accessing this, you can begin to add some
+script-bound functions to the ScriptEntity's ScriptProperties table with
+ease. The following example shows a simple function that displays the
+entity's position, id and name -- with name being a property added
+within script.
+
+```
+  // The entity is passed as this
+  int GM_CDECL gmEntityInfo(gmThread *a_thread)
+  {
+    ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_thread->ThisUserCheckType(s_entitytype));
+
+    if (sent == NULL)
+    {
+      a_thread->GetMachine()->GetLog().LogEntry("gmEntityInfo: Expected entity type as this");
+      return GM_EXCEPTION;
+    }
+
+    std::stringstream infotext;
+    infotext << "EntityId: ";
+    infotext << sent->EntityObject.Id;
+    infotext << " - Postition("; infotext << sent->EntityObject.X;
+    infotext << ","; infotext << sent->EntityObject.Y; infotext << ") - Name: ";
+
+    // Get name from table and pass to object
+    gmVariable namevar = sent->ScriptProperties->Get(a_thread->GetMachine(), "name");
+
+    if (namevar.IsNull() || namevar.m_type != GM_STRING)
+    {
+      infotext << " [No name]";
+    }
+    else
+    {
+      infotext << namevar.GetStringObjectSafe()->GetString();
+    }
+
+    std::cout << infotext.str() << std::endl;
+    return GM_OK;
+  }
+```
+
+**Example: ext_01.cpp**
+
+In the full example code ext_01.cpp (not shown), I added an entry to the
+ScriptProperties table to automatically hold this function for each
+entity created by the script engine:
+
+```
+  // Bind an additional method to the entity's prop table
+  sent->ScriptProperties->Set(a_thread->GetMachine(), "ShowInfo", gmVariable( a_thread->GetMachine()->AllocFunctionObject(gmEntityInfo)) );
+```
+
+The script we run can be modified as follows to use the new function:
+
+```
+  ent = createEntity();
+  ent.name = "somebody";
+  ent.ShowInfo();
+```
+
+And the output?
+
+```
+  EntityId: 1 -- Position(100,0) -- Name: somebody
+```
+
+In this section you've learned how to use GameMonkey Script to extend an
+existing native class and attach new data and functions to it. Armed
+with this information you are free to create powerful entity types and
+allow your script writers to extend them without any changes to the
+engine code.
+
+### Threads, The Stack and Function Calls
+
+As threads are an important part of GameMonkey Script, I will use this
+section to cover how they work in more detail. I will also discuss how a
+function is called within the GameMonkey Virtual Machine (VM) and how
+this is tied to threads.
+
+A thread on the VMis composed of the following components:
+
+- A unique identifier
+- A stack
+- A function to execute
+- A pointer to the current instruction (if any)
+- A list of blocks and signals pending on the thread
+- State information about the thread
+
+The thread stack is a effectively a list of gmVariable objects that is
+used to hold the function being executed, the variable for this, any
+function parameters passed to the thread and then finally any working
+variables, including return values from functions.
+
+The thread function is a gmFunctionObject which can be either a native
+function callback or a scripted function. A scripted function is a
+series of bytecode instructions that are interpreted by the GameMonkey
+VM to create the behaviours you see in script. The execution of the VM
+bytecode is dependent on the structures in the thread and the VM cannot
+execute a function without it.
+
+When a function is called in GameMonkey, what actually happens? The
+first thing pushed to the stack is a variable containing this, it will
+contain null if there is no value for this. A variable holding the
+function object is next to be pushed to the stack, followed by any
+function parameters in order. Finally, a stackframe is pushed to
+complete the setup and initialise all internal data and structures to
+ready the thread for execution on the VM. The stackframe is important as
+it allows the VM to maintain the correct pointers to instructions and
+data to, for example, allow nested function calls to be made within the
+system. The function is then executed by the virtual machine, either by
+calling a native function or by interpreting the bytecode involved with
+the scripted function. Any return value is pushed back to the stack and
+the stack frame is popped, allowing the script to continue where it left
+off before the function call.
+
+We can see this in action by manually creating a thread and calling a
+native function. The first code we write is a simple function that
+accepts two integer parameters and writes them to cout.
+
+```
+  int GM_CDECL gmFunctionTest(gmThread *a_thread)
+  {
+    GM_CHECK_INT_PARAM( a_param1, 0 );
+    GM_CHECK_INT_PARAM( a_param2, 1 );
+    std::cout << "Param 1: " << a_param1 << std::endl;
+    std::cout << "Param 2: " << a_param2 << std::endl;
+    return GM_OK;
+    }
+```
+
+Next, we follow the steps detailed above to call the function via the
+GameMonkey API.
+
+```
+  gmMachine gm;
+  int threadid = 0;
+
+  gmThread *thread = gm.CreateThread(&threadid);
+  thread->PushNull(); // Push 'this'
+  thread->PushFunction( gm.AllocFunctionObject(gmFunctionTest) ); // push function to call
+  thread->PushInt(50);
+  thread->PushInt(100);
+  thread->PushStackFrame(2);
+```
+
+**Example: functioncall_01.cpp**
+
+As you can see, we create a thread, push the required information to it
+and then finally execute it by pushing the stack frame using
+gmThread::PushStackFrame. If the function were a scripted function, you
+would need to run it by executing the thread using gmThread::Sys_Execute
+or by using gmMachine::Execute() to execute the whole machine.
+
+```
+  gmMachine gm;
+
+  // Create a global scripted function
+  gm.ExecuteString(
+    "global func = function(a, b) { print(\"Param 1:\", a); print(\"Param 2:\", b); };"
+  );
+
+  gmFunctionObject *func = gm.GetGlobals()->Get(&gm, "func").GetFunctionObjectSafe();
+
+  int threadid = 0;
+
+  gmThread *thread = gm.CreateThread(&threadid);
+  thread->PushNull(); // Push 'this'
+  thread->PushFunction( func ); // push function to call
+  thread->PushInt(50);
+  thread->PushInt(100);
+  thread->PushStackFrame(2);
+  thread->Sys_Execute();
+```
+
+**Example: functioncall_02.cpp**
+
+If we'd have wanted to return a value from the function it's a simple
+case of pushing it to the stack before we return and retrieving it
+either by getting the top of the stack from the thread, or if it was a
+scripted function the call to Sys_Execute accepts an optional pointer to
+a gmVariable allowing you to capture this if you need to.
+
+This section has shown you how to manually call functions and how they
+interact with the threads and stack. It is recommended that you use the
+gmCall helper for most of your script calls as it wraps all of this
+functionality for you already and reduces the chance of errors
+occurring.
+
+### Callback Return Values
+
+So far, all of the examples of bound functions you've seen have returned
+GM_OK or GM_EXCEPTION. This section will describe how these are used by
+the virtual machine and discuss other values you can use.
+
+When a function call is made or an operator callback is invoked, you
+have a chance to indicate success or failure to the VM execution engine.
+If the call is successful (GM_OK), everything continues as normal -- but
+what happens if there is an error? An error could be that you received
+the wrong parameter type to a function callback, or maybe even an
+internal game error that requires your script environment to be
+notified. In such cases, you would return a value of GM_EXCEPTION to the
+thread, which has the effect of causing it to terminate.
+
+Usable values are as follows:
+
+**Value**    | **Meaning**
+---|---| 
+GM_OK        | Success
+GM_EXCEPTION | An error occurred
+GM_SYS_YIELD | Causes a thread to immediately yield execution to another thread
+GM_SYS_BLOCK | A block has been set on the thread, see later for more detail
+GM_SYS_SLEEP | Force the thread to sleep after setting the Sys_SetTimeStamp and Sys_SetStartTime values accordingly.
+
+There are other values available but they are internal and shouldn't be
+used for risk of corrupting the execution of the VM.
+
+### Signalling via the API
+
+Like using signals in the script language you can signal threads from
+the API. This allows you to implement event-based systems that trigger
+game events as signals to the entire virtual machine as or to specific
+threads that are running on particular game entities. One use may be an
+RPG game that pops up a dialog box for a quest; in script you'd tell the
+engine to open the quest dialog with a specific text and wait for the
+user to accept or decline it. An example script would look like:
+
+```
+  ShowQuestDialog( Quests.SaveThePrincess );
+
+  response = block( QuestDialog.Accept, QuestDialog.Decline );
+  if (response == QuestDialog.Accept)
+  {
+    // do something
+  }
+  else
+  {
+    // do something else
+  }
+```
+
+In this example, the ShowQuestDialog() function would be a native
+function that pops up a non-modal dialog that itself waits for a button
+response event from your GUI subsystem. As the dialog is non-modal, you
+need your script to respond from the user's input in some way, so you
+block on two signals to indicate accept or decline. Because the thread
+is waiting for a block it becomes dormant in the GameMonkey machine and
+therefore takes up no execution time until it's woken by a signal. The
+signal itself would be fired by your script subsystem in response to a
+GUI button press event for that specific dialog.
+
+Let's look at some sample code:
+
+```
+  enum QuestDialog
+  {
+    QD_DECLINE,
+    QD_ACCEPT
+  };
+
+  // This function simulates a modal quest dialog
+  int GM_CDECL gmShowQuestDialog(gmThread *a_thread)
+  {
+    std::cout << "A princess is in danger, do you wish to save her?" << std::endl << "[Accept | Decline]" << std::endl;
+    return GM_OK;
+  }
+
+  void HandleUserAcceptQuest(gmMachine &gm, int threadid, QuestDialog response)
+  {
+    // Fire signal to thread to indicate user's choice
+    gm.Signal( gmVariable( (int)response ), threadid, 0 );
+  }
+
+  int main(int argc, char* argv[])
+  {
+    gmMachine gm;
+
+    // Bind ShowQuestDialog function to script
+    gm.GetGlobals()->Set( &gm, "ShowQuestDialog", gmVariable(gm.AllocFunctionObject( gmShowQuestDialog )) );
+
+    // Create a global table to hold Ids for QuestAccept/Decline
+    gmTableObject *dialogResponses = gm.AllocTableObject();
+    dialogResponses->Set( &gm, "Accept", gmVariable(QD_ACCEPT) ); // Accept = 0
+    dialogResponses->Set( &gm, "Decline", gmVariable(QD_DECLINE) ); // Decline = 0
+    gm.GetGlobals()->Set( &gm, "QuestDialog", gmVariable( dialogResponses ) );
+
+    // Run an example script that calls dialog and blocks on response
+    const char *script = "ShowQuestDialog(); \n"
+      "response = block( QuestDialog.Accept, QuestDialog.Decline ); \n"
+      "if (response == QuestDialog.Accept) { print(\"[Quest accepted]\"); } else { print(\"[Quest declined]\"); }";
+
+    int threadid = 0;
+
+    // Run script and capture thread it's running on
+    gm.ExecuteString( script, &threadid );
+    Sleep(5000); // Wait for 5 seconds to simulate user deciding to accept
+    HandleUserAcceptQuest(gm, threadid, QD_ACCEPT);
+
+    // Tick the machine along
+    gm.Execute(0);
+
+    return 0;
+  }
+```
+
+**Example: signals_01.cpp**
+
+The majority of the code is actually setting up our global script
+variables and binding the demonstration quest dialog function. The
+sample script is run on the machine which immediately calls the quest
+dialog function (in your implementation you'd open a real GUI window)
+and then immediately blocks for the response. The signal itself is sent
+via a call to gmMachine::Signal, which accepts a gmVariable and an
+optional thread Id -- you will see that this is identical to calling
+signal from script.
+
+A second example is that of a door created in script. The door itself
+will remain closed until the game instructs it to open, perhaps by a
+person using a switch or firing some kind of trigger. The script for the
+door is simple; the door is created and immediately blocks for the
+signal to open. When this trigger is received, an animation game event
+is played asynchronously while the door script sleeps for 5 seconds.
+After it resumes, the close animation is played and the door goes back
+to blocking -- this behaviour will repeat forever or until the thread is
+terminated by the game, perhaps in response to the door becoming
+impassible or destroyed.
+
+```
+  global DoorFunction = function() {
+    while(true)
+    {
+      print(this, "waiting for use...");
+      block("usedoor");
+      this:startAnimation("dooropen");
+      sleep(5);
+      this:startAnimation("doorclose");
+    }
+  };
+
+  createDoor(DoorFunction);
+```
+
+**Example: signals_02.cpp -- Door Script**
+
+The native callback createDoor() will create a new door instance and run
+the function you pass it. Note that in this example I just demonstrate
+the object using a text string, your game will most likely feature an
+actual door entity being created and returned as a user object.
+
+```
+  int GM_CDECL gmCreateDoor(gmThread *a_thread)  {
+
+    GM_CHECK_FUNCTION_PARAM(a_func, 0);
+
+    // Simple example, return "TESTDOOR" as the user object
+    gmStringObject *door = a_thread->GetMachine()->AllocStringObject("TESTDOOR");
+
+    // Call passed in function as a new thread (gmCall does this under the hood)
+    gmCall gmcall;
+      gmcall.BeginFunction(a_thread->GetMachine(), a_func, gmVariable(door), false);
+    gmcall.End();
+
+    a_thread->PushString(door);
+    return GM_OK;
+  }
+```
+
+**Example: signals_02.cpp**
+
+To open the door at any point in the game, you fire the signal. I'm
+executing the next frame of the VM manually here, but your game loop
+will be doing this each frame automatically.
+
+```
+  // Open the door... fire global signal for now
+  gm.Signal(gmVariable( gm.AllocStringObject("usedoor") ), GM_INVALID_THREAD, 0);
+```
+
+**Example: signals_02.cpp**
+
+The output of this whole example:
+
+```
+  TESTDOOR waiting for use...
+  TESTDOOR starting animation: dooropen
+  TESTDOOR starting animation: doorclose
+  TESTDOOR waiting for use...
+```
+
+**Output: signals_02.cpp**
+
+This example is an excellent way of showing how the thread that controls
+the door can be created within the game code itself, removing the need
+for a user to explicitly create them to run the door script. To the
+user, they are simply creating a door that will play out their
+behaviour, they don't even have to know about the signal being fired by
+the game.
+
+### Blocking via the API
+
+It is possible to set a thread to block using the API and it allows more
+flexibility than blocking in script. When you block from within the GM
+Scripting language itself the currently executing thread is suspended
+immediately and is set to the status of "blocked". Blocking a thread
+from the API allows you to continue processing as normal; the blocked
+state of the thread is only registered upon the next execution cycle of
+the virtual machine. To block a thread, you need to use the
+gmMachine::Sys_Block function; this function takes a thread Id and a
+list of gmVariables to block on. Although it is possible to block on a
+thread that isn't the current thread, it is not recommended as it may
+cause undesirable or unpredictable behaviour in the scripts running on
+the machine (such as a thread blocking for a signal that will never
+occur).
+
+A quick example will show you how to set up a block via script:
+
+```
+  enum
+  {
+    SIG_ZERO,
+    SIG_ONE
+  };
+
+  int GM_CDECL gmBlockTest(gmThread *a_thread)
+  {
+    gmVariable blocks[] = { gmVariable(SIG_ZERO), gmVariable(SIG_ONE) };
+
+    int ret = a_thread->GetMachine()->Sys_Block( a_thread, 2, blocks );
+    if (ret == -1)
+    {
+      return GM_SYS_BLOCK;
+    }
+    a_thread->Push(blocks[ret]);
+    return GM_OK;
+  }
+```
+
+**Example: blocks_01.cpp**
+
+In this callback function I have set up two variables containing the
+values 0 and 1 and have instructed the GameMonkey machine to block the
+currently running thread on them. Under the hood, the
+gmMachine::Sys_Block function will attempt to use up any signals already
+pending on the thread; if a matching signal is found for one of the
+blocks, it will return immediately with the index of the block variable
+you supplied. When this happens, I push the variable back to the thread
+stack as a return value so that it returns the block immediately to the
+user to allow them to check which block was signalled. If no
+corresponding signal is found, Sys_Block returns a value of -1 -- when
+this happens you return a value of GM_SYS_BLOCK to indicate to the VM
+that this thread should be suspended until a signal is received to wake
+it. When you bind the function above to the machine, it lets you run a
+script such as:
+
+```
+  r = blocktest();
+
+  print( "signal fired:", r);
+```
+
+This will block until you signal the thread either using
+gmMachine::Signal or the signal() command from script.
+
+Games often feature asynchronous actions, such as playing an animation
+or sound, actor pathfinding/movement and so on. In the real world, many
+of these actions will be kicked off with an event dropped onto a message
+queue which is picked by the relevant system. Imagine the case of an NPC
+being instructed to move across town; the entity management system will
+pick up the movement message and move the entity a little bit each frame
+until the NPC arrives at its destination many frames later. At this
+point the entity manager it will signal back to the game that the
+movement has completed.
+
+Your scripts will often want to trigger asynchronous behaviours but will
+need to treat them as if they are synchronous by waiting for the result
+of the task before deciding how to proceed. If the machine-bound
+function returned immediately after queuing the message, the script
+would continue as normal without waiting for completion. In a previous
+section you achieved this in script by using GameMonkey's blocking and
+signalling functionality; in this case you could fire your event and
+then immediately block for the signal back from the game engine to wake
+up the thread.
+
+```
+  doasyncbehaviour();
+  ret = block( "ok", "failed" );
+  // continue as normal
+```
+
+Although this works, it can be a little clunky in practice and requires
+that your script writers always remember to block after an asynchronous
+behaviour. In this next section I will demonstrate an example of working
+with asynchronous game events elegantly with GameMonkey Script.
+
+For this example I will allow you to imagine a town guard in an RPG game
+that wanders back and forth between two towers. When he gets to a tower,
+he'll inspect the area and move on if nothing is amiss. The guard's
+behaviour is described as the following series of states:
+
+![guardstates](guardstates.GIF)
+
+**Image: guardstates.gif**
+
+In the game engine this will be achieved by initiating the movement
+using a *goto* message to the entity manager. Upon arrival at the
+destination a *goto_success* message is sent back to the game system --
+should anything happen such as the destination being unreachable, the
+entity being attacked or so on, a *goto_failed* message is sent back to
+the game, along with other messages for the next action (if any).
+
+The sequence of events in this asynchronous call are as follows:
+
+1. Script calls NPCWalkTo( dest )
+2. Game pushes goto message to message queue
+3. Script call blocks thread and returns
+4. Game frame advances, entity manager picks up movement message
+5. Entity manager moves NPC each frame until destination is reached
+6. Message is sent back to script manager to inform destination reached
+7. Script manager signals thread of completion, script progresses as
+8. normal
+
+Look at the example code blocking_02.cpp for a simple yet realistic
+implementation of the above behaviour. In the code, we bind two
+functions to the GameMonkey machine, CreateNPC() which is tied into the
+game's entity manager and NPCGoto() which accepts an entity and a
+location as a parameter. In this simple example, the location is either
+TOWER_ONE or TOWER_TWO in the global Location table. In a real game
+you'd most likely specify a vector, or would bookmark real locations
+with names like TOWER_ONE. The first thing we do in the script is create
+the guard NPC and start a thread for it to run in.
+
+```
+  global GuardMove = function() {
+    this:stateSet(GuardGotoTowerOne);
+  };
+
+  npc = CreateNPC();
+  npc:thread(GuardMove);
+```
+
+The guard's behaviour function immediately jumps into the state that
+tells it to go to the first tower.
+
+```
+  global GuardGotoTowerOne = function() {
+
+    print("Going to Tower One...");
+
+    res = NPCGoto(this, Location.TOWER_ONE);
+
+    if (res == Event.SUCCESS)
+    {
+      print("Arrived at tower One");
+      this:stateSet(GuardWait);
+    }
+    else
+    {
+      print("Couldn't get there");
+    }
+  };
+```
+
+This script function calls the NPCGoto() function and passes TOWER_ONE
+as a location for this entity to travel to. The native code behind this
+function fires off a message to the game system that indicates we want
+to move the entity to the specified location.
+
+```
+  GM_CHECK_INT_PARAM(a_entity, 0);
+  GM_CHECK_INT_PARAM(a_location, 1);
+
+  // Push message to Game Message queue
+  NPCGotoMessage *msg = new NPCGotoMessage( a_entity, a_thread->GetId(), a_location );
+
+  s_Game.GetMessageSystem().PushMessage( msg );
+```
+
+The bound function then immediately sets up a block on the scripted
+thread that suspends it until we've received the success or failure
+result back from the game.
+
+```
+  gmVariable blocks[] = { gmVariable(SM_SUCCESS), gmVariable(SM_FAILED) };
+
+  int res = a_thread->GetMachine()->Sys_Block( a_thread, 2, blocks );
+
+  if (res == -1)
+  {
+    return GM_SYS_BLOCK;
+  }
+```
+
+The game continues as normal, the entity manager picks up the
+NPCGotoMessage we posted and processes the movement of the entity each
+frame. In this example we're using a time based trigger that fires after
+a few seconds, but in a real game you would move an entity's
+co-ordinates in the world.
+
+```
+  if (_Dur >= 2500.0f) // Simulate time passing
+  {
+
+    NPCArrivalMessage *msg = new NPCArrivalMessage(ent._Id, ent._ScriptThreadId, ent._Destination);
+
+    s_Game.GetMessageSystem().PushMessage(msg);
+    ent._State = Entity::ES_WAITING; // Go back to waiting state
+
+    _Dur = 0;
+  }
+```
+
+The script manager system is set up to listen for an NPCArrivalMessage;
+when it recieves one it will post the result of the movement request
+back on the entity's thread in the form of a signal.
+
+```
+if (a_msg->MessageType == MT_GOTO_SUCCESS)
+{
+  NPCArrivalMessage *msg = reinterpret_cast<NPCArrivalMessage*>(a_msg);
+
+  // Fire signal on thread
+  _Machine.Signal( gmVariable(SM_SUCCESS), msg->ScriptThreadId, 0 );
+}
+```
+
+The GameMonkey Script machine processes the signal on the next update
+and the thread resumes operation, in this case the script is written to
+change state to the waiting state and then progress from there to
+TOWER_TWO.
+
+As you can appreciate, this set up allows you to write scripts for
+entities as if they are synchronous and not worry about the complex
+message handling systems your engine may implement. By treating the
+NPCGoto function as a normal function call and hiding the blocking
+behaviour, you enable your script writers to write simple logic and not
+worry about anything that may happen internally in your game.
+
+## Best Practices
+
+Now that you've explored GameMonkey Script in detail you will be aware
+that is a highly flexible language; like many other programming
+languages there are a series of best-practices to follow for both
+scripting and embedding the language in your games.
+
+### Avoid inline script
+
+Although some of the examples here have scripts embedded within the C++
+code, this should be avoided in a production environment. The single
+biggest benefit of a scripted language is that it helps avoid recompiles
+of your game engine should game logic need changing -- by inlining your
+script you will lose out on this benefit. It is advised that you load
+your scripts at runtime using your own load routines; you should also
+bind a function similar to Lua's dofile function that allows you to load
+and execute scripts from files at runtime. A non-portable example is
+available via the gmSystemLib binding that ships with GM.
+
+### Minimise Globals
+
+Like many other programming languages, the use of global variables and
+functions should be kept to a minimum. Although convenient, a game will
+feature tens, hundreds, if not thousands of scripted functions to create
+its behaviours. When you rely entirely on globals you are forced to use
+warts to prefix each function name to allow you to differentiate between
+behaviours for different entity types. If specific behaviours and
+functions are to be shared across multiple entity types, it is worth
+considering, but for many cases it is not necessary. The best solution
+is to bind specific functions to your entity type libraries and to
+investigate some of the extensibility methods I discussed earlier to
+allow you to attach functions to a hidden table on the entity. This way,
+all the functions will implicitly be called with this as your entity
+type and you can code in a very object-oriented manner.
+
+You may then choose to 'wrap' the base entity creation routines in
+specialised versions that attach functions and properties automatically.
+For example:
+
+```
+  global createGuardNPC() = function(name) {
+
+    ent = createEntity();
+    ent.name = name;
+    ent.type = "GuardNPC";
+    ent.stateWander = function () { ... };
+    return ent;
+  }
+```
+
+Your users can then create specialised entities that come pre-made with
+behaviours and you have a central place for the definition.
+
+### Separate Logic across Files
+
+Like many scripting languages, GameMonkey doesn't have a default IDE --
+therefore you are responsible for organising and tracking the files
+involved in your project. Your game will likely feature the behaviours
+of multiple entity types in GameMonkey script so for ease of navigation
+throughout your project and debugging any issues it is advised that you
+store the logic of each entity in separate files.
+
+For example if you have "GuardNPC" and "MonsterNPC" as separate
+entities, it is recommended that you store all functions, data and code
+in a file for each and load them together using a master file.
+
+```
+  global createGuardNPC() = function(name) {
+    ent = createEntity();
+    ent.name = name;
+    ent.type = "GuardNPC";
+    ent.stateWander = function () { ... };
+    return ent;
+  };
+```
+
+**NPC_Guard.gm**
+
+```
+  global createMonsterNPC() = function(name) {
+    ent = createEntity();
+    ent.name = name;
+    ent.type = "Monster";
+    ent.stateWander = function () { ... };
+    return ent;
+  };
+```
+
+**NPC_Monster.gm**
+
+```
+  Game:LoadScript("NPC_Guard.gm");
+  Game:LoadScript("NPC_Monster.gm");
+```
+
+**NPCs.gm**
+
+This tip is linked heavily to the notion that you minimise globals; by
+defining and creating your entities in one file you can change scripts
+very quickly by accessing a single location that is well-named rather
+than hunting for specific references throughout a file.
+
+### Record Memory Use
+
+The GameMonkey virtual machine records the memory use of all internal
+objects and uses this information to determine when to run the garbage
+collector or allocate new memory; it is also useful for profiling to see
+how much memory is being consumed by your scripting system. It is a good
+practice to use the gmMachine::AdjustKnownMemoryUse method to indicate
+how much memory you're using or freeing every time you allocate or
+release an object.
+
+### Use the Log for Errors
+
+Whenever an error occurs in script callback, be it a parameter fault or
+another problem you should always try and write a meaningful error
+message to the log -- accessible by the gmMachine::GetLog() method. If
+your game is hooked into the output handlers of the GameMonkey Script
+machine, you can then feed these errors back to your users, possibly on
+a debug script console or otherwise. You could also choose to record the
+error in your game's main error log for later analysis or problems or
+issues.
+
+### Hook into the Machine
+
+The GameMonkey virtual machine has a global machine callback method for
+several internal events. This is achieved by setting the function
+gmMachine::s_machineCallback which then lets you hook the following
+commands:
+
+Machine Callback Command | Description
+---|---
+MC_COLLECT_GARBAGE       | When a Garbage Collection cycle begins
+MC_THREAD_EXCEPTION      | Whenever a thread causes an exception.
+MC_THREAD_CREATE         | Called whenever a thread is created on the machine
+MC_THREAD_DESTROY        | Called whenever a thread is about to be destroyed in the machine
+
+The most useful command callback to most people is the
+MC_THREAD_EXCEPTION command as it allows you to handle any error cleanly
+in your game and potentially reset or terminate the entity that caused
+the exception. The gmPrintCallback allows you to hook into the in-built
+print() function and redirect any output to your script debug windows.
+There are several other hooks into the machine that are intended for
+debug purposes, all of which allow you to greater insight into what's
+happening in the script engine to allow you to minimise bugs and
+problems during development of your game.
+
+### Understand Garbage Collection
+
+As discussed in a previous article, the GameMonkey Script garbage
+collector is an incremental mark & sweep collector; it will perform a
+little work on each execution cycle of the machine to check for objects
+that no longer have any references to the root of the machine. When
+binding and exposing your own objects to the machine they will become
+liable for garbage collection if you've set your callbacks up correctly.
+There will be certain occasions in which you don't want an object to be
+garbage collected, for example when compiling a local function to be
+tied to any new entities or if you want to expose a single C++ owned
+object as multiple variables in the machine. For cases like this you can
+call gmMachine::AddCPPOwnedGMObject() which tells the garbage collector
+to persist the object, effectively ignoring it in its cycle. To remove
+an object from this state, you call gmMachine::
+RemoveCPPOwnedGMObject(). There is a useful binding in the *src/binds*
+directory of the main distribution called gmGCRoot which allows you to
+wrap these objects in a smart pointer, protecting them from garbage
+collection whilst there are still outstanding references to them in your
+native code.
+
+### Fast String Lookups
+
+In the examples used in this article, I have used string comparisons to
+test which properties are being referred to in the GetDot/SetDot
+lookups. GameMonkey Script allows you to allocate a permanent string in
+the machine that isn't susceptible to garbage collection. As GameMonkey
+is optimised to reuse strings where possible it is possible to compare
+such strings by their gmStringObject* pointer alone. To do this, you
+would call gmMachine::AllocatePermanantStringObject and retain the
+gmStringObject* that is returned. In your operator callback code (or
+otherwise), you can now use this to compare any values you receive back
+from the machine. If the pointers are equal, you can guarantee that the
+string is the same. Look at ext_02.cpp for an example of how the
+extended entity code has been modified to handle this optimisation.
+
+### Tracking Threads
+
+It is desirable to track the creation of threads in the machine,
+particularly those that are created with your user type as this. By
+doing so, you can ensure that any pending threads are cleaned up when an
+object that 'owns' them is destroyed. For example, if you have a thread
+that is running to control the opening of a door and playing the
+relevant animation it makes very little sense having this logic around
+if the door is destroyed or becomes permanently impassable. By tracking
+threads that are associated with the door, you can then kill them all
+once the door is destroyed. The same would apply to game entities which
+could have many different threads running for them to control a variety
+of complex behaviours. An ideal way of controlling threads within the
+machine is to make their use implicit via your own API. The
+signals_02.cpp example demonstrates how a thread is created and run for
+a user object without the script writer having to specify it. By
+simplifying the thread creation in this way, you can track their
+creation as you are controlling it directly.
+
+## Summary
+
+This article has demonstrated how to use some of the more advanced
+features of GameMonkey Script, including the powerful threading
+functionality that is the key to providing complex scripted behaviours
+in your games.
+
+## Acknowledgements
+
+I would like to extend my gratitude to Greg Douglas for his help in
+verifying the technical information in this article and to Jeremy
+Swigart for his expert-user guidance and real-world examples provided by
+the Omni-Bot project.
+
+## References
+
+GameMonkey Script Homepage - http://www.somedude.net/gamemonkey/
+GameMonkect Script Forums - http://www.somedude.net/gamemonkey/forum/
+Omni-Bot - AI bots for multiple FPS games (powered by GameMonkey Script) -http://www.omni-bot.de/

+ 44 - 0
gmsrc/doc/tutorial/2-continuing/cpp/blocking_01.cpp

@@ -0,0 +1,44 @@
+#include "Windows.h"
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+enum
+{
+	SIG_ZERO,
+	SIG_ONE
+};
+
+int GM_CDECL gmBlockTest(gmThread *a_thread)
+{
+	gmVariable blocks[] = { gmVariable(SIG_ZERO), gmVariable(SIG_ONE) };
+	int ret = a_thread->GetMachine()->Sys_Block( a_thread, 2, blocks );
+	if (ret == -1)
+	{
+		return GM_SYS_BLOCK;
+	}
+	a_thread->Push(blocks[ret]);
+	return GM_OK;
+}
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+
+	gmFunctionObject *func = gm.AllocFunctionObject( gmBlockTest );
+	gm.GetGlobals()->Set(&gm, "blocktest", gmVariable(func) );
+
+	int threadid = 0;
+	gm.ExecuteString(
+		"r = blocktest();"
+		"print(\"signal received\", r);"
+		, &threadid
+		);
+	gm.Execute(0);
+	// Signal the thread
+	gm.Signal( gmVariable(SIG_ZERO), threadid, 0 );
+	gm.Execute(0);
+	return 0;
+}
+

+ 369 - 0
gmsrc/doc/tutorial/2-continuing/cpp/blocking_02.cpp

@@ -0,0 +1,369 @@
+#include "Windows.h"
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+#include <list>
+#include <vector>
+#include <fstream>
+#include <string>
+#include <iterator>
+
+namespace gmNPCLib
+{
+	bool Bind(gmMachine *a_machine);
+};
+
+enum
+{
+	MT_GOTO,
+	MT_GOTO_SUCCESS,
+	MT_GOTO_FAILED,
+};
+
+enum
+{
+	LOC_UNKNOWN,
+	LOC_TOWER_ONE,
+	LOC_TOWER_TWO,
+};
+
+enum
+{
+	SM_SUCCESS,
+	SM_FAILED,
+};
+
+struct GameMessage
+{
+	GameMessage(int a_MessageType) : MessageType(a_MessageType) { }
+	int MessageType;
+};
+
+struct NPCGotoMessage : GameMessage
+{
+	NPCGotoMessage(int a_npc, int a_threadid, int a_loc) : GameMessage(MT_GOTO), NPCId(a_npc), ScriptThreadId(a_threadid), Location(a_loc) { }
+
+	int ScriptThreadId;
+	int NPCId;
+	int Location;
+};
+
+struct NPCArrivalMessage : GameMessage
+{
+	NPCArrivalMessage(int a_npc, int a_threadid, int a_loc) : GameMessage(MT_GOTO_SUCCESS), NPCId(a_npc), ScriptThreadId(a_threadid), Location(a_loc) { }
+
+	int ScriptThreadId;
+	int NPCId;
+	int Location;
+};
+
+struct IMessageHandler
+{
+	virtual ~IMessageHandler() {}
+	virtual void HandleMessage(GameMessage *a_msg) = 0;
+};
+
+class MessageSystem
+{
+public:
+	MessageSystem() : _ActiveQueue(0) { }
+
+	void PushMessage(GameMessage *a_msg)
+	{
+		_MessageQueues[_ActiveQueue].push_back( a_msg );
+	}
+
+	void AddHandler(IMessageHandler *a_handler)
+	{
+		_Handlers.push_back(a_handler);
+	}
+
+	void DespatchMessages()
+	{
+		// Flip queues
+		char InactiveQueue = _ActiveQueue;
+		_ActiveQueue = 1 - _ActiveQueue;
+
+		MessageListItr it = _MessageQueues[InactiveQueue].begin();
+		for(;it != _MessageQueues[InactiveQueue].end(); ++it)
+		{
+			GameMessage *msg = (*it);
+			
+			// Iterate each handler and despatch
+			HandlerListItr hit = _Handlers.begin();
+			for(; hit != _Handlers.end(); ++hit)
+			{
+				(*hit)->HandleMessage(msg);
+			}
+
+			// finished
+			delete msg;
+		}
+		_MessageQueues[InactiveQueue].clear();
+	}
+
+protected:
+	typedef std::list<IMessageHandler *> HandlerList;
+	typedef HandlerList::iterator		 HandlerListItr;
+
+	typedef std::list<GameMessage*> MessageList;
+	typedef MessageList::iterator	MessageListItr;
+
+	HandlerList	_Handlers;
+
+	MessageList _MessageQueues[2];
+	char _ActiveQueue;
+};
+
+
+class Entity
+{
+public:
+	enum State
+	{
+		ES_WAITING,
+		ES_WALKING,
+	};
+
+	int _ScriptThreadId;
+	int _Id;
+	int _State;
+	int _Destination;
+};
+
+class EntityManager : public IMessageHandler
+{
+public:
+	EntityManager() : _EntityIds(0), _Dur(0) { }
+	
+	Entity &CreateEntity(int &a_entityid)
+	{
+		a_entityid = ++_EntityIds;
+		Entity e;
+		e._Id = a_entityid;
+		_Entities.push_back(e);
+		return _Entities[a_entityid - 1];
+	}
+
+	Entity &GetEntity(int a_entityid)
+	{
+		return _Entities[a_entityid - 1];		
+	}
+
+	void HandleMessage(GameMessage *a_msg)
+	{
+		if (a_msg->MessageType == MT_GOTO)
+		{
+			NPCGotoMessage *msg = reinterpret_cast<NPCGotoMessage*>(a_msg);
+			// Set entity state to walking
+			Entity &ent = GetEntity(msg->NPCId);
+			ent._State = Entity::ES_WALKING;
+		}
+	}
+
+	void Update(float a_delta);
+
+protected:
+	typedef std::vector<Entity>		EntityList;
+	typedef EntityList::iterator	EntityListItr;
+
+	EntityList _Entities;
+	float _Dur;
+	int _EntityIds;
+
+	
+};
+
+class ScriptManager : public IMessageHandler
+{
+public:
+
+	void Init()
+	{
+		BindNPCLib();
+
+		LoadScript("blocking_02.gm");
+	}
+
+	bool LoadScript(const char *a_filename)
+	{
+		std::ifstream file(a_filename);
+		if (!file)
+			return false;
+		
+		std::string fileString = std::string(std::istreambuf_iterator<char>(file),
+											 std::istreambuf_iterator<char>());
+		file.close();
+		return (_Machine.ExecuteString(fileString.c_str()) == 0);
+	}
+
+	void HandleMessage(GameMessage *a_msg)
+	{
+		if (a_msg->MessageType == MT_GOTO_SUCCESS)
+		{
+			NPCArrivalMessage *msg = reinterpret_cast<NPCArrivalMessage*>(a_msg);
+			// Fire signal on thread
+			_Machine.Signal( gmVariable(SM_SUCCESS), msg->ScriptThreadId, 0 );
+		}
+
+	}
+
+	void Update(float a_delta)
+	{
+		_Machine.Execute(a_delta * 1000.0f);
+	}
+
+protected:
+
+	bool BindNPCLib()
+	{
+		return gmNPCLib::Bind(&_Machine);
+	}
+
+	gmMachine _Machine;
+};
+
+class Game
+{
+public:
+
+	void Init()
+	{
+		_ScriptManager.Init();
+		_MessageSystem.AddHandler(&_ScriptManager);
+		_MessageSystem.AddHandler(&_EntityManager);
+		_Running = true;
+	}
+
+	void Run()
+	{
+		while(_Running)
+		{
+			float delta = 0.01f;
+			_MessageSystem.DespatchMessages();
+
+			_ScriptManager.Update(delta);
+			_EntityManager.Update(delta);
+		}
+	}
+
+	EntityManager &GetEntityManager() { return _EntityManager; }
+	MessageSystem &GetMessageSystem() { return _MessageSystem; }
+	ScriptManager &GetScriptManager() { return _ScriptManager; }
+
+protected:
+	bool _Running;
+
+	ScriptManager _ScriptManager;
+	EntityManager _EntityManager;
+	MessageSystem _MessageSystem;
+};
+
+/////// Global variable for game class
+Game s_Game;
+
+
+/// Implementation
+void EntityManager::Update(float a_delta)
+{
+	EntityListItr it = _Entities.begin();
+	for(; it != _Entities.end(); ++it)
+	{
+		Entity &ent = (*it);
+
+		if (ent._State == Entity::ES_WALKING)
+		{
+			_Dur+=a_delta;
+			if (_Dur >= 2500.0f)	// Simulate time passing
+			{
+				NPCArrivalMessage *msg = new NPCArrivalMessage(ent._Id, ent._ScriptThreadId, ent._Destination);
+				s_Game.GetMessageSystem().PushMessage(msg);
+				ent._State = Entity::ES_WAITING;	// Go back to waiting state
+				_Dur = 0;
+			}
+		}
+	}
+
+
+}
+
+namespace gmNPCLib
+{
+	gmType s_type;
+
+	int GM_CDECL gmNPCGoto(gmThread *a_thread)
+	{
+		GM_CHECK_NUM_PARAMS(2);
+		// Get entity
+		GM_CHECK_INT_PARAM(a_entity, 0);
+		GM_CHECK_INT_PARAM(a_location, 1);
+		
+		// Push message to Game Message queue
+		NPCGotoMessage *msg = new NPCGotoMessage( a_entity, a_thread->GetId(), a_location );
+		s_Game.GetMessageSystem().PushMessage( msg );
+
+		// Set up blocks on thread for either success message or failure message
+		gmVariable blocks[] = { gmVariable(SM_SUCCESS), gmVariable(SM_FAILED) };
+		int res = a_thread->GetMachine()->Sys_Block( a_thread, 2, blocks );
+		if (res == -1)
+		{
+			return GM_SYS_BLOCK;
+		}
+		a_thread->Push( blocks[res] );
+		return GM_OK;
+	}
+
+	int GM_CDECL gmCreateNPC(gmThread *a_thread)
+	{
+		int entity = 0;
+		Entity &ent = s_Game.GetEntityManager().CreateEntity(entity);
+		ent._ScriptThreadId = a_thread->GetId();
+		ent._Destination = LOC_UNKNOWN;
+		ent._State = Entity::ES_WAITING;
+		a_thread->PushInt(entity);
+		return GM_OK;
+	}
+
+	gmFunctionEntry s_lib[] = {
+
+		{ "CreateNPC", gmCreateNPC, NULL },
+		/// NPCGoto( npc, location )
+		{ "NPCGoto", gmNPCGoto, NULL },
+	};
+
+	bool Bind(gmMachine *a_machine)
+	{
+		a_machine->RegisterLibrary( s_lib, sizeof(s_lib) / sizeof(gmFunctionEntry) );
+
+		// Bind location info
+		gmTableObject *location = a_machine->AllocTableObject();
+		location->Set( a_machine, "TOWER_ONE", gmVariable(LOC_TOWER_ONE) );
+		location->Set( a_machine, "TOWER_TWO", gmVariable(LOC_TOWER_TWO) );
+		a_machine->GetGlobals()->Set(a_machine, "Location", gmVariable(location) );
+
+
+		gmTableObject *event = a_machine->AllocTableObject();
+		event->Set( a_machine, "SUCCESS", gmVariable(SM_SUCCESS) );
+		event->Set( a_machine, "FAILED", gmVariable(SM_FAILED) );
+		a_machine->GetGlobals()->Set(a_machine, "Event", gmVariable(event) );
+
+		return true;
+	}
+
+};
+
+int main(int argc, char* argv[])
+{
+/*
+	
+	gm.ExecuteString(
+		"NPCGoto(1, Location.TOWER_ONE);"
+		"print(123456);"
+		);
+*/
+	s_Game.Init();
+	s_Game.Run();
+
+	return 0;
+}
+

+ 48 - 0
gmsrc/doc/tutorial/2-continuing/cpp/blocking_02.gm

@@ -0,0 +1,48 @@
+global GuardGotoTowerOne = function()
+{
+	print("Going to Tower One...");
+	res = NPCGoto(this, Location.TOWER_ONE);
+	if (res == Event.SUCCESS)
+	{
+		print("Arrived at tower One");
+		this:stateSet(GuardWait);
+	}
+	else
+	{
+		print("Couldn't get there");
+	}
+};
+global GuardGotoTowerTwo = function()
+{
+	print("Going to Tower Two...");
+	res = NPCGoto(this, Location.TOWER_TWO);
+	if (res == Event.SUCCESS)
+	{
+		print("Arrived at tower Two");
+		this:stateSet(GuardWait);
+	}
+	else
+	{
+		print("Couldn't get there");
+	}
+};
+global GuardWait = function()
+{
+	print("Looking around...");
+	sleep(2);
+	print("Nothing here, moving on...");
+	if (stateGetLast() == GuardGotoTowerOne)
+	{
+		this:stateSet(GuardGotoTowerTwo);
+	}
+	else
+	{
+		this:stateSet(GuardGotoTowerOne);
+	}
+};
+global GuardMove = function()
+{
+	this:stateSet(GuardGotoTowerOne);
+};
+npc = CreateNPC();
+npc:thread(GuardMove);

+ 254 - 0
gmsrc/doc/tutorial/2-continuing/cpp/ext_01.cpp

@@ -0,0 +1,254 @@
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+#include <vector>
+#include <string>
+#include <sstream>
+
+struct ScriptEntity;
+struct Entity;
+
+struct Entity
+{
+	Entity() : Id(0), X(0), Y(0), ScriptObject(NULL) { }
+	Entity(int id) : Id(id), X(0), Y(0), ScriptObject(NULL) { }
+	int Id, X, Y;
+	ScriptEntity *ScriptObject;
+};
+
+struct ScriptEntity
+{
+	ScriptEntity(Entity &ent) : EntityObject(ent), ScriptProperties(NULL) { }
+	Entity &EntityObject;
+	gmTableObject *ScriptProperties;
+};
+
+
+class EntityManager 
+{
+public:
+	EntityManager() : _EntityIds(0) { }
+	
+	Entity &CreateEntity(int &a_entityid)
+	{
+		Entity e(++_EntityIds);
+		a_entityid = e.Id;
+		_Entities.push_back(e);
+		return _Entities[a_entityid - 1];
+	}
+
+	Entity &GetEntity(int a_entityid)
+	{
+		return _Entities[a_entityid - 1];		
+	}
+
+protected:
+	typedef std::vector<Entity>		EntityList;
+	typedef EntityList::iterator	EntityListItr;
+
+	EntityList _Entities;
+	int _EntityIds;
+
+};
+
+//// Global entity manager
+static EntityManager s_EntityManager;
+
+namespace gmEntityLib
+{
+	gmType s_entitytype = GM_NULL;
+	gmMemFixed s_scriptents( sizeof(ScriptEntity) );
+
+	// The entity is passed as this
+	int GM_CDECL gmEntityInfo(gmThread *a_thread)
+	{
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_thread->ThisUserCheckType(s_entitytype));
+		if (sent == NULL)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry("gmEntityInfo: Expected entity type as this");
+			return GM_EXCEPTION;
+		}
+		std::stringstream infotext;
+		infotext << "EntityId: ";
+		infotext << sent->EntityObject.Id;
+		infotext << " - Postition("; infotext << sent->EntityObject.X; infotext << ","; infotext << sent->EntityObject.Y; infotext << ") - Name: ";
+		// Get name from table and pass to object
+		gmVariable namevar = sent->ScriptProperties->Get(a_thread->GetMachine(), "name");
+		if (namevar.IsNull() || namevar.m_type != GM_STRING)
+		{
+			infotext << " [No name]";
+		}
+		else
+		{
+			infotext << namevar.GetStringObjectSafe()->GetString();
+		}
+		std::cout << infotext.str() << std::endl;
+		return GM_OK;
+	}
+
+	int GM_CDECL gmCreateEntity(gmThread *a_thread)
+	{
+		// Create an entity from the manager
+		int entityId = 0;
+		Entity &ent = s_EntityManager.CreateEntity(entityId);
+		// Allocate a script entity & construct it
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(s_scriptents.Alloc());
+		GM_PLACEMENT_NEW( ScriptEntity(ent), sent );
+		// Tie back to entity
+		ent.ScriptObject = sent;
+		// Create a property table
+		sent->ScriptProperties = a_thread->GetMachine()->AllocTableObject();
+		// Tell GM how much memory we're using
+		int memadjust = sizeof(gmTableObject) + sizeof(Entity) + sizeof(ScriptEntity);
+		a_thread->GetMachine()->AdjustKnownMemoryUsed(memadjust);
+
+		// Bind an additional method to the entity's prop table
+		sent->ScriptProperties->Set(a_thread->GetMachine(), "ShowInfo", gmVariable( a_thread->GetMachine()->AllocFunctionObject(gmEntityInfo) ) );
+
+		// return to client
+		a_thread->PushNewUser( sent, s_entitytype );
+		return GM_OK;
+	}
+
+
+	//// Dot Operators
+	void GM_CDECL gmOpGetDot(gmThread *a_thread, gmVariable *a_operands)
+	{
+		if (a_operands[0].m_type != s_entitytype)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid type passed" );
+			a_operands[0] = gmVariable::s_null;
+			return;
+		}
+		
+		// Get scriptentity back
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_operands[0].GetUserSafe(s_entitytype));
+
+		// Get name of 'get' prop
+		std::string propname = a_operands[1].GetCStringSafe();
+		
+		// Test for our known properties and return their values back immediately
+		if (propname == "X")
+		{
+			a_operands[0] = gmVariable(sent->EntityObject.X);
+		}
+		else if (propname == "Y")
+		{
+			a_operands[0] = gmVariable(sent->EntityObject.Y);
+		}
+		else if (propname == "Id")
+		{
+			a_operands[0] = gmVariable(sent->EntityObject.Id);
+		}
+		else
+		{
+			// Otherwise, return the value from the table!
+			a_operands[0] = sent->ScriptProperties->Get(a_thread->GetMachine(), propname.c_str());
+		}
+	}
+
+	void GM_CDECL gmOpSetDot(gmThread *a_thread, gmVariable *a_operands)
+	{
+		if (a_operands[0].m_type != s_entitytype)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid type passed" );
+			a_operands[0] = gmVariable::s_null;
+			return;
+		}
+		
+		// Get scriptentity back
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_operands[0].GetUserSafe(s_entitytype));
+
+		// Get name of 'get' prop
+		std::string propname = a_operands[2].GetCStringSafe();
+	
+		if (propname.length() == 0)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid property passed" );
+			a_operands[0] = gmVariable::s_null;
+			return;
+		}
+
+		// Test for our known properties and return their values back immediately
+		if (propname == "X")
+		{
+			sent->EntityObject.X = a_operands[1].GetIntSafe();
+		}
+		else if (propname == "Y")
+		{
+			sent->EntityObject.Y = a_operands[1].GetIntSafe();
+		}
+		else if (propname == "Id")
+		{
+			a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot cannot set Id" );
+			a_operands[0] = gmVariable::s_null;
+		}
+		else
+		{
+			// Otherwise, store a value in the table
+			sent->ScriptProperties->Set(a_thread->GetMachine(), propname.c_str(), a_operands[1]);
+		}
+	}
+
+
+	///////////////
+	// GC operations
+	void GM_CDECL gcDestruct(gmMachine *a_machine, gmUserObject *a_object)
+	{
+		GM_ASSERT( a_object->m_userType == s_entitytype );
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity *>(a_object->m_user);
+		// Do we want to tell the entitymanager to destry the object here?
+		// this will be implementation dependent, so let's not do anything for now as it's a sample		
+		// Free up the script entity
+		s_scriptents.Free(sent);
+		int memadjust = sizeof(gmTableObject) + sizeof(ScriptEntity); // Note, didn;t add Entity sizeof
+		a_machine->AdjustKnownMemoryUsed(-memadjust);
+	}
+
+	bool GM_CDECL gcTrace(gmMachine *a_machine, gmUserObject *a_object, gmGarbageCollector *a_gc, const int a_workLeftToGo, int &a_workDone)
+	{
+		GM_ASSERT( a_object->m_userType == s_entitytype );
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity *>(a_object->m_user);
+		a_workDone++;
+		a_gc->GetNextObject(sent->ScriptProperties);
+		a_workDone++;
+		return true;
+	}
+
+
+	gmFunctionEntry s_lib[] = {
+		{ "createEntity", gmCreateEntity, NULL }
+	};
+
+	void Bind(gmMachine *a_machine)
+	{
+		s_entitytype = a_machine->CreateUserType("entity");
+
+		// Register creation function
+		a_machine->RegisterLibrary( s_lib, sizeof(s_lib) / sizeof(gmFunctionEntry) );
+		a_machine->RegisterTypeOperator( s_entitytype, O_GETDOT, NULL, gmOpGetDot );
+		a_machine->RegisterTypeOperator( s_entitytype, O_SETDOT, NULL, gmOpSetDot );	
+		// Register GC callbacks
+		a_machine->RegisterUserCallbacks( s_entitytype, gcTrace, gcDestruct, NULL );
+	}
+};
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	gmEntityLib::Bind(&gm);
+
+	gm.ExecuteString(
+		"ent = createEntity();"
+		"ent.X = 100;"
+		"print(ent.X);"
+		"ent.name = \"somebody\";"
+		"ent.sayname = function() { print( \"My name is: \", .name ); };"
+		"ent.sayname();"
+		"ent.ShowInfo();"
+		);
+
+	return 0;
+}
+

+ 257 - 0
gmsrc/doc/tutorial/2-continuing/cpp/ext_02.cpp

@@ -0,0 +1,257 @@
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+#include <vector>
+#include <string>
+#include <sstream>
+
+struct ScriptEntity;
+struct Entity;
+
+struct Entity
+{
+	Entity() : Id(0), X(0), Y(0), ScriptObject(NULL) { }
+	Entity(int id) : Id(id), X(0), Y(0), ScriptObject(NULL) { }
+	int Id, X, Y;
+	ScriptEntity *ScriptObject;
+};
+
+struct ScriptEntity
+{
+	ScriptEntity(Entity &ent) : EntityObject(ent), ScriptProperties(NULL) { }
+	Entity &EntityObject;
+	gmTableObject *ScriptProperties;
+};
+
+
+class EntityManager 
+{
+public:
+	EntityManager() : _EntityIds(0) { }
+	
+	Entity &CreateEntity(int &a_entityid)
+	{
+		Entity e(++_EntityIds);
+		a_entityid = e.Id;
+		_Entities.push_back(e);
+		return _Entities[a_entityid - 1];
+	}
+
+	Entity &GetEntity(int a_entityid)
+	{
+		return _Entities[a_entityid - 1];		
+	}
+
+protected:
+	typedef std::vector<Entity>		EntityList;
+	typedef EntityList::iterator	EntityListItr;
+
+	EntityList _Entities;
+	int _EntityIds;
+
+};
+
+//// Global entity manager
+static EntityManager s_EntityManager;
+
+namespace gmEntityLib
+{
+	gmType s_entitytype = GM_NULL;
+	gmStringObject *s_xprop = NULL;
+	gmStringObject *s_yprop = NULL;
+	gmStringObject *s_idprop = NULL;
+	gmMemFixed s_scriptents( sizeof(ScriptEntity) );
+
+	// The entity is passed as this
+	int GM_CDECL gmEntityInfo(gmThread *a_thread)
+	{
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_thread->ThisUserCheckType(s_entitytype));
+		if (sent == NULL)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry("gmEntityInfo: Expected entity type as this");
+			return GM_EXCEPTION;
+		}
+		std::stringstream infotext;
+		infotext << "EntityId: ";
+		infotext << sent->EntityObject.Id;
+		infotext << " - Postition("; infotext << sent->EntityObject.X; infotext << ","; infotext << sent->EntityObject.Y; infotext << ") - Name: ";
+		// Get name from table and pass to object
+		gmVariable namevar = sent->ScriptProperties->Get(a_thread->GetMachine(), "name");
+		if (namevar.IsNull() || namevar.m_type != GM_STRING)
+		{
+			infotext << " [No name]";
+		}
+		else
+		{
+			infotext << namevar.GetStringObjectSafe()->GetString();
+		}
+		std::cout << infotext.str() << std::endl;
+		return GM_OK;
+	}
+
+	int GM_CDECL gmCreateEntity(gmThread *a_thread)
+	{
+		// Create an entity from the manager
+		int entityId = 0;
+		Entity &ent = s_EntityManager.CreateEntity(entityId);
+		// Allocate a script entity & construct it
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(s_scriptents.Alloc());
+		GM_PLACEMENT_NEW( ScriptEntity(ent), sent );
+		// Tie back to entity
+		ent.ScriptObject = sent;
+		// Create a property table
+		sent->ScriptProperties = a_thread->GetMachine()->AllocTableObject();
+		// Tell GM how much memory we're using
+		int memadjust = sizeof(gmTableObject) + sizeof(Entity) + sizeof(ScriptEntity);
+		a_thread->GetMachine()->AdjustKnownMemoryUsed(memadjust);
+
+		// Bind an additional method to the entity's prop table
+		sent->ScriptProperties->Set(a_thread->GetMachine(), "ShowInfo", gmVariable( a_thread->GetMachine()->AllocFunctionObject(gmEntityInfo) ) );
+
+		// return to client
+		a_thread->PushNewUser( sent, s_entitytype );
+		return GM_OK;
+	}
+
+
+	//// Dot Operators
+	void GM_CDECL gmOpGetDot(gmThread *a_thread, gmVariable *a_operands)
+	{
+		if (a_operands[0].m_type != s_entitytype)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid type passed" );
+			a_operands[0] = gmVariable::s_null;
+			return;
+		}
+		
+		// Get scriptentity back
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_operands[0].GetUserSafe(s_entitytype));
+		gmStringObject *p = a_operands[1].GetStringObjectSafe();
+		// Test for our known properties and return their values back immediately
+		if (p == s_xprop)
+		{
+			a_operands[0] = gmVariable(sent->EntityObject.X);
+		}
+		else if(p == s_yprop)
+		{
+			a_operands[0] = gmVariable(sent->EntityObject.Y);
+		}
+		else if (p == s_idprop)
+		{
+			a_operands[0] = gmVariable(sent->EntityObject.Id);
+		}
+		else 
+		{
+			// Otherwise, return the value from the table!
+			a_operands[0] = sent->ScriptProperties->Get(gmVariable(p));
+		}
+	}
+
+	void GM_CDECL gmOpSetDot(gmThread *a_thread, gmVariable *a_operands)
+	{
+		if (a_operands[0].m_type != s_entitytype)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid type passed" );
+			a_operands[0] = gmVariable::s_null;
+			return;
+		}
+		
+		// Get scriptentity back
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity*>(a_operands[0].GetUserSafe(s_entitytype));
+
+		// Get name of 'get' prop
+		gmStringObject *p = a_operands[2].GetStringObjectSafe();
+	
+		if (p == NULL)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot invalid property passed" );
+			a_operands[0] = gmVariable::s_null;
+			return;
+		}
+
+		// Test for our known properties and return their values back immediately
+		if (p == s_xprop)
+		{
+			sent->EntityObject.X = a_operands[1].GetIntSafe();
+		}
+		else if (p == s_yprop)
+		{
+			sent->EntityObject.Y = a_operands[1].GetIntSafe();
+		}
+		else if (p == s_idprop)
+		{
+			a_thread->GetMachine()->GetLog().LogEntry( "gmEntity:OpSetDot cannot set Id" );
+			a_operands[0] = gmVariable::s_null;
+		}
+		else
+		{
+			// Otherwise, store a value in the table
+			sent->ScriptProperties->Set(a_thread->GetMachine(), gmVariable(p), a_operands[1]);
+		}
+	}
+
+
+	///////////////
+	// GC operations
+	void GM_CDECL gcDestruct(gmMachine *a_machine, gmUserObject *a_object)
+	{
+		GM_ASSERT( a_object->m_userType == s_entitytype );
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity *>(a_object->m_user);
+		// Do we want to tell the entitymanager to destry the object here?
+		// this will be implementation dependent, so let's not do anything for now as it's a sample		
+		// Free up the script entity
+		s_scriptents.Free(sent);
+		int memadjust = sizeof(gmTableObject) + sizeof(ScriptEntity); // Note, didn;t add Entity sizeof
+		a_machine->AdjustKnownMemoryUsed(-memadjust);
+	}
+
+	bool GM_CDECL gcTrace(gmMachine *a_machine, gmUserObject *a_object, gmGarbageCollector *a_gc, const int a_workLeftToGo, int &a_workDone)
+	{
+		GM_ASSERT( a_object->m_userType == s_entitytype );
+		ScriptEntity *sent = reinterpret_cast<ScriptEntity *>(a_object->m_user);
+		a_workDone++;
+		a_gc->GetNextObject(sent->ScriptProperties);
+		a_workDone++;
+		return true;
+	}
+
+
+	gmFunctionEntry s_lib[] = {
+		{ "createEntity", gmCreateEntity, NULL }
+	};
+
+	void Bind(gmMachine *a_machine)
+	{
+		s_entitytype = a_machine->CreateUserType("entity");
+		// Register creation function
+		a_machine->RegisterLibrary( s_lib, sizeof(s_lib) / sizeof(gmFunctionEntry) );
+		a_machine->RegisterTypeOperator( s_entitytype, O_GETDOT, NULL, gmOpGetDot );
+		a_machine->RegisterTypeOperator( s_entitytype, O_SETDOT, NULL, gmOpSetDot );	
+		// Register GC callbacks
+		a_machine->RegisterUserCallbacks( s_entitytype, gcTrace, gcDestruct, NULL );
+		// Allocate permanent strings
+		s_xprop = a_machine->AllocPermanantStringObject("X");
+		s_yprop = a_machine->AllocPermanantStringObject("Y");
+		s_idprop = a_machine->AllocPermanantStringObject("Id");
+	}
+};
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	gmEntityLib::Bind(&gm);
+
+	gm.ExecuteString(
+		"ent = createEntity();"
+		"ent.X = 100;"
+		"print(ent.Id);"
+		"ent.name = \"somebody\";"
+		"ent.sayname = function() { print( \"My name is: \", .name ); };"
+		"ent.sayname();"
+		"ent.ShowInfo();"
+		);
+
+	return 0;
+}
+

+ 29 - 0
gmsrc/doc/tutorial/2-continuing/cpp/functioncall_01.cpp

@@ -0,0 +1,29 @@
+#include "Windows.h"
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+
+int GM_CDECL gmFunctionTest(gmThread *a_thread)
+{
+	GM_CHECK_INT_PARAM( a_param1, 0 );
+	GM_CHECK_INT_PARAM( a_param2, 1 );
+	std::cout << "Param 1: " << a_param1 << std::endl;
+	std::cout << "Param 2: " << a_param2 << std::endl;
+	return GM_OK;
+}
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	int threadid = 0;
+	gmThread *thread = gm.CreateThread(&threadid);
+	thread->PushNull(); // Push 'this'
+	thread->PushFunction( gm.AllocFunctionObject(gmFunctionTest) );	// push function to call
+	thread->PushInt(50);
+	thread->PushInt(100);
+	thread->PushStackFrame(2);
+	return 0;
+}
+

+ 26 - 0
gmsrc/doc/tutorial/2-continuing/cpp/functioncall_02.cpp

@@ -0,0 +1,26 @@
+#include "Windows.h"
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	// Create a global scripted function
+	gm.ExecuteString(
+		"global func = function(a, b) { print(\"Param 1:\", a); print(\"Param 2:\", b); };"
+		);
+	gmFunctionObject *func = gm.GetGlobals()->Get(&gm, "func").GetFunctionObjectSafe();
+	int threadid = 0;
+	gmThread *thread = gm.CreateThread(&threadid);
+	thread->PushNull(); // Push 'this'
+	thread->PushFunction( func );	// push function to call
+	thread->PushInt(50);
+	thread->PushInt(100);
+	thread->PushStackFrame(2);
+	thread->Sys_Execute();
+	return 0;
+}
+

+ 50 - 0
gmsrc/doc/tutorial/2-continuing/cpp/signals_01.cpp

@@ -0,0 +1,50 @@
+#include "Windows.h"
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+
+enum QuestDialog
+{
+	QD_DECLINE,
+	QD_ACCEPT
+};
+
+// This function simulates a modal quest dialog
+int GM_CDECL gmShowQuestDialog(gmThread *a_thread)
+{
+	std::cout << "A princess is in danger, do you wish to save her?" << std::endl << "[Accept | Decline]" << std::endl;
+	return GM_OK;
+}
+
+void HandleUserAcceptQuest(gmMachine &gm, int threadid, QuestDialog response)
+{
+	// Fire signal to thread to indicate user's choice	
+	gm.Signal( gmVariable( (int)response ), threadid, 0 );
+}
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	// Bind ShowQuestDialog function to script
+	gm.GetGlobals()->Set( &gm, "ShowQuestDialog", gmVariable(gm.AllocFunctionObject( gmShowQuestDialog )) );
+	// Create a global table to hold Ids for QuestAccept/Decline
+	gmTableObject *dialogResponses = gm.AllocTableObject();
+	dialogResponses->Set( &gm, "Accept", gmVariable(QD_ACCEPT) );	// Accept = 0
+	dialogResponses->Set( &gm, "Decline", gmVariable(QD_DECLINE) );	// Decline = 0
+	gm.GetGlobals()->Set( &gm, "QuestDialog", gmVariable( dialogResponses ) );
+	// Run an example script that calls dialog and blocks on response
+	const char *script = "ShowQuestDialog(); \n"
+			"response = block( QuestDialog.Accept, QuestDialog.Decline ); \n"
+			"if (response == QuestDialog.Accept) { print(\"[Quest accepted]\"); } else { print(\"[Quest declined]\"); }";
+	int threadid = 0;
+	// Run script and capture thread it's running on
+	gm.ExecuteString( script, &threadid );
+	Sleep(5000);	// Wait for 5 seconds to simulate user deciding to accept
+	HandleUserAcceptQuest(gm, threadid, QD_ACCEPT);
+	// Tick the machine along
+	gm.Execute(0);
+	return 0;
+}
+

+ 68 - 0
gmsrc/doc/tutorial/2-continuing/cpp/signals_02.cpp

@@ -0,0 +1,68 @@
+#include "Windows.h"
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+#include "gmCall.h"
+
+int GM_CDECL gmStartAnimation(gmThread *a_thread)
+{
+	GM_CHECK_STRING_PARAM(a_animname, 0);
+	std::cout << a_thread->ThisString() << " starting animation: " << a_animname << std::endl;
+	return GM_OK;
+}
+
+int GM_CDECL gmCreateDoor(gmThread *a_thread)
+{
+	GM_CHECK_FUNCTION_PARAM(a_func, 0);
+	// Simple example, return "TESTDOOR" as the user object
+	gmStringObject *door = a_thread->GetMachine()->AllocStringObject("TESTDOOR");
+	// Call passed in function as a new thread (gmCall does this under the hood)
+    gmCall gmcall;
+    gmcall.BeginFunction(a_thread->GetMachine(), a_func, gmVariable(door), false);
+    gmcall.End();
+	a_thread->PushString(door);
+	return GM_OK;
+}
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	
+	// Bind a create door function
+	gm.GetGlobals()->Set(&gm, "createDoor", gmVariable(gm.AllocFunctionObject(gmCreateDoor)));
+	gm.GetGlobals()->Set(&gm, "startAnimation", gmVariable(gm.AllocFunctionObject(gmStartAnimation)));
+
+	const char *script = "global DoorFunction = function() \
+						 {	\
+							 while(true)	\
+							 {	\
+								print(this, \"waiting for use...\"); \
+								block(\"usedoor\");	\
+								this:startAnimation(\"dooropen\"); \
+								sleep(5);	\
+								this:startAnimation(\"doorclose\"); \
+							 } \
+						 }; \
+						 createDoor(DoorFunction);";
+							
+	
+	int x = gm.ExecuteString(script);
+	if (x != 0)
+	{
+		bool first = true;
+		while(first)
+			std::cout << gm.GetLog().GetEntry(first) << std::endl;
+	}
+	else
+	{
+		// Open the door... fire global signal for now
+		gm.Signal(gmVariable( gm.AllocStringObject("usedoor") ), GM_INVALID_THREAD, 0);
+		while (1)
+		{
+			gm.Execute(1);
+		}
+	}
+	return 0;
+}
+

+ 47 - 0
gmsrc/doc/tutorial/2-continuing/cpp/this_01.cpp

@@ -0,0 +1,47 @@
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+#define GM_CHECK_THIS_NULL \
+	 if(GM_THREAD_ARG->GetThis()->m_type != GM_NULL) { GM_EXCEPTION_MSG("expecting this as null"); return GM_EXCEPTION; }
+
+#define GM_CHECK_THIS_INT \
+	 if(GM_THREAD_ARG->GetThis()->m_type != GM_INT) { GM_EXCEPTION_MSG("expecting this as int"); return GM_EXCEPTION; }
+
+#define GM_CHECK_THIS_FLOAT \
+	 if(GM_THREAD_ARG->GetThis()->m_type != GM_FLOAT) { GM_EXCEPTION_MSG("expecting this as null"); return GM_EXCEPTION; }
+
+#define GM_CHECK_THIS_STRING \
+	 if(GM_THREAD_ARG->GetThis()->m_type != GM_STRING) { GM_EXCEPTION_MSG("expecting this as string"); return GM_EXCEPTION; }
+
+#define GM_CHECK_THIS_TABLE \
+	 if(GM_THREAD_ARG->GetThis()->m_type != GM_TABLE) { GM_EXCEPTION_MSG("expecting this as table"); return GM_EXCEPTION; }
+
+#define GM_CHECK_THIS_FUNCTION \
+	 if(GM_THREAD_ARG->GetThis()->m_type != GM_FUNCTION) { GM_EXCEPTION_MSG("expecting this as function"); return GM_EXCEPTION; }
+
+#define GM_CHECK_THIS_USER(TYPE) \
+	 if(GM_THREAD_ARG->GetThis()->m_type != TYPE) { GM_EXCEPTION_MSG("expecting this as user type %d", TYPE); return GM_EXCEPTION; }
+
+
+int GM_CDECL gmThisTest(gmThread *a_thread)
+{
+	GM_CHECK_THIS_STRING;
+	std::cout << "'this' passed as " << a_thread->ThisString() << std::endl;
+	return GM_OK;
+}
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	// Bind the function to use by creating a gmFunctionObject
+	gmFunctionObject *threadfunc = gm.AllocFunctionObject( gmThisTest );
+	// Add function to the global table so scripts can access it
+	gm.GetGlobals()->Set(&gm, "thistest", gmVariable(threadfunc) );
+	// Call script to make callback, pass a variable containing "hello" as this
+	const char *script = "text = \"hello\"; text:thistest( threadfunc );";
+	gm.ExecuteString( script );
+	return 0;
+}
+

+ 27 - 0
gmsrc/doc/tutorial/2-continuing/cpp/threads_01a.cpp

@@ -0,0 +1,27 @@
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	// A test script which creates the function we're testing
+	const char *testscript = "global threadfunc = function() { print(\"Hello, threads!\"); };";
+	// Execute the script to create the function in the VM
+	if (gm.ExecuteString( testscript, NULL, true ))
+	{
+		bool first = true;
+		std::cout << gm.GetLog().GetEntry(first);
+		return 1;
+	}
+
+	int new_threadId = 0;
+	// Allocate a thread within the machine
+	gm.CreateThread( gmVariable::s_null, gm.GetGlobals()->Get(&gm, "threadfunc"), &new_threadId );
+	// Execute the machine
+	gm.Execute(1);
+
+	return 0;
+}
+

+ 27 - 0
gmsrc/doc/tutorial/2-continuing/cpp/threads_01b.cpp

@@ -0,0 +1,27 @@
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	// A test script which creates the function we're testing
+	const char *testscript = "global threadfunc = function() { print(\"'this' passed as - \", this); };";
+	// Execute the script to create the function in the VM
+	if (gm.ExecuteString( testscript, NULL, true ))
+	{
+		bool first = true;
+		std::cout << gm.GetLog().GetEntry(first);
+		return 1;
+	}
+
+	int new_threadId = 0;
+	// Allocate a thread within the machine
+	gm.CreateThread( gmVariable(gm.AllocStringObject("Hello, this!")), gm.GetGlobals()->Get(&gm, "threadfunc"), &new_threadId );
+	// Execute the machine
+	gm.Execute(1);
+
+	return 0;
+}
+

+ 22 - 0
gmsrc/doc/tutorial/2-continuing/cpp/threads_02.cpp

@@ -0,0 +1,22 @@
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+int GM_CDECL gmMyThreadFunc(gmThread *a_thread)
+{
+	std::cout << "Hello, threads!" << std::endl;
+	return GM_OK;
+}
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	// Bind the function to use by creating a gmFunctionObject
+	gmFunctionObject *threadfunc = gm.AllocFunctionObject( gmMyThreadFunc );
+	int new_threadId = 0;
+	// Allocate a thread within the machine
+	gm.CreateThread( gmVariable::s_null, gmVariable(threadfunc), &new_threadId );
+	return 0;
+}
+

+ 26 - 0
gmsrc/doc/tutorial/2-continuing/cpp/threads_03.cpp

@@ -0,0 +1,26 @@
+#include "stdafx.h"
+#include <iostream>
+#include "gmThread.h"
+
+int GM_CDECL gmMyThreadFunc(gmThread *a_thread)
+{
+	GM_ASSERT( a_thread->GetThis()->m_type == GM_STRING );
+	gmStringObject *thisstr = reinterpret_cast<gmStringObject *>(a_thread->GetThis()->m_value.m_ref);
+	std::cout << "'this' passed as " << thisstr->GetString() << std::endl;
+	return GM_OK;
+}
+
+int main(int argc, char* argv[])
+{
+	// Create gm virtual machine
+	gmMachine	gm;
+	// Bind the function to use by creating a gmFunctionObject
+	gmFunctionObject *threadfunc = gm.AllocFunctionObject( gmMyThreadFunc );
+	// Add function to the global table so scripts can access it
+	gm.GetGlobals()->Set(&gm, "threadfunc", gmVariable(threadfunc) );
+	// Call script to make callback, pass a variable containing "hello" as this
+	const char *script = "text = \"hello\"; text:thread( threadfunc );";
+	gm.ExecuteString( script );
+	return 0;
+}
+

BIN
gmsrc/doc/tutorial/2-continuing/guardstates.GIF


+ 25 - 0
gmsrc/doc/tutorial/2-continuing/scripts/blocking_01.gm

@@ -0,0 +1,25 @@
+/*
+  Yield based thread looping - bad!
+*/
+
+global WakeUp = false;
+
+global thread_1 = function( a_count )
+{
+  while (WakeUp == false)
+  {
+    // Snooze
+    print("zzz");
+    yield();
+  }
+  
+  print("I just woke up, boy was I tired!");
+  
+};
+
+// Launch thread
+thread( thread_1 );
+// Sleep for 1 secs then set the wakeup variable
+sleep(1);
+
+WakeUp = true;

+ 18 - 0
gmsrc/doc/tutorial/2-continuing/scripts/blocking_02.gm

@@ -0,0 +1,18 @@
+/*
+  Basic blocking and signalling #1
+*/
+
+global thread_1 = function()
+{
+  block("WAKEUP");
+
+  print("I just woke up, boy was I tired!");
+  
+};
+
+// Launch thread
+thread( thread_1 );
+// Sleep for 1 secs then set the wakeup variable
+sleep(1);
+
+signal("WAKEUP");

+ 29 - 0
gmsrc/doc/tutorial/2-continuing/scripts/blocking_03.gm

@@ -0,0 +1,29 @@
+/*
+  Basic blocking and signalling #3
+*/
+
+global thread_1 = function()
+{
+  block("WAKEUP");
+
+  print("I just woke up, boy was I tired! You should wake up too!");
+  
+  signal("YOUTOO");
+};
+
+global thread_2 = function()
+{
+  block("YOUTOO");
+
+  print("What did you wake me up for?");
+  
+};
+
+
+// Launch thread
+thread( thread_2 );
+thread( thread_1 );
+// Sleep for 1 secs then set the wakeup variable
+sleep(1);
+
+signal("WAKEUP");

+ 25 - 0
gmsrc/doc/tutorial/2-continuing/scripts/blocking_04.gm

@@ -0,0 +1,25 @@
+/*
+  Basic blocking and signalling #4
+*/
+
+global blockfunc = function()
+{
+	print( "Waiting for instruction, sir!" );
+	signal_received = block("attack", "move", "defend");
+	if(signal_received == "attack")
+	{
+		print("Attacking!");
+	}
+	else if (signal_received == "move")
+	{
+		print("Moving to position!");
+	}
+	else if (signal_received == "defend")
+	{
+		print("Defending til the death!");
+	}
+};
+
+thread( blockfunc );
+sleep(1);
+signal("attack");

+ 27 - 0
gmsrc/doc/tutorial/2-continuing/scripts/blocking_05.gm

@@ -0,0 +1,27 @@
+/*
+  Basic blocking and signalling #5
+*/
+
+global blockfunc = function(name)
+{
+	print( name + ", waiting for instruction, sir!" );
+	signal_received = block("attack", "move", "defend");
+	if(signal_received == "attack")
+	{
+		print(name + " is attacking!");
+	}
+	else if (signal_received == "move")
+	{
+		print(name + " is moving to position!");
+	}
+	else if (signal_received == "defend")
+	{
+		print(name + " is defending til the death!");
+	}
+};
+
+thread_1 = thread( blockfunc, "woob" );
+thread_2 = thread( blockfunc, "foo" );
+sleep(1);
+signal("attack", thread_1);
+signal("defend", thread_2);

+ 25 - 0
gmsrc/doc/tutorial/2-continuing/scripts/states_01.gm

@@ -0,0 +1,25 @@
+global awake = function()
+{
+	print("I'm awake!");
+};
+
+global resting = function()
+{
+	print("I am resting");
+	sig = block("wakeup");
+	if (sig == "wakeup")
+	{
+		stateSet( awake );
+	}
+};
+
+global init_state = function()
+{
+	// Set a state on the thread
+	// we're now using states
+	stateSet( resting );
+};
+
+thread( init_state );
+sleep(1);
+signal("wakeup");

+ 51 - 0
gmsrc/doc/tutorial/2-continuing/scripts/states_02.gm

@@ -0,0 +1,51 @@
+global ent_state_panic = function()
+{
+	print(.name + " is panicking, firing off alrams and attracting attention to you");
+};
+
+global ent_state_awake = function()
+{
+	print(.name + " is waking up");
+	this:stateSet( stateGetLast() );	// revert to previous state
+};
+
+global ent_state_sleeping = function()
+{
+	print(.name + " is sleeping");
+	sig = block("quiet_noise", "loud_bang", "kill");
+	if (sig == "quiet_noise")
+	{
+		this:stateSet( ent_state_awake );
+	}
+	else if (sig == "loud_bang")
+	{
+		this:stateSet( ent_state_panic );
+	}
+	else
+	{
+		print( .name + " killed" );
+	}
+};
+
+/// Initialise the state on the entity
+global ent_state_init = function(func)
+{
+	print( .name, " state initialised");
+	this:stateSet(func);
+};
+
+global ent_1 = { name = "roboguard 1000" };
+global ent_2 = { name = "old ticker" };
+
+// Create two threads, one for each entity and initialise them in the sleeping state
+ent_1.threadid = ent_1:thread( ent_state_init, ent_state_sleeping );
+ent_2.threadid = ent_2:thread( ent_state_init, ent_state_sleeping );
+
+sleep(1);
+print( "You stand on a twig");
+signal("quiet_noise");
+sleep(1);
+print( "You fire a gun at " + ent_1.name + " causing a loud noise");
+signal("loud_bang", ent_1.threadid);
+// Tell the entity to die
+signal("kill", ent_2.threadid);

+ 31 - 0
gmsrc/doc/tutorial/2-continuing/scripts/states_03.gm

@@ -0,0 +1,31 @@
+global awake = function()
+{
+	print("I'm awake!");
+};
+
+global waking = function()
+{
+	print("I am stirring...");
+};
+
+global resting = function()
+{
+	print("I am resting");
+	sig = block("wakeup");
+	if (sig == "wakeup")
+	{
+		stateSetExitFunction( waking );
+		stateSet( awake );
+	}
+	
+};
+
+global init_func = function()
+{
+	// set state on thread
+	stateSet( resting );
+};
+
+thread( init_func );
+sleep(1);
+signal("wakeup");

+ 30 - 0
gmsrc/doc/tutorial/2-continuing/scripts/states_04.gm

@@ -0,0 +1,30 @@
+global state_advance = function()
+{
+	print("Leaving cover and advancing");
+};
+
+global state_decide_action = function()
+{
+	print("I have to decide on a next action");
+};
+
+global state_hiding = function()
+{
+	print("Behind cover, waiting to advance");
+	sig = block("advance");
+	if (sig == "advance")
+	{
+		stateSet( awake );
+	}
+};
+
+global init_state = function()
+{
+	stateSet( state_hiding );
+};
+
+tid = thread( init_state );
+sleep(1);
+// Signal isn't thrown, tell this thread to change state
+print("Cover explodes!");
+stateSetOnThread( tid, state_decide_action );

+ 15 - 0
gmsrc/doc/tutorial/2-continuing/scripts/threads_01.gm

@@ -0,0 +1,15 @@
+
+global thread_1 = function( a_count )
+{
+ print( "[1] Starting..." );
+ for (i = 0; i < a_count; i = i + 1)
+ {
+  print( "[1] iteration: " + i );
+ };
+ print( "[1] Finishing..." );
+};
+
+print( "[0] Ready to execute..." );
+thread( thread_1, 100 );
+sleep(1);
+print( "[0] Thread created..." );

+ 16 - 0
gmsrc/doc/tutorial/2-continuing/scripts/threads_02.gm

@@ -0,0 +1,16 @@
+
+global thread_func = function( a_name, a_count )
+{
+ print( "["+a_name+"] Starting..." );
+ for (i = 0; i < a_count; i = i + 1)
+ {
+  print( "["+a_name+"] iteration: " + i );
+ };
+ print( "["+a_name+"] Finishing..." );
+};
+
+print( "[0] Ready to execute..." );
+thread( thread_func, 1, 100 );
+thread( thread_func, 2, 100 );
+sleep(1);
+print( "[0] Thread created..." );

+ 17 - 0
gmsrc/doc/tutorial/2-continuing/scripts/threads_03.gm

@@ -0,0 +1,17 @@
+
+global thread_func = function( a_name, a_count )
+{
+ print( "["+a_name+"] Starting..." );
+ for (i = 0; i < a_count; i = i + 1)
+ {
+  print( "["+a_name+"] iteration: " + i );
+  yield();
+ };
+ print( "["+a_name+"] Finishing..." );
+};
+
+print( "[0] Ready to execute..." );
+thread( thread_func, 1, 100 );
+thread( thread_func, 2, 100 );
+sleep(1);
+print( "[0] Thread created..." );

+ 17 - 0
gmsrc/doc/tutorial/2-continuing/scripts/threads_04.gm

@@ -0,0 +1,17 @@
+
+global thread_func = function( a_name, a_count )
+{
+ print( "["+a_name+"] Starting..." );
+ for (i = 0; i < a_count; i = i + 1)
+ {
+  print( "["+a_name+"] iteration: " + i );
+  yield();
+ };
+ print( "["+a_name+"] Finishing..." );
+};
+
+print( "[0] Ready to execute..." );
+thread( thread_func, 1, 100 );
+thread( thread_func, 2, 100 );
+sleep(1);
+print( "[0] Thread created..." );

+ 20 - 0
gmsrc/doc/tutorial/2-continuing/scripts/threads_this_01.gm

@@ -0,0 +1,20 @@
+
+global my_entity = {
+	x = 50, y = 100, name = "test"
+};
+
+
+global move_ent_left = function()
+{
+	print( "Starting thread - this.name = " + .name );
+	while( this.x > 0 )
+	{
+		this.x = this.x - 10;
+		print( this.name + " - x = " + this.x );
+		yield();
+	}
+	print( "Ending thread - this.name = " + .name );
+};
+
+my_entity:thread( move_ent_left );
+sleep(1);

+ 24 - 0
gmsrc/doc/tutorial/2-continuing/scripts/threads_this_02.gm

@@ -0,0 +1,24 @@
+
+global robot = {
+	x = 50, y = 100, name = "robot"
+};
+
+global player = {
+	x = 150, y = 200, name = "player"
+};
+
+global move_ent_left = function()
+{
+	print( "Starting thread - this.name = " + .name );
+	while( this.x > 0 )
+	{
+		this.x = this.x - 10;
+		print( this.name + " - x = " + this.x );
+		yield();
+	}
+	print( "Ending thread - this.name = " + .name );
+};
+
+robot:thread( move_ent_left );
+player:thread( move_ent_left );
+sleep(1);

+ 36 - 0
gmsrc/doc/tutorial/2-continuing/scripts/threads_this_03.gm

@@ -0,0 +1,36 @@
+
+global create_robot = function(x, y, name)
+{
+	return { x = x, y = y, name = name, id, class="robot" };
+};
+
+global behaviour_stupid = function()
+{
+	print( .name + " is acting stupidly" );
+};
+
+global behaviour_seek = function()
+{
+	print( .name + " is seeking resources" );
+};
+
+global behaviour_rest = function()
+{
+	print( .name + " is resting" );
+};
+
+global robot_def = {
+	{"tom", behaviour_seek},
+	{"mike", behaviour_rest}, 
+	{"jane", behaviour_stupid}, 
+	{"bob", behaviour_stupid},
+	{"sarah", behaviour_seek}
+};
+
+for(id = 0; id < 5; id = id + 1)
+{
+	robot = create_robot(1 * id, 10 * id, robot_def[id][0]);
+	robot:thread(robot_def[id][1]);
+}
+
+sleep(1);