home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / BASIC / PANSI2 / PANSI2.BAS < prev    next >
BASIC Source File  |  1993-05-30  |  29KB  |  928 lines

  1. 'PANSI2.BAS
  2. 'ANSI emulator for QuickBASIC 4.5(maby PDS) v1.50
  3. 'By Richard Geldreich July 24, 1992
  4. 'Version 2.0 completed May 30, 1993 (slow, eh?), by John Gallas
  5.  
  6. 'This program is hereby put into the public domain.  You may do basically
  7. 'whatever you want with it, but we ask that you give the authors some credit
  8. 'if you use this program in one of your own programs.
  9.  
  10. 'Don't forget that "CALL INTERRUPT"  is used- "INTRPT.OBJ" in the QB.LIB
  11. 'library...
  12.  
  13. '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  14. '! Don't forget to modify the "SendStatus" procedure for your !
  15. '!                       comm package!                        !
  16. '!    You also should modify PrintString for QB4.5 or PDS     !
  17. '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  18.  
  19. 'NOTE: This program assumes that the current segment is always
  20. 'pointing twards the video buffer!! If you change the current
  21. 'segment don't forget to change it back or sparks will fly when you
  22. 'write to the screen! (see GetVSeg)
  23.  
  24. '** Additions to version 2.0 **
  25. 'All I did was add the Avatar/0+ codes.  (Note: There is an additional file
  26. 'included in the archive called ANSIAVT.ARJ which contains all of the stats
  27. 'for ANSI and Avatar.)  The incredible modular design was all done by Rich.
  28. 'In fact, if it wasn't put together so well, it would've been VERY hard to
  29. 'add the Avatar support.
  30.  
  31. 'Info on usage:
  32. 'Boundaries x,y- makes sure that x and y are inside the maximum and minimum
  33. 'x and y coordinates, and if they aren't, it puts them there.
  34.  
  35. 'ClearScreen- used internally by the PrintAnsi procedure- you may
  36. 'use it to clear the current window(the current background color
  37. 'is used in the clear). The cursor is set to the upper left hand corner
  38. 'of the window after the window is cleared.
  39.  
  40. 'CursorControl A- if A is non-zero then the SetCursor routine(which
  41. 'is called by PrintAnsi) will update the cursor whenever it is moved.
  42. 'If it is zero then SetCursor won't touch the cursor's position.
  43.  
  44. 'GetVSeg- Returns the current video segment.
  45.  
  46. 'Init- you must call this before PrintAnsi can work properly. Sets
  47. 'up the color translation table, sets the window to the current screen
  48. 'page and size, sets the cursor to the upper-left hand corner of the
  49. 'window and tests the adapter to see if it's monochrome or color. All
  50. 'states are reset when this procedure is called.
  51.  
  52. 'Music A- if A is not zero, then ANSI music is enabled.
  53.  
  54. 'PrintAnsi Char- where Char is an ASCII code from 0-255. Recognizes
  55. 'ANSI escape sequences and Avatar/0+ codes. Processes the character and
  56. 'updates the display, if needed.
  57.  
  58. 'PrintString A$- prints a string to the display. Calls PrintAnsi for
  59. 'each character. Don't forget to modify this for PDS/QuickBASIC.
  60.  
  61. 'ScrollUpScreen- scrolls up the current window. Uses a BIOS call.
  62. 'Normally used internally by PrintAnsi.
  63.  
  64. 'SendStatus- sends a CPR sequence to the receiver.
  65. 'In other words, SendStatus will output the current X and Y coordinates
  66. 'of the cursor to the remote terminal. Used by some BBS's and doors
  67. 'to see if the user's terminal has ANSI capibilities. You must modify
  68. 'this procedure to output the status string to your comm package!
  69. '(this is used internally by PrintAnsi)
  70.  
  71. 'SetCursor- moves the cursor to its correct position(it doesn't turn
  72. 'it on however- use the LOCATE , , 1 command to do that). This procedure
  73. 'should work on all adapters, but I haven't tested it out on many
  74. 'cards yet... Use this to restore the cursor to where it should be
  75. 'after you move it.
  76.  
  77. 'SetWindow WorkPage, Lx,Ly,Hx,Hy- defines a window where all text
  78. 'is printed. if WorkPage is -1, then the BIOS data area is examined for
  79. 'the current screen page, otherwise WorkPage must indicate which page to
  80. 'write to. If Lx is -1, the the window will take up the entire screen
  81. 'otherwise Lx and Ly are the upper-left lines of the window(where
  82. '1,1 is the upper corner of the screen) and Hx and Hy are the lower-right
  83. 'coordinates of the window.
  84. '   The current cursor position is moved to the upper left corner of the
  85. 'new window. If the coordinates passed are invalid, the window is not
  86. 'modified.
  87.  
  88. 'Recurse Buffer$- Used with the ^V^Y Avatar/0+ repeat string code, repeats
  89. 'Buffer$ ASC(AvtBuf$) times.
  90.  
  91. '   That's all! You can add more functions if you need them; I've
  92. 'documented the PrintAnsi procedure enough for you to get
  93. 'a good idea of how it works.
  94.  
  95. DEFINT A-Z
  96.  
  97. DECLARE SUB ClearScreen ()
  98. DECLARE SUB CursorControl (a%)
  99. DECLARE FUNCTION GetVSeg% ()
  100. DECLARE SUB Init ()
  101. DECLARE SUB Music (a%)
  102. DECLARE SUB PrintAnsi (char%)
  103. DECLARE SUB PrintString (b$)
  104. DECLARE SUB Recurse (Buffer$)
  105. DECLARE SUB ScrollUpScreen ()
  106. DECLARE SUB SendStatus (x%, y%)
  107. DECLARE SUB SetCursor ()
  108. DECLARE SUB SetWindow (WorkPage%, Lx%, Ly%, Hx%, Hy%)
  109. DECLARE SUB Scroll (Direction%, Top%, Left%, Bottom%, Right%, Lines%, Attr%)
  110. DECLARE SUB Boundaries (x%, y%)
  111.  
  112. DECLARE SUB playme (a$)
  113.  
  114. TYPE RegType
  115.      ax    AS INTEGER
  116.      bx    AS INTEGER
  117.      cx    AS INTEGER
  118.      dx    AS INTEGER
  119.      bp    AS INTEGER
  120.      si    AS INTEGER
  121.      di    AS INTEGER
  122.      flags AS INTEGER
  123. END TYPE
  124.  
  125. DIM SHARED Xpos, Ypos               'cursor's position
  126. DIM SHARED MinX, MinY, MaxX, MaxY   'current window
  127. DIM SHARED SaveX, SaveY             'used by SCR and RCP
  128. DIM SHARED Colors(7), Attribute
  129. DIM SHARED CursorOn, VideoSegment, VideoOffset, CursorAddress, BytesPerLine
  130. DIM SHARED Monochrome, CRT          'monochrome adapter flag
  131. DIM SHARED ANSIMusic, MusicLevel
  132. DIM SHARED Level
  133. DIM SHARED Reserve, AvtBuf$, Insert, AvtFunc, tempbuf$
  134.  
  135. CONST True = -1, False = NOT True   'usefull stuff
  136.  
  137. '******START OF TEST PROGRAM
  138. 'The following code is not needed... It's only for testing!
  139. '
  140. 'Init
  141. 'SetWindow -1, 2, 2, 79, 24
  142. 'LOCATE 1, 1: PRINT STRING$(2000, 219);
  143. 'SetCursor
  144. 'CursorControl 1
  145. 'OPEN "com1:2400,n,8,1" FOR RANDOM AS #1
  146. 'DO
  147. '  IF NOT EOF(1) THEN x$ = INPUT$(LOC(1), #1): PrintString x$
  148. '  a$ = INKEY$
  149. '  IF LEN(a$) THEN PRINT #1, a$;
  150. 'LOOP
  151.  
  152. SUB Boundaries (x, y)
  153.  
  154. IF x > MaxX THEN x = MaxX
  155. IF x < MinX THEN x = MinX
  156. IF y > MaxY THEN y = MaxY
  157. IF y < MinY THEN y = MinY
  158.  
  159. END SUB
  160.  
  161. 'Clears the current window. The cursor is also set to the upper-left hand
  162. 'corner of the window.
  163. SUB ClearScreen
  164.     DIM Regs AS RegType
  165.     Regs.ax = &H600
  166.     a& = Attribute * 256&
  167.     IF a& > 32767 THEN a = a& - 65536 ELSE a = a&
  168.     Regs.bx = a
  169.     Regs.cx = (MinY * 256&) + MinX - 257
  170.     Regs.dx = (MaxY * 256&) + MaxX - 257
  171.     CALL INTERRUPT(&H10, Regs, Regs)
  172.  
  173.     Xpos = MinX: Ypos = MinY
  174.     SetCursor
  175.  
  176.  
  177. END SUB
  178.  
  179. 'Enables or disables cursor updating.
  180. SUB CursorControl (a)
  181.     IF a THEN
  182.         CursorOn = True
  183.     ELSE
  184.         CursorOn = False
  185.     END IF
  186. END SUB
  187.  
  188. 'Returns the current video segment.
  189. FUNCTION GetVSeg
  190.     GetVSeg = VideoSegment
  191. END FUNCTION
  192.  
  193. 'Initializes everything.
  194. SUB Init
  195.     DIM Regs AS RegType
  196.  
  197.     'default color, white on black (or black on white??)
  198.     Attribute = 7
  199.  
  200.     Level = 0: MusicLevel = 0   'reset levels
  201.     ANSIMusic = True            'ANSI music enabled
  202.     CursorOn = True             'cursor movement enabled
  203.  
  204.     'set the color translation table
  205.     Colors(0) = 0: Colors(1) = 4: Colors(2) = 2: Colors(3) = 6
  206.     Colors(4) = 1: Colors(5) = 5: Colors(6) = 3: Colors(7) = 7
  207.  
  208.     Regs.ax = 15 * 256
  209.     CALL INTERRUPT(&H10, Regs, Regs)
  210.     'if AL=7 then card is monochrome.
  211.     IF (Regs.ax AND 255) = 7 THEN
  212.         VideoSegment = &HB000
  213.         Monochrome = True
  214.     ELSE
  215.         VideoSegment = &HB800
  216.         Monochrome = False
  217.     END IF
  218.     DEF SEG = &H40
  219.     CRT = PEEK(&H63) + PEEK(&H64) * 256&
  220.  
  221.     'Set segment to the screen.
  222.     DEF SEG = VideoSegment
  223.  
  224.     'window defaults to screen's page & size
  225.     'Xpos, Ypos, SaveX, SaveY, MinX, MinY, MaxX, MaxY, VideoOffset and the
  226.     'cursor are set up within this procedure
  227.     SetWindow -1, -1, 0, 0, 0
  228.  
  229. END SUB
  230.  
  231. 'Enables/Disables ANSI music...
  232. SUB Music (a)
  233.     ANSIMusic = a
  234. END SUB
  235.  
  236. 'Prints an ASCII character on the screen; filters out ANSI escape sequences
  237. 'and Avatar sequences and parses and prints them.
  238. SUB PrintAnsi (char) STATIC
  239.     DIM Parameters(10)
  240.  
  241.     SELECT CASE Level
  242.     CASE 0
  243.         'normal mode
  244.         GOSUB ProcessChar
  245.     CASE 1
  246.         'Level=1 after a chr$(27) is received.
  247.         'valid escape sequence?
  248.  
  249.         IF char <> 91 THEN
  250.             Level = 0
  251.             GOSUB ProcessChar
  252.  
  253.         ELSE
  254.             'a valid escape sequence has been received
  255.             Level = 2
  256.             CurrentParameter = 0
  257.             NumParameters = 0
  258.             ValidParameter = False
  259.             FOR a = 0 TO 10: Parameters(a) = 1: NEXT
  260.         END IF
  261.     CASE 2
  262.  
  263.         'inside an escape sequence
  264.         GOSUB ProcessCode
  265.     END SELECT
  266. EXIT SUB
  267.  
  268. ProcessChar:
  269.     'processes a non-ANSI code
  270.     SELECT CASE char
  271.     'process CTRL-V
  272.     CASE 22
  273.         Reserve = -1
  274.         AvtBuf$ = ""
  275.         Level = 2
  276.     'process CTRL-Y
  277.     CASE 25
  278.         Reserve = 2
  279.         AvtBuf$ = ""
  280.         AvtFunc = 26
  281.         Level = 2
  282.     'process new page code
  283.     CASE 12
  284.         Attribute = 3
  285.         ClearScreen
  286.     'process escape character
  287.     CASE 27
  288.         Level = 1
  289.         Reserve = 0
  290.     'process enter
  291.     CASE 13
  292.         Xpos = MinX
  293.         SetCursor
  294.     'process line feed
  295.     CASE 10
  296.         Ypos = Ypos + 1
  297.         IF Ypos > MaxY THEN Ypos = MaxY: ScrollUpScreen
  298.         SetCursor
  299.     'process backspace(destructive)
  300.     CASE 8
  301.         IF Xpos > MinX THEN
  302.             Xpos = Xpos - 1
  303.             CursorAddress = CursorAddress - 2
  304.             POKE CursorAddress, 32: POKE CursorAddress + 1, Attribute
  305.             SetCursor
  306.         END IF
  307.     'process tab key(tab stops=8)
  308.     CASE 9
  309.         Xpos = ((Xpos \ 8) + 1) * 8
  310.         IF Xpos > MaxX THEN Xpos = MaxX
  311.         SetCursor
  312.     'process bell
  313.     CASE 7
  314.         'don't substitute a "BEEP" statement here!
  315.         'BEEP resets the cursor to where QB thinks it is!
  316.         SOUND 3140, 1.25
  317.     'any other character is sent to the screen
  318.     CASE ELSE
  319.  
  320.         'prints a character to the screen
  321.         IF Insert THEN
  322.             y = (MaxX - Xpos - 1) * 2
  323.             y = y + CursorAddress
  324.             FOR x = MaxX - 1 TO Xpos STEP -1
  325.                 POKE y, PEEK(y - 2)
  326.                 POKE y + 1, PEEK(y - 1)
  327.                 y = y - 2
  328.             NEXT x
  329.         END IF
  330.  
  331.         POKE CursorAddress, char: POKE CursorAddress + 1, Attribute
  332.         CursorAddress = CursorAddress + 2
  333.         Xpos = Xpos + 1
  334.  
  335.         IF Xpos > MaxX THEN
  336.  
  337.             Xpos = MinX
  338.             Ypos = Ypos + 1
  339.             IF Ypos > MaxY THEN
  340.                 Ypos = MaxY
  341.                 ScrollUpScreen
  342.             END IF
  343.             SetCursor
  344.         ELSE
  345.             IF CursorOn THEN
  346.                 Address = CursorAddress \ 2
  347.                 OUT CRT, &HE
  348.                 OUT CRT + 1, Address \ 256
  349.                 OUT CRT, &HF
  350.                 OUT CRT + 1, Address AND 255
  351.             END IF
  352.         END IF
  353.     END SELECT
  354. RETURN
  355. 'processes a character within an ansi escape sequence
  356. 'non-valid characters are sent to the screen
  357. ProcessCode:
  358. 'handles ANSI music...
  359. IF MusicLevel > 0 THEN
  360.     SELECT CASE MusicLevel
  361.     'see if the "F" in "ESC[MF" is received...
  362.     CASE 1
  363.         IF char <> 70 THEN          '"F"
  364.             MusicLevel = 0
  365.             Level = 0
  366.             GOSUB ProcessChar
  367.         ELSE
  368.             MusicLevel = 2
  369.             MusicString$ = ""
  370.         END IF
  371.         'Either add a char to the music string or play it...
  372.     CASE 2
  373.         IF char <> 14 THEN
  374.             'fall out if an escape character is received...
  375.             IF char = 27 THEN
  376.                 MusicString$ = ""
  377.                 MusicLevel = 0
  378.                 Level = 0
  379.                 GOSUB ProcessChar
  380.             'assume the character received to be part of the
  381.             'PLAY string
  382.             ELSE
  383.                 MusicString$ = MusicString$ + CHR$(char)
  384.             END IF
  385.         ELSE
  386.             IF ANSIMusic THEN
  387.                 'play the string- the PLAY command is in a seperate
  388.                 'module to keep error checking out of this module
  389.                 playme MusicString$
  390.             END IF
  391.             MusicString$ = ""
  392.             MusicLevel = 0
  393.             Level = 0
  394.         END IF
  395.     END SELECT
  396. ELSE
  397.     ' Reserve tells how many characters we're waiting for before our Avatar
  398.     ' sequence has been completed.  If its -1, it means we've recieved a
  399.     ' CONTROL-V, and we're awaiting the command character before we do
  400.     ' anything.  If the command requires more characters to come through, it
  401.     ' sets Reserve to the amount it needs, and it sets AvtFunc so we know
  402.     ' which function to use the characters for when they get here.
  403.     IF Reserve THEN
  404.        IF Reserve = -1 THEN
  405.           Reserve = 0
  406.           SELECT CASE char
  407.           CASE 1
  408.               '^V^A, set attribute to next byte recieved
  409.               Reserve = 1
  410.               AvtFunc = char
  411.               AvtBuf$ = ""
  412.               Insert = False
  413.           CASE 2
  414.               '^V^B, set blink on
  415.               Attribute = Attribute OR 128
  416.               Level = 0
  417.               Insert = False
  418.           CASE 3
  419.               '^V^C, move cursor up 1
  420.               Ypos = Ypos - 1
  421.               IF Ypos < MinY THEN Ypos = MinY
  422.               SetCursor
  423.               Level = 0
  424.               Insert = False
  425.           CASE 4
  426.               '^V^D, move down
  427.               Ypos = Ypos + 1
  428.               IF Ypos > MaxY THEN Ypos = MaxY
  429.               SetCursor
  430.               Level = 0
  431.               Insert = False
  432.           CASE 5
  433.               '^V^E, move left
  434.               Xpos = Xpos - 1
  435.               IF Xpos < MinX THEN Xpos = MinX
  436.               SetCursor
  437.               Level = 0
  438.               Insert = False
  439.           CASE 6
  440.               '^V^F, move right
  441.               Xpos = Xpos + 1
  442.               IF Xpos > MaxX THEN Xpos = MaxX
  443.               SetCursor
  444.               Level = 0
  445.               Insert = False
  446.           CASE 7
  447.               '^V^G, clear to EOL
  448.               a = CursorAddress
  449.               FOR x = Xpos TO MaxX
  450.                   POKE a, 32: POKE a + 1, Attribute: a = a + 2
  451.               NEXT
  452.               SetCursor
  453.               Level = 0
  454.               Insert = False
  455.           CASE 8
  456.               '^V^H, locate cursor at Y,X (next 2 bytes)
  457.               Reserve = 2
  458.               AvtBuf$ = ""
  459.               AvtFunc = char
  460.               Insert = False
  461.           CASE 9
  462.               '^V^I, Insert mode on
  463.               Insert = True
  464.               Level = 0
  465.           CASE 10
  466.               '^V^J, scroll area up, reserve the next 5 characters for our
  467.               'function.
  468.               Reserve = 5
  469.               AvtBuf$ = ""
  470.               AvtFunc = char
  471.               Insert = False
  472.           CASE 11
  473.               '^V^K, scroll down
  474.               Reserve = 5
  475.               AvtBuf$ = ""
  476.               AvtFunc = char
  477.               Insert = False
  478.           CASE 12
  479.               '^V^L, Clear block
  480.               Reserve = 3
  481.               AvtBuf$ = ""
  482.               AvtFunc = char
  483.               Insert = False
  484.           CASE 13
  485.               '^V^M, fill block to attr, char, etc
  486.               Reserve = 4
  487.               AvtBuf$ = ""
  488.               AvtFunc = char
  489.               Insert = False
  490.           CASE 14
  491.               '^V^N, delete char, scroll line left
  492.               a = CursorAddress
  493.               FOR x = Xpos TO MaxX - 1
  494.                   POKE a, PEEK(a + 2): POKE a + 1, PEEK(a + 3): a = a + 2
  495.               NEXT
  496.               POKE a, 32
  497.               POKE a + 1, Attribute
  498.               SetCursor
  499.               Level = 0
  500.               Insert = False
  501.           CASE 25
  502.               '^V^Y, repeat string
  503.               Reserve = 1
  504.               AvtBuf$ = ""
  505.               AvtFunc = char
  506.           CASE ELSE
  507.               Level = 0
  508.               Reserve = 0
  509.               GOSUB ProcessChar
  510.               RETURN
  511.           END SELECT
  512.        ELSE
  513.           'reserve > 0
  514.           'Add it to our buffer
  515.           AvtBuf$ = AvtBuf$ + CHR$(char)
  516.           IF LEN(AvtBuf$) = Reserve THEN  'if we got all the chars we need
  517.              Reserve = 0
  518.              SELECT CASE AvtFunc
  519.              CASE 26  'repeat character C, N times
  520.                 Level = 0
  521.                 Reserve = 0
  522.                 a = ASC(RIGHT$(AvtBuf$, 1))
  523.                 b = ASC(LEFT$(AvtBuf$, 1))
  524.                 z = CursorAddress
  525.                 FOR x = 1 TO a
  526.                     POKE z, b
  527.                     POKE z + 1, Attribute
  528.                     z = z + 2
  529.                     Xpos = Xpos + 1
  530.                     IF Xpos > MaxX THEN
  531.                         Xpos = 1
  532.                         Ypos = Ypos + 1
  533.                         IF Ypos > MaxY THEN
  534.                             Ypos = MaxY
  535.                             ScrollUpScreen
  536.                         END IF
  537.                     END IF
  538.                 NEXT x
  539.                 SetCursor
  540.              CASE 1
  541.                 'set attribute
  542.                 Attribute = ASC(AvtBuf$)
  543.                 SetCursor
  544.                 Level = 0
  545.                 Reserve = 0
  546.              CASE 8
  547.                 'locate cursor at Y,X
  548.                 Xpos = ASC(RIGHT$(AvtBuf$, 1))
  549.                 Ypos = ASC(LEFT$(AvtBuf$, 1))
  550.                 Boundaries Xpos, Ypos
  551.                 Level = 0
  552.                 Reserve = 0
  553.                 SetCursor
  554.              CASE 10
  555.                 'scroll up!
  556.                 a = ASC(LEFT$(AvtBuf$, 1))
  557.                 y = ASC(MID$(AvtBuf$, 2, 1))
  558.                 x = ASC(MID$(AvtBuf$, 3, 1))
  559.                 Y2 = ASC(MID$(AvtBuf$, 4, 1))
  560.                 X2 = ASC(MID$(AvtBuf$, 5, 1))
  561.                 '(Direction%, Top%, Left%, Bottom%, Right%, Lines%, Attr%)
  562.                 Boundaries x, y
  563.                 Boundaries X2, Y2
  564.                 Scroll 0, y, x, Y2, X2, a, Attribute
  565.                 SetCursor
  566.                 Level = 0
  567.                 Reserve = 0
  568.              CASE 11
  569.                 'scroll down!
  570.                 a = ASC(LEFT$(AvtBuf$, 1))
  571.                 y = ASC(MID$(AvtBuf$, 2, 1))
  572.                 x = ASC(MID$(AvtBuf$, 3, 1))
  573.                 Y2 = ASC(MID$(AvtBuf$, 4, 1))
  574.                 X2 = ASC(MID$(AvtBuf$, 5, 1))
  575.                 '(Direction%, Top%, Left%, Bottom%, Right%, Lines%, Attr%)
  576.                 Boundaries x, y
  577.                 Boundaries X2, Y2
  578.                 Scroll 1, y, x, Y2, X2, a, Attribute
  579.                 SetCursor
  580.                 Level = 0
  581.                 Reserve = 0
  582.              CASE 12
  583.                 'clear block
  584.                 a = ASC(LEFT$(AvtBuf$, 1))
  585.                 y = ASC(MID$(AvtBuf$, 2, 1))
  586.                 x = ASC(MID$(AvtBuf$, 3, 1))
  587.                 y = Ypos + y
  588.                 x = Xpos + x
  589.                 Boundaries x, y
  590.                 Scroll 0, Ypos, Xpos, y, x, 0, Attribute
  591.                 SetCursor
  592.                 Level = 0
  593.                 Reserve = 0
  594.              CASE 13  'toughie, fill block
  595.                 At = ASC(LEFT$(AvtBuf$, 1))
  596.                 c = ASC(MID$(AvtBuf$, 2, 1))
  597.                 y = ASC(MID$(AvtBuf$, 3, 1))
  598.                 x = ASC(MID$(AvtBuf$, 4, 1))
  599.                 z = CursorAddress
  600.                 Z2 = z
  601.                 x = Xpos + x
  602.                 y = Ypos + y
  603.                 Boundaries x, y
  604.                 FOR d = Ypos TO y - Ypos
  605.                    FOR a = Xpos TO x - Xpos
  606.                       POKE z, c
  607.                       POKE z + 1, At
  608.                       z = z + 2
  609.                    NEXT a
  610.                    z = Z2 + 160
  611.                    Z2 = z
  612.                 NEXT d
  613.                 SetCursor
  614.                 Level = 0
  615.                 Reserve = 0
  616.              CASE 28
  617.                 Level = 0
  618.                 Reserve = 0
  619.                 Recurse tempbuf$
  620.                 SetCursor
  621.                 tempbuf$ = ""
  622.              CASE 27
  623.                 tempbuf$ = AvtBuf$
  624.                 AvtBuf$ = ""
  625.                 Reserve = 1
  626.                 AvtFunc = 28
  627.              CASE 25
  628.                 Reserve = ASC(AvtBuf$)
  629.                 AvtBuf$ = ""
  630.                 AvtFunc = 27
  631.              CASE ELSE
  632.              END SELECT
  633.           END IF
  634.        END IF
  635.        RETURN
  636.     END IF
  637.     'ANSI music
  638.     SELECT CASE char
  639.     CASE 77                             '"M"
  640.         MusicLevel = 1
  641.     CASE 48 TO 57                       '0-9
  642.         'all parameters should be lower than 199...
  643.         IF CurrentParameter < 199 THEN
  644.             CurrentParameter = CurrentParameter * 10 + (char - 48)
  645.             ValidParameter = True
  646.         ELSE
  647.             Level = 0
  648.             GOSUB ProcessChar
  649.         END IF
  650.     CASE 59
  651.         GOSUB MakeParameter             '";"
  652.     'CUP-set cursor's position
  653.     CASE 72, 102                        'H or f
  654.         GOSUB MakeParameter
  655.         Ypos = MinY + a - 1
  656.         a = Parameters(1): IF a = 0 THEN a = 1
  657.         Xpos = MinX + a - 1
  658.         IF Xpos > MaxX THEN Xpos = MaxX
  659.         IF Ypos > MaxY THEN Ypos = MaxY
  660.         SetCursor
  661.         Level = 0
  662.     'CUU- cursor up
  663.     CASE 65                             'A
  664.         GOSUB MakeParameter
  665.         Ypos = Ypos - a
  666.         IF Ypos < MinY THEN Ypos = MinY
  667.         SetCursor
  668.         Level = 0
  669.     'CUD-cursor down
  670.     CASE 66                             'B
  671.         GOSUB MakeParameter
  672.         Ypos = Ypos + a
  673.         IF Ypos > MaxY THEN Ypos = MaxY
  674.         SetCursor
  675.         Level = 0
  676.     'CUF-cursor forward
  677.     CASE 67                             'C
  678.         GOSUB MakeParameter
  679.         Xpos = Xpos + a
  680.         IF Xpos > MaxX THEN Xpos = MaxX
  681.         SetCursor
  682.         Level = 0
  683.     'CUB-cursor backward
  684.     CASE 68                              'D
  685.         GOSUB MakeParameter
  686.         Xpos = Xpos - a
  687.  
  688.         IF Xpos < MinX THEN Xpos = MinX
  689.         SetCursor
  690.         Level = 0
  691.     'SCR-save cursor position
  692.     CASE 115                            's
  693.         SaveX = Xpos: SaveY = Ypos
  694.         Level = 0
  695.     'RCP-restore cursor position
  696.     CASE 117                            'u
  697.         Xpos = SaveX: Ypos = SaveY
  698.         Level = 0
  699.         SetCursor
  700.     'ED-erase display(ESC[2J and ESC[J work
  701.     'both work)
  702.     CASE 74                             'J
  703.         ClearScreen
  704.         Level = 0
  705.     'EL-erase in line
  706.     CASE 75                             'K
  707.         a = CursorAddress
  708.         FOR x = Xpos TO MaxX
  709.             POKE a, 32: POKE a + 1, Attribute: a = a + 2
  710.         NEXT
  711.         Level = 0
  712.     'SGR-sets new color
  713.     CASE 109                            'm
  714.         GOSUB MakeParameter
  715.         'if no color codes then stuff 0 into the table
  716.         IF NumParameters = 0 THEN Parameters(0) = 0: NumParameters = 1
  717.         FOR a = 0 TO NumParameters - 1
  718.             P = Parameters(a)
  719.             SELECT CASE P
  720.             CASE IS <= 8
  721.                 SELECT CASE P
  722.                 'all attributes off
  723.                 CASE 0
  724.                     Attribute = 7
  725.                 'high-intensity
  726.                 CASE 1
  727.                     Attribute = Attribute OR 8
  728.                 'blinking
  729.                 CASE 5
  730.                     Attribute = Attribute OR 128
  731.                 'inverse
  732.                 CASE 7
  733.                     Attribute = (Attribute AND 136) OR (Attribute AND 7) * 16 OR (Attribute AND 112) \ 16
  734.                 END SELECT
  735.                 'set foreground
  736.             CASE 30 TO 37
  737.                 IF NOT Monochrome THEN
  738.                     Attribute = (Attribute AND 248) OR Colors(P - 30)
  739.                 END IF
  740.                 'set background
  741.             CASE 40 TO 47
  742.                 IF NOT Monochrome THEN
  743.                     Attribute = (Attribute AND 143)
  744.                     Attribute = Attribute OR Colors(P - 40) * 16
  745.                 END IF
  746.             END SELECT
  747.         NEXT
  748.         Level = 0
  749.     'DSR-outputs a CPR sequence
  750.     'This function outputs the string "ESC[#;#R" where
  751.     '#;# is the current Y and current X coordinate
  752.     'to the receiver.
  753.     'Calls SendStatus to do its dirty work...
  754.     CASE 110
  755.         SendStatus Xpos, Ypos
  756.         Level = 0
  757.     'any other code is assumed to be invalid;it's just sent to the
  758.     'screen
  759.     CASE ELSE
  760.         Level = 0
  761.         GOSUB ProcessChar
  762.     END SELECT
  763. END IF
  764. RETURN
  765. 'stores a numeric parameter into the parameter table
  766. MakeParameter:
  767.     'check to see if a least one digit has been received
  768.     'for this parameter and there's room left in the table
  769.     IF ValidParameter AND NumParameters < 10 THEN
  770.         'add parameter to table
  771.         Parameters(NumParameters) = CurrentParameter
  772.         NumParameters = NumParameters + 1
  773.         CurrentParameter = 0
  774.         ValidParameter = False
  775.     END IF
  776.  
  777.     'Set A equal to the first parameter and make it 1 if it's 0
  778.     a = Parameters(0)
  779.     IF a = 0 THEN a = 1
  780.  
  781. RETURN
  782. END SUB
  783.  
  784. 'Prints a string to the display.
  785. SUB PrintString (b$)
  786.     a& = SADD(b$)
  787.     IF a& < 0 THEN a& = a& + 65536
  788.  
  789.     ' You must change the next line if you're using QB4.5!
  790.     'It is currently coded for PDS.
  791.  
  792.     'Segment = VARSEG(B$) + A& \ 16
  793.  
  794.     Segment = VARSEG(b$) + a& \ 16    'change to VARSEG(B$) for QB4.5 & QBASIC
  795.  
  796.     Address = a& MOD 16
  797.     FOR b = Address TO Address + LEN(b$) - 1
  798.         DEF SEG = Segment
  799.         A1 = PEEK(b)
  800.         DEF SEG = VideoSegment
  801.         PrintAnsi A1
  802.     NEXT
  803.  
  804. END SUB
  805.  
  806. SUB Recurse (Buffer$)
  807.  
  808. 'This huge bloated confusing piece of code is what makes the ^V^Y repeat
  809. 'code go.  It checks for embedded ^V^Y codes, and if they're in there, it
  810. 'attempts to expand them.  It does still however have the dreaded avatar
  811. 'bug where if they send "^V^Y^KHello!!!^V^Y^Z^Z" or something similar,
  812. 'it'll lock up.  Just go through that string ^^ and you'll figure out where
  813. 'the bug is.
  814.  
  815. y = ASC(AvtBuf$)
  816. FOR a = 1 TO y
  817.    FOR b = 1 TO LEN(Buffer$)
  818.       c = ASC(MID$(Buffer$, b, 1))
  819.       IF c = 22 THEN
  820.          IF ASC(MID$(Buffer$, b + 1, 1)) = 25 THEN
  821.             'Its a ^V^Y code, so we gotta expand it
  822.             c = ASC(MID$(Buffer$, b + 2, 1))
  823.             r$ = MID$(Buffer$, b + 3, c)
  824.             s$ = ""
  825.             FOR z = 1 TO ASC(MID$(Buffer$, b + 3 + c, 1))
  826.                s$ = s$ + r$
  827.             NEXT z
  828.             Buffer$ = LEFT$(Buffer$, b - 1) + s$ + MID$(Buffer$, b + 4 + c)
  829.             c = -1
  830.          END IF
  831.          IF c > -1 THEN PrintAnsi c
  832.       ELSE
  833.          PrintAnsi c
  834.       END IF
  835.    NEXT b
  836. NEXT a
  837.  
  838. END SUB
  839.  
  840. SUB Scroll (Direction%, Top%, Left%, Bottom%, Right%, Lines%, Attr%)
  841.  
  842. 'CONST UP = &H700, DOWN = &H600
  843.  
  844.     DIM reg AS RegType  'need $include qb.bi
  845.     Top% = Top% - 1
  846.     Left% = Left% - 1
  847.     Bottom% = Bottom% - 1
  848.     Right% = Right% - 1
  849.     IF Direction% = 1 THEN reg.ax = &H700 ELSE reg.ax = &H600
  850.     reg.ax = reg.ax + Lines%         'zero lines will clear viewport
  851.     reg.bx = Attr% * 256             'attribute for blank area
  852.     reg.cx = Top% * 256 + Left%      'Top Left Coords
  853.     reg.dx = Bottom% * 256 + Right%  'Bottom Right Coords
  854.     CALL INTERRUPT(&H10, reg, reg)
  855.  
  856. END SUB
  857.  
  858. SUB ScrollUpScreen
  859.     DIM Regs AS RegType
  860.     Regs.ax = &H601
  861.  
  862.     a& = Attribute * 256&
  863.     IF a& > 32767 THEN a = a& - 65536 ELSE a = a&
  864.     Regs.bx = a
  865.  
  866.     Regs.cx = (MinY * 256&) + MinX - 257
  867.     Regs.dx = (MaxY * 256&) + MaxX - 257
  868.     CALL INTERRUPT(&H10, Regs, Regs)
  869. END SUB
  870.  
  871. 'Sends the screen's status to the receiver. You must modify the
  872. '"PRINT #1, A$;" command to print to your comm package.
  873. 'Sends "ESC[##;##R" where ##;## is Y;X.
  874. SUB SendStatus (x, y)
  875.     a$ = CHR$(27) + "[" + RIGHT$("0" + MID$(STR$(y), 2), 2)
  876.     a$ = a$ + ";" + RIGHT$("0" + MID$(STR$(x), 2), 2) + "R"
  877.  
  878. '*****Change the next line to print this string out to your comm package!!****
  879.     PRINT #1, a$;          'DON'T insert a line feed!!
  880.  
  881. END SUB
  882.  
  883. 'Sets the cursor- uses OUT's for speed
  884. SUB SetCursor
  885.     'Must do this...
  886.  
  887.     LOCATE , , 1, 12, 13
  888.  
  889.     CursorAddress = (Xpos - 1) * 2 + (Ypos - 1) * BytesPerLine + VideoOffset
  890.     IF CursorOn THEN
  891.         Address = CursorAddress \ 2
  892.         OUT CRT, &HE
  893.         OUT CRT + 1, Address \ 256
  894.         OUT CRT, &HF
  895.         OUT CRT + 1, Address AND 255
  896.     END IF
  897.  
  898. END SUB
  899.  
  900. 'Sets a new printing window.
  901. SUB SetWindow (WorkPage, Lx, Ly, Hx, Hy)
  902.     DEF SEG = &H40
  903.     IF WorkPage = -1 THEN
  904.         VideoOffset = PEEK(&H4E) + PEEK(&H4F) * 256&
  905.     ELSE
  906.         VideoOffset = (PEEK(&H4C) + PEEK(&H4D) * 256&) * WorkPage
  907.     END IF
  908.  
  909.     ScreenX = PEEK(&H4A)
  910.     ScreenY = PEEK(&H84) + 1
  911.  
  912.     IF Lx = -1 THEN
  913.         MinX = 1: MinY = 1
  914.         MaxX = ScreenX: MaxY = ScreenY
  915.         BytesPerLine = MaxX * 2
  916.     ELSE
  917.         'change window size if coordinates are valid
  918.         IF Lx <= Hx AND Ly <= Hy AND Hx <= ScreenX AND Hy <= ScreenY THEN
  919.             MinX = Lx: MaxX = Hx: MinY = Ly: MaxY = Hy
  920.         END IF
  921.     END IF
  922.     DEF SEG = VideoSegment
  923.     Xpos = MinX: Ypos = MinY
  924.     SaveX = MinX: SaveY = MinY
  925.     SetCursor
  926. END SUB
  927.  
  928.