
MORTAL'S LORD II NEW LANGUAGE PARSER
------------------------------------

Yet another little tool to help in the creation of Lord II worlds.
This utility is the second part in my project to create my own world.
What you ask does it do?

Well as you know Seth Able (the orginal Lord II world and REF engine
designer made a nice little engine to read REF files; however, Seth
really sucked when it came to structure (sorry Seth but it's true).
So what I have done is created 2 programs to aid in the quicker and
clearer design of REF files.

These programs are shareware and to register them both you should feel
inclined to send me a whole $2 bucks. If you don't then you're a cheap
ass and you will never receive the version without the startup timer!
The sample IGM included with the package is entirely free. Feel free
to use it however you please, but DO NOT distribute it individually.
The example MOUND.REF was entirely created using MParse.exe. To see for
yourself type "MParse.exe MOUND.LST MOUND.MEF MOUND.REF". This will
cause the parser to create MOUND.REF using the information in MOUND.LST
and MOUND.MEF.

No elements of this package may be distributed indiviually. In otherwords
MReplace.exe may not be separated from the package and distributed
individually. You may not attempt to reverse engineer or in anyway alter
the binary code in order to alter it's functionality.

This material is copyright (C) of Robert Cummings AKA |\/|ortal. To send
me my $2 bucks mail your cheque or money order to:

                      Robert Cummings
                      4-52 Maclaren Street
                      Ottawa, Ontario
                      K2P 0K4

I can also be reached at my e-mail address (for bugs or stuff):

                      rcumming@aurora.carleton.ca

Do not send cash... cash will be pocketted and you will not be sent the
registered version. Sorry but your names will be encrypted into the
registered versions and to do that I need some kind of evidence of who
you are. Note that MParse uses a couple of the temporary player
long integer variables to aid in it's math. You should not attempt to
use `p29 or `p30 since using them may have undesirable effects. It's
a small price to pay for the power of the new language.


MReplace.exe
------------

This little program will make your life a world easier all by itself!
This file takes as parameters the name of a pair list file (explained
later), the name of an input file and the name of an output file.

The list file is a file consisting of search strings and corresponding
replacement strings. Search strings are always encased in square brackets
"[" and "]". Replacement strings always follow their search criteria and
are placed within curly brackets "{" and "}". Anything not found within
these bracket pairs is considered a comment (i.e. junk).

The input file is the name of the text file in which you wish to replace
all the search criteria with the replacement criteria.

The ouput file is the new file which will contain none of the search
criteria but rather the strings which will have replaced the search
criteria.

The power behind this as it relates to idea of REF building is that you
can now do the following in the list file:

[##Experience]  {`P01}

Then when you run MReplace.exe with the list file containing this pair
on an input file containing the string ##Experience then the output file
will contain `P01 wherever ##Experience is in the input file. Thus this
should already make REF building clearer. Search criteria are not case
sensitive; however, literal copying of the replacement criteria is done.
My convention is to lead my function names with "#" and lead variable
names in my replacement list file with "##".

An example list file is included with the package. Note that the more
search/replace pairs you have the longer it will take to produce the new
output file. Also note that to include any of the special meaning
characters "}", "]", "\", you must first escape them within the string
using the "\" character.


MParse.exe
----------

Now this sucker does a lot of work. For it's parameters it takes a list
file as defined above, an input file, and an output file. The input file
is a text file corresponding to MEF decription that follows. MEF is the
extension I have decided will describe a Mortal's New Lord II Language
file. The very first thing MParse does is to call MReplace.exe with the
list file and input file as it's parameters. The results of MReplace will
be stored in a temporary file which will then be parsed. Note you should
not need to run the utility REFINDEX (written by someone else) on the
resultant REF files since I produce REF's which are lead by @declare
statements fo each routine. Note though that I don't bother to declare
the labels since as far as I'm concerned you should never jump to a label
in a routine from a different routine. If you do want to do that then
shouldn't it be a routine of it's own?? Just a little structure thought.
Note that all commands in the ref language are NOT case sensitive and I
just write them the way I do for clarity. The MEF language structure
will, to all you C/C++ programmers, have a fairly familiar feel. The
MEF language description follows:

    Strings:

      Strings are text encased between double quotations. The
      expression "I like ice cream" is a string. To include a
      double quotation within your string you escape it like
      followes "Sarah exclaimed, \"What a fabulous idea!\""
      Simple. Also note since these will be converted to REF
      code then you can put anything you please in them that
      would be expanded in a normal REF. Note though that when
      MReplace runs it will not care wether it is within a
      string or not so it is important that the search criteria
      for MReplace are unique strings of your choosing. In most
      cases an `sDD variable can be used in the place of a
      string. If not you will get an error when you attempt to
      parse the code. An example is #NewRoutine and #Comment
      which require string literals. Note that long strings
      may be split across lines. The following is equivalent:

          #Comment( "This comment will appear in the REF code" );

          #Comment(
              "This comment will appear"
              " in the REF code" );

      The comment string could also have been split up on the
      same string or anywhere for that matter. Whitespace is ignored
      everywhere except within a string.

    Integers:

      Integers are exactly as they sound. Numbers! Use the
      characters '0' to '1' to make one. For instance #Halt
      takes an integer for it's parameter. #Halt( 15 ); is a
      valid #Halt command. In most places where integers are
      required you may also use any of the varables that contain
      integers' Be careful what you use though since the variable
      map is used to assign a value to the user's map number
      whereas &map is the expandable version.

    Block Expressions:

      The #NewRoutine, #If and #While statements are all block
      expressions. In other words all code is to be executed in
      lieu of these statements must be enclosed within curly
      brackets, "{" and "}". It doesn't matter what format you use
      to place them because they will always be interpretted as
      an opening block token. The following are the same:

          #NewRoutine( "Foo" )
          {
            #Comment( "an empty routine" );
          }

          #NewRoutine( "Foo" ){
            #Comment( "an empty routine" );
          }

          #NewRoutine(        "Foo"          )
          { #Comment( "an empty routine" ); }

    Comments:

      There are 2 types of comments in the MEF language. The
      #Comment command will take whatever string(s) are contained
      in it's parameter list and explicitly write them as comments
      in the REF code. This is useful in case you want to go
      through the REF code and see what's what. The other form
      of comment is a comment to the MEF parser. It is marked
      by two forward slashes "//". Anything following these on the
      same line will be ignored by the parser. It's like a comment
      in C/C++ of the same type. These comments will not end up
      in the produced REF file.

    Math:

      Assignment of values to variables is done using the "="
      character. For instance,

          `s03 = "This is a string assignment";

      would assign the string after the equals character to the
      global string variable `s03. Integer asignment is done in
      the same manner:

          `t63 = 69;

      Assignment works on any assignable variable name. Remember
      once again that map is the assignable variable and &map is
      the expandable version. Note also that some functions return
      values and must be assigned to a variable. For instance
      to generate a random number between 10 and 60 we would do the
      following:

          `p08 = #Random( 50 ) + 10;

      The math operators are still rather simplistic. I thought
      about incorporating complex math functionality so that
      coders could write things like `p01 += ((15 *`p02) + `t11) / 5;
      but I couldn't be bothered thinking about it at the time and
      also to do this would require temporaray storage in an IDF
      file to be useful. If I get enough e-mails or other
      indications that you really want it then I may be sparked to
      action. Until such time though you have the following:

          ++, --, +=, -=, *=, /=

      These work exactly as in C/C++, The following is an example.

          `p17 = 1;
          `p17++;          // `p17 now contains the value 2
          `p17--;          // `p17 now contains the value 1
          `p17 += 50;      // now it's 51
          `p17 *= 4;       // now it's 204
          `p17 -= 54;      // now it's 150
          `p17 /= 30;      // now it's 5

      So thats the pattern. Note that the "+=" operator works on
      string variables also. For instance:

          `s10 = "The sly fox";
          `s10 += " jumped over the fence!";

      would result in `s10 holding the string:

          "The sly fox jumped over the fence!"

    Equivalence Evaluation:

      Once again I've done some extra work for you. The following
      equivalence operators may be used in an #If or #While
      statement:

          ==, >, <, >=, <=, !=

      Note also that some functions may only be used within an if
      statement and do not require any of the above listed operators.
      An example is:

          #If( BitIsSet?( `t33, 7 ) ){ }

      would evaluate to true if the 7th bit in the variable `t33
      was set to a 1. An example #While statement follows:

          `p23 = 1;
          #While( `p23 <= 50 )
          {
            `p23 = #GetNumberFromUser( 2, 51 );
          }

      Following are a list of functions that can only be called within
      an #If or #While statement:

          #DuplicateName?( <`S Var> )

              If the name contained in the `sDD type variable already
              exists in the player file then the conditional will be
              true. You can use !#DuplicateName? to determine the
              value of the opposite conditional.

          #BitIsSet?( <`T Var>, whichBit )

              If the bit defined by whichBit is a 1 in the `tDD type
              variable then the conditional is true. whichBit may
              be defined by an integer variable.

          #BitIsClear?( <`T Var>, whichBit )

              If the bit defined by whichBit is a 0 in the `tDD type
              variable then the conditional is true. whichBit may
              be defined by an integer variable.

          #ContainsString?( "aString", <`S var> )

              If the `sDD type variable named as the second parameter
              contains the string aString then the conditional
              evaluates to true. aString may also be a `sDD type
              variable.

          #FileExists?( "fileName" )

              If the file named by fileName exists then the conditional
              evaluates to true. fileName may be indicated with a
              `sDD type string variable also. You can use !#FileExists?
              to determine the value of the opposite conditional.


          #PlayerDeleted?( <playerNumber> )

              This conditional will evaluate to true if the player
              defined my playerNum has been deleted. playerNumber can
              be any integer type token. You can use !#PlayerDeleted?
              to determine the value of the opposite conditional.

    List of Functions:

      #Comment( "first line" "of comment",
                "second line of comment", ... );

          Comments may be as long as you please. Parameters follow
          the string literal format and may be split up. Each time
          the parameter separator token is encountered "," then the
          following comment string begins on a new line in the
          generated REF file.

      #InLine( "first line" "of code",
                "second line of code", ... );

          Inline code may be as long as you please. Parameters follow
          the string literal format and may be split up. Each time
          the parameter separator token is encountered "," then the
          following string of code begins on a new line in the
          generated REF file. Note that inline code must be in Seth's
          REF code format. I take no responsability for code that
          doesn't work because you inlined it. Come to think of it
          I take no responsibility for code that doesn't work in any
          event :) But I might fix a bug if one exists :) The inline
          command is for you in case I have a bug in my program, missed
          something or in case you want to make an optimization that
          my parser doesn't make. The inlines are written to the REF
          file explicitly and do not receive any kind of formatting.

      #NewRoutine( "routineName" ){ }

          This defines the beginning of a new routine. The new routine
          will be named routineName. Note that the parenthesis ARE
          required and so are the curly block brackets. All the
          routines' code will be contained between the brackets.
          Attempting to create a #NewRoutine from within an existing
          routine will generate an error.

      #Label( "labelName" );

          This generates a label with the name labelName in the REF
          file. Using a call to #Goto( "labelName" ); will let you
          jump to your new label. Note the following label names
          should not be used:

              WhileCheck_XXXX, WhileStart_XXXX, WhileEnd_XXXX

          Since the parser automatically generates labels in this
          format when it evaluates while loops. The number of X
          digits is arbitrary.

      #Goto( "labelName" );

          Performs a jump in the REF file to a label by the name
          of labelName.

      #PutLongInIDF( "fileName", <whichRecord>, <saveValue> );

          Saves an integer in the whichRecord slot in the IDF file
          named by fileName. Note that fileName must include an
          extension. A string variable may be used for fileName
          and integer variables may be used for whichRecord and
          saveValue. See also #GetLongFromIDF.
     
      #NewDayResetIDF( "fileName" );

          Resets an IDF file if it is a new day. A string variable
          may be used for fileName.

      #UpdateTempFile();

          This function write current player data to to the file
          UPDATE.TMP. Useful for when you just can't wait until a
          script is finished.

      #AppendLogFile( "firstLine of text",
                      "second line of text", ... );

          Lines of text are written to the games log file. Each line
          of text must be separated by the comma separator token. You
          may have as many lines of text as you please. String
          variables may also be used.

      #DeleteFile( "fileName" );

          Delete the file indicated by fileName. A string variable
          may be used for the fileName.

      #TrimFile( "fileName", <maxLines> );

          Truncate a file indicated by fileName to the number of lines
          indicated by maxLines. A stirng variable may be used for
          the fileName and an integer variable may be used for the
          maximum number of lines.

      #CopyFile( "sourceFile", "destinationFile" );

          Copy sourceFile to destinationFile. String variables may be
          used for the filenames.

      #CopyFileToAnsi( "sourceFile", "destinationFile" );

          Copy ascii sourceFile to ansi destinationFile. Filenames
          may be indicated using string variables.

      #CopyFileToAscii( "sourceFile", "destinationFile" );

          Copy ansi sourceFile to ascii destinationFile. Filenames
          may be indicated using string variables.

      #Delay( <number of tenths of seconds> );

          Delay will make the script delay for the specified number
          of tenths of seconds. The parameter indicating the length
          of the delay must be an integer literal.

      #DisplayFile( "fileName", [optional NOSKIP, NOPAUSE] );

          Displays a file on the screen. You may specify 0 or more
          of the options which affect the way it is displayed.

      #ReadFromFile( "fileName", <var to store in>, <var to store in>, ... );

          Reads variable amount of data from the file defined by
          fileName and stores the appropriate type of data into the list
          of variables following the fileName parameter. A string
          variable may be used in place of fileName.

      #WriteToFile( "fileName", <var to store in>, <var to store in>, ... );

          Writes variable amount of data out to the file defined by
          fileName and stores the appropriate type of data in the file
          as defined by the list of variables following the fileName
          parameter. A string variable may be use din place of fileName.

      #LocalBeep();

          Generates a beep to any user who is logged into the game in
          local mode.

      #GotoXY( <xCoord>, <yCoord> );

          Repositions the cursor to the coordinates defined by xCoord
          and yCoord. xCoord and yCoord may be defined by integer
          literals or variables.

      #PlayerGotoXY( <xCoord>, <yCoord> );

          Repositions the player at the coordinates defined by xCoord
          and yCoord. xCoord and yCoord may be defined by integer
          literals or variables.
          
      #WarpPlayer( <xCoord>, <yCoord>, <mapNumber> );

          Repositions the player at the coordinates defined by xCoord
          and yCoord in the map defined by mapNumber. The map number
          is the block number and not the physically stored map
          number. Each parameter may be defined by integer literals or
          variables.
          
      #MoveBackPlayer();

          Returns the player to the coordinates they were at before
          they activated a REF.

      #SendToStatusBar( "aMessage" );

          Sends aMessage to the status bar queue where it will be
          displayed in due time. aMessage may be a string variable.

      #WriteOnStatusBar( "aMessage" );

          Writes aMessage on the status bar immediately. Any message
          already on the status bar will be overwritten. aMessage may
          be a string variable.

      #AddPlayer();

          Adds a player to the player database. You the coder are
          responsible for making sure the player is unique. Before
          this the player's name should be set and a check for it's
          uniqueness should be made.

      #SetBit( <`T Var> <whichBit> );

          Sets the bit in `T Var defined by whichBit to a 1. `T Var
          is any of the variables with the format `tDD. I think
          whichBit must be between 1 and 8 (not sure wether Seth
          uses 0 or 1 based indexing). whichBit may be defined by an
          integer variable.

      #ClearBit( <`T Var> <whichBit> );

          Sets the bit in `T Var defined by whichBit to a 0. `T Var
          is any of the variables with the format `tDD. I think
          whichBit must be between 1 and 8 (not sure wether Seth
          uses 0 or 1 based indexing). whichBit may be defined by an
          integer variable.

      #ToggleBit( <`T Var> <whichBit> );

          Sets the bit in `T Var defined by whichBit to a the opposite
          of it's current value. `T Var is any of the variables with
          the format `tDD. I think whichBit must be between 1 and 8
          (not sure wether Seth uses 0 or 1 based indexing). whichBit
          may be defined by an integer variable.

      #PopUpBuyItemManager( <item1>, <item2>, ... );

          Pops up the buy item manager with the items defined by the
          parmaters item1, item2, ... You can have as many items as you
          want in the manager. Items may be defined by integer variables.
          Item numbers correspond to the item numbers in the item
          data file.

      #PopUpSellItemmanager();

          Pops up the sell item manager. User is able to sell any items
          which they own at half the buy price. Quest items will be
          greyed out and unsellable. Item settings are changed in the
          item editor. See about obtaining a copy of MEditor which is
          the Lord II world and item editor written by myself.

      #PopUpMenu( "option1", "option2", ... );

          Pops up a menu from which the user can choose an option.
          Each option is defined by a comma token separated string.
          Note that options may be conditionally shown. The following
          are examples of conditional menu options:

              #PopUpMenu(
                  // always shown since no conditinal
                  "I am cool",

                  // shown only if `p01 equals 50
                  "=`p01 50 I am fairly cool",

                  // shown only if `p01 does not equal 50
                  "!`p01 50 I am not fairly cool",

                  // shown only if `p01 is greater than 50
                  ">`p01 50 I am some really cool stuff",

                  // shown only if `p01 is less than 50
                  "<`p01 50 I am not so cool it seems",

                  // shown only if `p01 is between 70 and 80
                  ">`p01 70 <`p01 80 I am prefectly cool",

                  // shown only if bit 6 of `t69 is 1
                  "+`t69 6 I have completed the quest",

                  // shown only if bit 6 of `t69 is 0
                  "-`t69 6 I have not completed the quest" );

          You'll note that these expressions are exactly as Seth
          defined them for his REF code. I could have made them more
          readable, but that just seemed tedious and a waste of time.
          Note also that the above syntax for any function is legal.
          You can have comments between any parameters and parameters
          can be located anywhere. I believe that menu options may
          be indicated with string variables also.


      #Busy();

          This makes a player appear red to any other players. If
          they attempt to interact with the player when this is set
          then they will be given a busy message. I have no idea how
          one would turn busy off... seems Seth lacks a few things.

      #ClearLines( <firstLine>, <lastLine> );

          This would clear the lines on the screen from firstLine
          to lastLine inclusive. Integer variables may be used to
          indicate the lines to be cleared.

      #ClearScreen();

          Clears the whole screen.

      #ClearName();

          This clears the name line of the game window.
          Personally I've never seen it used and have never tried
          it out.

      #ClearUserText();

          This clears the user text.
          Personally I've never seen it used and have never tried
          it out.

      #ClearGameText();

          This clears the game text.
          Personally I've never seen it used and have never tried
          it out.

      #ClearPicture();

          This clears the picture.
          Personally I've never seen it used and have never tried
          it out.

      #ClearAll()

          This clears the user text, picture, game text, name and then
          redraws the screen.
          Personally I've never seen it used and have never tried
          it out.

      #Return;

          This cause the script to terminate immediately.

      #Drawmap();

          This draws the map the user is currently on. It does not
          bother to draw the player or any other players. Use
          #UpdatePlayers() to show all the players.

      #DrawMapBlock( <xCoord>, <yCoord> );

          This will draw a single map block with whatever is in the
          map description file for the coordinates xCoord and yCoord.
          Any players currently at these coordinates will also
          be drawn. The coordinates may be indicated using integer
          variables.

      #SetFight( "monsterName", "encounterString", "powerKillString",
                 <gender>,
                 "weapon1", "weapon2", "weapon3", "weapon4", "weapon5",
                 <defense>, <expReward>, <goldReward>, <monsterHPs>,
                 "victoryRoutine", "defeatRoutine", "fleeRoutine" );

          This sets up a fight routine which will be executed right
          after the user is returned to the map screen.

          monsterName is a string or string variable which indicates
          the name of the monster to be fought.

          encounterString is the message displayed when the player
          first encounters the monster.

          powerKillString is the message the user sees if they do a
          power move and kill the monster.

          gender is the creature's sex. 0 is female, 1 is male, 2 is it.
          You can use integer variables here also.

          weapon1-5 are string which define the attacks a monster has.
          They are of the following format:

              "weapon name|<power>"

          The first weapon is mandatory the others are not. If the
          monster only has one weapon then weapon2-5 would be set to

              "NONE|NONE"

          defense is the monsters ability to defend against damage.

          expRewarded is the amount of experience the player gets if
          they successfully defeat the monster.

          goldRewarded is the amount of gold rewarded to the player
          if they successfully defeat the monster.

          monsterHPs is the number of hitpoints the monster has.

          victoryRoutine is the REF FileName|REF Label pair that
          determines the routine to be executed if the player successfully
          defeats the monster. i.e,

              "victory.ref|turkeyDie"

          If no routine is to be executed then use

              "NONE|NONE"

          defeatRoutine and fleeRoutine follow the same format and are
          run if the player is defeated or flees respecitively. String
          variables may be used in place of strings as may integer
          variables for integer values.

      #SetGraphics( <graphicsLevel> );

          Sets the current graphics mode. Seth figures this will never
          be needed and I personally agree, but it's included anyways.
          graphicsLevel is the new graphics level and may be indicated
          using an integer variable.

      #Halt( <errorLevel> );

          Exits Lord II with the specified errorLevel. errorLevel may
          be defined using integer variables.


      #Break;

          Exits the innermost #While loop.

      #Continue;

          Jumps to the top of the innermost #While loop

      #ItemExit();

          Tell's Lord II to return to the map screen after an item's
          REF has been invoked.

      #MorePrompt();

          Displays a [MORE] prompt in the middle of the current line
          and waits for the user to hit a key.

      #BottomMorePrompt();

          Displays a [MORE] prompt in the middle of last line on the
          screen and waits for the user to hit a key.

      #TopMorePrompt();

          Displays a [MORE] prompt in the middle of first line on the
          screen and waits for the user to hit a key.

      #WaitTillKeyPressed();

          Waits until a key is pressed by the player. No prompt is
          given.

      #RestoreCursorPosition();

          Sets the cursor to the cursor position last saved by a call
          to #SaveCursorPosition.

      #SaveCursorPosition();

          Saves the current location of the cursor for later retrieval
          by a call to #LoadCursorPosition.

      #LoadGlobals();

          Loads all globals variables as were saved by the last call
          to #SaveGlobals.

      #SaveGlobals();

          Saves all the current global variable values for later
          retrieval.

      #LoadMap( <mapNumber> );

          This will load the map defined by mapNumber from the map
          file. Note that mapNumber refers to the block number not the
          physical storage location. mapNumber may be an integer
          variable also. Note to have the player actually switch maps
          you will need to set the map variable to mapNumber also.

      #LoadWorld();

          This will load all globals and world data. It has never been
          used and I didn't bother to try it out.

      #SaveWorld();

          This will save all the the stats and world data. It's current
          use is for saving random generated stats for the day.

      #SetMorePrompt( "newPrompt" );

          Sets the text to be used for calls to #MorePrompt.

      #OffMap();

          This takes the layer's symbol off the map so the user appears
          to dissapear/go into a building. Pity Seth didn't put in a
          command to make the user reappear.

      #ShowWorldMap();

          This displays the world map. All areas marked as visible will
          be shown.

      #DisplayPauseOff();

          Stops the display of large text bodies from pausing ever 24
          lines.

      #DisplayPauseOn();

          Turns 24 line pausing back on for large text bodies.

      #SetWorldName( "newName" );

          Sets the status bar name of the game.

      #RunRoutine( "routineName", "refFile" );

          Runs the routine routineName in the REF file refFile. Execution
          will return to the calling routine.

      #JumpToRoutine( "routineName", "refFile" );

          Jumps REF execution to the routine defined by routineName in
          the REF file refFile. Execution will not return to the
          calling routine.

      #ShowText( "firstLine", "secondLine", ... );

          Displays multiple lines of text. Each line of text
          is separated by a comma separator token. String variables,
          integer variables, integers and integer variables may
          be used. Embedded expandable variables can be used within
          strings to facilitate formatting.

      #ShowScrollableText( "firstLine", "secondLine", ... );

          Same as #Showtext but lines of text are put in a nifty
          scrollable window.

      #PutText( "a line of text" );

          Displays a line of text at the current cursor position.
          A string variable may be used rather than a string literal.

      #ShowSay( "some text" );

          I'm not quite sure how this works but it uses the @Say
          command and I think it places text at the current cursor
          location and attempts to format it to fit a small window.
          Seth is notorious for not describing his commands very
          clearly.

      #UpdatePlayers();

          Draws all the players in the area at their current locations.

      #SetRequiredVersion( <versionNum> );

          Sets the version of Lord II needed to run the program. If
          the player is using a lower version then they will receive
          an error.

      #SetPlayerName( "aName" );

          This will copy whatever is in `s10 to the current player's
          name.

      #PadString( <newLength> );

          This will pad the end of a string with spaces until it is of
          length newLength. newlength may defined by an integer variable.

      #PadStringFront( <newLength> );

          This will pad the front of a string with spaces until it is of
          length newLength. newlength may defined by an integer variable.

      #TrimString( <`S Var> );

          The variable defined by a variable of the form `sDD will have
          all if it's leading and ending spaces removed.

      #StripString( <`S Var> );

          Strips out all the codes from the string stored in an `sDD
          type variable.

      #StripBadString( <`S Var> );

          Strips out all illegal codes from the `sDD type variable and
          replace all badwords as defined in badword.dat with their
          "goodly" counterparts.

      #StringToUpper( <`S Var> );

          Converts a string to all upper case characters.

      #ReplaceSubString( "oldSubString", "newSubString", <`S Var> );

          Replaces the first occurrence of oldSubString with the
          string newSubString in the `sDD type variable given as
          the third parameter. oldSubString and newSubString may
          be defined by a string variable also.

      #ReplaceAllSubString( "oldSubString", "newSubString", <`S Var> );

          Replaces all occurrences of oldSubString with the
          string newSubString in the `sDD type variable given as
          the third parameter. oldSubString and newSubString may
          be defined by a string variable also.

      #StripStringCodes( <`S Var> );

          This will srip out all string codes from the `sDD type
          variable passed as parameter.

      #LordRank( "fileName", <`P Var> );

          This ranks players according to the `pDD type variable
          passed as the second parameter. The output is stored in
          fileName. filename may be defined by a string variable.

      #Rank( "fileName", <`P Var>, [ranking procedure] );

          This ranks players according to the `pDD type variable
          passed as the second parameter. The output is stored in
          fileName. filename may be defined by a string variable.
          I have no idea how this works but somehow a ranking
          procedure is needed and it does something. Seth says
          absolutely nothing about how this works and it really bugs
          me since it's not obvious.

    Assign Functions:

      The following functions return a value and must be assigned to
      a variable of their respective return type. A couple of examples
      follow:

          // stores a random number from 1 to 100 in `p69
          `p69 = #Random( 100 ) + 1;

          // stores the string length in `p69
          `p69 = #StringLength( `s10 );

          // stores any key the user is holding down in `s05
          `s05 = #KeyPressed?();

      Following are the functions which must be assigned:

      #Random( <maxRange) ) [+ <additive modifier>];

          This returns a random number from from 0 to maxRange.
          The random number then optionally has an additive modifier
          added to it. In this way you can generate random numbers
          between any integer and any other integer.
          
      #StringLength( <`S Var> );

          Returns the length of the `sDD type variable given as it's
          parameter. The length is the length after all string codes
          have been stripped out.

      #RawStringLength( <`S Var> );

          Returns the length of the `sDD type variable given as it's
          parameter. The length is the length which includes all
          string codes.

      #GetLongFromIDF( "fileName", <whichEntry> );

          Returns the long integer stored at whichEntry in the file
          named by fileName. Varaibles may be used to define the
          parameters.

      #KeyPressed?();

          Checks if the user had input a key and if so it returns the
          input key as a string. If there is no key waiting then it
          returns "_".

      #WaitForKey();

          Waits until the user inputs a key and then returns it as a
          string.

      #GetNumberFromUser( <maxDigits>,
                          [optional <foreColour>, <backColour>, <defaultNum>] );

          Gets a number from the user of maxDigits length. The user has
          the option to define the foreground and background colours of
          the input bar; however, when I tried testing it with set colours
          they didn't work. defaultNum indicates that the input bar should
          start up with this number as default. All of the parameters may
          be defined with variables. This returns an integer.

      #GetValidKeyFromUser( "validKeys" );

          Waits for the key to hit one of the keys listed in the validKeys
          string. If the user just hits enter then the first character in
          the validKeys string is considered to have been input. The
          return value is a string.

      #GetStringFromUser( <maxLength> [optional "default"] );

          Gets the user to input a string of at most maxLength
          characters and returns it. Optionally you may specify
          a default string for the input bar to open on.

      #ChoosePlayer();

          This will prompt the player for a partial or full user
          name. The function will return the player's number or
          0 if no such player exists.


Well thats it all (I think) If you have any ideas for other functions
which could be expanded into REF code then please feel free to e-mail
me and I may include them in future versions. Don't ask for a #for
loop though. I thought about it and I know how to make it work with
a minimal amount of data but as far as I'm concerned a #While loop
is sufficient for all looping.



















