_                _   _                 ____            _     _ 	
   / \   _ __   ___ | |_| |__   ___ _ __  |  _ \ _ __ ___ (_) __| |	
  / _ \ | '_ \ / _ \| __| '_ \ / _ \ '__| | | | | '__/ _ \| |/ _\` |	
 / ___ \| | | | (_) | |_| | | |  __/ |    | |_| | | | (_) | | (_| |	
/_/   \_\_| |_|\___/ \__|_| |_|\___|_|    |____/|_|  \___/|_|\__,_|	
                                                                bbs
  XQTRs lair...
Home // Blog // NULL emag. // Files // Docs // Tutors // GitHub repo
-------------------------------------------------------------------------------
    MPL Functions, Variables, Constants, Records and more
-------------------------------------------------------------------------------
    
  INDEX
  
  1. Date Functions
  2. String Manipulation
  3. Theme Related
  4. Screen Manipulation 
  Math & Number Related
  
-------------------------------------------------------------------------------
    

1. Date Functions
-------------------------------------------------------------------------------

  Function DateU2D(UnixDT:Longint):Longint
         Converts a unix time date to a DOS date time.
  
  Function DateD2U(DosDT:Longint):Longint
         Converts a DOS time date to a Unix date time.
  

  Function TIMESTR (DT: LongInt, Mode: Byte)
  changed to
  Function TIMESTR (DT: LongInt, Mode: Boolean)

         This function converts a packed datetime number into a time
         string.  The passed mode variable defines the format of the time
         string returned.  Valid options are:

              0 = 24 hour format: HH:MM:SS
              1 = 12 hour format: HH:MMa or HH:MMp

         Example:

         WriteLn ('The current time is: ', TimeStr(DateTime, 1))

         The above example outputs the current time to the screen using the
         TIMESTR and DATETIME functions.

  
  Function DATETIME : LongInt

         This function returns the current Date and Time in the packed
         format.  DATESTR and TIMESTR can be used to convert this value
         into strings.

         Example:

         WriteLn ('Current Date: ', DateStr(DateTime), 0)
         WriteLn ('Current Time: ', TimeStr(DateTime), 1)

         The above example outputs the current date and time to the screen
         using the DATESTR and TIMESTR functions.  The DateTime function
         which is passed to DATESTR and TIMESTR, contains the current date
         and time in the packed format.

  
  Function DATE2DOS (Str : String) : LongInt
        
        This function takes a MM/DD/YY format date and converts it to DOS 
        packed datetime format. 
  
  
  Function DATE2JULIAN (Str : String) : LongInt
        
        This function takes a MM/DD/YY format date and converts it to a Julian 
        date format.
        
  
  Function DATEG2J (Str : String) : LongInt
        
        This function takes a gregorian date format (MMDDYY) and converts it to
        a Julian format
        
  
  Function DATEJ2G (LI : LongInt) : String
        
        This function takes a julian date format and converts it to a gregorian 
        format (MMDDYY).
        
  
  Function DateValid(S: String) : Boolean
  
        Takes a MM/DD/YY date and returns true or false depending on if the 
        date is valid (ie, month is 01-12, etc).
  

  DateJulian:LongInt;
        Returns the longint Julian value of the current date.
        
  
  Function DATESTR (DT: LongInt, dType: Byte)

         This function will take a packed datetime number and convert it to
         a date string.  The dType parameter is used to set the format of the
         date which is returned.  Valid types are:

              
              1 = Returns date in format: MM/DD/YY
              2 = Returns date in format: DD/MM/YY
              3 = Returns date in format: YY/DD/MM

         Example:

         GetThisUser
         WriteLn ('Welcome.  You last called on ', DateStr(UserLast))

         The above example loads the currently logged in user's information
         into the USER variables using GETTHISUSER, then displays the last
         time the user has called to the screen using the DATESTR procedure. 
          No longer accepts 0 as the users current date format.  Pass the 
          user's actual date format to it if you want that.  For example:
          Str := DateStr(MyDateTime, UserDateType);
         The other parameters (ie 1 = MM/DD/YY) work as they used to.
         
 + New MPL function DateUnix returns the current date/time in Unix format

 + New MPL function DateU2D (unixdate): Converts  to a DOS date

 + New MPL function DateD2U (dosdate): Converts  to a Unix date
         
  
  Function DateStrJulian(DT: LongInt, dType: Byte)
  
        Works just like DateStr but accepts a Julian date.
        
  
  Function DayOfWeek:Byte;

        Returns a number between 0-6 depending on the day of the week:
            0 = Sun, 1 = Mon, 2 = Tue, 3 = Wed, 4 = Thu, 5 = Fri, 6 = Sat
            
  
  Function DaysAgo(J:LongInt) : LongInt

        This function takes a Julian date value and returns the number of days
        between the current date and the passed date.
        
  
  Function TIMER : LongInt

         This function will return the current number of seconds which have
         passed since midnight.  This function can be used to time how long
         a user is doing something.

         Example:

         Var StartTime LongInt
         Var EndTime   LongInt
         Var Total     LongInt
         Var Str       String

         StartTime := Timer
         Write ('Enter something: ')
         Str := Input (40, 11, 'Nothing')
         EndTime := Timer

         Total := EndTime - StartTime
         WriteLn ('You took ', Total, ' seconds to type something!')

         The above example will prompt the user to type something and time
         how long in seconds they took.  WriteLn will then display the
         number of seconds the user took to the screen.
  
  
  Function TimerMS : LongInt
      
        This may or may not stay but it provides a way to do millsecond timing 
        of things.
  
  
  Function TimerMin : LongInt
          
        Same as TimerMS, but gives time in Minutes
          
  
  Procedure FormatDate(dosDate, mask) : String;
  
        Allows you to convert a DOS format date to a string using the mask:
            YYYY - 4 digit year
              YY - 2 digit year
              MM - 2 digit month
             DDD - 3 char weekday (ie Mon Tue)
              DD - 2 digit day
              HH - 2 digit hour
              II - 2 digit minute
              SS - 2 digit second
             NNN - 3 char month (ie Jan, Feb, Mar)
       
       
  Function datedos2str(D:Longint; T:Byte) : String
        
        4 = MM/DD/YYYY
        5 = DD/MM/YYYY
        6 = YYYY/MM/DD
        
        
  Function datejulian2str(D:Longint; T:Byte) : String
  
        4 = MM/DD/YYYY
        5 = DD/MM/YYYY
        6 = YYYY/MM/DD
  


2. String Manipulation
-------------------------------------------------------------------------------
  
  Function POS (Sub: String, S: String) : Byte

         This function returns the starting position of a substring in a
         string.

         Example:

         Var A Byte

         A := POS('World', 'Hello World')
         WriteLn (A)

         The above example would output "7" to the screen becase POS
         returns the position of the text "World" in the string
         "Hello World".  If POS does not find a match, a zero will be
         returned.  IE: A := POS('Blah', 'Hello World') would return a zero
         because the text "Blah" was not found in the string "Hello World".

  
  Function CHR (B: Byte) : Char

         This function will take a numerical byte value and return it's
         ASCII character.  The byte value must be between 0 and 255 as
         there are only 255 characters in the ASCII character set.

         Example:

         WriteLn ('Hello', Chr(32), 'World')

         This will output the text "Hello World" to the screen.  The ASCII
         number for the space character is 32 and by passing a 32 to CHR,
         a space is returned.
         

  Function COPY (S: String, Index: Byte, Count: Byte) : String;

         This function will copy a defined part of a string and return
         the copied portion as a string.

         Example:

         Var Str String

         Str := 'Hello World'
         WriteLn (Copy(Str, 1, 5))

         This will output "Hello" to the screen.  The copy function takes
         the given Str and copies Count number of character from the Index.
         So the above copies 5 characters starting at the 1st character in
         Str and WriteLn outputs it to the screen.
         

  Procedure DELETE (S: String, Index: Byte, Count: Byte)

         This procedure will delete a defined portion of a string
         variable.

         Example:

         Var Str String

         Str := 'Hello World'
         Delete (Str, 6, 6);
         WriteLn (Str)

         This example will delete 6 characters from the string Str starting
         at the 6th character.  The resulting output from WriteLn will be
         "Hello"

  Procedure INSERT (Source: String, Target: String, Index: Byte)

         This procedure will insert text into a string at a specified
         location.

         Example:

         Var Str String

         Str := 'Mystic v1.00'
         Insert ('BBS ', Str, 8)
         WriteLn (Str)

         The above example will insert the text "BBS" into the Str variable
         starting at the 8th character in the string.  The result WriteLn
         output would be "Mystic BBS v1.00"

  Function INT2STR (L: LongInt) : String

         This function converts a numerical type variable to a string
         type variable.

         Example:

         Var A Byte
         Var S String

         A := 255
         S := Int2Str(A)
         WriteLn (S)

         The above example sets the numerical variable to the value of
         255, which is then converted to a string variable using Int2Str.
         The resulting value of S will be '255' as WriteLn will output to
         the screen.

  Function LENGTH (S: String) : Byte

         This function returns the length in characters of the passed
         string variable.

         Example:

         WriteLn (Length('Hello World'))

         The above example would output "11" to the screen, which is the
         number of characters in the text passed to Length.

  Function LOWER (S: String) : String

         This function converts a passed string variable to all lower
         case letters.

         Example:

         WriteLn (Lower('HELLO'))

         The above statement would output the text "hello" to the screen.
         The original text of HELLO is converted to all lower case letters
         and than displayed by WriteLn.

  Function ORD (C: Char) : Byte

         This function returns the ASCII code of the passed Char variable.
         This function works the exact opposite of the CHR function.

         Example:

         WriteLn (Ord(' '))

         The above example would output the text "32" to the screen because
         32 is the ASCII character code for space.
  
  Function INITIALS (String) : String
  
        This function takes a user name and attempts to return one or two 
        character  initials.
            S := Initials('Jack Phlash'); // should return "JP"
            
  
  Function INPUT (Field: Byte, Max: Byte, Mode: Byte, Default: string) : String
  
        This function gives input to the user, and returns the result of
        the input as a string variable.

         The Field parameter is the size of the input field (in characters)
         that the user will be able to see.  If the field size is smaller
         than the maximum number of characters allowed in the input, the
         input line will scroll when the user reaches the end.  This field
         is usually set to the same as the Max parameter.

         The Max parameter is the maximum number of characters that
         Input will allow to be entered.  Note that the Field parameter, in
         most cases, should be set to the same value as this.

         The Mode parameter is the type of input that will be accepted, and
         can be any one of the following input types:

              1 : Standard input.  All characters allowed.
              2 : Upper case input.  Allows all characters, but will convert
                  any lower case letters into upper case.
              3 : Proper input.  Allows all characters, but will convert
                  the first letter in each word to an upper case letter.
              4 : Phone input.  Allows only numbers and will pre-format them
                  using the USA-style phone numbers.  IE: XXX-XXX-XXXX.
                  Note that the length of this input should always be 12,
                  as that is the length of the USA phone number format.
              5 : Date input.  Allows only numbers and will pre-format them
                  using the date format (ie XX/XX/XX) that is currently
                  selected by the user.  NOTE: The date input will always
                  return the date in the MM/DD/YY format, regardless of what
                  format the user has selected.  For example, if the user
                  has selected the DD/MM/YY format, Input will expect the
                  user to enter the date in that format, but will then
                  convert it to MM/DD/YY when it returns the date back to
                  the MPE program.
              6 : Password input.  Allows all characters, but will convert
                  any lower case letters into upper case.  The character
                  that is typed is NOT echoed to the screen.  Instead, it
                  is replaced by the * character so that what they have
                  entered will not be shown on the screen.

         NOTE: If any of the above input values are increased by 10, Input
         will create an input field using the foreground/background color
         that has been defined for that language.  For example, input type
         11 will function the same as input type 1, but will fill an input
         field to the maximum field length.

         The Default parameter can be used to force a default text into
         the input field.  If you do not wish to have any default text in
         the buffer, supply a blank string parameter (ie '').

         EXAMPLE:

         Var Str String

         Write ('Enter something: ')
         Str := Input (30, 30, 1, '')

         The above example will print the text "Enter something: " to the
         screen and the allow input of up to 30 characters in length, using
         input type 1 (allows all characters).  No default text has been
         supplied so the input field will be empty by default.

         Var Str String

         Write ('Enter something: ')
         Str := Input (30, 30, 11, 'Default')

         The above example will function just like the first example, except
         it will create an input field background and stuff the text of
         "Default" into the input field.
         
    
  Function INPUTNY (Text: String) : Boolean

         This function prompts the user with a Yes/No question, defaulting
         to No. TRUE will be returned if the user answered Yes, or FALSE if
         the user answered No.  The passed Text variable is the text that is
         displayed to the user asking the question.

         Example:

         If Not InputNY('Do you want to run this program? ')
              Halt
         

         The above example will prompt the user with the Yes/No question
         passed as .  This question will default to No.  If the user
         answers No, the program will halt from being executed.
         

  Function INPUTYN (Text: String) : Boolean

         This function prompts the user with a Yes/No question, defaulting
         to Yes.  TRUE will be returned if the user answered Yes, or FALSE
         if the user answered No.  The passed Text variable is the text
         that is displayed to the user asking the question.

         Example:

         If Not InputYN('Do you want to run this program? ')
              Halt
  
         The above example will prompt the user with a Yes/No question,
         asking "Do you want to run this program?".  If the user responds
         No, the program will not run, using the Halt command.
         

  Function ISARROW : Boolean

         This function is used along with the READKEY function.  After
         READKEY is called, this function can be checked to process various
         extended keys, such as arrow keys.  When ISARROW is true, READKEY
         will return the following:

         ASCII #     Char     Key Pressed
         -------     ----     -----------
         71          G        Home
         72          H        Up Arrow
         73          I        Page Up
         75          K        Left Arrow
         77          M        Right Arrow
         79          O        End
         80          P        Down Arrow
         81          Q        Page Down
         83          S        Delete

         The character returned by READKEY can be checked by either the
         ASCII # or the actual character.  Below is an example:

         Example:

         Var Ch Char

         Ch := ReadKey                 # Input one key

         If IsArrow                    # Is key returned an arrow key?
           If Ch = 'H'
             WriteLn ('Up arrow')
           Else If Ch = Chr(80)
             WriteLn ('Down arrow')
         Else                          # No arrow key.  A normal character
           WriteLn ('You entered character: ', Ch)
         End

         The above example reads a key with READKEY and then uses the
         ISARROW function to process the Up Arrow and Down Arrow keys.
  

  Function StrMci(Str:String) : String;   [mci2str also works]
  
        StrMci takes an entire string and attempts to translate any MCI codes 
        found in it, returning the entire result. Ex:
            S := StrMci('Hello |UH');
            
  
  Function PADCT (S: String, N: Byte, C: Char) : String

         This function pads a string to the center with the specified
         character.

         Example:

         Var Str String

         Str := PadCT('Hello World', 80, ' ')
         WriteLn (Str)

         The above example would display the text "Hello World" centered on
         the screen.  The PadCT function returns the text "Hello World"
         centered in 80 spaces with the character of " " used to fill the
         blank spaces.


  Function PADLT (S: String, N: Byte, C: Char) : String

         This function returns a text string padded with spaces to the
         left side.

         Example:

         Var Str String

         Str := PadLT('Hello World', 79, ' ')

         The above example would return a string which is 79 characters in
         length with the text "Hello World" as the leftmost part of the
         string.  The passed character is the character that is used to
         fill the blank spaces.


  Function PADRT (S: String, N: Byte, C: Char) : String

         This function returns a text string padded with spaces to the
         right side.

         Example:

         Var Str String

         Str := PadRT('Hello World', 79, ' ')

         The above example would return a string which is 79 characters in
         length with the text "Hello World" being the rightmost part of the
         string.  The empty spaces are filled with the passed charcter (in
         this case ' ').


  Function STR2INT (S: String) : LongInt

         This function converts a passed string variable to a numerical
         variable.  The passed string variable must contain a valid number.

         Example:

         Var A Byte
         Var S String

         S := '100'
         A := Str2Int(S)

         WriteLn (S)
         WriteLn (A)

         The above example will output "100" twice the screen.  The
         variable S is assigned to '100' and the function Str2Int converts
         the string into a numerical value which is assigned to variable
         A.


  Function STRIPMCI (S : String) : String

         This function will strip the passed string variable of all MCI
         codes and return the "cleaned" version.

         Example

         Var S String

         S := '|10|H|02ello |10W|02orld|07'

         WriteLn ('Normal   : ', S)
         WriteLn ('Stripped : ', StripMCI(S))

         The above example assigns a string with MCI codes in it to the S
         variable.  It then writes the original string and the stripped
         string to the screen, so the difference is shown.


  Function STRREP (Ch: Char, Num: Byte) : String

         This function returns a string filled with character  to the
         length of .

         Example:

         WriteLn (strRep('-', 60 ))

         The above example will use strRep to create a string 60 characters
         long of the character '-', then write it to the screen.  So the
         outputted text would look like:

         "------------------------------------------------------------"


  Function UPPER (S: String) : String

         This function coverts the passed string variable to all upper
         case letters.

         Example:

         WriteLn (Upper('hello'))

         The above example would output the text "HELLO" to the screen.
         The UPPER function converts the passed text of "hello" to all
         upper cased letters, which is then printed to the screen by
         WriteLn.
    

  Function StrComma(L:LongInt) : String;
  
        Accepts a longint and returns it as a string, with commas added where
        applicable: Ex:
            WriteLn (strComma(1000000));  // will print 1,000,000
  
  
  Function StripL(Str1,Str2:String) : String;

        Strips the left side of a string of any specified leading characters. Ex:
            Var S : String = '    Hello';
            S := StripL(S, ' ');
            
      
  Function StripR(Str1,Str2:String) : String;
        Strips the right side of a string of any specifcied trailing character:
            Var S : String = 'Hello     ';
            S := StripR(S, ' ');
     
     
  Function StripB(Str1,Str2:String) : String;
  
        Strips both sides of the string if a specific character.
            Var S : String = '     Hello     ';
            S := StripB(S, ' ');
  
  
  Function StripLow(S: String) : String
  
        Strips all chracters from a string that are less than ascii code #32. Ex:
            Var S : String = #12#12#12#12 + 'Hello';
            S := StripLow(S);
  
  
  Function stripmci(S:String) : String
        
        Returns a string without any MCI codes if included in the string.
        
  
  Function StripPipe(Str:String) : String
  
      Takes a string and strips only pipe color codes from it. Ex:
          S := StripPipe('|15Hello there, |UH');  //returns "Hello There, |UH"
          
  
  Function MCILength(Str:String) : Byte;
  
        Works just like "Length" except it tries to ignore MCI codes.  It doesn't 
        check for actual validity of MCI codes. Ex:
            Var B : Byte;
            B := MCILength('|15Hello|UH');
            WriteLn ('Length should be 5: ' + Int2Str(B));
  
  Function Initials(Str:String) : String
  
        Takes a user name and attempts to return one or two character initials. Ex:
            S := Initials('Jack Phlash'); // should return "JP"
        
        
  Function StrWrap(S:String; S2:String; Pos:Byte) : String;
  
        strWrap takes two strings and wraps them after the word closest to the 
        maximum supplied length.  It optionally returns the actual position where it
        wrapped. Ex:
            Var Str   : String = 'This will wrap';
            Var Str2  : String = '';
            Var Where : Byte;
            Where := strWrap(Str, Str2, 10);
            WriteLn ('It wrapped at ' + Int2Str(Where));
            WriteLn ('First string: ' + Str);
            WriteLn ('Second string: ' + Str2);
  
  
  Function Replace(S:String; Find:String; Rep:String):String;

        Replace replaces all occurances of a supplied text and returns a 
        string.  Ex:
            Var Str : String = 'Hello Hello Hello';
            Str := Replace(Str, 'Hello', 'World');  // Str is now World World 
                                                    // World
                                                    
  
  Function WordCount(S: String; C:Char):Integer;
  
        Returns the number of words in a string using the final parameter to 
        define the character that determines what separates words.  Ex:
            Str := 'Hello this is a test';
            WriteLn ('Str has ' + Int2Str(WordCount(Str, ' ')) + 
            ' words in it.');
              
      
  Function WordGet(P:Byte; S:String; C:Char):String;
  
        Returns the actual word at a specific word count. Ex:
            Str := 'Hello this is a test';
            WriteLn('The second word was: ' + WordGet(2, Str, ' '));

      
  Function WordPos((P:Byte; S:String; C:Char):Integer;
  
        WordPos returns the character position in the string where s specific 
        word is located.  Ex:
            Str := 'Hello this is a test';
            WriteLn ('Second word is at: ' + Int2Str(WordPos(2, Str, ' ')));
      
      
  Function Real2Str(R:Real; D:Byte) : String;
  
        This takes a string and decimal place value.  Example:
            Var
              R : Real;
            Begin
              R := 1234.1234;
              WriteLn (Real2Str(R, 2));  // Will print 1234.12
            End
            

3. Theme Related
-------------------------------------------------------------------------------

  Function GETPROMPT (N : Word) : String

         This function will return a prompt from the current user's language
         file.  The passed N varliable is the prompt number to return.

         Example:

         WriteLn(GetPrompt(1))

         The above example writes prompt #1 from the user's currently
         selected language file to the screen.
  
  
  Procedure SetPromptInfo(D:Byte; S:String);
  
        This allows you to set Mystic's internal "changing" PromptInfo MCI codes 
        (the |&X codes).  For example:
            SetPromptInfo(1, 'Hello!');
            WriteLn ('This MCI code would like to say: |&1');

4. Screen Manipulation
-------------------------------------------------------------------------------
  
  Variables
  =========
  
  allowarrow  : boolean
  
          Undocumented
          
          
  textattr    :   Byte
          
          Returns the text attribute (color) of the screen.
          
  
  AllowMci        boolean
          
          Toggles on/off MCI code parsing. This is used outside of MPL so 
          adjust this with caution.
          
          
  Functions
  =========
  
  Function GRAPHICS : Byte

         This function returns the user's current graphics mode in
         numerical format:

              0 = ASCII graphics mode
              1 = ANSI graphics mode

         Example:

         If Graphics = 1
              WriteLn ('ANSI graphics')
         Else
              WriteLn ('ASCII graphics')
         EndIf

         The above example will print the user's current graphics mode
         to the screen.  If the user has ANSI (graphics mode 1), "ANSI
         graphics" will be printed.  If the user does not have ANSI
         (graphics mode 0), "ASCII graphics" will be printed to the screen.
  
  
  Function PausePos : Byte
  
        Gives access to Mystic's internal line counter used for screen pauses.
  
  
  Procedure MOVEX (Pos : Byte)

         This procedure is used to move the cursor to the passed X coordinate
         on the screen.  It only works if the user has ANSI graphics enabled.

         Example:

         MoveX (20)
         WriteLn ('This text starts on the 20th space')
         

  Procedure MOVEY (Pos : Byte)

         This procedure is used to move the cursor to the passed Y coordinate
         on the screen.  It only works if the user has ANSI graphics enabled.

         Example:

         MoveY (10)
         WriteLn ('This is on the 10th line of the screen')
         
  
  Procedure GetScreenInfo(1, X, Y, Attr);
  
        This allows you to read Mystic's internal ScreenInfo codes, used in 
        Templates so your MPLs can easily have templates just like Mystic!  
        These are the |!X codes. Example:

           Var
             X, Y, Attr : Byte;
           Begin
             GetScreenInfo(1, X, Y, Attr);

             WriteLn('The value of the !1 MCI code was:');
             WriteLn('   X: ' + Int2Str(X));
             WriteLn('   Y: ' + Int2Str(Y));
             WriteLn('Attr: ' + Int2Str(Attr));
           End;
  
     
  Function GetCharXY(X,Y;Byte) : Char;
  
          Returns the character located on the user's screen at the XY
          location. Ex:
              Var Ch : Char;
              Ch := GetCharXY(1, 1);
              WriteLn('The user has the following character at 1,1: ' + Ch);
              
     
  Function GetAttrXY(X,Y;Byte) : Byte;
  
        Returns the attribute of the character at position XY on the user's 
        screen:
            Var Attr : Byte;
            Attr := GetAttrXY(1, 1);
            WriteLn ('The attribure of the character at 1,1 is: ' + 
            strI2S(Attr));
  

  Procedure GotoXY (X: Byte, Y:Byte)
  
        This procedure will move the cursor to a specified X and Y position on 
        the screen. This only works for users who have ANSI graphics
        
  
  Procedure WritePipe(S: String);
  
        Works just like Write but only parses Pipe color codes instead of all 
        MCI codes.
        
  
  Procedure WritePipeLn(S: String);
  
        Is WritePipe with a CRLF at the end.
        

  Procedure WriteRaw(S: String);
  
        Works just like write except it does not parse any pipe color codes OR 
        MCI codes.

  WriteRawLn(S: String);
  Works just like WriteRaw except with a CRLF added to the end.
  
  WriteXY(X,Y,At:Byte; Str:String);
  Writes a string of text at the defined X/Y location with a specific text
  attribute.  This of course requires the user has ANSI to function properly.
      WriteXY (1, 10, 8, 'Prints at X:1 Y:10 with dark grey text');
      
  WriteXYPipe(X,Y,At,F:Byte; Str:String);
  This procedure writes a string of text at the defined location, similar to 
  WriteXY *except* it parses pipe color codes *and* requires a "maximum field 
  size" of which it will always extend or restrict the length of the text 
  within that field. Ex:
        WriteXYPipe (1, 10, 8, 50, 'This pads to 50 chars at location 1,10');
  
  Procedure WRITE (Text)

         This procedure is used to write text to the screen without
         going to the next line (ie, without sending a carriage return).

         All text to be printed to the screen should be enclosed inside of
         ' characters.  If you wish to print the value of a variable to
         the screen, just include the variable name without the '
         characters.  If you wish to combine multiple text and variables,
         they must be separated by commas.

         Examples:

         Write ('Hello ')
         Write ('World')

         This example will write the text "Hello World" to the screen.

         Write ('Hello World')

         This example does the exact same thing as the function above, but
         makes a little more sense.

         Var Str String

         Str := 'Hello World'
         Write (Str)

         This example will write the value held in the variable Str to the
         screen.  The resulting output will be "Hello World"

         Var Str String

         Str := 'Hello '
         Write (Str, 'World')

         This example will write the value of the variable Str to the
         screen, followed by the text "World".  The resulting output will
         be "Hello World".  An unlimited number of variables and text can
         be outputted with the Write statement, but they must all be
         separated by a comma, as shown above.

         If a ' character needs to be printed to the screen, it can be done
         by doubling the ' character.  For example:

         Write ('This is how it''s done.')

         The resulting screen output will be "This is how it's done", with
         only one ' character.

         All MCI display codes can be used within the Write statement.  If
         you wish to change the display colors, use the MCI color system to
         do so.  For example:

         Write ('~14Hello World')

         This example will write the text Hello World in yellow to the
         screen.  All MCI display codes are available to the write
         statement.

    Procedure WRITELN (Text)

         This procedure outputs text to the screen.  It functioning is
         identical to the WRITE statement except that it goes to the next
         line after the text is printed (ie, it sends a carriage return).

         For example:

         WriteLn ('Hello')
         WriteLn ('World')

         The above example will write the text "Hello" on one line, and
         then the text of "World" on the next line.
         
  clrscr           none         none
  clreol           none         none
  
  Function WHEREX : Byte

         This function returns the current X coordinate of the cursor.

         Example:

         Var X Byte
         Var Y Byte

         X := WhereX
         Y := WhereY

         WriteLn ('      World')
         GotoXY  (X, Y)
         WriteLn ('Hello')

         The above example will save the current X and Y cursor positions
         and then write the text "World" to the screen.  After which, it
         will return to the saved X and Y position and write the text
         "Hello" to the screen.  The end result will be the text of
         "Hello World" written to the screen.  Note: GotoXY can only be
         used if the user has ANSI graphics mode.

    Function WHEREY : Byte

         This function returns the current Y coordinate of the cursor.
         For more information on this function, please see the definition
         of the WHEREX function.
  
  Procedure DISPFILE (FN: String)

         This procedure displays a text or ANSI file to the screen.  If a
         path not included in the passed filename, Mystic will look for
         the file in the language text file directory.  If no file
         extension is provided in the passed file name, Mystic will display
         the correct file according to the user's graphics settings
         (ie .ANS for ANSI, .ASC for non-ansi).

         Example:

         DispFile ('WELCOME')

         The above example will display the text file "WELCOME" from the
         language text file directory.  Since there is no file extension
         provided, Mystic will display "WELCOME.ANS" or "WELCOME.ASC"
         depending on what the user's terminal settings are.
  
  disptemplate     s            None
  outbs            bo           None
  textcolor        bo           None
  outpipe          s            None
  outpipeln        s            None
  outraw           s            None
  outrawln         s            None
  bufaddstr        s            None
  
  BufFlush;
  This causes Mystic to immediately send whatever is in the output buffer to 
  the client.
  

Program related
---------------
  Variables
  
  PathChar : String;
  Returns the Path character used, according to the system. For Linux is / and
  for Windows is \.
  
  ProgParams : String
  Returns any of the parameters passed to the MPL program as a single string.
  
  ProgName : String;
  Returns the path and filename of the current MPL program.
  
  Procedures/Functions
  
  Procedure HALT
  This procedure will exit the program and return the user back to the BBS 
  immediately. 
  
  Procedure DELAY (MS: Word)
         This procedure will delay for a specified number of milliseconds.
         Example:
         DELAY (1000)
         The above example will delay the program for one second.
         
  Function RANDOM (Max: Word) : Word

         This function will return a random number within the range
         specified.

         Example:

         Var A Byte

         A := Random(255)
         WriteLn (A)

         The above example will generate a random number within the range
         of 0 to 255 in the variable A and then print it to the screen.       
  
  
  randomize        none         none
  
  Function PARAMCOUNT : Byte

         This function is used to determine the number of command line
         options which have been passed to the MPE program.  For more
         information, see the PARAMSTR function.

         Example:

         If ParamCount < 2
              WriteLn ('Invalid command line.')
              Halt
         EndIf

         The above example will check to see if less than 2 command line
         options have been passed to the MPE program.  If there are less
         than two, the program will terminal with a "invalid command line"
         message.

    Function PARAMSTR (Number : Byte) : String

         This function returns the command line option specified by the
         NUMBER parameter.  A command line is the optional data which
         is passed on the "Data" field of a menu command.  For example,
         when defining a menu command which executes an MPE program in
         the menu editor, the text after the program name becomes command
         line options.

         Menu Command: GX
         Data        : BULLETIN p1 p2 p3 p4

         If the above was defined in the menu editor, the following would
         be true:

         ParamCount  would return 4
         ParanStr(0) would return "BULLETIN"
         ParamStr(1) would return "p1"
         ParamStr(2) would return "p2"
         ParamStr(3) would return "p3"
         ParamStr(4) would return "p4"

         Note that ParamStr(0) will ALWAYS return the file name of the
         MPE program being executed.  Even when there are no other
         parameters defined.
  
  IgnoreGroups    boolean
  Is used to cause all group ACS evaluations to return true even if they are 
  not in the group.  This is also used outside of MPL so change it with caution.
  
  shutdown        boolean
  
  Procedure SYSOPLOG (S: String)

         This procedure will add a line into the sysop log file found in
         the logs directory.

         Example:

         SysopLog ('User ran this program.')

         The above example will write the text "User ran this program" in
         the system log file, using the same format as Mystic uses in the
         log files (ie, the date and time will automatically be added).
  
  Procedure HANGUP

         This procedure will stop the program immediately, hangup up on the
         user, and return Mystic BBS to the waiting for caller screen.

         Example:

         If InputYN ('Do you want to hangup now? ')
              HangUp
         EndIf

         The above example will prompt the user with a Yes/No question
         asking "Do you want to hangup now?" and if the user responds
         "Yes", they will be logged off the BBS using the HangUp command.
  
  Procedure MENUCMD (CM: String, Data: String)

         This procedure will allow menu commands to be ran from within a
         program.   is the menu command, and  is the menu command
         data.

         Example:

         MenuCmd ('NW', '')

         The above example will run the menu command "NW" with the optional
         data field set to nothing.  This example will display the Who's
         Online list.  See MYSTIC.DOC for a list of all available menu
         commands.

    Function NODENUM : Byte

         This function returns the current node number which the program
         is being ran on.

         Example:

         WriteLn ('Welcome to node number ', NodeNum)

         The above example will print the text "welcome to node number x"
         to the screen, where the x will be the current node number which
         the program is being ran on.
  
  Function LOCAL : Boolean

         This function returns TRUE if the user is logged into the BBS
         system locally.  It will return FALSE if the user is connected
         via a remote location.

         Example:

         If Local Then
           WriteLn ('Local caller detected.')
         Else
           WriteLn ('Remote caller detected.')
         EndIf

Keyboard Related
----------------
  
  Variables
  =========
  
  isarrow         boolean
  
  Procedures
  ==========
  
  Function READKEY : Char

         This function will read a key from the buffer and return it as
         a char variable.  If there are no keys in the buffer, readkey will
         wait for a key to be pressed.

         Example:

         Var Ch Char

         Repeat Until KeyPressed
         Ch := ReadKey

         WriteLn ('You entered: ', Ch)

         The above example will wait for a key to be pressed by using the
         KEYPRESSED function.  Afterwards, the key will be read into the
         CH variable using readkey, and then print it to the screen.
  
  getkey           l            String
  getyn            so           boolean
  getstr           bbhs         String
  pause            none         None
  more             none         String
  onekey           so           String
  
  Procedure STUFFKEY (S : String)

         This function will stuff a string of text into the keyboard
         buffer.  This can be used to force your program into thinking
         the user had actually typed "S".

         Example:

         Var Ch Char

         StuffKey ('A')
         Ch := ReadKey
         WriteLn ('You entered: ', Ch)

         The above example will stuff the character "A" into the input
         buffer, where it will be read into Ch using the ReadKey function.
         It is possible to stuff entire strings of text into the buffer
         too.

         Example:

         Var Str String
         StuffKey 'Hello World'
         Str := Input (20, 20, 1, '')

         The above example will stuff "Hello World" into the input buffer.
         This will cause the input function to think the user has actually
         typed in "Hello World".  In this case, the above is the same as
         supplying "Hello World" in the  field of the Input
         function.
  
  Function KEYPRESSED : Boolean

         This function returns TRUE if a key has been pressed either
         remotely or locally.  Keep in mind two things about this
         function:

              (1) It doesn't check for inactivity timeout.  If you are
                  using this function to wait for a key to be pressed then
                  you may want to use the TIMER function and check for
                  inactivity.
              (2) This function only returns whether a key was PRESSED.
                  It does not actually read the key out of the buffer.
                  See the READKEY function for reading keys from the
                  buffer.

         Example:

         Repeat
         Until KeyPressed

         WriteLn ('You pressed a key!')

         The above example will wait for a key to be pressed and then
         write to the screen "You pressed a key!".
  
  PurgeInput;
  This will clear out any local or remote input data.
  
  OneKeyRange
  This function works similar to OneKey, except that it will also allow for a 
  number input within a certain range.  The number value is stored in a 
  variable called RangeValue and the function returns a #0 if a number was 
  entered.  For example:
       Var
         Ch : Char;
       Begin
         Write ('Enter letters A-G or a number between 1-50: ');

         Ch := OneKeyRange('ABCDEFG', 1, 50);

         If Ch = #0 Then
           WriteLn ('You entered a number: ' + Int2Str(RangeValue))
         Else
           WriteLn ('You entered character: ' + Ch);
       End.
  
  MorePrompt;
  Displays the system more prompt and returns a Char value of either Y N or C 
  depending on what the user selected.
  
  Pause;
  Displays the system pause prompt, for those that don't like doing a 
  "Write('|PA')".
  
File I/O
--------

  Variables
  
  ioresult        LongInt
  The result of the last call is now stored in the "IoResult" variable.  Ex:
      fAssign (MyFile, 'myfile.txt' 66);
      fReset  (MyFile);

      If IoResult <> 0 Then
        WriteLn('Unable to open file!');
  
  DIRECTORY READING VARS (FOR FINDFIRST/NEXT/CLOSE):

  doserror        Integer
  dirname         String
  dirsize         LongInt
  dirtime         LongInt
  dirattr         Byte
  
  Procedures
  ==========
  
  Function fEOF (Handle) : Boolean

         This function will return true if the file position of an opened
         file is at the End Of the File (EOF).  The passed Handle value is
         the file number of the already opened file.

         Example:

         Var Str String

         FOpen (1, Text, Reset, 'BLAH.TXT')
         While Not fEOF(1)
              FReadLn (1, Str)
              WriteLn (Str)
         End
         FClose (1)

         The above example will open a text file under the filename of
         BLAH.TXT.  The WHILE loop is used to repeat the code until the
         EOF (end of file) is reached.  The FCLOSE statement will close
         the file after it is done being accessed.

         The result of the above example will be (in pseudocode):

         1. Open text file.
         2. If not at the end of file, run this code:
         3. Read line from text file into string variable
         4. Print line read from text file to the screen.
         5. Goto 2.
         6. Close the text file.

         So the above example will basically write the entire text file to
         the screen.
  
  SizeOf(Var) : Integer;
  Returns the size of a variable or record type
  
  
  FillChar(Var; Size:Integer; C:Char);
  Fills a variable/record with a specific character. Ex:
       type
         myuserrecord = record
           username  : string[30];
           somevalue : array[1..5] of byte;
         end;
       var
         u : myuserrecord;
       begin
         fillchar(u, sizeof(u), #0);
       end.
  
  Function FileExist (FileName: String) : Boolean

         The above function will check to see if a file exists, and return
         TRUE if it does.  The passed FileName string if the path and file
         name of the file to check.  This file should not already be opened
         with the FOPEN procedure.

         Example:

         If FileExist('BLAH.TXT')
              WriteLn ('BLAH.TXT exists.')
         Else
              WriteLn ('BLAH.TXT does NOT exist.')
         

         The above example will check to see if the file "BLAH.TXT" exists
         and if it does, will output "BLAH.TXT exists" to the screen.  If
         BLAH.TXT does NOT exist, the output will be "BLAH.TXT does NOT
         exist".
  
  Procedure FileErase (FileName: String)

         This procedure is used to erase an existing file from the disk.
         The FileName variable is a string variable which contains the
         file name which is to be erased.  The result of the FERASE
         procedure can be checked by checking the DOSERROR function.
         DOSERROR will return a 0 if successful or a 2 if an error occured.

         Example:

         FileErase ('C:\HELLO.TXT')

         The above example will erase the file "C:\HELLO.TXT" if it exists.
  
  DirExist(S:String) : Boolean;
  Returns true or false if a directory exists.
  
  Function FileCopy (Source: String, Dest: String) : Boolean

         This function will copy a file from the specified source location
         to the specified destination location.  The function will return
         as TRUE if the file was copied successfully, or FALSE if an error
         occured.  Note:  The file which is being copied should not already
         be opened for File I/O by the program.

         Example:

         Write ('Copying C:\HELLO.TXT -> D:\HELLO.TXT: ')

         If FileCopy ('C:\HELLO.TXT', 'D:\HELLO.TXT')
              WriteLn ('OK')
         Else
              WriteLn ('ERROR')
         

         The above example will attempt to copy the file "C:\HELLO.TXT" to
         the destination of "D:\HELLO.TXT".  If the file is copied without
         any problems an "OK" will be printed to the screen.  If an error
         occured while copying, "ERROR" will be printed to the screen.
  
  JustFile(S:String) : String;
  Takes a string arguement and returns only the filename. Ex:
      WriteLn ('This MPX filename is: ' + JustFile(ProgName));
      
  JustFileName(S:String) : String;
  Takes a string arguement and returns only the base filename (ie, not the 
  extension so it basically just removes a file extension).  This does not
  remove a path, JustFile does that.
   
  JustFileExt(S:String) : String;
  Takes a string arguement and returns only the file extension.
  
  fassign          Fsl          None
  freset           F            None
  frewrite         F            None
  fclose           F            None
  fseek            F            None
  feof             F            boolean
  
  Function FILEPOS (Handle) : LongInt

         This function returns the current file position of an opened
         file.  The passed Handle is the file handle number used when the
         file was opened.  The FilePos function only works for files that
         are opened as Binary, since Text files are read line by line.

         Example:

         fOpen (1, Bin, Reset, 'TEST.DAT')
         If FilePos(1) = FileSize(1)
              WriteLn ('END OF FILE.')
         EndIf
         fClose (1)

         The above example opens the file "TEST.DAT" for binary and then
         writes to the screen if the file position is at the end of the
         file.  The above statement "FilePos(1) = FileSize(1)" is the same
         as "Eof(1)" since it's stating "if the file position is equal to
         the total file size, then we're at the end of the file."

    Function FILESIZE (Handle) : LongInt

         This function returns the total file size of an opened file.  The
         passed Handle is the file handle number used when the file was
         opened.  This function only works with files that have been opened
         as Binary since Text files are read line by line.

         Example:

         fOpen (1, Bin, Reset, 'TEST.DAT')
         WriteLn ('This file is ', FileSize(1), ' bytes in size.')
         fClose (1)

         The above example opens the file "TEST.DAT", writes the size of
         the file to the screen, and then closes the file.
  
  fread            F*w          None
  freadrec
  fwrite           F*w          None
  rwriterec
  freadln          FS           None
  fwriteln         FS           None
  pathsep          none         String

  Function DOSERROR : Byte
         This function returns the current DosError and is used with the
         FindFirst and FindNext functions.  The possible values which may
         be returned by DosError are as follows:

         Value  Meaning
         -----  ---------------------
           0    No error
           2    File not found
           3    Path not found
           5    Access denied
           6    Invalid handle
           8    Not enough memory
          10    Invalid environment
          11    Invalid format
          18    No more files
         -----  ---------------------

         Example:

         FindFirst ('*.*', AnyFile)
         While DosError = 0
              WriteLn ('File Name: ', DirName)
              FindNext
         WEnd
         FindClose                

         The above example will list all files in the current directory.
         The DosError function is used to return when there are no more
         files to be listed.  For more information on this see the reference
         for the FindFirst and FindNext functions.

    Procedure FINDCLOSE
         This function is used along with the FindFirst and FindNext
         functions.  It is called only after all "Find" procedures have
         completed.  See the "FindFirst" and "FindNext" command references
         for more information.

    Procedure FINDFIRST (Mask : String, Attributes)

         This function is used to search a drive for files using a supplied
         file mask and attribute list.  The results of the search are held
         in the DIR variables as listed below.

         Mask : The mask variable must contain at least a file mask
                (ie "*.*") but can also contain a drive and directory name
                as well (ie "C:\MYSTIC\TEXT\*.*").

         Attributes : The file attributes are used to specify what type of
                      files to return in the DIR variables.  The following
                      is a list of supported file attributes:

                      Attribute   Description
                      ----------- -------------------------
                      ReadOnly    Return files marked as "read only".
                      Hidden      Return files marked as "hidden".
                      SysFile     Return files marked as "system files".
                      VolumeID    Return files marked as "volume ID".
                      Directory   Return files marked as "directory".
                      Archive     Return files marked as "archive".
                      AnyFile     Returns any and all files.

                      These attributes can be combined when passed to
                      FindFirst.  For example: READONLY + HIDDEN will return
                      any files which have been marked as "readonly" OR
                      "hidden".  Example: DIRECTORY will only return names
                      of directories.

         DIR Variables : The DIR variables are what contain the information
                         returned by the FindFirst command.  If your program
                         is going to use these variables, it must be declared
                         with the USES statement at the beginning of your
                         program source code.  The following DIR variables
                         are supported:

                         DirName : Holds the file name.
                         DirSize : Holds the file size.
                         DirTime : Holds the file date and time in packed
                                   date format.  The DateSTR and TimeSTR
                                   functions will need to be used in order
                                   to display these.

         Example:

         USES DIR

         WriteLn ('The following files are in the C:\ directory:')
         WriteLn ('')

         FindFirst ('C:\*.*', ReadOnly + Archive)
         While DosError = 0
              WriteLn ('File Name: ', DirName)
              WriteLn ('     Size: ', DirSize)
              WriteLn ('     Date: ', DateSTR(DirTime), 0)
              WriteLn ('     Time: ', TimeSTR(DirTime), 1)
              Write   ('Press a key to search for more.~PN')
              FindNext
         WEnd
         FindClose

         WriteLn ('No more files have been found.')

         The above example will list all files which fit the file mask of
         "C:\*.*" and fit the attributes of either ReadOnly or Archive.
         The DOSERROR function is used to determine when there are no more
         files found (See the DOSERROR reference).  If a file has been
         found, it will then be printed to the screen using the DIR
         variables.  The FindNext functon is used to find the next file
         that matches the name and attributes specified in the earlier call
         to FindFirst.  FindClose is used when all "Find" functions have been
         completed.

    Procedure FINDNEXT

         This procedure is used to find the next file which matches the file
         mask and attibutes specified in the last call to FindFirst.

         Example:

         Uses DIR

         FindFirst ('*.*', Archive)
         While DosError = 0
              WriteLn ('File Name: ', DirName)
              FindNext
         WEnd
         FindClose

         The above example uses the FindFirst/FindNext functions to do a
         listing of all files in the current directory.  The DosError
         function is used to determine when no more files have been found.
  
  JustPath(S: String) : String;
  Takes a string arguement and returns only the path (including the trailing
  backslash).  Ex:
      WriteLn ('This MPX is located in ' + JustPath(ProgName));
      
  getsauce         sSSSS        boolean
  
  FileOpen
     FileEOF
     FileRead
     FileSeek
     FilePos
     FileSize
     FileWrite
     FileWriteBlock
     FileRead
     FileReadBlock
     FileClose
  
  AddSlash(String) : String;
  Takes a directory and appends the appropriate ending backslash or forward
  slash depending on operating system.  If the slash is already there, it does
  nothing.
  
  AppendText (FileName, Text: String)
  This procedure will append a single line of text onto a text file.  If the
  file does not exist, it will be created.  Example:
      AppendText("c:\test.txt', 'This is a line of text added to test.txt!')
  
User Related
------------

  Variables

  userid          LongInt
  username        String[30]
  userhandle      String[30]
  userpw          String[20]
  useradd         String[30]
  usercity        String[25]
  userzip         String[10]
  userhphone      String[15]
  userdphone      String[15]
  usergender      String[1]
  userbday        LongInt    // julian date
  useremail       String[40]
  userinfo        String[40]
  usersec         Byte
  userstart       String[20]
  userexp         String[8]
  userexpto       Byte
  useraf1         LongInt
  useraf2         LongInt
  userdtype       Byte
  userscrnsize    Byte
  userhotkey      Boolean
  userfsedit      Boolean
  userquotewin    Boolean
  userflist       Boolean
  usermread       Boolean
  usermidx        Boolean
  usermeidx       Boolean
  userchat        Boolean
  usersig         Boolean
  usersigptr      LongInt
  userarc         String[4]
  usertheme       String[20]
  usercname       String[30]
  userinvis       Boolean
  useravail       Boolean
  userpip         String[20]
  userpname       String[50]
  usertime        Integer
  usercmbase      Word
  usercmgroup     Word
  usercfbase      Word
  usercfgroup     Word
  usercall        LongInt
  usertcall       Word
  userdls         LongInt
  usertdls        Word
  userdlkb        LongInt
  usertdlkb       LongInt
  userfcall       LongInt   //dos date
  userlcall       LongInt   //dos date
  userposts       LongInt
  useremails      LongInt
  useruls         LongInt
  userulkb        LongInt
  userbank        Word
  userlastpw      String[8]
  uservyes        Byte
  uservno         Byte
  userdoors       LongInt
  userflag        LongInt
  useropts        Array[1..10] of String[60];
  UserLastOn
  UserFirstOn
  
  Procedure UPUSER (Sec: Byte)

         This procedure will upgrade the currently logged in user's
         security level using the validation system.  The passed value
         is the security level to upgrade to and must be between the
         range of 0 to 255.

         Example:

         WriteLn ('Upgrading your access to level 20')
         UpUser (20)

         The above example will do a validation upgrade to the security
         level of 20.
  
  Function ACS (S: String) : Boolean

         This function processes an ACS string and returns true if the user
         has passed.

         Example:

         If ACS('s10g1')
              WriteLn ('You have access to this.')
         Else
              WriteLn ('Sorry, you do not have access.')
         EndIf

         The above example checks to see if the user passes the ACS string
         of "s10g1" and prints the result to the screen.
  
  
  Function GETUSER (N: Integer) : Boolean

         This procedure will read user data into the USER variables.  The
         supplied N is the record number to read.  The function returns
         true if the record was read, or false if a record was not read.
         The following USER variables will be set when a record is read:

         Variable Name   Type     Description
         -------------------------------------------------------------------
         USERDELETED     Boolean  Is the user marked as deleted?
         USERNAME        String   User's real name.
         USERALIAS       String   User's BBS alias.
         USERPASSWORD    String   User's password.
         USERADDRESS     String   User's street address.
         USERCITY        String   User's City/State.
         USERZIP         String   User's ZipCode.
         USERHPHONE      String   User's home phone number.
         USERDPHONE      String   User's data phone number.
         USERBDAY        String   User's birth date.
         USERSEX         Char     User's gender (M = Male, F = FeMale).
         USERSEC         Byte     User's security level (0-255).
         USERMENU        String   User's Starting Menu (if blank, Mystic
                                  uses the default menu as setup in the
                                  configuration).
         USERFIRST       LongInt  User's date/time of first call to the BBS.
                                  This is stored in the packed date format
                                  so in order to display the date & time,
                                  the functions of DATESTR and TIMESTR need
                                  to be used.
         USERLAST        LongInt  User's date/time of the last call to the
                                  BBS.  This is also stored in a packed date
                                  format, so the same rules for USERFIRST
                                  apply to this.
         USERCALLS       LongInt  User's total calls to the BBS system.
         USERTCALLS      Integer  User's number of calls to the BBS today.
         USERDLS         LongInt  User's total # of downloaded files.
         USERTDLS        Integer  User's total # of downloaded files today.
         -------------------------------------------------------------------

         Example:

         Var A Integer

         A := 1
         While GetUser(A)
              WriteLn ('User Alias: ', UserAlias)
              A := A + 1
         WEnd

         The above example will list all user accounts on the BBS system.

   Procedure GETTHISUSER;

         This procedure loads the user information for the currently
         logged in user into the USER variables.  See the GETUSER function
         for a reference of the USER variables.

         Example:

         GetThisUser
         WriteLn ('Welcome to this BBS, ', UserAlias)
         WriteLn ('You have called ', UserCalls, ' times!')

         The above example will load the currently logged in user
         information into the user variables, then display a line of
         text welcoming them to the BBS.
  
  Procedure PUTTHISUSER

         This procedure will save the USER variables into the currently
         logged in user's record.  See the GETUSER function for a list of
         the USER variables which are saved by the PutThisUser function.

         Example:

         GetThisUser
         WriteLn ('Welcome ', UserAlias, '.  Your account is being deleted.')
         UserDeleted := True
         PutThisUser
         HangUp

         The above example will load the USER variables with the currently
         logged in user's information, then mark them as deleted with the
         UserDeleted variable.  Their account is then saved with the
         PutThisUser procedure and then they are hangup on using the HangUp
         command.

    Procedure PUTUSER (N: Integer)

         This procedure will save the USER variables into the user file.
         The passed N parameter is the record number to save under.  See
         the GETUSER function for a list of the USER variables which are
         saved by the PutUser procedure.

         Example:

         If GetUser(1)
              UserDeleted := True
              PutUser(1)
         EndIf

         The above example will attempt to load the data from user record
         1 into the USER variables.  If the data is loaded without any
         errors, it will mark the user as deleted using the USERDELETED
         variable, and then save the record back to the user file.
  
  
  
  getuserbyname    s            boolean
  getuserbyid      l            boolean
  
  IsUser(Str:String) : Boolean;
  Takes a string value which can contain either a user realname, handle, or 
  user perm index number.  If the user exists, it will return a TRUE result or 
  FALSE if the user does not exist.
  
  settimeleft      i            none


FBASE Unit
----------
  
  FBaseIndex
  FGROUPHIDDEN
  MGROUPHIDDEN
  
  fbasefn" returns the file base's filename
  
MBASE Unit
----------

  Function GETMBASE (N : Word) : Boolean

         This procedure will read message base data into the MBASE variables.
         The supplied N is the record number to read.  The function will
         return TRUE if the record was read successfully, or FALSE if the
         record was not read.  The "USES MBASE" command must be called at
         the start of your program for the MBASE functions to work
         correctly.

         The following MBASE variables will be set when a record is read:

         Variable Name   Type     Description
         -------------------------------------------------------------------
         MBASENAME      String    Name
         MBASEQWK       String    QWK name
         MBASEFILE      String    File name
         MBASEPATH      String    Storage Path
         MBASEPTYPE     Byte      Post type: 0 = Public, 1 = Private
         MBASEACS       String    ACS level
         MBASERACS      String    Read ACS level
         MBASEPACS      String    Post ACS level
         MBASESACS      String    SysOp ACS level
         MBASEPW        String    Password
         MBASECQUOTE    Byte      Quote color (text attribute)
         MBASECTEXT     Byte      Text color
         MBASECTEAR     Byte      Tear color
         MBASECORIG     Byte      Origin color
         MBASEBTYPE     Byte      Base type: 0 = JAM, 1 = Squish
         MBASEAKA       Byte      Network address AKA #
         MBASEORIG      String    Origin line
         MBASEREAL      Boolean   Use real names?
         MBASEDNSCAN    Byte      New scan? 0 = no, 1 = yes, 2 = always
         MBASEDQSCAN    Byte      QWK scan? 0 = no, 1 = yes, 2 = always
         MBASEHDR       String    Header file
         MBASEINDEX     Integer   Index number (*NEVER* change this)

         Example:

         Var A Word

         A := 1
         While GetMBase
              WriteLn ('Base name: ', MBaseName)
              A := A + 1
         Wend

         The above example will list all available message base systems on
         the BBS.

  GetMBStats(id:LongInt; ExMsgF, ExMsgT: Boolean; total, new, yours: Longint);
  This can be used as a function or a procedure (returning true if successful).
  It takes 6 parameters.
      #1: Message base number
      #2: Exclude messages FROM the current user in stats
      #3: Exclude messages TO the current user that have already been read
      #4: Total messages (this is a VAR parameter)
      #5: New messages (this is a VAR parameter)
      #6: New messages to you (this is a VAR parameter)
    Example:

          uses mbase;

          var
            count, total, new, yours : longint;
          begin
            count := 1;  //start @1 to skip email base

            while getmbase(count) do begin
              getmbstats(count, true, true, total, new, yours);

              writeln('base       : ' + mbasename);
              writeln('total msgs : ' + int2str(total));
              writeln('new msgs   : ' + int2str(new));
              writeln('your msgs  : ' + int2str(yours));
              writeln('');

              count := count + 1
            end;
          end.
          
  GetMBaseTotal (Compress: Boolean) : LongInt
  This function returns the total message bases on the system.  If Compressed
  is true, then it will return the total number of message bases the user has
  access to (slower to calculate).  If it is false, it returns the raw total 
  number of bases on the system.
  
  GetMailStats(Total, UnRead:LongInt);
  Returns the number of e-mail messages and the number of unread email messages:
       Var
         Total, UnRead: LongInt;
       Begin
         GetMailStats(Total, UnRead);

         WriteLn ('You have ' + Int2Str(Total) + ' emails, ' + Int2Str(UnRead) + ' unread');
       End;
       
  CfgNetDesc (array 1..30 of string[25] contains network descriptions) and 
  MBaseNetAddr (contains the network address target of the message base).  Ex:
      Uses CFG, MBASE;
      Begin
        If GetMBase(1) Then
          WriteLn ('Base #1 is in network: ' + CfgNetDesc[MBaseNetAddr]);
      End.
      
  Procedure PUTMBASE

         This procedure will save the currently loaded MBASE variables into
         a message base record.  See the GETMBASE function for a list of
         valid MBASE variables.

         Example:

         If GetMBase(1) Then
              MBaseName := 'Message Base #1'
              PutMBase(1)
         EndIf

         The above example will read the data for message base #1, set the
         name to "Message Base #1" and write the data back to the data file.
  
CFG Unit
--------

  Variables
  
  cfgpathsys      string[60]
  cfgpathdata     string[60]
  cfgpathlogs     string[60]
  cfgpathmsgs     string[60]
  cfgpathfile     string[60]
  cfgpathmail     string[60]
  cfgpathmenu     string[60]
  cfgpathtext     string[60]
  cfgpathansi     string[60]
  cfgpathmpl      string[60]
  cfgtimeout      word
  
  CfgTNNodes
  Variable, which now contains the number of telnet nodes to allow.  These are
  basically interchangable in your MPL code but it is changing to more
  accurately reflect what Mystic is doing.
  
  CfgTempPath
  returns the location of the current node temporary directory.
  
  CfgChatStart and CfgChatEnd.
  These return the byte of the chat hour start and end variables from the 
  System Configuration
  
  CfgSeeInvis
  Gives you access to the "See Invisible" ACS value from Mystic's configuration
  
  ReadEnv(S:String) : String;
  Returns the value of an environment variable of the operating system.
  
  menucmd          ss           None
  
  Procedure GETCFG

         This procedure will load the current configuration data into the
         CFG variables.  The "USES CFG" command must be used at the start
         of your program for GETCFG to work.  The following variables will
         be loaded:

         CFGSYSPATH     : System Path
         CFGDATAPATH    : Data Path
         CFGMSGSPATH    : Message Base Path
         CFGPROTPATH    : Protocol Path
         CFGARCSPATH    : Archive Path
         CFGQWKPATH     : Local QWK Path
         CFGMPEPATH     : Script (MPE) Path
         CFGATTPATH     : File Attach Path
         CFGLOGSPATH    : System Logs Path
         CFGTEXTPATH    : Text Files Path (for the current language)
         CFGMENUPATH    : Menu Files Path (for the current language)
         CFGSTATUSTYPE  : Returns status line mode (0 = 2 line, 1 = 1 line)

         Example:

         Uses CFG
         GetCFG
         WriteLn ('Mystic BBS is installed in ', CfgSysPath)

         The above example will load the configuration into the CFG
         variables, and then print the directory where Mystic BBS is
         installed in to the screen.
  
Bit Operations
---------------
  
  BitCheck(Pos:Byte; AnyVar) : Boolean
  Accepts a bit position and checks it against an integer, returning true or
  false if the bit is on.  So for example in the Records, the third bit in
  UserFlags is UserDeleted:
      GetThisUser
      If BitCheck(3, UserFlags) Then WriteLn('User is marked deleted');
  
  
  BitToggle(Pos:Byte; AnyVar);
  Accepts a bit position and an integer and toggles the bit.
      GetThisUser
      BitToggle(3, UserFlags);  // undeletes if they are deleted or deletes if
                                // they are not deleted.
                                
                                
  BitSet(Pos:Byte; AnyVar; True:Boolean);
  Accepts a bit position and an integer and sets the bit ON/OFF based on a
  boolean:
      GetThisUser
      BitSet(3, UserFlags, True);  // user is marked as deleted
      
  MPL now fully supports bitwise math and operators!  The following are
   implemented:

      AND - Bitwise AND
      OR  - Bitwise OR
      XOR - Bitwise exclusive OR
      SHL - Bitwise shift left
      SHR - Bitwise shift right

   Example:
     Const
       UserDeleted = $04;  // established bit for userdeleted from records.pas
                           // note: this value has changed check records.pas!
     Begin
       GetThisUser
       If UserFlags AND UserDeleted <> 0 Then
         WriteLn('User is deleted');
     End;

Math & Number Related
---------------------

  Types
  =====
    Real
    Integer
    Byte
    Word
    
  Procedures
  ==========
  
  Mod (%)
  Gets the mod of a division. Example:
      A := 10 % 8;

  POWER operator in mathmatical equations:
      A := 2 ^ 3;

  Function odd(l:LongInt):Boolean
  Returns True if number is odd.
  
  Real2Str(R:Real; D:Byte) : String;
  This takes a string and decimal place value.  Example:
      Var
        R : Real;
      Begin
        R := 1234.1234;
        WriteLn (Real2Str(R, 2));  // Will print 1234.12
      End
      
  ABS (Num: LongInt) : LongInt; 
  This value takes a signed integer and returns the absolute value.  

Special Things...
-----------------

  Message Editor

   MsgEditor, MsgEditSet, MsgEditGet.  These allow
   access to the internal Mystic msg editor (line and/or full) from within
   MPL.  It even allows you to define wrap position and template to completely
   make it look like its not the Mystic editor!

   As a little hint the MsgEditSet and MsgEditGet stuff could be used to post
   process message text on posts.  Like say for example you wanted to write
   a MPL that allows users to add Tag lines, you could do that by replacing
   the "Saving message..." prompt and using those two in order to modify the
   text before it is saved by Mystic!

   Rather than trying to explain it all, here is an example of all 3:

     Var
       Lines    : Integer = 0;
       WrapPos  : Integer = 79;
       MaxLines : Integer = 200;
       Forced   : Boolean = False;
       Template : String  = 'ansiedit';
       Subject  : String  = 'My subject';
       Count    : Integer;
     Begin
       MsgEditSet (1, 'this is line 1');
       MsgEditSet (2, 'this is line 2!');

       Lines := 2;

       SetPromptInfo(1, 'MsgTo');  // if template uses &1 for "To:" display

       If MsgEditor(0, Lines, WrapPos, MaxLines, Forced, Template, Subject) Then Begin
         WriteLn('User selected to save.');
         WriteLn('There are ' + Int2Str(Lines) + ' of text in buffer:');

         For Count := 1 to Lines Do
           WriteLn(MsgEditGet(Count));

         Pause;
       End Else Begin
         WriteLn('User aborted the edit.');

         Pause;
       End
     End


  Classes
  =======
  
  MPL now has the ability to interface directly with internal Mystic BBS
   classes.  This opens up a whole world of new possibilities in the future
   (for example) sockets, full remote ANSI screen library (boxes, listboxes)
   data sorting, and more.

   Classes must first be created and then freed after using.  Mystic will
   create the class instance and return a handle to that specific class to
   use with the functions.  Finally, the class is freed.  Two new functions
   go with this:

      ClassCreate (ClassHandle, ClassType)
      ClassFree (ClassHandle)

 + MPL now supports the ANSI box class.  There are three functions which
   go along with this: BoxOpen, BoxClose, and BoxOptions.  The Box class
   will automatically save and and subsequently restore the text under the
   box when it is closed.

   See TESTBOX.MPS for an example.

 + MPL now supports the ANSI input class.  There are several functions which
   go along with this: InputString, InputNumber, InputEnter, InputOptions.
   This class allows you more freedom over input functions than the standard
   MPL input functions do.

   See TESTINPUT.MPS for an example.
   
   MPL now supports ANSI screen class.  This allows the ability to save and
   restore portions of the user's screen.  The example below saves the screen
   coordinates defined as: X1:20, Y1:5, X2:60, Y2:10.  It then clears the
   screen and then restores the saved portion of the screen.

      Var SavedScreen : LongInt;

      ClassCreate (SavedScreen, 'image');
      ImageGet    (SavedScreen, 20, 5, 60, 10);

      ClrScr;
      WriteLn ('Press a key to restore');

      Pause;

      ImagePut (SavedScreen);
      ClassFree (SavedScreen);

      Pause;