Lore And Lutes Object Oriented Programming Language
Documentation For C++ Game Developers Vs. 1.01 (10/27/2002)

Written By: Andy Stone
ASFC By: Andy Stone (astone42@attbi.com)
Visit: http://loreandlutes.sourceforge.net for more information.
See copying.txt or copying for licensing information.
==============================================

Changes (Document Versions):
============================
1.0:  Initial document.
1.01: Fixed some dumb spelling mistakes, re-worded a few things so they
      sound better.

What LOOP Is:
=============
The Lore And Lutes Object Oriented Programming Language (LOOP) is a library
which includes code made to be modified into a scripting language. If you've
ever edited a Lore And Lutes (L&L) game then you've used LOOP when you edit a
class. This document describes how to use the LOOP library to create your
own scripting language for games written in C++.

LOOP Dependencies:
==================
LOOP depends on ASFC, and thus SDL and SDL_image, you'll need to have these
libraries running and set up for development on your system before
you can start programming with LOOP. Also I suggest that you read up
on ASFC before trying to delve into the world of LOOP. You can read the ASFC
documentation online at <http://loreandlutes.sourceforge.net>.

Example compilation:
g++ *.cpp -lasfc -lloop -lSDL -lSDL_image

The LOOP Object:
================
To use LOOP you really only need to take advantage of one class: LOOP_LOOP.
If you want to program in your own commands for the scripting language you'll
have to delve deeper into other classes but for now just know you need this
class. The first thing you should do though is create a program that will
run a generic loop script:

#include <loop/loop.h>
#include <loop/looplib_standard.h>

int main(int argc, char *argv[])
{
  LOOP_LOOP LOOP;
  LOOP_LOOPLib_Standard lib;
  string file;
  string class;
  string member;

  cout << "Linking the standard library to LOOP\n";
  lib.Link(&LOOP);

  cout << "What file would you like to execute? "
  cin  >> file;
  cout << "\nLoading: " << file << endl
  LOOP.ReadClass(file);

  cout << "What class would you like to create an instance of?";
  cin  >> class;
  cout << "\nCreating a new instance of class"
  oLOOP.NewInstance(0, class, SCOPE_LOCAL);

  cout << "What member would you like to call: ";
  cin  >> member;
  oLOOP.GosubInstance(class, member);
  cout << "\nGosubing " << member << endl;

  cout << "Executing file for 100 iterations:\n"
  for(int i = 0; i < 100; i++)
    oLOOP.RunInstance(0);

  cout << "Finished\n";

  return 0;
}

Go ahead and create a project, copy and paste that code, and compile.
If everything works as it should then you can use this program to test
LOOP scripts that show up in this document.

A bit about the source
----------------------
Reading the source you'll probably notice the ReadClass() member is called.
This member will read a text file and compile it in memory so that LOOP
can execute it. The NewInstance command will create a new instance
of class and the RunInstance will run an instance. Near the top you'll see
an instance of LOOPLib_Standard created. This object is the standard LOOP
library which includes basic commands for LOOP like #StrEqu and #Cout. The
Link() member links this library to LOOP thus making all the commands in
the lib accessible by LOOP.

Now test that code
------------------
If you compile and build the program above you should be able to run generic
LOOP scripts (ones that only use the the standard LOOP lib). To test
LOOP create the follow file save it as test.script:

@test

:test
  #cout "Hello, World!"
#return
^

Next run the generic LOOP Scriipt runner and enter the following information:

Linking the standard library to LOOP
What file would you like to execute? test.script
Loading: test.script
What class would you like to create an instance of? test
Creating a new instance of class
What member would you like to call: test
Gosubing test
Executing file for 100 iterations:

If everything works properley you should get these results:

Hello, World!

Writing loop script files
==========================
If you've programmed classes within the L&L editor before then you already
know how to write LOOP scripts (if so you can just skim this section, be sure
to read the Starting and Ending Classes section though as it differs from
how you write L&L scripts in L&L). Otherwise I've got some explainin' to do.
A LOOP script is simply a text file that includes a list of commands just like
a normal program. Like any programming language LOOP requires that you write
in a certain way (syntax).

Sample LOOP Script
------------------
@TestClass

:SayHello
  #cout "Hello, World!"
#Return

^

LOOP is L + OOP
---------------
LOOP in some respects is an object oriented language, in that
you write classes that contain members and you can have inheritance. It
however isn't strongly typed, there are really only three variable types.
So it's not truly an Object Oriented Language. Nevertheless, its important
that you understand the basic concept of OOP before you try to program and
use LOOP. Being that if you're reading this document you probably know how
to program C++ I'll assume you know OOP.

Starting and Ending Class
-------------------------
Each script file you create will contain a class, the first line of all
script files should include an at sign (@) and the name of the class you
want this file to contain. For example if you want a class named TestClass
the file should start out like this:

@TestClass

Class names can contain any character you want except [, ], (, or ).

To end a class place a caret at where the class ends. For example a
generic class format is:

@ClassName
  //Class Code
^

Anything after the carret will be ignored by the LOOP parser so you can
place comments and notes there if you'd like. Be careful to end the class
though as forgetting to do so can confuse LOOP and might freeze it.

Comments
--------
LOOP uses C++ style comments, two slashes denote a line comment telling the
LOOP parser to ignore everything until the end of a line. /* and */s are
block comments and are ignored just as they are in C.

Commands
--------
To actually make LOOP do something you have to use commands! Commands are
programmed in C++ and this doc will explain how to make your own commands
later on. To use a command type a pound sign (#) followed by the command's
identifier, followed by any parameters you want to pass to it. Separate all
parameters with spaces. For example the command cout takes a string parameter
and will output this parameter onto the console:

#cout "This command couts"

There are three types of parameters LOOP accepts, ints, floats, and strings.
Constants of those three types are passed just like that are in most
languages. For example a string is passed by enclosing the string in double
quotes ("), ints are passed by typing a whole number, and floats are passed
by typing a number with a decimal point. Ints and floats may be positive
or negative.

Example:
#cout       "String "
#coutInt    -1234
#cout       " " 
#coutFloat  1.234

Result:
String -1234 1.234

Variables are passed by enclosing the variable identifier in brackets [].

Variables
---------
In LOOP there are three types of variables:

string   Holds a string of characters like "Hello"
int      Holds an integer number like 123. Int is held in memory just like an
         int in C++.
float    Holds a number with a decimal point, like 123.4. In memory a float
         is actually stored as a double.

There are also two categories of variables public and private. By default
whether a variable is public or private won't effect LOOP. You have to
program in the difference yourself if you like.

To create a public variable write a percent sign (%) followed by the type
of variable, a space, and in double quotes the identifier you want for this
variable. Example:

%string  "varString"   //Creates a string called varString
%int     "varInt"      //Creates an int called varInt
%float   "varFloat"    //Creates a float called varFloat

To create a private variable write a dollar sign ($) followed by the type
of variable, a space, and in double quotes the identifier you want for this
variable. Example:

%string  "varPubString"   //Creates a public string called varPubString
%int     "varPubInt"      //Creates a public int called varPubInt
%float   "varPubFloat"    //Creates a public float called varPubFloat

To pass a variable to a command simply enclose the variable's identifier in
[]s. For example:

%string "message"
#StrEqu [message] "Hello, World!"
#cout   [message]

Labels
------
Labels mark a location within a program. To create a label type a colon (:)
followed by the identifier you'd like for this label. For example:

:label

Label's are used to mark the beginning of methods (sub routines), that
#Gosub or #Goto commands call.

The Standard Library
--------------------
In LOOP a library is a set of several commands. LOOP comes packaged with
a sample library called the "LOOP Standard Library". Its not neccessary
to use this library but its highly suggested. The commands in the standard
standard library are listed below.

The rightmost column in the table below specifies what types parameters are
passed. I for int, F for float, S for string. If a parameter is enclosed in
[]s that means a variable has to be passed. For example the table entry
for RemoveSubStr looks like this:

RemoveSubStr    Removes the sub string between the two passed ints.    [S]II

So RemoveSubStr expects a string variable to be passed and two integer
variables or constants.

Example:

@Test
%string "string"

:Test
  #StrEqu [string] "String oops!"
  #RemoveSubStr [string] 7 11
  #cout [string]
#Return
^

Result:
String!

==============================================================================
Command          Desc                                               Pass
Debugging
---------
Cout             Writes a string onto the console                   S
CoutFloat        Writes a float onto the console                    F
CoutInt          Writes an int onto thte console                    I
CoutDebugInfo    Display LOOP debugging information.

Conditional
-----------
IfStrEqu         If two strings equal execute the command on the    SS
                 next line. If the next command is #begin execute
                 all commands between #begin and #end. If the two
                 strings aren't equal skip the next line unless
                 it's a begin and which case skip to the #end
                 command associated with the #begin command.
IfIntEqu         Like IfStrEqu but compares two ints                II
IfIntGT          If int is greater than                             II
IfIntLT          If int is less than                                II
IfIntGTI         If int is greater than or equal to                 II
IfIntLTI         If int is less than or equal to                    II
IfFloatEqu       If float is equal to                               FF
IfFloatGT        If float is greater than                           FF
IfFloatLT        If float is less than                              FF
IfFloatGTI       If int is greater than or equal to                 FF
IfFloatLTI       If int is less than or equal to                    FF

Misc
----
Begin            Used to mark the beginning of a conditional
                 block for #If commands
End              Used to mark the ending of a conditional
                 block for #If commands

String Manipulation
-------------------
StrEqu           Sets the the first string passed equal to the      [S]S
                 second
AppendStr        Add the 2nd string passed to the end of the 1st    [S]S
InsertStr        Insert 2nd string into 1st                         [S]SI
RemoveSubStr     Removes the sub string between the two passed ints [S]II
UpperString      Capitalize the 2nd string, place it in the 1st     [S]S
SubStr           Grab the sub string between the 2 int locals       [S]SII
StrSize          Return the size of a string                        [I]S

Int Manipulation
----------------
IntEqu           Set int equal to                                   [I]I
IntInc           Increment the value of an int by 1                 [I]
IntDec           De-increment the value of an int by 1              [I]
IntAdd           Find the sum of two ints                           [I]II
IntSub           Find the difference between two ints               [I]II
IntMul           Find the product between two ints                  [I]II
IntDiv           Return the ratio between two ints                  [I]II
IntMod           Find the modulo between two ints                   [I]II

Float Manipulation
------------------
FloatEqu         Set float equal to                                 [F]F
FloatInc         Increment the value of a float by 1                [F]
FloatDec         De-increment the value of a float by 1             [F]
FloatAdd         Find the sum between two floats                    [F]FF
FloatSub         Find the difference between two floats             [F]FF
FloatMul         Find the product between two floats                [F]FF
FloatDiv         Find the ratio between two floats                  [F]FF

Seek
----
Goto             Set the point of execution to a label             S
GoSub            Set the point of execution to a label. Return to  S
                 this point when the next #Return command is
                 called.
Send             Perform a goto command on another instance        SS
GoSend           Perform a gosub command on another instance       SS
Return           Used for marking the end of a method called by
                 a #GoSub or #GoSend statement


Sample LOOP script:
===================
//This loop script will print all the even numbers between 0 and 100
//when the PrintEvens method is called.

@Mathematician
%int "counter"
%ing "mod"

:PrintEvens
    #IntEqu [counter] 0

    :Update
        #IfIntLTI [counter] 100
        #Begin
            #coutInt [counter]
            #cout " "
            #IntAdd [counter] [counter] 2
            #Goto "Update"
        #End
#Return

^

To run this script using the generic LOOP runner enter the following info:
Linking the standard library to LOOP
What file would you like to execute? script.script
Loading: script.script
What class would you like to create an instance of? Mathematician
Creating a new instance of Mathematician
What member would you like to call: PrintEvens
Gosubing PrintEvens
Executing file for 100 iterations:

Creating Your Own LOOP Library
==============================
Once you've learned how to create your own scripts using the standard
LOOP library you may like to create your own library of commands. Doing
so is fairly easy once you get everything set up, but getting everything
set up can be a pain!

The way LOOP handles commands is fairly easy, you create a function that
maps to your command, then you tell LOOP where this function is, what
command it links to, and what parameters are passed to the command. Whenever
LOOP encounters your new command in a script it calls through a function
pointer your function. This sounds easy but its not!

Anyways, the first thing you need to do is create .h and .cpp files for your
library. Copy in the code for each file as seen in appendix A (near the
bottom of the file).

You'll notice that the .h file includes the following headers:
#include <loop/loopmacros.h>
#include <loop/info.h>
#include <loop/loop.h>

loopmacros includes macros that make it possible for you to pass a function
within a class to LOOP, if you've ever used function pointers you may have
encountered troubles with this before. The macro will create a static member
in your library class that will map to the dynamic member to be executed. If
you don't understand that don't worry just know you have to use the macros
in there.

The info header includes an info object, an info object will be passed to the
function you create for your new command. The info object holds information
about what parameters are passed, what instance is passing it, and includes
a few helpful members that make LOOP command programming easier for you.

And the loop header includes the main LOOP object which will get passed to
a member your about to program called Link(). Link() will link() all of
the commands in your library to the main LOOP_LOOP object.

Now go through the file and anywhere it says Insert<something>here insert
the appropriate name. For example replace:


InsertNameHere:     With the name of your library. For example MyLib.
InsertCommandType:  With a helpful description about what types of commands
                    you're defining below.
InsertCommmandName: Insert the name of the command you want to create.

Pay close attention to this line:
LOOPPORT(LOOPCMDPRT_InsertCommmandName, LOOPLib_InsertNameHere, LOOPCMD_InsertCommandName);

LOOPPORT is the macro that defines members for your LOOP command that
will be called whenever the command is encountered in a script. The first
parameter passed will define a port function which helps resolve some issues
with how function pointers work, the second param passed is the name of
the class your member functions dwell under, and the third parameter tells
the macro what you want your actual member function to be called.

If you want your library to include more than one command simply copy
that line as many times as necessary replacing all the InsertNameHeres
with the name of each command.

Next near the bottom of the .cpp file you should have these lines:

void LOOPLib_InsertNameHere::LOOPCMD_InsertCommandName(LOOP_Info oInfo)
{
  //Inset command code here
}

This is a template of what your member function will look like. Replace
the Insert<something> text with the appropriate information. If you like
you can change the identifier of the LOOP_Info variable (oInfo) passed.

Next scroll up to your Link() member, which will link your library to the
LOOP object. Take a gander at this code:

poLOOP->NewCommand("InsertCommandName", &LOOPCMDPRT_InsertCommandName, this);
		poLOOP->AddParam(PARAM_INSERTPARAMTYPE1);
		poLOOP->AddParam(PARAM_INSERTPARAMTYPE2);
		poLOOP->AddParam(PARAM_INSERTPARAMTYPE3);
		poLOOP->AddParam(PARAM_INSERTPARAMTYPE4);

Replace all Insert<somethings> with the correct information. The AddParameter
calls below tell LOOP what type of parameters will get passed to your
new command in the order they should get passed. Possible params to pass
include:
	
PARAM_INT           Pass an int variable or int constant
PARAM_FLOAT         Pass a float variable or float constant
PARAM_STRING        Pass a string varaible or string constant
PARAM_INT_REF       Pass an int variable
PARAM_FLOAT_REF     Pass a float variable
PARAM_STRING_REF    Pass a string variable

You can add as many or as a few parameters as you'd like. If your library
has more than one command (most likely) simply copy and paste the code for
all the commands you need. For example a library for two commands called
#WriteInt and #WriteString might have a Link() member that looks like this: 

void LOOPLib_TestLib::Link(LOOP_LOOP* poLOOP)
{
	poLOOP->NewCommand("WriteInt", &LOOPCMDPRT_WriteInt, this);
		poLOOP->AddParam(PARAM_INT);
	poLOOP->NewCommand("WriteString", &LOOPCMDPRT_WriteString, this);
		poLOOP->AddParam(PARAM_STRING);
}

The Info Object
===============
As you write code for your command's function (replacing the 
//Inset command code here comment) you'll probably want to get information
about the parameters that were passed to your command. You can get this
information from the LOOP_Info variable. LOOP_Info includes the following
members for reading parameters:

int    GrabInt       (int iNumber);
double GrabFloat     (int iNumber);
string GrabString    (int iNumber);
int    GrabIntRef    (int iNumber);
int    GrabFloatRef  (int iNumber);
int    GrabStringRef (int iNumber);

Set the iNumber param equal to which <int/float/string> is passed. For
example if you had a command called drawline that took 4 ints for
coods it might look like this:

void LOOPLib_MyLib::LOOPCMD_DrawLine(LOOP_Info oInfo)
{
	FunctionElsewhereThatDrawsALine
	(
		oInfo.GrabInt(0), oInfo.GrabInt(1),
		oInfo.GrabInt(2), oInfo.GrabInt(4)
	);
}

Realize that if you have a member that gets passed variables both
by reference and by non-reference the iNumber parameter for non reference
grabbing members also maps to the reference passed variables. For example
if you had a command called PassVars that took i[i]i and you executed
this in a script:

#PassVars 10 20 30

Then:

oInfo.GrabInt(0) = 10
oInfo.GrabInt(1) = 20
oInfo.GrabInt(2) = 30
oInfo.GrabIntRef(0) = An integer representing the location of the intref
                      variable. This will be iLocation for the SetInt()
                      member if you choose to use it.


If you'd like to change the value of a variable passed by reference
you can use the Variable Setting members of the LOOP_Info object:
		
void SetInt   (int iLocation, int iTo);
void SetFloat (int iLocation, double dTo);
void SetString(int iLocation, string sTo);

Adding to this documentation
=============================
Currently there's a lot of information that could be added to this doc but
hasn't been mostly because I'm busy coding :-). But if you have something
that you think should be added, or if you use LOOP and know just what this doc
needs feel free to help me. E-Mail me, Andy Stone, at astone42@attbi.com.
Also if you notice any dumb spelling or grammar mistakes that just stand out
and bug you e-mail me where the are and I'll try to fix those too. Thanks.

Errors, Bugs, Questions, Comments?
==========================================
E-Mail me (Andy) or Eoin:
Andy Stone (astone42@attbi.com)

Appendix A: Template LOOP Library Class
=======================================
templatelib.h
---------------

#include <loop/loopmacros.h>
#include <loop/info.h>
#include <loop/loop.h>

class LOOPLib_InsertNameHere
{	public:
	//- [Constuctors] -
 		LOOP_LOOPLib_Standard();
 		void Link(LOOP_LOOP* poLOOP);
 		
	//- [InsertCommandType] -
		LOOPPORT(LOOPCMDPRT_InsertCommmandName, LOOPLib_InsertNameHere, LOOPCMD_InsertCommandName);

 	private:
 	//Vars
};

templatelib.cpp
---------------
#include "templatelib.h"

LOOPLib_InsertNameHere::LOOPLib_InsertNameHere()
{
}


void LOOPLib_InsertNameHere::Link(LOOP_LOOP* poLOOP)
{
	poLOOP->NewCommand("InsertCommandName", &LOOPCMDPRT_InsertCommandName, this);
		poLOOP->AddParam(PARAM_INSERTPARAMTYPE1);
		poLOOP->AddParam(PARAM_INSERTPARAMTYPE2);
		poLOOP->AddParam(PARAM_INSERTPARAMTYPE3);
		poLOOP->AddParam(PARAM_INSERTPARAMTYPE4);
	//Repeat for more commands...
}

void LOOPLib_InsertNameHere::LOOPCMD_InsertCommandName(LOOP_Info oInfo)
{
  //Inset command code here
}