{
 ßßßßßßßß  ßßßßßß    ßß   ßß
   ßß     ßß   ßß   ßß  ßß
  ßß     ßß   ßßß  ßßßßß  The DoorKit!
 ßß     ßß   ßß   ßß  ßß
ßß     ßßßßßß    ßß    ßß
The BBS Door Development Kit By The People - For The People!


   Feel free to modify or optimize this code at will. All I ask is that if
   find a better way to do things (and you will), please send me a copy of
   your modifications. Thanks in advance!....Larry L. Athey....

   This is the "Artsy - Fartsy" unit. These procedures and functions are for
   ANSI display purposes and door enhancement.}

{$A+,B-,D+,E+,F+,G+,I-,L+,N-,O+,P-,Q-,R-,S-,T-,V+,X+}
UNIT DOORKIT3;

INTERFACE

USES _EXIT;

{Ä--[Headers]-ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}

PROCEDURE ShowProgramAd;
{^ This will clear the screen and display a banner teliing the name and
   description of your program. You will most likely want to customize
   this before you write any doors with this kit.}
PROCEDURE CPrompt(HotKey : CHAR ; Txt : STRING);
{^ Simply draws text on the screen like most BBSes use in the selections in
   their file listings and message readers. (ie: [S]election). Keeping the
   HotKey and Txt separate is faster than using Copy/Delete on a string.}
PROCEDURE MenuKey(X,Y : BYTE ; HotKey : CHAR ; Txt : STRING);
{^ Just like CPrompt except this draws the prompt at X/Y coordinates on the
   screen. ANSI must be enabled for this to work.}
PROCEDURE YesNoBox;
{^ Simply draws a colored [Y/N] on the screen.}
PROCEDURE FancyPrompt;
{^ Displays a fancy "Your Selection:" on the screen.}
PROCEDURE Select;
{^ Displays a fancy "Select:" on the screen.}
PROCEDURE YnPrompt(Txt : STRING);
{^ Prints your "Txt" on the screen followed by a colored [Y/n].}
PROCEDURE NyPrompt(Txt : STRING);
{^ Prints your "Txt" on the screen followed by a colored [y/N].}
PROCEDURE AnyKey;
{^ Displays a nice "Press Any Key To Continue" prompt and waits for keypress.}
PROCEDURE OutTxt(FG,BG : BYTE ; Txt : STRING);
{^ Special procedure. Prints text on both screens in the colors
   specified by the FG and BG variables. If the user does not have
   ANSI enabled, then no color codes are sent.}
PROCEDURE OutTxtL(FG,BG : BYTE ; Txt : STRING);
{^ Same as above except a line feed is sent after the text.}
PROCEDURE OutTxtXY(X,Y,FG,BG : BYTE ; Txt : STRING);
{^ Special procedure. Prints text on both screens at X/Y coordinates
   in the colors specified by the FG and BG variables. This procedure
   requires the user to have ANSI enabled!}
PROCEDURE OutTxtXYL(X,Y,FG,BG : BYTE ; Txt : STRING);
{^ Same as above except a line feed is sent after the text.}
PROCEDURE LineBar(FG,BG,L : BYTE);
{^ Draws a thin line across the screen in FG/BG colors at L length.}
FUNCTION SecretInput(Len : BYTE; Default : STRING) : STRING;
{^ Special procedure. Creates an input field for getting passwords.
   the result of all input is hidden from the user's view.}
FUNCTION NameInput(Len : BYTE; Default : STRING) : STRING;
{^ Special procedure. Creates an input field that will automatically
   force all input to proper case.}
FUNCTION NormalInput(Len : BYTE; Default : STRING) : STRING;
{^ Special procedure. Creates an input field, all characters accepted}
FUNCTION CapsInput(Len : BYTE; Default : STRING) : STRING;
{^ Special procedure. Creates an input field that will automatically
   force all input to upper case letters}
FUNCTION NumberInput(Len : BYTE; Default : STRING) : STRING;
{^ Special procedure. Creates an input field but will only allow the
   input of numeric characters}
FUNCTION NamePrompt(StrLength : BYTE ; InStr : STRING) : STRING;
{^ Similar to NameInput except the user is required to have ANSI
   enabled. This will produce an input field on the screen filled
   with underscores and will have a bracket on both ends.}
FUNCTION NormalPrompt(StrLength : BYTE ; InStr : STRING) : STRING;
{^ Similar to NormalInput but follows the same rules as NamePrompt.}
FUNCTION NumberPrompt(StrLength : BYTE ; InStr : STRING) : STRING;
{^ Similar to NumberInput but follows the same rules as NamePrompt.}
FUNCTION SecretPrompt(StrLength : BYTE ; InStr : STRING) : STRING;
{^ Similar to SecretInput but follows the same rules as NamePrompt.}
FUNCTION CapsPrompt(StrLength : BYTE ; InStr : STRING) : STRING;
{^ Similar to CapsInput but follows the same rules as NameIprompt.}
FUNCTION SysField(X,Y,Style,StrLength : BYTE ; InStr : STRING) : STRING;
{^ Special procedure. Say for example you wanted to create a feature in
   your door where you have various input fields at specific locations.
   You would use this to draw a fields on the screen. Then you would use
   it in conjunction with the next procedure to make it look like your
   fields are shifting and showing the field that is active. ANSI must
   be enabled. (Style = 0-Normal 1-Number 2-Name 3-Secret 4-Caps)}
PROCEDURE DummyField(X,Y,StrLength : BYTE ; InStr : STRING);
{^ See the above description.}
PROCEDURE DrawWin(X1,Y1,X2,Y2 : BYTE ; Title : STRING);
{^ Draws a window on both screens at X1,Y1,X2,Y2 coordinates with a title.
   ANSI graphics required for this.'}
PROCEDURE ClearWin(X1,Y1,X2,Y2 : BYTE);
{^ Clears a window with the CS.Wbg color, ANSI graphics required for this.}
PROCEDURE DrawButton(HotKey : CHAR ; Txt : STRING ; HighLight : BOOLEAN);
{^ Draws a simulated raised button on the screen.}
PROCEDURE SysButton(X,Y : BYTE ; HotKey : CHAR ; Txt : STRING);
{^ Draws a simulated raised button on the screen at X/Y coorinates. This is
   mainly meant to be used with DrawWin since the button uses the window
   background color on its edges. ANSI is required for this.}
PROCEDURE DrawMenu(X1,Y1,X2,Y2 : BYTE);
{^ Creates a simulated drop down menu at X1,Y1,X2,Y2, ANSI required.}
PROCEDURE MenuItem(X,Y : BYTE ; HotKey : CHAR ; Txt : STRING);
{^ Adds a selection to a drop down menu, ANSI required.}
PROCEDURE MenuLine(X,Y,L : BYTE);
{^ Adds a dividing line to a drop down menu, ANSI required.}
PROCEDURE MenuBarItem(X,Y : BYTE ; HotKey : CHAR ; Txt : STRING);
{^ Since you are making simulated drop down menus, they have to drop down
   from a menu bar. Most times a menu bar is nothing more than going to the
   1,1 coordinate and doing an sClrEol. After that, you will add items to
   your menu bar. ANSI required.}
PROCEDURE InfoBox(Width : BYTE ; Height : BYTE);
{^ Creates a nice 3D frame on the screen, ANSI required.}
PROCEDURE InfoText(Txt : STRING);
{^ Creates a nice banner on the screen just like AnyKey does.}
PROCEDURE RunEntryForm(ScriptFile : STRING);
{^ Runs a Dynamic Entry Form (ie: Script).}
PROCEDURE CvtColors(InStr : STRING ; LF : BOOLEAN);
{^ Displays a text string with embedded "Fancy Bracket" color codes and
   automatically changes color of the text is displayed. (If LF is true,
   a linefeed will be sent).}
FUNCTION StripColors(InStr : STRING) : STRING;
{^ Similar to CvtColors except this one strips color codes.}
PROCEDURE RipToText;
{^ If a caller is connected in RIP graphics mode, you must make a call to
   this procedure to throw RIPterm back into text mode. To throw RIPterm
   back into RIP graphics mode, simply use ShowScreen() to display a *.RIP}
PROCEDURE ShowTextFile(TextFile : STRING);
{^ This displays a text file to the user in the "Text Reader" where they
   can use [P]revious, [M]ore, [T]op, [B]ottom and [Q]uit keys.}
PROCEDURE ShowScreen(Scr : STRING);
{^ This is a non-stop display of an ANSI/ASCII/RIP/MAX screen file where
   each line is checked for global system variables and translated.}
PROCEDURE IceText(S : STRING ; LF : BOOLEAN);
{^ Prints a text string on the screen similar to how "Ice" products do.}
PROCEDURE ChatSelect;
{^ This procedure can be called from any other procedure to throw the door
   into SysOp/User chat. Depending on the user's graphics capabilities, the
   door will decide which chat mode to use. There are split screen chat and
   line chat chat modes. Line chat mode will only be used in the event the
   caller only has TTY graphics capabilities.}
PROCEDURE DVWrite(X,Y : WORD; Attr : BYTE; S : STRING);
{^ No this doesn't have anything to do with DesqView. This means Direct Video
   Write. This allows you to display something on the local screen without it
   ever affecting the user's video. You can change colors, move the cursor to
   specific X/Y coordinates, you name it, and there is never any effect on the
   user's screen. That's just an advantage of writing directly to the video
   RAM rather than going through the BIOS.}
PROCEDURE AlertTones;
{^ Produces five ^G tones with a 200ms delay between tones. Use this to alert
   the user of an error. The sysop will only hear the tones if the door is
   running locally, otherwise the tones are sent straight to the comport.}

IMPLEMENTATION

USES CRT, TDK_VARS, DOORKIT1, DOORKIT2, ANSIUNIT, SVGAANSI, SVGADOOR;

{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE ShowProgramAd;
BEGIN
  TextAttr := 7;
  sClrScr;
  LineBar(1,0,79);
  IceText(ProgramName,TRUE);
  IceText(ProgramDesc,TRUE);
  IceText('Copyright 1995-1997 Larry Athey - BBS Utiliteez Software',TRUE);
  LineBar(1,0,79);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE CPrompt(HotKey : CHAR ; Txt : STRING);
BEGIN
  Set_Color(CS.CPBfg,CS.CPBbg); sWriteC('[');
  Set_Color(CS.CPKfg,CS.CPKbg); sWriteC(HotKey);
  Set_Color(CS.CPBfg,CS.CPBbg); sWriteC(']');
  Set_Color(CS.CPTfg,CS.CPTbg); sWrite(Txt + ' ');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE MenuKey(X,Y : BYTE ; HotKey : CHAR ; Txt : STRING);
BEGIN
  sGotoXY(X,Y);
  Set_Color(CS.CPBfg,CS.CPBbg); sWriteC('[');
  Set_Color(CS.CPKfg,CS.CPKbg); sWriteC(HotKey);
  Set_Color(CS.CPBfg,CS.CPBbg); sWriteC(']');
  Set_Color(CS.CPTfg,CS.CPTbg); sWrite(Txt);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE YesNoBox;
BEGIN
  Set_Color(CS.CPBfg,CS.CPBbg); sWrite(' [');
  Set_Color(CS.CPKfg,CS.CPKbg); sWriteC('Y');
  Set_Color(CS.CPBfg,CS.CPBbg); sWriteC('/');
  Set_Color(CS.CPKfg,CS.CPKbg); sWriteC('N');
  Set_Color(CS.CPBfg,CS.CPBbg); sWrite('] ');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE FancyPrompt;
BEGIN
  OutTxt(9,0,'Y');
  OutTxt(11,0,'o');
  OutTxt(15,0,'ur Selecti');
  OutTxt(11,0,'o');
  OutTxt(9,0,'n');
  OutTxt(8,0,': ');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE Select;
BEGIN
  OutTxt(9,0,'S');
  OutTxt(11,0,'e');
  OutTxt(15,0,'le');
  OutTxt(11,0,'c');
  OutTxt(9,0,'t');
  OutTxt(8,0,':');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE YnPrompt(Txt : STRING);
BEGIN
  Set_Color(CS.CPTfg,CS.CPTbg); sWrite(Txt);
  Set_Color(CS.CPBfg,CS.CPBbg); sWrite(' [');
  Set_Color(CS.CPKfg,CS.CPKbg); sWriteC('Y');
  Set_Color(CS.CPBfg,CS.CPBbg); sWriteC('/');
  Set_Color(CS.CPKfg,CS.CPKbg); sWriteC('n');
  Set_Color(CS.CPBfg,CS.CPBbg); sWrite('] ');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE NyPrompt(Txt : STRING);
BEGIN
  Set_Color(CS.CPTfg,CS.CPTbg); sWrite(Txt);
  Set_Color(CS.CPBfg,CS.CPBbg); sWrite(' [');
  Set_Color(CS.CPKfg,CS.CPKbg); sWriteC('N');
  Set_Color(CS.CPBfg,CS.CPBbg); sWriteC('/');
  Set_Color(CS.CPKfg,CS.CPKbg); sWriteC('y');
  Set_Color(CS.CPBfg,CS.CPBbg); sWrite('] ');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE AnyKey;
BEGIN
  Set_Color(1,0);  sClrEol; sWrite('°±²');
  Set_Color(15,1); sWrite(' Press Any Key To Continue ');
  Set_Color(1,0);  sWrite('²±°');
  sReadKey;
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE OutTxt(FG,BG : BYTE ; Txt : STRING);
BEGIN
  Set_Color(FG,BG);
  sWrite(Txt);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE OutTxtL(FG,BG : BYTE ; Txt : STRING);
BEGIN
  Set_Color(FG,BG);
  sWriteln(Txt);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE OutTxtXY(X,Y,FG,BG : BYTE ; Txt : STRING);
BEGIN
  sGotoXY(X,Y);
  Set_Color(FG,BG);
  sWrite(Txt);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE OutTxtXYL(X,Y,FG,BG : BYTE ; Txt : STRING);
BEGIN
  sGotoXY(X,Y);
  Set_Color(FG,BG);
  sWriteln(Txt);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE LineBar(FG,BG,L : BYTE);
VAR
  Loop : BYTE;
BEGIN
  Set_Color(FG,BG);
  FOR Loop := 1 TO L DO sWriteC('Ä');
  sWriteln('');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION InputDriver(Len : BYTE; Name,Showit,AllCap,NumInput : BOOLEAN; tLine : STRING) : STRING;
VAR
  Ch      : CHAR;
  Insrt   : BOOLEAN;
  Loop,
  J,Place : BYTE;
  Temp,
  RTemp   : STRING;
BEGIN
  Insrt := TRUE;
  IF tLine = '' THEN Place := 1 ELSE Place := LENGTH(tLine) + 1;
  IF (Graphics = TTY) AND (tLine <> '') THEN sWrite(tLine);
  REPEAT
    Ch := sReadKey;
    IF Name THEN BEGIN
      IF Place = 1 THEN Ch := UPCASE(Ch) ELSE IF tLine[Place - 1] = #32 THEN Ch := UPCASE(Ch);
    END;
    IF AllCap THEN Ch := UPCASE(Ch);
    IF (NumInput AND (Ch IN [#0..#31,'0'..'9','-','+','/'])) OR NOT NumInput THEN
    CASE Ch OF
      #0,
      #27,
      #127 : BEGIN
             Temp := Ch;
             IF Ch = #0  THEN Temp := s_ReadKey;
             IF Ch = #27 THEN Temp := Temp + sReadKey + sReadKey;
             IF Ch = #22 THEN BEGIN
               sWaitInput(250);
               IF sKeyPressed THEN Temp := Temp + sReadKey;
             END;
             J := 0;
             REPEAT
               IF Temp = CursorMove.Home[J] THEN BEGIN
                 IF Place - 1 <> 0 THEN sCursorLeft(Place - 1);
                 Place := 1;
                 Temp  := '';
               END ELSE IF Temp = CursorMove.EndKey[J] THEN BEGIN
                 IF LENGTH(tLine) - Place + 1 <> 0 THEN sCursorRight(LENGTH(tLine) - Place + 1);
                 Place := BYTE(tLine[0]) + 1;
                 Temp  := '';
               END ELSE IF Temp = CursorMove.Left[J] THEN BEGIN
                 IF Place <> 1 THEN BEGIN
                   DEC(Place);
                   sCursorLeft(1);
                 END;
                 Temp := '';
               END ELSE IF Temp = CursorMove.Right[J] THEN BEGIN
                 IF Place < BYTE(tLine[0]) + 1 THEN BEGIN
                   INC(Place);
                   sCursorRight(1);
                 END;
                 Temp := '';
               END ELSE IF Temp = CursorMove.INSERT[J] THEN BEGIN
                 Insrt := NOT Insrt;
                 Temp  := '';
               END ELSE IF Temp = CursorMove.DELETE[J] THEN BEGIN
                 Temp := '';
                 IF Place < BYTE(tLine[0]) + 1 THEN BEGIN
                   DELETE(tLine,Place,1);
                   IF ShowIt THEN sWrite(COPY(tLine,Place,255) + BackSpaceChar) ELSE BEGIN
                     FOR Loop := Place TO LENGTH(tLine) DO sWrite('ž');
                     sWrite(BackSpaceChar);
                   END;
                   sCursorLeft(BYTE(tLine[0]) - Place + 1 + 1);
                 END;
               END;
               INC(J);
             UNTIL (J = 2) OR (Temp = '');
           END;
      #8 : IF Place <> 1 THEN BEGIN
             IF Place = BYTE(tLine[0]) + 1 THEN BEGIN
               DEC(tLine[0]);
               sWrite(#8 + BackSpaceChar);
               DEC(Place);
             END ELSE BEGIN
               DEC(Place);
               DELETE(tLine,Place,1);
               IF (ShowIt) AND (Graphics <> TTY) THEN BEGIN
                 sCursorLeft(1);
                 sWrite(COPY(tLine,Place,255) + BackSpaceChar)
               END ELSE BEGIN
                 sCursorLeft(1);
                 FOR Loop := Place TO LENGTH(tLine) DO sWrite('ž');
                 sWrite(BackSpaceChar);
               END;
             END;
             sCursorLeft(LENGTH(COPY(tLine,Place,255) + BackSpaceChar));
           END;
      #1..#31 : ;
      ELSE BEGIN
        IF (LENGTH(tLine) <> Len) OR ((NOT Insrt) AND (Place - 1 <> Len)) THEN BEGIN
          IF Place = LENGTH(tLine) + 1 THEN BEGIN
            IF ShowIt THEN sWrite(Ch) ELSE sWrite('ž');
            tLine := tLine + Ch;
            INC(Place);
          END ELSE BEGIN
            IF NOT Insrt THEN BEGIN
              IF ShowIt THEN sWrite(Ch) ELSE sWrite('ž');
              tLine[Place] := Ch;
              INC(Place);
            END ELSE BEGIN
              INSERT(Ch,tLine,Place);
              IF ShowIt THEN sWrite(COPY(tLine,Place,255)) ELSE BEGIN
                FOR Loop := Place TO LENGTH(tLine) DO sWrite('ž');
              END;
              sCursorLeft(LENGTH(COPY(tLine,Place,255)) - 1);
              INC(Place);
            END;
          END;
        END ELSE BEGIN
          IF NOT WrapInput THEN sWrite(#7) ELSE BEGIN
            Temp[0]  := #0;
            RTemp[0] := #0;
            Loop := BYTE(tLine[0]);
            IF POS(#32,tLine) <> 0 THEN BEGIN
              WHILE (tLine[loop] <> #32) DO BEGIN
                sWrite(#8 + BackSpaceChar);
                Temp := Temp + tLine[Loop];
                DEC(Loop);
                DEC(tLine[0]);
              END;
              IF Temp[0] <> #0 THEN FOR Loop := BYTE(Temp[0]) DOWNTO 1 DO RTemp := RTemp + Temp[Loop];
            END;
            Ch := #13;
          END;
        END;
      END;
    END;
  UNTIL Ch = #13;
  InputDriver := tLine;
  sWriteln('');
END;
{ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ }
FUNCTION SecretInput(Len : BYTE; Default : STRING) : STRING;
BEGIN
  SecretInput := InputDriver(Len,FALSE,FALSE,FALSE,FALSE,Default);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION NameInput(Len : BYTE; Default : STRING) : STRING;
BEGIN
  NameInput := InputDriver(Len,TRUE,TRUE,FALSE,FALSE,Default);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION NormalInput(Len : BYTE; Default : STRING) : STRING;
BEGIN
  NormalInput := InputDriver(Len,FALSE,TRUE,FALSE,FALSE,Default);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION CapsInput(Len : BYTE; Default : STRING) : STRING;
BEGIN
  CapsInput := InputDriver(Len,FALSE,TRUE,TRUE,FALSE,Default);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION NumberInput(Len : BYTE; Default : STRING) : STRING;
BEGIN
  NumberInput := InputDriver(Len,FALSE,TRUE,FALSE,TRUE,Default);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION NamePrompt(StrLength : BYTE ; InStr : STRING) : STRING;
VAR
  X,Y,Loop : BYTE;
BEGIN
  IF SvgaActive THEN X := Where_X + 1 ELSE X := WHEREX + 1;
  IF SvgaActive THEN Y := Where_Y ELSE Y := WHEREY;
  BackSpaceChar := '_';
  Set_Color(CS.Bfg,CS.Wbg);
  sWriteC('[');
  Set_Color(CS.Ffg,CS.Fbg);
  sWrite(InStr);
  FOR Loop := LENGTH(InStr) TO (StrLength - 1) DO sWriteC('_');
  Set_Color(CS.Bfg,CS.Wbg);
  sWriteC(']');
  IF InStr = '' THEN sGotoXY(X,Y) ELSE sGotoXY(X + LENGTH(InStr),Y);
  Set_Color(CS.Ffg,CS.Fbg);
  NamePrompt := NameInput(StrLength,InStr);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION NormalPrompt(StrLength : BYTE ; InStr : STRING) : STRING;
VAR
  X,Y,Loop : BYTE;
BEGIN
  IF SvgaActive THEN X := Where_X + 1 ELSE X := WHEREX + 1;
  IF SvgaActive THEN Y := Where_Y ELSE Y := WHEREY;
  BackSpaceChar := '_';
  Set_Color(CS.Bfg,CS.Wbg);
  sWriteC('[');
  Set_Color(CS.Ffg,CS.Fbg);
  sWrite(InStr);
  FOR Loop := LENGTH(InStr) TO (StrLength - 1) DO sWriteC('_');
  Set_Color(CS.Bfg,CS.Wbg);
  sWriteC(']');
  IF InStr = '' THEN sGotoXY(X,Y) ELSE sGotoXY(X + LENGTH(InStr),Y);
  Set_Color(CS.Ffg,CS.Fbg);
  NormalPrompt := NormalInput(StrLength,InStr);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION NumberPrompt(StrLength : BYTE ; InStr : STRING) : STRING;
VAR
  X,Y,Loop : BYTE;
BEGIN
  IF SvgaActive THEN X := Where_X + 1 ELSE X := WHEREX + 1;
  IF SvgaActive THEN Y := Where_Y ELSE Y := WHEREY;
  BackSpaceChar := '_';
  Set_Color(CS.Bfg,CS.Wbg);
  sWriteC('[');
  Set_Color(CS.Ffg,CS.Fbg);
  sWrite(InStr);
  FOR Loop := LENGTH(InStr) TO (StrLength - 1) DO sWriteC('_');
  Set_Color(CS.Bfg,CS.Wbg);
  sWriteC(']');
  IF InStr = '' THEN sGotoXY(X,Y) ELSE sGotoXY(X + LENGTH(InStr),Y);
  Set_Color(CS.Ffg,CS.Fbg);
  NumberPrompt := NumberInput(StrLength,InStr);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION SecretPrompt(StrLength : BYTE ; InStr : STRING) : STRING;
VAR
  X,Y,Loop : BYTE;
BEGIN
  IF SvgaActive THEN X := Where_X + 1 ELSE X := WHEREX + 1;
  IF SvgaActive THEN Y := Where_Y ELSE Y := WHEREY;
  BackSpaceChar := '_';
  Set_Color(CS.Bfg,CS.Wbg);
  sWriteC('[');
  Set_Color(CS.Ffg,CS.Fbg);
  FOR Loop := 1 TO StrLength DO sWriteC('_');
  Set_Color(CS.Bfg,CS.Wbg);
  sWriteC(']');
  IF InStr = '' THEN sGotoXY(X,Y) ELSE sGotoXY(X + LENGTH(InStr),Y);
  Set_Color(CS.Ffg,CS.Fbg);
  SecretPrompt := SecretInput(StrLength,InStr);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION CapsPrompt(StrLength : BYTE ; InStr : STRING) : STRING;
VAR
  X,Y,Loop : BYTE;
BEGIN
  IF SvgaActive THEN X := Where_X + 1 ELSE X := WHEREX + 1;
  IF SvgaActive THEN Y := Where_Y ELSE Y := WHEREY;
  BackSpaceChar := '_';
  OutTxt(CS.Bfg,CS.Wbg,'[');
  Set_Color(CS.Ffg,CS.Fbg);
  InStr := AllCaps(InStr); sWrite(InStr);
  FOR Loop := LENGTH(InStr) TO (StrLength - 1) DO sWriteC('_');
  OutTxt(CS.Bfg,CS.Wbg,']');
  IF InStr = '' THEN sGotoXY(X,Y) ELSE sGotoXY(X + LENGTH(InStr),Y);
  Set_Color(CS.Ffg,CS.Fbg);
  CapsPrompt := CapsInput(StrLength,InStr);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION SysField(X,Y,Style,StrLength : BYTE ; InStr : STRING) : STRING;
VAR                  {^ 0-Normal 1-Number 2-Name 3-Secret 4-Caps}
  OldFg,
  OldBg,
  OldBr,
  Loop : BYTE;
BEGIN
  sGotoXY(X,Y);
  OldFg := CS.Ffg;
  OldBg := CS.Fbg;
  OldBr := CS.Bfg;
  CS.Ffg := 15;
  CS.Fbg := 0;
  CS.Bfg := 14;
  CASE Style OF
    0 : InStr := NormalPrompt(StrLength,InStr);
    1 : InStr := NumberPrompt(StrLength,InStr);
    2 : InStr := NamePrompt(StrLength,InStr);
    3 : InStr := SecretPrompt(StrLength,InStr);
    4 : InStr := CapsPrompt(StrLength,InStr);
  END;
  CS.Ffg := OldFg;
  CS.Fbg := OldBg;
  CS.Bfg := OldBr;
  IF Style <> 3 THEN DummyField(X,Y,StrLength,InStr) ELSE DummyField(X,Y,StrLength,'');
  SysField := InStr;
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE DummyField(X,Y,StrLength : BYTE ; InStr : STRING);
VAR
  Loop : BYTE;
BEGIN
  OutTxtXY(X,Y,CS.Wh,CS.Wbg,' ');
  OutTxtXY(X + 1,Y,7,0,InStr);
  FOR Loop := LENGTH(InStr) TO (StrLength - 1) DO sWriteC('_');
  OutTxt(CS.Wh,CS.Wbg,' ');
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE DrawWin(X1,Y1,X2,Y2 : BYTE ; Title : STRING);
CONST
  Vs : CHAR = 'Ū';
  Hs : CHAR = 'ß';
  Tl : CHAR = 'Ś';
  Tr : CHAR = 'æ';
  Bl : CHAR = 'Ą';
  Br : CHAR = 'Ł';
  H  : CHAR = 'Ä';
  V  : CHAR = '³';
VAR
  X,L1,L2 : BYTE;
BEGIN
  sGotoXY(X1,Y1);
  OutTxt(CS.Hfg,CS.Hbg,' ' + Title);
  IF SvgaActive THEN X := Where_X ELSE X := WHEREX;
  FOR L1 := X TO X2 DO OutTxt(CS.Hfg,CS.Hbg,' ');
  OutTxtXY(X1,Y1 + 1,CS.Wh,CS.Wbg,Tl);
  FOR L1 := (X1 + 1) TO (X2 - 1) DO OutTxt(CS.Wh,CS.Wbg,H);
  OutTxtXY(X2,Y1 + 1,CS.Wl,CS.Wbg,Tr); OutTxt(CS.Sfg,CS.Sbg,Vs);
  FOR L1 := (Y1 + 2) TO (Y2 - 1) DO BEGIN
    OutTxtXY(X1,L1,CS.Wh,CS.Wbg,V);
    FOR L2 := (X1 + 1) TO (X2 - 1) DO OutTxt(CS.Wh,CS.Wbg,' ');
    OutTxt(CS.Wl,CS.Wbg,V); OutTxt(CS.Sfg,CS.Sbg,Vs);
  END;
  OutTxtXY(X1,Y2,CS.Wh,CS.Wbg,Bl);
  FOR L1 := (X1 + 1) TO (X2 - 1) DO OutTxt(CS.Wl,CS.Wbg,H);
  OutTxtXY(X2,Y2,CS.Wl,CS.Wbg,Br); OutTxt(CS.Sfg,CS.Sbg,Vs);
  sGotoXY(X1 + 2,Y2 + 1);
  FOR L1 := (X1 + 2) TO (X2 + 1) DO OutTxt(CS.Sfg,CS.Sbg,Hs);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE ClearWin(X1,Y1,X2,Y2 : BYTE);
VAR
  L1,L2 : BYTE;
BEGIN
  FOR L1 := Y1 TO Y2 DO BEGIN
    sGotoXY(X1,L1);
    FOR L2 := X1 TO X2 DO OutTxt(CS.Wh,CS.Wbg,' ');
  END;
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE DrawButton(HotKey : CHAR ; Txt : STRING ; HighLight : BOOLEAN);
VAR
  BL,BR : CHAR;
  FG    : BYTE;
BEGIN
  BR := 'Ż'; BL := 'Ž';
  OutTxt(8,0,BL);
  IF HighLight THEN FG := 1 ELSE FG := 8;
  IF HighLight THEN OutTxt(4,7,' ' + HotKey);
  IF NOT HighLight THEN OutTxt(8,7,' ' + HotKey);
  OutTxt(FG,7,Txt + ' ');
  OutTxt(8,0,BR);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE SysButton(X,Y : BYTE ; HotKey : CHAR ; Txt : STRING);
VAR
  L1,Sfg,Sbg : BYTE;
  Vs,Hs      : CHAR;
BEGIN
  Vs := 'Ü';
  Hs := 'ß';
  OutTxtXY(X,Y,4,7,' ' + HotKey);
  OutTxt(0,7,Txt + ' ');
  OutTxt(0,CS.Wbg,Vs);
  sGotoXY(X + 1,Y + 1);
  FOR L1 := 1 TO (LENGTH(Txt) + 3) DO OutTxt(0,CS.Wbg,Hs);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE DrawMenu(X1,Y1,X2,Y2 : BYTE);
CONST
  Vs : CHAR = 'Ū';
  Hs : CHAR = 'ß';
  Tl : CHAR = 'Ś';
  Tr : CHAR = 'æ';
  Bl : CHAR = 'Ą';
  Br : CHAR = 'Ł';
  H  : CHAR = 'Ä';
  V  : CHAR = '³';
VAR
  L1,L2 : BYTE;
BEGIN
  sGotoXY(X1,Y1);
  OutTxtXY(X1,Y1,0,7,Tl);
  FOR L1 := (X1 + 1) TO (X2 - 1) DO OutTxt(0,7,H);
  OutTxtXY(X2,Y1,0,7,Tr);
  FOR L1 := (Y1 + 1) TO (Y2 - 1) DO BEGIN
    OutTxtXY(X1,L1,0,7,V);
    FOR L2 := (X1 + 1) TO (X2 - 1) DO OutTxt(0,7,' ');
    OutTxt(0,7,V);
    OutTxt(CS.Sfg,CS.Sbg,Vs);
  END;
  OutTxtXY(X1,Y2,0,7,Bl);
  FOR L1 := (X1 + 1) TO (X2 - 1) DO OutTxt(0,7,H);
  OutTxtXY(X2,Y2,0,7,Br); OutTxt(CS.Sfg,CS.Sbg,Vs);
  Set_Color(CS.Sfg,CS.Sbg);
  sGotoXY(X1 + 2,Y2 + 1);
  FOR L1 := (X1 + 2) TO (X2 + 1) DO sWriteC(Hs);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE MenuItem(X,Y : BYTE ; HotKey : CHAR ; Txt : STRING);
BEGIN
  OutTxtXY(X,Y,1,7,HotKey);
  OutTxt(0,7,Txt);
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE MenuLine(X,Y,L : BYTE);
VAR
  Loop : BYTE;
BEGIN
  OutTxtXY(X,Y,0,7,'Ć');
  FOR Loop := 1 TO (L - 2) DO OutTxt(0,7,'Ä');
  OutTxt(0,7,'“');
  Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE MenuBarItem(X,Y : BYTE ; HotKey : CHAR ; Txt : STRING);
BEGIN
   OutTxtXY(X,Y,4,7,HotKey);
   OutTxt(0,7,Txt);
   Set_Color(7,0);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE InfoBox(Width : BYTE ; Height : BYTE);
CONST
  LTC  : CHAR = 'É';
  RTC  : CHAR = '»';
  LBC  : CHAR = 'Č';
  RBC  : CHAR = '¼';
  HBAR : CHAR = 'Ķ';
  VBAR : CHAR = 'ŗ';
VAR
  Row,Loop : BYTE;
BEGIN
  IF SvgaActive THEN Row := Where_Y ELSE Row := WHEREY;
  Set_Color(9,0);
  sGotoXY(1,Row); sWriteC(LTC);
  FOR Loop := 2 TO (Width - 1) DO sWriteC(HBAR);
  Set_Color(1,0); sWritelnC(RTC);
  IF SvgaActive THEN Row := Where_Y ELSE Row := WHEREY;
  FOR Loop := 1 TO Height DO BEGIN
    Set_Color(9,0);
    sGotoXY(1,Row); sWriteC(VBAR);
    Set_Color(1,0);
    sGotoXY(Width,Row); sWritelnC(VBAR);
    IF SvgaActive THEN Row := Where_Y ELSE Row := WHEREY;
  END;
  Set_Color(9,0);
  sWriteC(LBC);
  Set_Color(1,0);
  FOR Loop := 2 TO (Width - 1) DO sWriteC(HBAR);
  sGotoXY(Width,Row); sWritelnC(RBC);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE InfoText(Txt : STRING);
VAR
  LB,RB : STRING[4];
BEGIN
  LB := '°±²Ū';
  RB := 'Ū²±°';
  Set_Color(1,0);  sWrite(LB);
  Set_Color(15,1); sWrite(Txt);
  Set_Color(1,0);  sWrite(RB);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE RunEntryForm(ScriptFile : STRING);
TYPE EntryFields = ARRAY[1..50] OF STRING;
VAR
  Go1,
  Go2,Go3,
  GotText : BOOLEAN;
  OldGfx,
  Loop,FC : BYTE;
  Scrn,
  InFile,
  OutFile : Text;
  Cmd,
  V1,V2,
  ScrLine : STRING;
  _Field  : ^EntryFields;
BEGIN
  IF NOT FExist(ScriptFile) THEN EXIT;
  NEW(_Field);
  sClrScr;
  GotText := FALSE; FC := 0;
  ASSIGN(InFile,ScriptFile);
  RESET(InFile);
  WHILE NOT EOF(InFile) DO BEGIN
    Go1 := TRUE; Go2 := FALSE; Go3 := FALSE;
    Cmd := ''; V1 := ''; V2 := '';
    READLN(InFile,ScrLine);
    ScrLine := CvtVars(ScrLine);
    FOR Loop := 1 TO LENGTH(ScrLine) DO BEGIN
      IF (Go2) AND (ScrLine[Loop] = '@') THEN BEGIN
        Go1 := FALSE;
        Go2 := FALSE;
        Go3 := TRUE;
      END;
      IF Go1 THEN Cmd := Cmd + ScrLine[Loop];
      IF Go2 THEN V1 := V1 + ScrLine[Loop];
      IF (Go3) AND (ScrLine[Loop] <> '@') THEN V2 := V2 + ScrLine[Loop];
      IF (Go1) AND (ScrLine[Loop] = '@') THEN BEGIN
        Go1 := FALSE;
        Go2 := TRUE;
        Go3 := FALSE;
      END;
    END;
    Cmd := AllCaps(Cmd);
    IF Cmd = 'SCREENFILE@' THEN BEGIN
      V1 := AllCaps(V1);
      OldGfx := Graphics;
      CASE Graphics OF
        RIP  : IF FExist(V1 + '.RIP') THEN ShowScreen(V1 + '.RIP')
               ELSE BEGIN
                 RipToText;
                 Graphics := ANSI;
               END;
        MAX  : IF FExist(V1 + '.MAX') THEN ShowScreen(V1 + '.MAX')
               ELSE BEGIN
                 RipToText;
                 Graphics := ANSI;
               END;
      AVATAR : IF FExist(V1 + '.AVT') THEN ShowScreen(V1 + '.AVT')
                                      ELSE Graphics := ANSI;
        ANSI : IF FExist(V1 + '.ANS') THEN ShowScreen(V1 + '.ANS')
                                      ELSE Graphics := TTY;
        TTY  : ShowScreen(V1 + '.ASC');
      END;
      sWriteln('');
      Graphics := OldGfx;
    END;
    IF (Cmd = 'TEXTFILE@') AND (NOT GotText) THEN BEGIN
      GotText := TRUE;
      V1 := AllCaps(V1);
      ASSIGN(OutFile,V1);
      IF NOT FExist(V1) THEN REWRITE(OutFile) ELSE APPEND(OutFile);
    END;
    IF Cmd = 'PROMPTTEXT@' THEN BEGIN
      Set_Color(CS.CPTfg,CS.CPTbg);
      CvtColors(V1,FALSE);
    END;
    IF Cmd = 'LINEFEED@' THEN sWriteln('');
    IF Cmd = 'ANYKEY@' THEN AnyKey;
    IF Cmd = 'PROPERPROMPT@' THEN BEGIN
      INC(FC); sWriteC(' ');
      IF Graphics = TTY THEN _Field^[FC] := NameInput(StrToInt(V1),V2)
                        ELSE _Field^[FC] := NamePrompt(StrToInt(V1),V2);
    END;
    IF Cmd = 'NORMALPROMPT@' THEN BEGIN
      INC(FC); sWriteC(' ');
      IF Graphics = TTY THEN _Field^[FC] := NormalInput(StrToInt(V1),V2)
                        ELSE _Field^[FC] := NormalPrompt(StrToInt(V1),V2);
    END;
    IF Cmd = 'NUMBERPROMPT@' THEN BEGIN
      INC(FC); sWriteC(' ');
      IF Graphics = TTY THEN _Field^[FC] := NumberInput(StrToInt(V1),V2)
                        ELSE _Field^[FC] := NumberPrompt(StrToInt(V1),V2);
    END;
    IF Cmd = 'CAPITALPROMPT@' THEN BEGIN
      INC(FC); sWriteC(' ');
      IF Graphics = TTY THEN _Field^[FC] := CapsInput(StrToInt(V1),V2)
                        ELSE _Field^[FC] := CapsPrompt(StrToInt(V1),V2);
    END;
    IF Cmd = 'HIDDENPROMPT@' THEN BEGIN
      INC(FC); sWriteC(' ');
      IF Graphics = TTY THEN _Field^[FC] := SecretInput(StrToInt(V1),V2)
                        ELSE _Field^[FC] := SecretPrompt(StrToInt(V1),V2);
    END;
    IF Cmd = 'OUTTEXT@' THEN BEGIN
      IF V2 <> '' THEN WRITE(OutFile,V1)
                  ELSE WRITELN(OutFile,V1);
      IF (V2 <> '') AND (StrToInt(V2) <= FC) THEN WRITELN(OutFile,_Field^[StrToInt(V2)]);
    END;
    IF Cmd = 'RUNBATCHFILE@' THEN BEGIN
      RipToText;
      RunBatFile(V1);
    END;
    IF Cmd = 'SHOWTEXTFILE@' THEN ShowTextFile(V1);
    IF Cmd = 'CLS@' THEN sClrScr;
  END;
  DISPOSE(_Field);
  IF GotText THEN CLOSE(OutFile);
  CLOSE(InFile);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION GoodColor(TempStr : STRING ; ChangeColor : BOOLEAN) : BOOLEAN;
VAR
  FG : BYTE;
BEGIN
  FG := 50;
  IF TempStr = '{0}'  THEN FG := 0;
  IF TempStr = '{1}'  THEN FG := 1;
  IF TempStr = '{2}'  THEN FG := 2;
  IF TempStr = '{3}'  THEN FG := 3;
  IF TempStr = '{4}'  THEN FG := 4;
  IF TempStr = '{5}'  THEN FG := 5;
  IF TempStr = '{6}'  THEN FG := 6;
  IF TempStr = '{7}'  THEN FG := 7;
  IF TempStr = '{8}'  THEN FG := 8;
  IF TempStr = '{9}'  THEN FG := 9;
  IF TempStr = '{10}' THEN FG := 10;
  IF TempStr = '{11}' THEN FG := 11;
  IF TempStr = '{12}' THEN FG := 12;
  IF TempStr = '{13}' THEN FG := 13;
  IF TempStr = '{14}' THEN FG := 14;
  IF TempStr = '{15}' THEN FG := 15;
  IF TempStr = '{16}' THEN FG := 16;
  IF TempStr = '{17}' THEN FG := 17;
  IF TempStr = '{18}' THEN FG := 18;
  IF TempStr = '{19}' THEN FG := 19;
  IF TempStr = '{20}' THEN FG := 20;
  IF TempStr = '{21}' THEN FG := 21;
  IF TempStr = '{22}' THEN FG := 22;
  IF TempStr = '{23}' THEN FG := 23;
  IF TempStr = '{24}' THEN FG := 24;
  IF TempStr = '{25}' THEN FG := 25;
  IF TempStr = '{26}' THEN FG := 26;
  IF TempStr = '{27}' THEN FG := 27;
  IF TempStr = '{28}' THEN FG := 28;
  IF TempStr = '{29}' THEN FG := 29;
  IF TempStr = '{30}' THEN FG := 30;
  IF TempStr = '{31}' THEN FG := 31;
  IF FG <> 50 THEN BEGIN
    IF ChangeColor THEN SetFore(FG);
    GoodColor := TRUE;
  END ELSE GoodColor := FALSE;
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
FUNCTION StripColors(InStr : STRING) : STRING;
VAR
  Loop : BYTE;
  Cvt  : BOOLEAN;
  Temp : STRING;
  Hold : STRING;
BEGIN
  Cvt  := FALSE;
  Temp := '';
  Hold := '';
  FOR Loop := 1 TO LENGTH(InStr) DO BEGIN
    IF InStr[Loop] = '{' THEN Cvt := TRUE;
    IF Cvt THEN Temp := Temp + InStr[Loop]
           ELSE Hold := Hold + InStr[Loop];
    IF ((Cvt) AND (InStr[Loop] = '}')) OR (Loop = LENGTH(InStr)) THEN BEGIN
      IF NOT GoodColor(Temp,FALSE) THEN Hold := Hold + Temp;
      Cvt := FALSE;
      Temp := '';
    END;
  END;
  StripColors := Hold;
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE CvtColors(InStr : STRING ; LF : BOOLEAN);
VAR
  Loop : BYTE;
  Cvt  : BOOLEAN;
  Temp : STRING;
BEGIN
  Cvt  := FALSE;
  Temp := '';
  FOR Loop := 1 TO LENGTH(InStr) DO BEGIN
    IF InStr[Loop] = '{' THEN Cvt := TRUE;
    IF NOT Cvt THEN sWriteC(InStr[Loop]);
    IF Cvt THEN Temp := Temp + InStr[Loop];
    IF (Cvt) AND (InStr[Loop] = '}') THEN BEGIN
      IF NOT GoodColor(Temp,TRUE) THEN sWrite(Temp);
      Cvt := FALSE;
      Temp := '';
    END;
  END;
  IF LF THEN sWriteln('');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE RipToText;
BEGIN
  Set_Color(0,0);
  SendStr(#13#10);
  SendStr(AnsiColor + '!|1K|*|#|#|#' + #13#10);
  Set_Color(7,0);
  sClrScr;
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE ShowTextFile(TextFile : STRING);
TYPE TextData = RECORD
     TLine    : STRING;
     END;
VAR
  T         : TextData;
  TDat      : FILE OF TextData;
  Ch        : CHAR;
  Count,
  SvgaY,
  Loop,Cnt  : INTEGER;
  File_Name : TEXT;
BEGIN;
  IF Graphics = RIP THEN RipToText;
  IF Graphics <> MAX THEN sClrScr;
  ASSIGN(File_Name,TextFile);
  ASSIGN(TDat,GetFilePath(TextFile) + 'TEXT' + IntToStr(DoorSys.Node) + '.DAT');
  IF NOT FExist(TextFile) THEN BEGIN
    ErrorLog('Text File Not Found: ' + TextFile,6,FALSE);
    EXIT;
  END;
  IF (NOT Local) AND (Graphics IN [MAX,RIP,AVATAR]) THEN BEGIN
    DVWrite(2,24,15,PadRight('Displaying Text File: ' + CvtVars(GetFileName(TextFile)),' ',78));
  END;
  RESET(File_Name);
  REWRITE(TDat);
  Count := 0;
  Cnt   := 0;
  IF Graphics = MAX THEN BEGIN
    MaxCommand('');
    MaxCommand(#12);
    MaxCommand('’~ż’');
    MaxCommand('’~1,21,638,47,1,''Text Reader''’');
    MaxCommand('’~ 1,246’');
    MaxCommand('’~1,48,637,349’');
    MaxCommand('’~¢0,47,638,350,8’');
    MaxCommand('’~0,350,638,391’');
    MaxCommand('’~®10,361,80,20,81’');
    MaxCommand('’~®100,361,80,20,84’');
    MaxCommand('’~®190,361,80,20,66’');
    MaxCommand('’~®280,361,80,20,80’');
    MaxCommand('’~®370,361,80,20,13’');
    MaxCommand('’~38,363,4,2,''Q{0}uit''’');
    MaxCommand('’~128,363,4,2,''T{0}op''’');
    MaxCommand('’~209,363,4,2,''B{0}ottom''’');
    MaxCommand('’~295,363,4,2,''P{0}revious''’');
    MaxCommand('’~394,363,4,2,''M{0}ore''’');
    MaxCommand('’~ž’');
    MaxCommand('’~’');
  END;
  WHILE NOT EOF (File_Name) DO BEGIN
    INC(Cnt);
    INC(Count);
    READLN(File_Name,T.TLine);
    FOR Count := 1 TO LENGTH(T.TLine) DO IF T.TLine[Count] = '' THEN T.TLine[Count] := ' ';
    T.TLine := CvtVars(T.TLine);
    WRITE(TDat,T);
    IF Count = 22 THEN Count := 0;
  END;
  CLOSE(File_Name);
  RESET(TDat);
  Count := 0;
  SvgaY := 39;
  WHILE NOT EOF(TDat) DO BEGIN
    INC(Count);
    READ(TDat,T);
    IF Graphics <> MAX THEN BEGIN
      Set_Color(CS.TxFG,0);
      CvtColors(T.TLine,TRUE);
    END ELSE BEGIN
      INC(SvgaY,14);
      MaxCommand('’~5,' + IntToStr(SvgaY) + ',0,3,' + #39 + T.TLine + #39 + '’');
    END;
    IF (Count = 21) OR EOF(TDat) THEN BEGIN
      IF ((NOT Local) AND (Graphics <> MAX)) OR
         ((Local) AND (SvgaAnsiOn)) OR ((Local) AND (Graphics <> MAX)) THEN BEGIN
        Set_Color(7,0);
        LineBar(1,0,79);
        CPrompt('Q','uit'); CPrompt('T','op'); CPrompt('B','ottom'); CPrompt('P','revious'); CPrompt('M','ore');
      END;
      IF Graphics = MAX THEN MaxCommand('’~’');
      REPEAT Ch := UPCASE(SvgaReadKey) UNTIL Ch IN ['Q','T','B','P','M',#13,#27];
      IF Ch = #27 THEN Ch := 'Q';
      CASE Ch OF
        'Q' : BEGIN
                CLOSE(TDat);
                ERASE(TDat);
                EXIT;
              END;
        'T' : BEGIN
                Count := 0;
                SEEK(TDat,Count);
              END;
        'B' : BEGIN
                Count := Cnt - 21;
                IF Count < 0 THEN Count := 0;
                SEEK(TDat,Count);
                Count := 0;
              END;
        'P' : BEGIN
                Count := (FILEPOS(TDat) - 42);
                IF Count < 0 THEN Count := 0;
                SEEK(TDat,Count);
                Count := 0;
              END;
        ELSE Count := 0;
      END;
      IF (Graphics = MAX) AND (Ch <> 'Q') AND (NOT EOF(TDat)) THEN BEGIN
        SvgaY := 39;
        MaxCommand('’~’');
        MaxCommand('’~ 1,246’');
        MaxCommand('’~1,48,637,349’');
      END;
      IF (Graphics <> MAX) AND (Ch <> 'Q') AND (NOT EOF(TDat)) THEN sClrScr;
    END;
  END;
  CLOSE(TDat);
  ERASE(TDat);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE ShowScreen(Scr : STRING);
VAR
  DoAnsi    : BOOLEAN;
  Ch        : CHAR;
  Loop1     : WORD;
  Loop2     : WORD;
  LN        : STRING;
  File_Name : TEXT;
BEGIN;
  IF NOT FExist(Scr) THEN EXIT;
  IF (SvgaActive) AND (SvgaAnsiOn) THEN TextAttr := 7;
  IF NOT SvgaActive THEN HideCursor;
  IF (Graphics = RIP) OR (Graphics = MAX) THEN BEGIN
    SendStr(#13#10);
    SendStr(#12#13#10);
    IF NOT SvgaActive THEN CLRSCR;
  END;
  IF Graphics = TTY THEN sClrScr;
  IF (NOT Local) AND (Graphics IN [MAX,RIP,AVATAR]) THEN BEGIN
    DVWrite(2,24,15,PadRight('Displaying Screen File: ' + CvtVars(GetFileName(Scr)),' ',78));
  END;
  Loop1 := 0;
  Loop2 := 0;
  ASSIGN(File_Name,Scr);
  DoAnsi := FALSE;
  IF POS('.ANS',Scr) > 0 THEN BEGIN
    RESET(File_Name);
    WHILE NOT EOF(File_Name) DO BEGIN
      READ(File_Name,Ch);
      IF Ch = #27 THEN DoAnsi := TRUE;
    END;
  END;
  RESET(File_Name);
  WHILE NOT EOF(File_Name) DO BEGIN
    INC(Loop1);
    READLN(File_Name,LN);
  END;
  CLOSE(File_Name);
  RESET(File_Name);
  WHILE NOT EOF(File_Name) DO BEGIN
    INC(Loop2);
    READLN(File_Name,LN);
    LN := CvtVars(LN);
    CASE Graphics OF
      MAX, RIP, AVATAR : SendStr(LN + #13#10);
      ANSI : BEGIN
               IF DoAnsi THEN BEGIN
                 IF Loop2 < Loop1 THEN BEGIN
                   SendStr(LN + #13#10);
                   IF NOT SvgaActive THEN AnsiWriteln(LN + #13#10);
                 END ELSE BEGIN
                   SendStr(LN);
                   IF NOT SvgaActive THEN AnsiWriteln(LN);
                 END;
               END ELSE BEGIN
                 IF Loop2 < Loop1 THEN CvtColors(LN,TRUE)
                                  ELSE CvtColors(LN,FALSE);
               END;
             END;
      TTY  : IF Loop2 < Loop1 THEN sWriteln(LN) ELSE sWrite(LN);
    END;
    IF NOT Carrier THEN BEGIN
      ErrLevel := 3;
      HALT(ErrLevel);
    END;
  END;
  CLOSE(File_Name);
  IF NOT SvgaActive THEN ShowCursor;
  CurColor := TextAttr;
  IF Graphics <> TTY THEN sGotoXY(VirtX,VirtY);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE IceText(S : STRING ; LF : BOOLEAN);
VAR
  TLength : BYTE;
  Loop    : BYTE;
BEGIN
  TLength := LENGTH(S);
  FOR Loop := 1 TO TLength DO BEGIN
    IF (ORD(S[Loop]) >= 65) AND (ORD(S[Loop]) <= 90) THEN Set_Color(15,0) ELSE
    IF (ORD(S[Loop]) >= 97) AND (ORD(S[Loop]) <= 122) THEN Set_Color(11,0) ELSE
    IF (ORD(S[Loop]) > 127) OR (ORD(S[Loop]) < 32) THEN Set_Color(1,0) ELSE Set_Color(9,0);
    sWrite(S[Loop]);
  END;
  IF LF THEN sWriteln('');
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE FullScreenChat;
VAR
  FG,
  Loop,
  UserX,
  UserY,
  SysopX,
  SysopY   : BYTE;
  Quit     : BOOLEAN;
  Ch       : CHAR;
  SText,
  UText    : STRING[80];
BEGIN
  DoorSys.UpdateSecs := FALSE;
  DoorSys.UpdateIdle := FALSE;
  sClrScr;
  InfoText(Center(ProgramName,71));
  sGotoXY(1,2); InfoBox(79,8);
  InfoText(Center(ProgramDesc,71));
  sGotoXY(1,13); InfoBox(79,8);
  InfoText('CTRL-W (Clear Window)                               CTRL-Y (Clear Line)');
  IF NOT SvgaActive THEN DVWrite(1,24,8,Center('Press The ESCape Key To Terminate Chat Mode!',79));
  sGotoXY(3,2);  IceText(' ' + #31 + ' ' + Ctl.SFirst + ' ' + Ctl.SLast + ' ' + #31 + ' ',FALSE);
  sGotoXY(3,13); IceText(' ' + #31 + ' ' + DoorSys.UserName + ' ' + #31 + ' ',FALSE);
  SysopX   := 2;
  SysopY   := 3;
  UserX    := 2;
  UserY    := 14;
  Quit     := FALSE;
  DoorSys.LocalKey := TRUE;
  sGotoXY(2,3);
  WITH DoorSys DO REPEAT
    REPEAT
      Ch := sReadKey;
    UNTIL Ch IN [#0,#8,#13,#23,#25,#27,' '..#255];
    CASE Ch OF
      #0 : BEGIN
             sReadKey;
             Ch := #0;
           END;
      #8 : IF LocalKey THEN BEGIN
             DEC(SysopX);
             DELETE(SText,LENGTH(SText),1);
             IF SysopX < 2 THEN SysopX := 2;
             Ch := #0;
             sGotoXY(SysopX,SysopY); sWrite(' ');
             sGotoXY(SysopX,SysopY);
           END ELSE BEGIN
             DEC(UserX);
             DELETE(UText,LENGTH(UText),1);
             IF UserX < 2 THEN UserX := 2;
             Ch := #0;
             sGotoXY(UserX,UserY); sWrite(' ');
             sGotoXY(UserX,UserY);
           END;
      #13: IF LocalKey THEN BEGIN
             SysopX := 2;
             SText  := '';
             INC(SysopY);
             IF SysopY > 10 THEN SysopY := 3;
             sGotoXY(SysopX,SysopY);
             sWrite(PadRight(' ',' ',77));
             IF SysopY < 10 THEN sGotoXY(SysopX,SysopY + 1) ELSE sGotoXY(SysopX,3);
             sWrite(PadRight(' ',' ',77));
             sGotoXY(SysopX,SysopY);
             Ch := #0;
           END ELSE BEGIN
             UserX := 2;
             UText := '';
             INC(UserY);
             IF UserY > 21 THEN UserY := 14;
             sGotoXY(UserX,UserY);
             sWrite(PadRight(' ',' ',77));
             IF UserY < 21 THEN sGotoXY(UserX,UserY + 1) ELSE sGotoXY(UserX,14);
             sWrite(PadRight(' ',' ',77));
             sGotoXY(UserX,UserY);
             Ch := #0;
           END;
      #23: IF LocalKey THEN BEGIN
             FOR Loop := 3 TO 10 DO BEGIN
               sGotoXY(2,Loop);
               sWrite(PadRight(' ',' ',77));
             END;
             SysopX := 2;
             SysopY := 3;
             SText  := '';
             sGotoXY(SysopX,SysopY);
             Ch := #0;
           END ELSE BEGIN
             FOR Loop := 14 TO 21 DO BEGIN
               sGotoXY(2,Loop);
               sWrite(PadRight(' ',' ',77));
             END;
             UserX := 2;
             UserY := 14;
             UText := '';
             sGotoXY(UserX,UserY);
             Ch := #0;
           END;
      #25: IF LocalKey THEN BEGIN
             SysopX := 2;
             SText  := '';
             sGotoXY(SysopX,SysopY);
             sWrite(PadRight(' ',' ',77));
             sGotoXY(SysopX,SysopY);
             Ch := #0;
           END ELSE BEGIN
             UserX := 2;
             UText := '';
             sGotoXY(UserX,UserY);
             sWrite(PadRight(' ',' ',77));
             sGotoXY(UserX,UserY);
             Ch := #0;
           END;
      #27: IF NOT LocalKey THEN BEGIN
             DELAY(50);
             WHILE sKeyPressed DO sReadKey;
             Ch := #0;
           END;
    END;
    Quit := Ch = #27;
    IF (ORD(Ch) >= 65) AND (ORD(Ch) <= 90) THEN FG := 15 ELSE
    IF (ORD(Ch) >= 97) AND (ORD(Ch) <= 122) THEN FG := 11 ELSE
    IF (ORD(Ch) > 127) OR (ORD(Ch) < 32) THEN FG := 1 ELSE FG := 9;
    IF (NOT Quit) AND (Ch <> #0) AND (Ch <> #27) THEN BEGIN
      IF LocalKey THEN BEGIN
        IF Ch = ' ' THEN SText := '' ELSE SText := SText + Ch;
        sGotoXY(SysopX,SysopY); OutTxt(FG,0,Ch);
        INC(SysopX);
        IF SysopX = 79 THEN BEGIN
          IF SText <> '' THEN BEGIN
            sGotoXY(SysOpX - LENGTH(SText),SysOpY);
            sWrite(PadRight(' ',' ',LENGTH(SText)));
          END;
          SysopX := 2;
          INC(SysopY);
          IF SysopY > 10 THEN SysopY := 3;
          sGotoXY(SysopX,SysopY);
          sWrite(PadRight(' ',' ',77));
          IF SysopY < 10 THEN sGotoXY(SysopX,SysopY + 1) ELSE sGotoXY(SysopX,3);
          sWrite(PadRight(' ',' ',77));
          IF SText <> '' THEN BEGIN
            sGotoXY(SysopX,SysopY);
            IceText(SText,FALSE);
            INC(SysopX,LENGTH(SText));
          END;
        END;
        sGotoXY(SysopX,SysopY);
      END ELSE BEGIN
        IF Ch = ' ' THEN UText := '' ELSE UText := UText + Ch;
        sGotoXY(UserX,UserY); OutTxt(FG,0,Ch);
        INC(UserX);
        IF UserX = 79 THEN BEGIN
          IF UText <> '' THEN BEGIN
            sGotoXY(UserX - LENGTH(UText),UserY);
            sWrite(PadRight(' ',' ',LENGTH(UText)));
          END;
          UserX := 2;
          INC(UserY);
          IF UserY > 21 THEN UserY := 14;
          sGotoXY(UserX,UserY);
          sWrite(PadRight(' ',' ',77));
          IF UserY < 21 THEN sGotoXY(UserX,UserY + 1) ELSE sGotoXY(UserX,14);
          sWrite(PadRight(' ',' ',77));
          IF UText <> '' THEN BEGIN
            sGotoXY(UserX,UserY);
            IceText(UText,FALSE);
            INC(UserX,LENGTH(UText));
          END;
        END;
        sGotoXY(UserX,UserY);
      END;
    END;
  UNTIL Quit;
  DoorSys.UpdateSecs := TRUE;
  DoorSys.UpdateIdle := TRUE;
  Set_Color(7,0);
  sClrScr;
  PurgeInput;
  IceText('Press Any Key To Redraw Screen',FALSE);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE LineChat;
CONST
  SysopText   : BYTE = 15;
  CallerText  : BYTE = 11;
VAR
  InputKey    : CHAR;
  Loop,I      : BYTE;
  CL,
  Temp,
  RTemp,
  Movement    : STRING;
  OldLocalKey : BOOLEAN;
BEGIN
  sClrScr;
  OutTxtL(15,0,Ctl.SFirst + ' ' + Ctl.SLast + ' Is Here At Your Services....');
  DoorSys.UpdateSecs := FALSE;
  DoorSys.UpdateIdle := FALSE;
  CL[0]       := #0;
  Movement[0] := #0;
  TextAttr    := SysopText;
  OldLocalKey := TRUE;
  WITH DoorSys DO REPEAT
    InputKey := sReadkey;
    IF LocalKey <> OldLocalKey THEN BEGIN
      IF LocalKey THEN TextAttr := SysopText ELSE TextAttr := CallerText;
      OldLocalKey := LocalKey;
    END;
    IF WrapLength <= BYTE(CL[0]) THEN BEGIN
      Temp[0]  := #0;
      RTemp[0] := #0;
      Loop     := BYTE(CL[0]);
      IF POS(#32,CL) <> 0 THEN WHILE (CL[Loop] <> #32) DO BEGIN
        sWrite(#8#32#8);
        Temp := Temp + CL[Loop];
        DEC(Loop);
      END ELSE WHILE (Loop >= WrapLength) DO BEGIN
        sWrite(#8#32#8);
        Temp := Temp + CL[Loop];
        DEC(Loop);
      END;
      IF Temp[0] <> #0 THEN FOR Loop := BYTE(Temp[0]) DOWNTO 1 DO RTemp := RTemp + Temp[Loop];
      sWrite(#13#10 + RTemp);
      CL := RTemp;
    END;
    IF (NOT (Inputkey IN [#13,#27,#8,#27,#0])) THEN BEGIN
      sWrite(InputKey);
      CL := CL + InputKey;
    END ELSE
    CASE InputKey OF
      #0  : Movement := s_ReadKey;
      #8  : IF CL <> '' THEN BEGIN
              sWrite(#8#32#8);
              DEC(CL[0]);
            END;
      #13 : BEGIN
              sWriteln('');
              CL := '';
            END;
      #27 : IF NOT LocalKey THEN Movement := InputKey + sReadKey + sReadKey;
    END;
    IF Movement <> '' THEN BEGIN
      FOR Loop := Tty TO Ansi DO BEGIN
        IF Movement = CursorMove.Up[Loop] THEN Movement := '' ELSE
        IF Movement = CursorMove.Down[Loop] THEN Movement := '' ELSE
        IF Movement = CursorMove.Left[Loop] THEN Movement := '' ELSE
        IF Movement = CursorMove.Right[Loop] THEN Movement := '' ELSE
        IF Movement = CursorMove.Insert[Loop] THEN Movement := '' ELSE
        IF Movement = CursorMove.Delete[Loop] THEN Movement := '' ELSE
        IF Movement = CursorMove.Home[Loop] THEN Movement := '' ELSE
        IF Movement = CursorMove.EndKey[Loop] THEN Movement := '';
      END;
      IF Movement <> '' THEN BEGIN
        FOR I := 1 TO LENGTH(Movement) DO sWrite(Movement[I]);
        Movement := '';
      END;
    END;
  UNTIL (LocalKey AND (InputKey = #27));
  DoorSys.UpdateSecs := TRUE;
  DoorSys.UpdateIdle := TRUE;
  Set_Color(7,0);
  sClrScr;
  PurgeInput;
  IceText('Press Any Key To Redraw Screen',FALSE);
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE ChatSelect;
BEGIN
  InChat := TRUE;
  IF (Graphics = RIP) OR (Graphics = MAX) THEN RipToText;
  Set_Color(7,0);
  IF Graphics = TTY THEN LineChat ELSE FullScreenChat;
  InChat := FALSE;
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE DVWrite(X,Y : WORD; Attr : BYTE; S : STRING); Assembler;
{X and Y are 1 based, not 0 zero based!}
Asm
  push ds
  mov bx,[y]
  DEC bx
  SHL bx,1
  mov ax,bx
{$ifopt G+}
  SHL bx,2
{$else}
  SHL bx,1
  SHL bx,1
{$endif}
  add ax,bx
  add ax,[DVseg]
  mov es,ax
  mov di,[x]
  DEC di
  SHL di,1
  add di,[DVofs]
  lds si,s
  mov cl,BYTE PTR [si]
  INC si
  mov ah,attr
@1 :
  mov al,BYTE PTR [si]
  mov WORD PTR es : [di],ax
  INC si
  add di,2
  DEC cl
  jnz @1
  pop ds
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE AlertTones;
VAR
  Loop : BYTE;
BEGIN
  FOR Loop := 1 TO 5 DO BEGIN
    IF NOT Local THEN SendStr(^G) ELSE WRITE(^G);
    DELAY(200);
  END
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}

END.
