home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / grafik / wct_unit / xcrt.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-05-24  |  23.4 KB  |  834 lines

  1. unit xcrt;
  2.  
  3. { Written by William C. Thompson (wct@po.cwru.edu) - 1991
  4.   Parts of this unit were taken from HTScreen, written by
  5.   Harold Thunem. }
  6.  
  7. { If anyone has an idea for a procedure, please E-mail and I
  8.   will consider including it in my unit.  It should be something
  9.   that you do often. }
  10.  
  11. (* Features to be added:
  12.   Another unit containing definitions for different musical tones *)
  13.  
  14. { Designer's Notes:
  15.   1. This unit was written was with the goal of making tedious crt
  16.      routines much more bearable by modularizing the entire process.
  17.      Another goal is to make the routines very fast by directly
  18.      affecting memory.  Consequently, much of the error checking has
  19.      been left out.  The user is responsible for error checking his
  20.      own code.  In many cases this proves to give the user more
  21.      control, and there is little or no overhead if the code was
  22.      written with some care.  For example, many times a rectangle
  23.      is defined by (x1,y1) & (x2,y2) which represent the upper-left
  24.      and lower-right corners, respectively.  If x1>x2 or y1>y2 the
  25.      call is often ignored.
  26.   2. When setting foreground colors, you can set the blink constant
  27.      by adding 128 (pre-defined as 'blink') to the foreground color.
  28.   3. As yet, this unit is only designed to handle screens with
  29.      80 columns.  Including checking for 40 columns would slow
  30.      down the procedures which are intended to be very fast.
  31.      A program using 40 columns could easily borrow the ideas
  32.      used in this unit.  I have confirmed that they do work for
  33.      43/50 rows.  Many don't work for 40 columns.
  34.   4. All window-like procedures are in absolute coordinates.  Once
  35.      again, it is up to the user to maintain relative coordinates
  36.      somehow (it is not very difficult) because that would slow down
  37.      the routines for other uses.
  38.   5. My apologies for my somewhat abnormal style of indentation, but
  39.      at least it is consistent (unlike some other code I have seen).
  40.      You may also notice that I avoid white spaces and capitalization
  41.      with a passion.  It seems very silly to worry about how many
  42.      spaces I have put between variables, so I don't put any unless
  43.      absolutely necessary.  I do try to keep my commenting neat, when
  44.      convenient. }
  45.  
  46. interface
  47.  
  48. uses crt,dos,keydef,strings;
  49.  
  50. const
  51.   blackbg=$00;
  52.   bluebg=$10;
  53.   greenbg=$20;
  54.   cyanbg=$30;
  55.   redbg=$40;
  56.   magentabg=$50;
  57.   brownbg=$60;
  58.   lightgraybg=$70;
  59.  { Setting the text color and background color at the same time can
  60.    be very tedious.  You have to say TextColor(X) and TextBackGround(Y),
  61.    which is much too much typing.  You can also be clever and set
  62.    TextAttr:=Y*16+X, which is a pain.  This can be made simpler by
  63.    setting TextAttr:=YBG+X, which sets the background color at the
  64.    same with a minimum of typing.  It also lets you avoid trying to
  65.    set background colors to 8-15, something that I have tried often.
  66.    More importantly, it makes it clearer to see what is happening.
  67.  
  68.    For example, instead of
  69.  
  70.    TextColor(White); TextBackGround(Cyan) or TextAttr:=Cyan*16+White,
  71.  
  72.    much simpler (and a little faster) would be
  73.  
  74.    TextAttr:=CyanBG+White.
  75.  
  76.     If you wish to set only the background or foreground color (but
  77.     not both), you can still use TextColor and TextBackGround. }
  78.  
  79.   { Text fonts, 25 or 43/50 rows }
  80.   ega43font=1;
  81.   normalfont=2;
  82.  
  83.  { border constants }
  84.   noborder=0;
  85.   singleborder=1;
  86.   doubleborder=2;
  87.   dtopsside=3;
  88.   stopdside=4;
  89.  
  90.  { textline constants }
  91.   thinhoriz=0;
  92.   thinvert=1;
  93.   thickhoriz=2;
  94.   thickvert=3;
  95.  
  96. type
  97.   screenbuffer=array [1..50] of array [1..80] of record
  98.     ch: char;
  99.     attr: byte;
  100.     end;
  101.   screen=^screenbuffer;
  102.   { This is a maximum size for a screen - 80 columns * 50 rows = 4000.
  103.     The maximum space required would then be 8000 bytes. }
  104.   blockbuffer=array[0..3999] of word;
  105.   blockbufferptr=^blockbuffer;
  106.   block=record
  107.     rows,cols: byte;
  108.     sp: blockbufferptr;
  109.     end;
  110.   getoneofstring=string[120];
  111.   writexystring=string[80];
  112.  
  113. var
  114.   originalscreen: screen;
  115.   actualscreen: screen;
  116.   activescreen: screen;
  117.   badkeybeep: boolean;     { beep when a bad is pressed? }
  118.   badkeyhz: word;          { sound to emit for bad key }
  119.   badkeydur: word;         { duration of bad key beep }
  120.   goodkeybeep: boolean;    { beep when a good key is pressed }
  121.   goodkeyhz: word;         { sound to emit for good key }
  122.   goodkeydur: word;        { duration of good key beep }
  123.   cursorinitial, cursoroff, cursorunderline,
  124.     cursorhalfblock, cursorblock: word;    { cursor settings }
  125.   preserveattr: boolean;
  126.   { If preserveattr=true, putch will preserve the attribute settings
  127.     for a location on the screen.  If preserveattr=false (default),
  128.     it will change the color attributes to the setting held in
  129.     textattr. }
  130.   crtrows,                 { Number of rows }
  131.   crtcols,                 { Number of columns }
  132.   videomode:byte;          { Video-mode }
  133.   videoseg: word;          { Location of screen in memory }
  134.   explodesteps: byte;      { Number of steps to explode a window }
  135.  
  136. procedure beep(hz,dur: word);
  137. procedure disablespeaker;
  138. procedure enablespeaker;
  139. procedure bordercolor(color:byte);
  140. function getch(x,y: byte):char;
  141. function getattr(x,y: byte):byte;
  142. procedure putch(x,y: byte; c: char);
  143. procedure putattr(x,y:byte; attr:byte);
  144. function shadowattr(attr:byte):byte;
  145. procedure writexy(x,y: byte; s: writexystring);
  146. procedure rightjust(x,y: byte; s: writexystring);
  147. procedure centerjust(x,y:byte; s:writexystring);
  148. procedure textbox(x1,y1,x2,y2: word; border:byte);
  149. procedure textline(startat,endat,c:word; attr:byte);
  150. procedure colorblock(x1,y1,x2,y2: word; c:byte);
  151. procedure fillblock(x1,y1,x2,y2:word; ch:char);
  152. procedure shadowblock(x1,y1,x2,y2:word);
  153. procedure attrblock(x1,y1,x2,y2:word; attr:byte);
  154. procedure scrollblockup(x1,y1,x2,y2,wakeattr:byte);
  155. procedure scrollblockdown(x1,y1,x2,y2,wakeattr:byte);
  156. procedure explodeblock(x1,y1,x2,y2:byte);
  157. function readallkeys:char;
  158. procedure flushkeyboard;
  159. function yesorno:char;
  160. function getoneof(s:getoneofstring):char;
  161. function getcursor:word;
  162. procedure setcursor(curs:word);
  163. procedure makescreen(var s: screen);
  164. procedure killscreen(var s: screen);
  165. procedure setactivescreen(var s: screen);
  166. procedure setvisualscreen(var s: screen);
  167. procedure writewindow(var f: file; var w: block);
  168. procedure readwindow(var f: file; var w: block);
  169. procedure savewindow(x1,y1,x2,y2: word; var w: block);
  170. procedure killwindow(var w:block);
  171. procedure drawstrip(w:block; x1,y1:byte; row:byte; x2,x3:byte);
  172. procedure recallwindow(x1,y1:word; var w: block);
  173. procedure explodewindow(x1,y1: byte; w:block);
  174. procedure crunchwindow(x1,y1:byte; w:block);
  175. function getfont:byte;
  176. procedure setfont(font:byte);
  177. function getvideomode:byte;
  178. procedure setvideomode(mode:byte);
  179. procedure xcrtinit;
  180.  
  181. implementation
  182.  
  183. const
  184.   borders:array[0..4] of string[6]=('      ',
  185.                                     #218+#196+#191+#179+#217+#192,
  186.                                     #201+#205+#187+#186+#188+#200,
  187.                                     #213+#205+#184+#179+#190+#212,
  188.                                     #214+#196+#183+#186+#189+#211);
  189.  
  190. var
  191.   regs: registers;
  192.   visualscreenptr: ^screen;
  193.  
  194. procedure beep(hz,dur: word);
  195. begin
  196.   sound(hz);
  197.   delay(dur);
  198.   nosound
  199. end;
  200.  
  201. procedure disablespeaker;
  202. { This procedure turns off the 0 & 1 bits of port[$61], which controls
  203.   the speaker }
  204. begin
  205.   port[$61]:=port[$61] and $FC;
  206. end;
  207.  
  208. procedure enablespeaker;
  209. { This procedure turns the 0 & 1 bits of port[$61] back on }
  210. begin
  211.   port[$61]:=port[$61] or $03;
  212. end;
  213.  
  214. procedure bordercolor(color:byte);
  215. { Colors the border around the (1,1) (80,25) corners Color }
  216. begin
  217.   fillchar(regs,sizeof(regs),0);
  218.   regs.ax:=$0B00;
  219.   regs.bh:=$00;
  220.   regs.bl:=12;
  221.   intr($10,regs);
  222. end;
  223.  
  224. function getch(x,y: byte):char;
  225. { returns character at absolute position (x,y) through memory
  226.   The error checking has been removed to speed up function }
  227. begin
  228.   getch:=activescreen^[y,x].ch;
  229. end;
  230.  
  231. function getattr(x,y: byte):byte;
  232. { returns color attribute at absolute position (x,y) through memory
  233.   The error checking has been removed to speed up function }
  234. begin
  235.   getattr:=activescreen^[y,x].attr;
  236. end;
  237.  
  238. procedure putch(x,y: byte; c: char);
  239. { QUICKLY writes c to absolute position (x,y) through memory
  240.   This is at least 10 times faster than a gotoxy(x,y), write(c)
  241.   Another bonus is that the cursor doesn't move.
  242.   The error checking has been removed  }
  243. begin
  244.   if not preserveattr then begin
  245.     activescreen^[y,x].ch:=c;
  246.     activescreen^[y,x].attr:=textattr;
  247.     end
  248.   else activescreen^[y,x].ch:=c;
  249. end;
  250.  
  251. procedure putattr(x,y,attr: byte);
  252. { Directly change the color attributes of char at absolute screen (x,y) }
  253. begin
  254.   activescreen^[y,x].attr:=attr;
  255. end;
  256.  
  257. function shadowattr(attr:byte):byte;
  258. { Returns an appropriate shadow attribute.  First it masks out the
  259.   upper four bits (background of shadow is always black) as well as
  260.   the 3rd bit (a shadow should be a dark color).  Unfortunately,
  261.   if the text color is black, you can't see it, so there is a
  262.   special case for that (sets it to lightgray). }
  263. var
  264.   temp: byte;
  265. begin
  266.   temp:=attr and $07;
  267.   if temp=black then shadowattr:=lightgray
  268.   else shadowattr:=temp
  269. end;
  270.  
  271. procedure writexy(x,y: byte; s: writexystring);
  272. { Writes string s at absolute (x,y) - left justified }
  273. var
  274.   i: byte;
  275. begin
  276.   for i:=1 to length(s) do putch(x+i-1,y,s[i])
  277. end;
  278.  
  279. procedure rightjust(x,y: byte; s: writexystring);
  280. { Right justifies string s at absolute (x,y) }
  281. begin
  282.   writexy(x-length(s)+1,y,s)
  283. end;
  284.  
  285. procedure centerjust(x,y:byte; s:writexystring);
  286. { Centers string s about x at y }
  287. begin
  288.   writexy(x-length(s) div 2,y,s)
  289. end;
  290.  
  291. procedure textbox(x1,y1,x2,y2: word; border:byte);
  292. { draws a text box defined by the two points }
  293. var
  294.   i: integer;
  295.   ch: char;
  296.   s: string[6];
  297. begin
  298.   if not border in [1..4] then exit;
  299.   s:=borders[border];
  300.   { handle special cases first, x1=x2 or y1=y2 }
  301.   if x1=x2 then   { straight line down }
  302.     for i:=y1 to y2 do putch(x1,i,s[4])
  303.   else if y1=y2 then  { straight line across }
  304.     for i:=x1 to x2 do putch(i,y1,s[2])
  305.   else if (x1<x2) and (y1<y2) then begin
  306.     { draw corners }
  307.     putch(x1,y1,s[1]);
  308.     putch(x1,y2,s[6]);
  309.     putch(x2,y2,s[5]);
  310.     putch(x2,y1,s[3]);
  311.     { draw lines }
  312.     for i:=y1+1 to y2-1 do putch(x1,i,s[4]);
  313.     for i:=y1+1 to y2-1 do putch(x2,i,s[4]);
  314.     for i:=x1+1 to x2-1 do begin
  315.       putch(i,y1,s[2]);
  316.       putch(i,y2,s[2]);
  317.       end
  318.     end
  319. end;
  320.  
  321. procedure textline(startat,endat,c:word; attr:byte);
  322. { The first two parameters are the starting and ending values
  323.   of the range of the line, vertical or horizontal.  The third
  324.   is the constant value.  i.e. horiz => (x1,x2,y), vert => (y1,y2,x) }
  325. var
  326.   i: integer;
  327. begin
  328.   if attr mod 2=0 then begin
  329.     gotoxy(startat,c);
  330.     if attr div 2=0 then for i:=startat to endat do putch(i,c,#196)
  331.     else for i:=startat to endat do putch(i,c,#205)
  332.     end
  333.   else
  334.     if attr div 2=0 then for i:=startat to endat do putch(c,i,#179)
  335.     else for i:=startat to endat do putch(c,i,#186)
  336. end;
  337.  
  338. procedure colorblock(x1,y1,x2,y2:word; c:byte);
  339. { Fills block with █ in the specified color - preserves color settings.
  340.   Can conflict with shadowing - ShadowBlock changes the background
  341.   color of the shadowed region to black and foreground colors to
  342.   the approriate shadowed color.  Therefore, if you shadow a region
  343.   containing █'s, it will not make them black.  Make sense?  If you
  344.   intend to use shadowing, you are better off making regions with
  345.   background colors and using FillBlock.  In addition, if text is to
  346.   be put in the area, the text must have an appropriate background
  347.   color.  ColorBlock should basically only be used for cosmetic
  348.   purposes (such as filling in the sides of the screen), as it
  349.   conflicts with so many other routines. }
  350. var
  351.   i,j:byte;
  352.   sc: byte;
  353. begin
  354.   sc:=textattr;
  355.   textcolor(c);
  356.   for i:=x1 to x2 do
  357.     for j:=y1 to y2 do putch(i,j,#219);
  358.   textattr:=sc
  359. end;
  360.  
  361. procedure fillblock(x1,y1,x2,y2:word; ch:char);
  362. { Fills a block with the specified character using the current
  363.   color settings.  If you want to empty a region, set the colors
  364.   by setting (as an example) TextAttr=CyanBG+White (cyan background
  365.   with a white foreground) and the fill the block with ' '. }
  366. var
  367.   i,j:byte;
  368.   w: word;
  369. begin
  370.   for i:=x1 to x2 do
  371.     for j:=y1 to y2 do putch(i,j,ch);
  372. end;
  373.  
  374. procedure shadowblock(x1,y1,x2,y2:word);
  375. { Shadows a block using the appropriate shadowing
  376.   for each character's color attribute }
  377. var
  378.   i,j:byte;
  379. begin
  380.   for i:=x1 to x2 do
  381.     for j:=y1 to y2 do putattr(i,j,shadowattr(getattr(i,j)))
  382. end;
  383.  
  384. procedure attrblock(x1,y1,x2,y2:word; attr:byte);
  385. { Changes the foreground and background colors within the
  386.   specified rectangle.  This is different from shadowblock,
  387.   which uses the appropriate shadowing for a color attribute. }
  388. var
  389.   i,j: byte;
  390. begin
  391.   for i:=x1 to x2 do
  392.     for j:=y1 to y2 do putattr(i,j,attr);
  393. end;
  394.  
  395. procedure scrollblockup(x1,y1,x2,y2,wakeattr:byte);
  396. { Scrolls a block up and leaves the wakeattr color in the empty row }
  397. begin
  398.   fillchar(regs,sizeof(regs),0);
  399.   regs.ah:=$06;
  400.   regs.al:=$01;
  401.   regs.bh:=wakeattr;
  402.   regs.ch:=y1-1;
  403.   regs.cl:=x1-1;
  404.   regs.dh:=y2-1;
  405.   regs.dl:=x2-1;
  406.   intr($10,regs);
  407. end;
  408.  
  409. procedure scrollblockdown(x1,y1,x2,y2,wakeattr:byte);
  410. { Scrolls a block down and leaves the wakeattr color in the empty row }
  411. begin
  412.   fillchar(regs,sizeof(regs),0);
  413.   regs.ah:=$07;
  414.   regs.al:=$01;
  415.   regs.bh:=wakeattr;
  416.   regs.ch:=y1-1;
  417.   regs.cl:=x1-1;
  418.   regs.dh:=y2-1;
  419.   regs.dl:=x2-1;
  420.   intr($10,regs);
  421. end;
  422.  
  423. procedure explodeblock(x1,y1,x2,y2:byte);
  424. { explodes a block }
  425. var
  426.   i,r1,r2,c1,c2: byte;
  427.   mr,mc,dr,dc: real;
  428. begin
  429.   dr:=(x2-x1+1)/(explodesteps*2+1);
  430.   dc:=(y2-y1+1)/(explodesteps*2+1);
  431.   mr:=(x1+x2+1)/2;
  432.   mc:=(y1+y2+1)/2;
  433.   for i:=1 to explodesteps do begin
  434.     r1:=trunc(mr-i*dr);
  435.     r2:=trunc(mr+i*dr);
  436.     c1:=trunc(mc-i*dc);
  437.     c2:=trunc(mc+i*dc);
  438.     fillblock(r1,c1,r2,c2,' ');
  439.     end;
  440.   fillblock(x1,y1,x2,y2,' ');
  441. end;
  442.  
  443. function readallkeys:char;
  444. { This function correctly reads in a keypress and returns the
  445.   correct value for "other" keys.  See the KEYDEF unit for what
  446.   each special key returns.  Note: the function doesn't return
  447.   an actual character for special keys (F1-F10,etc.) - it is only
  448.   a character to represent the special key that was pressed. }
  449. var
  450.   ch: char;
  451. begin
  452.   ch:=readkey;
  453.   if ch=#0 then readallkeys:=transformedkey(readkey)
  454.   else readallkeys:=ch
  455. end;
  456.  
  457. procedure flushkeyboard;
  458. { flushes the keyboard type-ahead buffer }
  459. begin
  460.   fillchar(regs,sizeof(regs),0);
  461.   regs.ax:=$0C00;
  462.   intr($21,regs)
  463. end;
  464.  
  465. procedure badkeysound;
  466. begin
  467.   beep(badkeyhz,badkeydur);
  468. end;
  469.  
  470. procedure goodkeysound;
  471. begin
  472.   beep(goodkeyhz,goodkeydur)
  473. end;
  474.  
  475. function yesorno:char;
  476. { waits for the user to press 'y','Y','n','N' }
  477. var
  478.   ch: char;
  479. begin
  480.   repeat
  481.     ch:=upcase(readallkeys);
  482.     if not (ch in ['Y','N']) and badkeybeep then badkeysound
  483.   until ch in ['Y','N'];
  484.   yesorno:=ch;
  485.   if goodkeybeep then goodkeysound
  486. end;
  487.  
  488. function getoneof(s:getoneofstring):char;
  489. { waits for the user to input a character contained in cs }
  490. var
  491.   ch: char;
  492. begin
  493.   repeat
  494.     ch:=readallkeys;
  495.     if badkeybeep and (pos(ch,s)<=0) then badkeysound
  496.   until pos(ch,s)>0;
  497.   getoneof:=ch;
  498.   if goodkeybeep then goodkeysound;
  499. end;
  500.  
  501. function getcursor:word;
  502. { returns cursor size }
  503. begin
  504.   getcursor:=(mem[$0040:$0060] shl 4)+mem[$0040:$0061];
  505. end;
  506.  
  507. procedure setcursor(curs:word);
  508. { sets cursor size }
  509. begin
  510.   fillchar(regs,sizeof(regs),0);
  511.   regs.ah:=$01;
  512.   regs.ch:=curs mod 16;
  513.   regs.cl:=curs div 16;
  514.   intr($10,regs);
  515. end;
  516.  
  517. procedure makescreen(var s: screen);
  518. begin
  519.   if maxavail<80*50*2 then halt(1);
  520.   getmem(s,80*50*2);
  521. end;
  522.  
  523. procedure killscreen(var s: screen);
  524. begin
  525.   if s=activescreen then exit;
  526.   if visualscreenptr=@s then exit;
  527.   freemem(s,80*50*2);
  528. end;
  529.  
  530. procedure setactivescreen(var s: screen);
  531. begin
  532.   activescreen:=s;
  533. end;
  534.  
  535. procedure setvisualscreen(var s: screen);
  536. var
  537.   temp: pointer;
  538.   buf: blockbufferptr;
  539.   swapped: word;
  540.   section: word;
  541. begin
  542.   { swap actual screen contents and s^ }
  543.   swapped:=0;
  544.   repeat
  545.     if maxavail>4000-swapped then section:=4000
  546.     else section:=maxavail;
  547.     getmem(buf,section*2);
  548.     move(actualscreen^[(swapped div 80)+1,(swapped mod 80)+1],buf^[swapped],section*2);
  549.     move(s^[(swapped div 80)+1,(swapped mod 80)+1],actualscreen^[(swapped div 80)+1,(swapped mod 80)+1],section*2);
  550.     move(buf^[swapped],s^[(swapped div 80)+1,(swapped mod 80)+1],section*2);
  551.     freemem(buf,section*2);
  552.     swapped:=swapped+section;
  553.   until swapped>=4000;
  554.   { swap the pointers }
  555.   temp:=s;
  556.   s:=visualscreenptr^;
  557.   visualscreenptr^:=temp;
  558.   { visualscreenptr contains the address of the old visual screen pointer }
  559.   visualscreenptr:=@s;
  560. end;
  561.  
  562. procedure writewindow(var f: file; var w: block);
  563. { writes window to a file
  564.   1/16/92 - Improved speed by using BLOCKWRITE
  565.   4/22/92 - changed parameter to a file that must be pre-reset }
  566. var
  567.   i,j: byte;
  568. begin
  569.   with w do begin
  570.     blockwrite(f,rows,1);
  571.     blockwrite(f,cols,1);
  572.     blockwrite(f,sp^,rows*cols*2);
  573.     end;
  574. end;
  575.  
  576. procedure readwindow(var f: file; var w: block);
  577. { 1/16/92 - Improved speed by using BLOCKREAD
  578.   4/22/92 - changed parameter to a file that must be pre-reset }
  579. begin
  580.   with w do begin
  581.     blockread(f,rows,1);
  582.     blockread(f,cols,1);
  583.     getmem(sp,rows*cols*2);
  584.     blockread(f,sp^,rows*cols*2);
  585.     end;
  586. end;
  587.  
  588. procedure savewindow(x1,y1,x2,y2: word; var w: block);
  589. { This procedure saves a screen block.  It is not intended to
  590.   open up a window, but can be used to store what is underneath
  591.   a window.  (absolute coordinates).  1/15/92 - Doubled speed of
  592.   SaveWindow and RecallWindow by utilizing MOVE.  }
  593. var
  594.   i,j: word;
  595.   size: word;
  596. begin
  597.   with w do begin
  598.     rows:=0;
  599.     cols:=0;
  600.     if (x2<x1) and (y2<y1) then exit;    { invalid window }
  601.     rows:=y2-y1+1;
  602.     cols:=x2-x1+1;
  603.     size:=rows*cols*2;    { bytes required to store screen }
  604.     getmem(sp,size);      { allocate sufficient space }
  605.     for j:=y1 to y2 do
  606.       move(activescreen^[j,x1],sp^[(j-y1)*cols],cols*2);
  607.     end
  608. end;
  609.  
  610. procedure killwindow(var w:block);
  611. { Free space taken up by screen block }
  612. begin
  613.   freemem(w.sp,w.rows*w.cols*2);
  614.   w.rows:=0;
  615.   w.cols:=0
  616. end;
  617.  
  618. procedure drawstrip(w:block; x1,y1:byte; row:byte; x2,x3:byte);
  619. { Draws one strip of a block
  620.   w = block to be drawn
  621.   x1,y1 = upper-left corner of block (absolute)
  622.   row = (absolute row to be drawn)
  623.   x2,x3 = x limits of strip to be drawn }
  624. begin
  625.   if x3<x2 then exit;
  626.   with w do
  627.     move(sp^[(row-y1)*cols+(x2-x1)],
  628.          memw[videoseg:(row-1)*160+(x2-1)*2],
  629.          (x3-x2+1)*2)
  630. end;
  631.  
  632. procedure recallwindow(x1,y1:word; var w:block);
  633. { redraw window at (x1,y1) (absolute coordinates) }
  634. var
  635.   i,j: word;
  636. begin
  637.   with w do
  638.     for j:=y1 to y1+rows-1 do
  639.       drawstrip(w,x1,y1,j,x1,x1+cols-1);
  640. end;
  641.  
  642. procedure explodewindow(x1,y1: byte; w:block);
  643. { Explodes a window with (x1,y1) as upper-left corner. }
  644. var
  645.   mx,my: real;
  646.   dx,dy: real;
  647.   x2,x3: byte;
  648.   i,j,k: byte;
  649. begin
  650.   with w do begin
  651.     mx:=x1+cols/2;
  652.     my:=y1+rows/2;
  653.     dx:=cols/(explodesteps*2+1);
  654.     dy:=rows/(explodesteps*2+1);
  655.     for k:=1 to explodesteps do
  656.       for j:=trunc(my-k*dy) to trunc(my+k*dy) do begin
  657.         x2:=trunc(mx-k*dx);
  658.         x3:=trunc(mx+k*dx);
  659.         drawstrip(w,x1,y1,j,x2,x3);
  660.         end;
  661.     recallwindow(x1,y1,w)
  662.     end;
  663. end;
  664.  
  665. procedure crunchwindow(x1,y1:byte; w:block);
  666. { Draw window from outside-in, opposite to explode window }
  667. var
  668.   dx,dy: real;
  669.   x2,y2: byte;  { upper-left of inner box }
  670.   x3,y3: byte;  { lower-right of inner box }
  671.   j,k: byte;
  672. begin
  673.   with w do begin
  674.     dx:=cols/(explodesteps*2+1);
  675.     dy:=rows/(explodesteps*2+1);
  676.     for k:=1 to explodesteps do begin
  677.       x2:=round(x1+k*dx);
  678.       y2:=round(y1+k*dy);
  679.       x3:=round(x1+cols-1-k*dx);
  680.       y3:=round(y1+rows-1-k*dy);
  681.       for j:=y1 to y1+rows-1 do
  682.         if (j<=y2) or (j>=y3) then drawstrip(w,x1,y1,j,x1,x1+cols-1)
  683.         else begin
  684.           drawstrip(w,x1,y1,j,x1,x2);
  685.           drawstrip(w,x1,y1,j,x3,x1+cols-1)
  686.           end;
  687.       end;
  688.     recallwindow(x1,y1,w);
  689.     end;
  690. end;
  691.  
  692. function getfont:byte;
  693. { gets the number of rows on the screen }
  694. begin
  695.   fillchar(regs,sizeof(regs),0);
  696.   regs.ah:=$11;
  697.   regs.al:=$30;
  698.   regs.bh:=$02;
  699.   intr($10,regs);
  700.   getfont:=regs.dl+1;
  701. end;
  702.  
  703. procedure setfont(font:byte);
  704. { sets the number of rows on the screen:25 or 43/50 }
  705. begin
  706.   if font=normalfont then begin
  707.     fillchar(regs,sizeof(regs),0);
  708.     regs.ah:=$00;
  709.     regs.al:=videomode;
  710.     intr($10,regs);
  711.     crtrows:=25;
  712.     end
  713.   else begin
  714.     fillchar(regs,sizeof(regs),0);
  715.     regs.ah:=$11;
  716.     regs.al:=$12;
  717.     regs.bh:=$00;
  718.     intr($10,regs);
  719.     crtrows:=getfont;
  720.     end;
  721. end;
  722.  
  723. function getvideomode:byte;
  724. { Returns the Video mode }
  725. begin
  726.   fillchar(regs,sizeof(regs),0);
  727.   regs.ah:=$0F;
  728.   intr($10,regs);
  729.   getvideomode:=regs.al;
  730. end;
  731.  
  732. procedure setvideomode(mode:byte);
  733. { sets the video mode }
  734. begin
  735.   if not mode in [$02,$03,$07] then exit;
  736.   fillchar(regs,sizeof(regs),0);
  737.   regs.ah:=$00;
  738.   regs.al:=mode;
  739.   intr($10,regs);
  740. end;
  741.  
  742. procedure xcrtinit;
  743. { initializes some variables }
  744. begin
  745.  { initialize bad key settings }
  746.   badkeybeep:=false;
  747.   badkeyhz:=250;
  748.   badkeydur:=50;
  749.  { initialize good key settings }
  750.   goodkeybeep:=false;
  751.   goodkeyhz:=150;
  752.   goodkeydur:=10;
  753.  { initialize misc. stuff }
  754.   explodesteps:=10;
  755.   preserveattr:=false;
  756.  { initialize videomode }
  757.   videomode:=getvideomode;
  758.   if not videomode in [$02,$03,$07] then halt;   { invalid video mode }
  759.  { initialize cursor stuff }
  760.   cursorinitial:=getcursor;
  761.   crtcols:=80;
  762.   case videomode of
  763.     $02,$03:begin
  764.       cursorunderline:=118;  { 6-7 }
  765.       cursorhalfblock:=116;  { 4-7 }
  766.       cursorblock:=113;      { 1-7 }
  767.       cursoroff:=1;          { 0-1 }
  768.       videoseg:=$B800;
  769.       end;
  770.     $07:begin
  771.       cursorunderline:=203;  { 11-12 }
  772.       cursorhalfblock:=198;   { 6-12 }
  773.       cursorblock:=193;       { 1-12 }
  774.       cursoroff:=1;           { 0- 1 }
  775.       videoseg:=$B000;
  776.       end;
  777.     end;
  778.   actualscreen:=ptr(videoseg,0);
  779.   originalscreen:=ptr(videoseg,0);
  780.   visualscreenptr:=@originalscreen;
  781.   activescreen:=actualscreen;
  782.   crtrows:=getfont;
  783. end;
  784.  
  785. begin
  786.   xcrtinit;
  787. end.
  788.  
  789. This is a list of the CRT procedures and functions.  I would like to replace
  790. them all with my own routines eventually.
  791.  
  792. AssignCrt         ClrEol √          ClrScr √          Delay
  793. DelLine           GotoXY            HighVideo         InsLine
  794. KeyPressed        LowVideo          NormVideo         NoSound
  795. ReadKey √         Sound             TextBackground √  TextColor √
  796. TextMode √        WhereX            WhereY            Window
  797.  
  798. function xreadkey:char;
  799. var
  800.   r: registers;
  801. begin
  802.   with r do begin
  803.     ah:=8;
  804.     msdos(r);
  805.     xreadkey:=chr(r.al);
  806.   end;
  807. end;
  808.  
  809. procedure xclrscr;
  810. var
  811.   t: boolean;
  812. begin
  813.   t:=preserveattr;
  814.   preserveattr:=false;
  815.   fillblock(1,1,crtcols,crtrows,' ');
  816.   preserveattr:=t
  817. end;
  818.  
  819. procedure xclreol;
  820. begin
  821.   writexy(wherex,wherey,rep(' ',crtcols+1-wherex))
  822. end;
  823.  
  824. procedure xtextbackground(c:byte);
  825. begin
  826.   textattr:=(textattr and $8F) or (c*16)
  827. end;
  828.  
  829. procedure xtextcolor(c:byte);
  830. begin
  831.   textattr:=(textattr and $F0) or c
  832. end;
  833.  
  834.