parse-wormedit: convert pbm format to monochrome pnm
[wormy.git] / shiar.pas
1 UNIT SHIAR;       {YEAH!!                           {ITS_ALL_YOU'LL_EVER_NEED}
2 {$G+}
3
4 INTERFACE                                           {WHAT_HAVE_WE_GOT_HERE?}
5
6 USES DOS,CRT;                                       {LET'S_USE_THESE_TOO}
7
8 CONST
9   MOUSEINTR = $33;                                  {MOUSE_INTERRUPT_NUMBER}
10   TIMERINTR = 8;                                    {TIMER_INTERRUPT_NUMBER}
11   PIT_FREQ = $1234DD;                               {PIT_FREQUENCY}
12   VGA = $A000;                                      {ADRESS_OF_THE_VGA_SCREEN}
13   MODESETS:ARRAY[0..15,0..20]OF WORD =              {VIDEO_RESOLUTION_SETTING}
14     {320X200} ((2,320,200,0,$0014,$E317,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
15     {320X240} (10,320,240,$E3,$2C11,$0D06,$3E07,$4109,$EA10,$DF12,$0014,$E715,
16                $0616,$E317,0,0,0,0,0,0,0),
17     {360X200} (8,360,200,$E7,$6B00,$5901,$5A02,$8E03,$5E04,$8A05,$0014,$E317,
18                0,0,0,0,0,0,0,0,0),
19     {360X240} (16,360,240,$E7,$AC11,$6B00,$5901,$5A02,$8E03,$5E04,$8A05,$0D06,
20                $3E07,$4109,$EA10,$DF12,$0014,$E715,$0616,$E317,0),
21     {376X282} (17,376,282,$E7,$6E00,$5D01,$5E02,$9103,$6204,$8F05,$6206,
22                $F007,$6109,$3710,$8911,$3312,$2F13,$0014,$3C15,$5C16,$E317),
23     {320X400} (3,320,400,$E3,$4009,$0014,$E317,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
24     {320X480} (10,320,480,$E3,$AC11,$0D06,$3E07,$4009,$EA10,$DF12,$0014,$E715,
25                $0616,$E317,0,0,0,0,0,0,0),
26     {360X400} (9,360,400,$E7,$6B00,$5901,$5A02,$8E03,$5E04,$8A05,$4009,$0014,
27                $E317,0,0,0,0,0,0,0,0),
28     {360X480} (17,360,480,$E7,$6B00,$5901,$5A02,$8E03,$5E04,$8A05,$0D06,$3E07,
29                $4009,$EA10,$AC11,$DF12,$2D13,$0014,$E715,$0616,$E317),
30     {360X360} (15,360,360,$E7,$6B00,$5901,$5A02,$8E03,$5E04,$8A05,$4009,$8810,
31                $8511,$6712,$2D13,$0014,$6D15,$BA16,$E317,0,0),
32     {376X308} (17,376,308,$E7,$6E00,$5D01,$5E02,$9103,$6204,$8F05,$6206,$0F07,
33                $4009,$3710,$8911,$3312,$2F13,$0014,$3C15,$5C16,$E317),
34     {376X564} (17,376,564,$E7,$6E00,$5D01,$5E02,$9103,$6204,$8F05,$6206,$F007,
35                $6009,$3710,$8911,$3312,$2F13,$0014,$3C15,$5C16,$E317),
36     {256X200} (8,256,200,$E3,$5F00,$3F01,$4202,$9F03,$4C04,$0005,$0014,$E317,
37                0,0,0,0,0,0,0,0,0),
38     {256X224} (17,256,224,$E3,$5F00,$3F01,$4002,$8203,$4A04,$9A05,$0B06,$3E07,
39                $4109,$DA10,$9C11,$BF12,$2013,$0014,$C715,$0416,$E317),
40     {256X240} (16,256,240,$E3,$5F00,$3F01,$4202,$9F03,$4C04,$0005,$0D06,$3E07,
41                $4109,$EA10,$AC11,$DF12,$0014,$E715,$0616,$E317,0),
42     {256X256} (17,256,256,$E3,$5F00,$3F01,$4002,$8203,$4E04,$9A05,$2306,$B207,
43                $0008,$6109,$0A10,$AC11,$FF12,$4014,$0715,$1716,$A317));
44
45 TYPE
46   VIRT = ARRAY[1..64000]OF BYTE;                 {TO_STORE_BITMAP_FILES}
47   VIRPTR = ^VIRT;                                {POINTER_TO_VIRTUAL}
48   PALETTE = ARRAY[0..255]OF RECORD R,G,B:BYTE; END; {TO_STORE_MCGA_PALETTE}
49   TSOUND = RECORD                                   {USE_TO_STORE_SOUNDS}
50     DATA:POINTER;                                    {POINTER_TO_THE_SND_DATA}
51     SIZE:WORD;                                       {SIZE_OF_THE_SOUND_DATA}
52   END; {TSOUND}
53
54 VAR WIDTH:INTEGER;                                  {WIDTH_GRAPHICAL_SCREEN}
55     VALID_OP_CODE:BOOLEAN;                          {USED_FOR_CHECKING_CPU}
56     MAXTIME:INTEGER;                                {TRIGGER_TIME}
57     BIOSTIMERHANDLER:PROCEDURE;                     {}
58     CLOCKTICKS:LONGINT;                             {TIMER_TICKS_EXPIRED}
59     TIMEEXPIRED:BOOLEAN;                            {TRUE_IF_TIME_HAS_EXPIRED}
60
61 FUNCTION  FILEEXIST(FIS1:STRING):BOOLEAN;
62 PROCEDURE COFF;
63 PROCEDURE CLRKEY;
64 FUNCTION  KEY:INTEGER;
65 FUNCTION  MIN(MII1,MII2:INTEGER):INTEGER;
66 FUNCTION  MAX(MAI1,MAI2:INTEGER):INTEGER;
67 FUNCTION  ZERO(ZEF1:LONGINT;ZEI1:WORD):STRING;
68 FUNCTION  POW(POI1:LONGINT;POI2:INTEGER):LONGINT;
69 FUNCTION  FPR(FPR1:REAL;FPI1,FPI2:BYTE):STRING;
70 FUNCTION  FP(FPR1:REAL;FPI1,FPI2:BYTE):STRING;
71 FUNCTION  PSET(PSS1:STRING;PSI1:WORD):STRING;
72 FUNCTION  DRPSET(PSS1:STRING;PSI1:WORD):STRING;
73 FUNCTION  CC(CCC1:CHAR;CCI1:BYTE):STRING;
74 FUNCTION  UPCS(UPS1:STRING):STRING;
75 FUNCTION  LOCS(LOS1:STRING):STRING;
76 FUNCTION  PARAMETER(PAS1:STRING):BOOLEAN;
77 FUNCTION  ACTIVE:BYTE;
78 FUNCTION  SGN(SGN1:REAL):INTEGER;
79 FUNCTION  COMP8088:BOOLEAN;
80 FUNCTION  COMP80186:BOOLEAN;
81 FUNCTION  COMP80286:BOOLEAN;
82 FUNCTION  COMP80386:BOOLEAN;
83 FUNCTION  COMP80486:BOOLEAN;
84 FUNCTION  EMSTAT(VAR VERS:BYTE;VAR SIZE,FREE:WORD):BOOLEAN;
85 FUNCTION  XMSTAT(VAR VERS:WORD;VAR SIZE,FREE:WORD):BOOLEAN;
86 PROCEDURE GETMOUSEPOS(VAR X,Y:WORD;VAR BUTTON1,BUTTON2:BOOLEAN);
87 PROCEDURE MOUSE(AI:WORD;VAR A,B,C,D:WORD);
88 FUNCTION  BYTE2HEX(B:BYTE):STRING;
89 FUNCTION  WORD2HEX(W:WORD):STRING;
90 FUNCTION  DWORD2HEX(L:LONGINT):STRING;
91 PROCEDURE SETTIMER(TIMERHANDLER:POINTER;FREQUENCY:WORD);
92 PROCEDURE SHUTDOWNTIMER;
93 PROCEDURE TIMERHANDLER; INTERRUPT;
94
95 PROCEDURE SETVIDEO(X,Y:WORD);
96 PROCEDURE XMODE(MODE:BYTE);
97 PROCEDURE SETXVID(X,Y,COL:WORD);
98 PROCEDURE SETMCGA;
99 PROCEDURE SETVGA;
100 PROCEDURE SETTEXT;
101 FUNCTION  TESTVESA(VAR X,Y:WORD):BOOLEAN;
102 FUNCTION  TESTATI:BOOLEAN;
103 PROCEDURE SCREENOFF;
104 PROCEDURE SCREENON;
105 PROCEDURE CLS(COL:BYTE;WHERE:WORD);
106 PROCEDURE XCLS(COL:BYTE;WHERE:WORD);
107 PROCEDURE WAITRETRACE;
108 PROCEDURE SETPAL(COL,R,G,B:BYTE);
109 PROCEDURE GETPAL(COL:BYTE;VAR R,G,B:BYTE);
110 PROCEDURE FADECURS;
111 PROCEDURE FADEDOWN;
112 PROCEDURE FADEOUT;
113 {PROCEDURE PUTPIXEL(X,Y:INTEGER;COL:BYTE;WHERE:WORD);{}
114 PROCEDURE PUTXPIX(X,Y:INTEGER;COL:BYTE);
115 PROCEDURE PUTPIX(X:INTEGER;COL:BYTE;WHERE:WORD);
116 PROCEDURE XPUTPIX(X:INTEGER;COL:BYTE);
117 FUNCTION  GETPIXEL(X,Y:INTEGER;WHERE:WORD):BYTE;
118 FUNCTION  GETXPIX(X,Y:INTEGER;WHERE:WORD):BYTE;
119 PROCEDURE BLACKBAR(X1,Y1,X2,Y2:INTEGER;WHERE:WORD);
120 PROCEDURE XBLACKBAR(X1,Y1,X2,Y2:INTEGER;WHERE:WORD);
121 PROCEDURE BAR(X1,Y1,X2,Y2:INTEGER;COL:BYTE;WHERE:WORD);
122 PROCEDURE XBAR(X1,Y1,X2,Y2:INTEGER;COL:BYTE);
123 PROCEDURE HLINE(X,XX,Y:INTEGER;COL:BYTE;WHERE:WORD);
124 PROCEDURE XHLINE(X,XX,Y:INTEGER;COL:BYTE);
125 PROCEDURE LINE(X,Y,XX,YY:INTEGER;COL:BYTE;WHERE:WORD);
126 PROCEDURE XLINE(X,Y,XX,YY:INTEGER;COL:BYTE);
127 PROCEDURE FLIP(SOURCE,DEST:WORD);
128 PROCEDURE FLIPSCR(SOURCE,DEST:WORD);
129
130
131 IMPLEMENTATION                                      {THE_CODE}
132
133 FUNCTION FILEEXIST(FIS1:STRING):BOOLEAN;
134 VAR FIF1:FILE;
135 BEGIN {DOES_FILE_EXISTS}
136   ASSIGN(FIF1,FIS1); {$I-} RESET(FIF1); CLOSE(FIF1); {$I+}
137   FILEEXIST:=(IORESULT=0)AND(FIS1<>'');
138 END; {FILEEXIST}
139
140 PROCEDURE COFF; ASSEMBLER;
141 ASM {CURSOR_OFF}
142 { CAR1.AH:=1;   CAR1.BH:=0;   INTR($10,CAR1);
143  CAR1.AH:=3;   CAR1.CH:=0;   INTR($10,CAR1);}
144   MOV AH,1
145   MOV BH,0
146   INT 10H
147   MOV AH,3
148   MOV CH,0
149   INT 10H
150 END; {COFF}
151
152 PROCEDURE CLRKEY;
153 VAR CLC1:CHAR;
154 BEGIN {CLEAR_ALL_KEYS}
155   WHILE KEYPRESSED DO CLC1:=READKEY;
156 END; {CLRKEY}
157
158 FUNCTION KEY:INTEGER;
159 VAR KEC1:CHAR; KEC2:INTEGER;
160 BEGIN {READ_CHAR}
161   KEC2:=-1;
162   IF KEYPRESSED THEN BEGIN
163     KEC1:=READKEY; KEC2:=ORD(KEC1);
164     IF KEC1=CHR(0)THEN BEGIN KEC1:=READKEY; KEC2:=ORD(KEC1)+256; END; {EXTENDED}
165   END; {KEY_IS_PRESSED}
166   KEY:=KEC2;
167 END; {KEY}
168
169 FUNCTION MIN(MII1,MII2:INTEGER):INTEGER;
170 BEGIN {RETURN_SMALLEST_VALUE}
171   IF MII2<MII1 THEN MIN:=MII2 ELSE MIN:=MII1;
172 END; {MIN}
173
174 FUNCTION MAX(MAI1,MAI2:INTEGER):INTEGER;
175 BEGIN {RETURN_LARGEST_VALUE}
176   IF MAI2>MAI1 THEN MAX:=MAI2 ELSE MAX:=MAI1;
177 END; {MAX}
178
179 FUNCTION ZERO(ZEF1:LONGINT;ZEI1:WORD):STRING;
180 VAR ZES1:STRING;
181 BEGIN {PLACE_ZEROES}
182   STR(ZEF1:0,ZES1); WHILE LENGTH(ZES1)<ZEI1 DO ZES1:='0'+ZES1;
183   ZERO:=ZES1;
184 END;  {ZERO}
185
186 FUNCTION POW(POI1:LONGINT;POI2:INTEGER):LONGINT;
187 VAR POI3:INTEGER; POI4:LONGINT;
188 BEGIN {POWER}
189   POI4:=1; FOR POI3:=1TO POI2 DO POI4:=POI4*POI1; POW:=POI4;
190 END; {POW}
191
192 FUNCTION FPR(FPR1:REAL;FPI1,FPI2:BYTE):STRING;
193 BEGIN {FLOATING_POINT_TO_STRING}
194   FPR:=ZERO(TRUNC(FPR1),FPI1)+'.'+ZERO(ROUND(FRAC(FPR1)*POW(10,FPI2)),FPI2);
195 END; {FP}
196
197 FUNCTION FP(FPR1:REAL;FPI1,FPI2:BYTE):STRING;
198 BEGIN {FLOATING_POINT_TO_STRING}
199   FP:=ZERO(TRUNC(FPR1),FPI1)+'.'+ZERO(TRUNC(FRAC(FPR1)*POW(10,FPI2)),FPI2);
200 END; {FP}
201
202 FUNCTION PSET(PSS1:STRING;PSI1:WORD):STRING;
203 BEGIN {PLACE_DOTS}
204   IF(LENGTH(PSS1)>PSI1)AND(PSI1>3)THEN BEGIN
205     WHILE LENGTH(PSS1)>PSI1-3 DO DELETE(PSS1,LENGTH(PSS1),1);
206     PSS1:=PSS1+'...';
207   END; {TOO LARGE}
208   PSET:=PSS1;
209 END; {PSET}
210
211 FUNCTION DRPSET(PSS1:STRING;PSI1:WORD):STRING;
212 BEGIN {PLACE_DOTS_KEEP_DRIVE_LETTER}
213   IF LENGTH(PSS1)>PSI1 THEN BEGIN
214     INSERT('...',PSS1,4); WHILE LENGTH(PSS1)>PSI1 DO DELETE(PSS1,7,1);
215   END; {TOO LARGE}
216   DRPSET:=PSS1;
217 END; {DRPSET}
218
219 FUNCTION CC(CCC1:CHAR;CCI1:BYTE):STRING;
220 VAR CCS1:STRING; CCI2:BYTE;
221 BEGIN {COPY_CHAR}
222   CCS1:=''; FOR CCI2:=1TO CCI1 DO CCS1:=CCS1+CCC1; CC:=CCS1;
223 END; {CC}
224
225 FUNCTION UPCS(UPS1:STRING):STRING;
226 VAR UPI1:INTEGER;
227 BEGIN {UPCASE}
228   FOR UPI1:=1TO LENGTH(UPS1)DO UPS1[UPI1]:=UPCASE(UPS1[UPI1]); UPCS:=UPS1;
229 END; {UPCS}
230
231 FUNCTION LOCS(LOS1:STRING):STRING;
232 VAR LOI1:INTEGER;
233 BEGIN {LOCASE}
234   FOR LOI1:=1TO LENGTH(LOS1)DO BEGIN
235     LOS1[LOI1]:=UPCASE(LOS1[LOI1]);
236     IF(LOS1[LOI1]>='A')AND(LOS1[LOI1]<='Z')THEN LOS1[LOI1]:=CHR(ORD(LOS1[LOI1])+32);
237   END; {MAKE LOWER CASE}
238   LOCS:=LOS1;
239 END; {LOCS}
240
241 FUNCTION PARAMETER(PAS1:STRING):BOOLEAN;
242 VAR PAI1:INTEGER; PAS2:STRING;
243 BEGIN  {PARAMETER}
244   PARAMETER:=FALSE;
245   IF PARAMCOUNT>0THEN FOR PAI1:=1TO PARAMCOUNT DO BEGIN
246     PAS2:=UPCS(PARAMSTR(PAI1));
247     IF(PAS2='/'+UPCS(PAS1))OR(PAS2='-'+UPCS(PAS1))OR(PAS2=UPCS(PAS1))
248      OR(PAS2='>'+UPCS(PAS1))THEN PARAMETER:=TRUE;
249   END; {FOR}
250 END;  {PARAMETER}
251
252 FUNCTION ACTIVE:BYTE; ASSEMBLER;
253 ASM
254   MOV AH,2
255   INT 16H
256   MOV AH,0
257 {Bits: $01=RSH  $02=LSH  $04=CTL  $08=ALT  $10=SCR  $20=NUM  $40=CAP  $80=INS
258  Example: IF(ACTIVE AND$01<>0)THEN WRITELN('RIGHT SHIFT PRESSED');}
259 END;
260
261 FUNCTION SGN(SGN1:REAL):INTEGER;
262 BEGIN
263   IF SGN1>0THEN SGN:=1 ELSE IF SGN1<0THEN SGN:=-1 ELSE SGN:=0;
264 END; {SGN}
265
266 PROCEDURE INTR6HANDLER; INTERRUPT;
267 BEGIN
268   VALID_OP_CODE:=FALSE;
269   ASM ADD WORD PTR SS:[BP+18],3 END; {A_SINGLE_ASSEMBLER_CODE}
270 END; {INTR6HANDLER}
271
272 FUNCTION COMP8088:BOOLEAN; ASSEMBLER;
273 ASM {RETURNS_TRUE_IF_8088_COMPATIBLE_FOUND}
274   MOV AX,SP
275   PUSH SP
276   POP BX
277   CMP AX,BX
278   JZ @@1
279   XOR AX,AX
280 @@1:
281   MOV AX,1
282 END; {COMP8088}
283
284 FUNCTION COMP80186:BOOLEAN;
285 VAR X:PROCEDURE;
286 BEGIN
287   IF COMP8088 THEN COMP80186:=FALSE ELSE BEGIN
288     VALID_OP_CODE:=TRUE;
289     GETINTVEC(6,@X);
290     SETINTVEC(6,ADDR(INTR6HANDLER));
291     INLINE($C1/$E2/$05); {SHL DX,5}
292     SETINTVEC(6,@X);
293     COMP80186 :=VALID_OP_CODE;
294   END;
295 END;
296
297 FUNCTION COMP80286:BOOLEAN; ASSEMBLER;
298 ASM {RETURNS_TRUE_IF_COMPUTER_IS_286_COMPATIBLE}
299   PUSHF
300   POP BX
301   AND BX,0FFFH
302   PUSH BX
303   POPF
304   PUSHF
305   POP BX
306   AND BX,0F000H
307   XOR AX,AX
308   CMP BX,0F000H
309   JZ  @@1
310   INC AX
311 @@1:
312 END; {COMP80286}
313
314 FUNCTION COMP80386:BOOLEAN;
315 VAR X:PROCEDURE;
316 BEGIN {RETURNS_TRUE_IF_COMPUTER_IS_80386_COMPATIBLE}
317   IF NOT COMP8088 THEN COMP80386:=FALSE ELSE BEGIN
318     VALID_OP_CODE:=TRUE;
319     GETINTVEC(6,@X);
320     SETINTVEC(6,ADDR(INTR6HANDLER));
321     INLINE($0F/$20/$C2); {MOV EDX,CR0}
322     SETINTVEC(6,@X);
323     COMP80386:=VALID_OP_CODE;
324   END; {8088_COMPATIBLE>RUN_TEST}
325 END; {COMP80386}
326
327 FUNCTION COMP80486:BOOLEAN;
328 VAR X:PROCEDURE;
329 BEGIN {RETURNS_TRUE_IF_CPU_IS_80486_COMPATIBLE}
330   IF NOT COMP8088 THEN COMP80486:=FALSE ELSE BEGIN
331     VALID_OP_CODE:=TRUE;
332     GETINTVEC(6,@X);
333     SETINTVEC(6,ADDR(INTR6HANDLER));
334     INLINE($0F/$C1/$D2); {XADD DX,DX}
335     SETINTVEC(6,@X);
336     COMP80486:=VALID_OP_CODE;
337   END; {8088_COMPATIBLE>RUN_TEST}
338 END; {COMP80486}
339
340 FUNCTION EMSTAT(VAR VERS:BYTE;VAR SIZE,FREE:WORD):BOOLEAN;
341 TYPE ARTYPE=ARRAY[1..8]OF CHAR;
342 VAR P:^ARTYPE;
343     REG:REGISTERS;
344 BEGIN {RETURN_EMS_STATS}
345   EMSTAT:=FALSE; GETINTVEC($67,POINTER(P)); P:=PTR(SEG(P^),$0A);
346   IF P^='EMMXXXX0'THEN BEGIN
347     REG.AH:=$40; INTR($67,REG);
348     IF REG.AH<>0THEN HALT ELSE BEGIN
349       REG.AH:=$46; INTR($67,REG); IF REG.AH<>0THEN HALT;
350       VERS:=REG.AL; {VERSION_IS_(REG.AL SHR 4).(REG.AL AND $F)}
351       REG.AH:=$42; INTR($67,REG); IF REG.AH<>0THEN HALT;
352       SIZE:=REG.DX; FREE:=REG.BX; {SIZE_UNIT_IS_64_BYTES_OR_(2^4)_KB}
353       EMSTAT:=TRUE;
354     END; {NO_ERRORS}
355   END; {EMM_INSTALLED}
356 END; {EMSTAT}
357
358 FUNCTION XMSTAT(VAR VERS:WORD;VAR SIZE,FREE:WORD):BOOLEAN;
359 VAR P:LONGINT;
360     REG:REGISTERS;
361     VER:WORD;
362 BEGIN
363   XMSTAT:=FALSE; REG.AX:=$4300; INTR($2F,REG);
364   IF REG.AL=$80THEN BEGIN
365     XMSTAT:=TRUE;
366     ASM {GET_VERSION_NUMBER}
367       MOV AX,4310h
368       INT 2Fh
369       MOV WORD PTR [P],BX
370       MOV WORD PTR [P+2],ES
371       MOV AH,00h
372       CALL [P]
373       MOV [VER],AX
374     END; {ASM}
375     VERS:=VER;
376   END; {XMS_FOUND}
377 END; {XMSTAT}
378
379 PROCEDURE GETMOUSEPOS(VAR X,Y:WORD;VAR BUTTON1,BUTTON2:BOOLEAN);
380 VAR REGS:REGISTERS;
381 BEGIN {RETURNS_POSITION_OF_MOUSE_AND_PRESS-STATUS_OF_BUTTONS}
382   REGS.AX:=3; INTR(MOUSEINTR,REGS); X:=REGS.CX; Y:=REGS.DX;
383   BUTTON1:=(REGS.BX AND 1)<>0; BUTTON2:=(REGS.BX AND 2)<>0;
384 END; {GETMOUSEPOS}
385
386 PROCEDURE MOUSE(AI:WORD;VAR A,B,C,D:WORD);
387 VAR AA,BB,CC,DD:WORD;
388 BEGIN
389   BB:=B; CC:=C; DD:=D;
390   ASM
391     MOV AX,[AI]
392     MOV BX,[BB]
393     MOV CX,[CC]
394     MOV DX,[DD]
395     INT 33H
396     MOV [AA],BX
397     MOV [BB],BX
398     MOV [CC],CX
399     MOV [DD],DX
400   END; {DO_IT}
401   A:=AA; B:=BB; C:=CC; D:=DD;
402 END; {MOUSE}
403
404 PROCEDURE _HEXBYTE; ASSEMBLER;
405 ASM {USED_FOR_HEX_CONVERT_FUNCTIONS_BELOW}
406   MOV  CX,2
407 @@1:
408   PUSH CX
409   MOV  CL,4
410   ROL  DL,CL
411   MOV  AL,DL
412   AND  AL,0Fh
413   DAA
414   ADD  AL,0F0h
415   ADC  AL,40h
416   STOSB
417   POP  CX
418   LOOP @@1
419 END; {_HEXBYTE}
420
421 FUNCTION BYTE2HEX(B:BYTE):STRING; ASSEMBLER;
422 ASM {CONVERTS_A_HEX_REPRESENTATION_OF_THE_BYTE_INTO_A_STRING}
423   CLD
424   LES  DI,@RESULT
425   MOV  AL,2
426   STOSB
427   MOV  DL,[B]
428   CALL _HEXBYTE
429 END; {BYTE2HEX}
430
431 FUNCTION WORD2HEX(W:WORD):STRING; ASSEMBLER;
432 ASM {CONVERT_THE_HEXADECIMAL_VALUE_OF_A_WORD_TO_A_STRING}
433   CLD
434   LES  DI,@RESULT
435   MOV  AL,4
436   STOSB
437   MOV  DX,[W]
438   MOV  CX,2
439 @@1:
440   PUSH CX
441   XCHG DL,DH
442   CALL _HEXBYTE
443   POP  CX
444   LOOP @@1
445 END; {WORD2HEX}
446
447 FUNCTION DWORD2HEX(L:LONGINT):STRING; ASSEMBLER;
448 ASM {CONVERTS_A_LONGINT_HEX_VALUE_INTO_A_STRING}
449   CLD
450   LES  DI,@RESULT
451   MOV  AL,8
452   STOSB
453   MOV  BX,SP
454   MOV  DS,SS:[BX+6]
455   MOV  BX,SS:[BX+8]
456   MOV  CX,2
457 @@1:
458   PUSH CX
459   XCHG DX,BX
460   MOV  CX,2
461 @@2:
462   PUSH CX
463   XCHG DL,DH
464   CALL _HEXBYTE
465   POP  CX
466   LOOP @@2
467   POP  CX
468   LOOP @@1
469 END; {DWORD2HEX}
470
471 PROCEDURE SETTIMER(TIMERHANDLER:POINTER;FREQUENCY:WORD);
472 VAR COUNTER:LONGINT;
473 BEGIN
474   CLOCKTICKS:=0; TIMEEXPIRED:=FALSE; COUNTER:=$1234DD DIV FREQUENCY; {@INIT}
475   GETINTVEC(TIMERINTR,@BIOSTIMERHANDLER); SETINTVEC(TIMERINTR,TIMERHANDLER);
476   PORT[$43]:=$34; PORT[$40]:=COUNTER MOD 256; PORT[$40]:=COUNTER SHR 8;
477 END; {SETTIMER}
478
479 PROCEDURE SHUTDOWNTIMER;
480 BEGIN {RESTORE_EVERYTHING_AS_IT_WAS}
481   PORT[$43]:=$34; PORT[$40]:=$00; PORT[$40]:=$00; {@RESTORE_NORMAL_CLOCK_FREQUENCY}
482   SETINTVEC(TIMERINTR,@BIOSTIMERHANDLER); {RESTORE_NORMAL_TICKER_HANDLER}
483 END; {SHUTDOWNTIMER}
484
485 PROCEDURE TIMERHANDLER;
486 BEGIN
487   INC(CLOCKTICKS);
488   IF CLOCKTICKS>=MAXTIME THEN BEGIN
489      TIMEEXPIRED:=TRUE; CLOCKTICKS:=0;
490      ASM PUSHF END; {PUSH_ALL_VALUES} BIOSTIMERHANDLER;
491   END {TIME_EXPIRED} ELSE PORT[$20]:=$20; {@ACKNOWLEDGE_THE_INTERRUPT}
492 END; {TIMERHANDLER}
493
494
495 PROCEDURE SETVIDEO(X,Y:WORD); ASSEMBLER;
496 ASM {SET_CUSTOM_VIDEO_MODE}
497   MOV AX,[X]
498   MOV BX,[Y]
499   INT 10H
500 END; {SETVIDEO}
501
502 PROCEDURE XMODE(MODE:BYTE);
503 VAR MTEMP:BYTE;
504 BEGIN
505   ASM
506     MOV AX,0013h
507     INT 10h
508   END; {GET_INTO_MCGA_MODE}
509   PORT[$03C4]:=1; PORT[$03C5]:=PORT[$03C5]OR$20; PORTW[$03C4]:=$0604;
510   IF MODESETS[MODE,3]<>0THEN PORT[$03C2]:=BYTE(MODESETS[MODE,3]);
511   FOR MTEMP:=4TO MODESETS[MODE,0]+3DO PORTW[$03D4]:=MODESETS[MODE,MTEMP];
512   WIDTH:=MODESETS[MODE,1]SHR 2; PORTW[$03C4]:=$0F02;
513   FILLCHAR(MEM[$A000:0],$8000,0); FILLCHAR(MEM[$A000:$8000],$8000,0);
514   DELAY(100); PORT[$03C4]:=1; PORT[$03C5]:=PORT[$03C5]AND$DF;
515 END; {XMODE}
516
517 PROCEDURE SETXVID(X,Y,COL:WORD);
518 BEGIN {SET_CUSTON_UNCHAINED_VIDEO_MODE}
519   ASM
520     MOV AX,[X]
521     MOV BX,[Y]
522     INT 10H
523   END;
524   PORT[$03C4]:=1; PORT[$03C5]:=PORT[$03C5]OR$20; {@TURN_VGA_SCREEN_OFF}
525   PORTW[$03C4]:=$0604; {@TURN_OFF_CHAIN-4_BIT}
526   PORTW[$03D4]:=$E317; {@TURN_OFF_WORD_MODE}
527   PORTW[$03D4]:=$0014; {@TURN_OFF_DOUBLEWORD_MODE}
528   PORTW[$03D4]:=$000C; PORTW[$03D4]:=$000D; {@OFFSET}
529   PORTW[$03C4]:=$0F02; {@CLEAR_ENTIRE_VIDEO_MEMORY}
530   FILLCHAR(MEM[$A000:1],$FFFF,0); MEM[$A000:0]:=0;
531   WIDTH:=COL SHR 2; DELAY(100); {@GIVE_A_SMALL_DELAY}
532   PORT[$03C4]:=1; PORT[$03C5]:=PORT[$03C5]AND$DF; {@TURN_SCREEN_BACK_ON}
533 END; {SETXVID}
534
535 PROCEDURE SETMCGA;
536 BEGIN {SETS_VIDEO_TO_NORMAL_320x200x256}
537   ASM
538     MOV AX,0013H
539     INT 10H
540   END; {ASSEMBLER_TRICK}
541   PORTW[$03C4]:=$0A04; {@TURN_OFF_CHAIN-4_BIT}
542 END; {SETMCGA}
543
544 PROCEDURE SETVGA; ASSEMBLER;
545 ASM {SET_SCREEN_MODE_TO_640x480x256}
546   MOV AX,4F02H
547   MOV BX,0100H
548   INT 10H
549 END; {SETVGA}
550
551 PROCEDURE SETTEXT; ASSEMBLER;
552 ASM {SET_SCREEN_MODE_TO_TEXT}
553   MOV AX,0003H
554   INT 10H
555 END; {SETTEXT}
556
557 FUNCTION TESTVESA(VAR X,Y:WORD):BOOLEAN;
558 TYPE ARTYPE=ARRAY[0..255]OF BYTE;
559 VAR P:^ARTYPE;
560     R:REGISTERS;
561 BEGIN {RETURNS_PRESENT_VESA_CARD_VERSION_IF_PRESENT}
562   TESTVESA:=FALSE; GETMEM(P,SIZEOF(P)); X:=0;
563   R.AH:=$4F; R.AL:=$00; R.ES:=SEG(P^); R.DI:=OFS(P^); INTR($10,R);
564   IF(R.AX=$004F)AND(P^[0]=ORD('V'))AND(P^[1]=ORD('E'))AND(P^[2]=ORD('S'))
565     AND(P^[3]=ORD('A'))THEN BEGIN
566       TESTVESA:=TRUE; X:=P^[5]*$100+P^[4]; END; {FOUND}
567   FREEMEM(P,SIZEOF(P));
568 END; {TESTVESA}
569
570 FUNCTION TESTATI:BOOLEAN;
571 VAR P:STRING[9];
572 BEGIN {RETURNS_TRUE_IF_ATI_VIDEO_CARD_IS_PRESENT}
573   MOVE(MEM[$C000:$0031],P,9);
574   IF P='761295520'THEN TESTATI:=TRUE ELSE TESTATI:=FALSE;
575 END; {TESTATI}
576
577 PROCEDURE SCREENOFF;
578 BEGIN
579   PORT[$03C4]:=1; PORT[$03C5]:=PORT[$03C5]OR$20;
580 END; {SCREENOFF}
581
582 PROCEDURE SCREENON;
583 BEGIN
584   PORT[$03C4]:=1; PORT[$03C5]:=PORT[$03C5]AND$DF;
585 END; {SCREENON}
586
587 PROCEDURE CLS(COL:BYTE;WHERE:WORD);
588 BEGIN {CLEARS_SCREEN_TO_ONE_COLOR}
589   FILLCHAR(MEM[WHERE:0],64000,COL);
590 END; {CLS}
591
592 PROCEDURE XCLS(COL:BYTE;WHERE:WORD);
593 BEGIN {CLEARS_THE_UNCHAINED_SCREEN_TO_A_SINGLE_COLOR}
594   PORTW[$03C4]:=$0F02; FILLCHAR(MEM[WHERE:0],64000,COL);
595 END; {XCLS}
596
597 PROCEDURE WAITRETRACE;ASSEMBLER;
598 ASM {WAIT_FOR_A_VERTICAL_SCREEN_RETRACE}
599   MOV DX,3DAH
600 @@1:
601   IN  AL,DX
602   AND AL,08h
603   JNZ @@1
604 @@2:
605   IN  AL,DX
606   AND AL,08H
607   JZ  @@2
608 END; {WAITRETRACE}
609
610 PROCEDURE SETPAL(COL,R,G,B:BYTE); ASSEMBLER;
611 ASM {SET_A_PALETTE_COLOR}
612   MOV DX,3C8H
613   MOV AL,[COL]
614   OUT DX,AL
615   INC DX
616   MOV AL,[R]
617   OUT DX,AL
618   MOV AL,[G]
619   OUT DX,AL
620   MOV AL,[B]
621   OUT DX,AL
622 END; {SETPAL}
623
624 PROCEDURE GETPAL(COL:BYTE;VAR R,G,B:BYTE);
625 VAR RT,GT,BT:BYTE;
626 BEGIN {GET_A_PALETTE_COLOR}
627   ASM
628     MOV DX,3C7H
629     MOV AL,[COL]
630     OUT DX,AL
631     INC DX
632     INC DX
633     IN  AL,DX
634     MOV [RT],AL
635     IN  AL,DX
636     MOV [GT],AL
637     IN  AL,DX
638     MOV [BT],AL
639   END;
640   R:=RT; G:=GT; B:=BT;
641 END; {GETPAL}
642
643 PROCEDURE FADECURS;
644 VAR R,G,B:BYTE;
645 BEGIN {FADE_OUT_COLOR_SEVEN}
646   GETPAL(7,R,G,B);
647   REPEAT
648     WAITRETRACE; IF G>0THEN DEC(G); IF B>0THEN DEC(B); IF R>0THEN DEC(R);
649     SETPAL(7,R,G,B);
650   UNTIL R+G+B<3; {FADE_TO_BLACK}
651 END; {FADECURS}
652
653 PROCEDURE FADEDOWN;
654 VAR FADETEMP,FADECTEMP:INTEGER;
655     FADETMP,FADETMP2:ARRAY[1..3]OF BYTE;
656     FADECOL:ARRAY[1..255,1..3]OF BYTE;
657     FADECOLI:ARRAY[1..255,1..3]OF REAL;
658 BEGIN {NATURALLY_FADES_OUT_THE_256_COLOR_PALETTE}
659   FOR FADECTEMP:=1TO 255DO BEGIN
660     GETPAL(FADECTEMP,FADECOL[FADECTEMP,1],FADECOL[FADECTEMP,2],FADECOL[FADECTEMP,3]);
661     FADECOLI[FADECTEMP,1]:=FADECOL[FADECTEMP,1]/32;
662     FADECOLI[FADECTEMP,2]:=FADECOL[FADECTEMP,2]/32;
663     FADECOLI[FADECTEMP,3]:=FADECOL[FADECTEMP,3]/32;
664   END; {CALCULATE_STEPS_FOR_EACH_COLOR}
665   FOR FADETEMP:=0TO 31DO BEGIN
666     REPEAT UNTIL TIMEEXPIRED; TIMEEXPIRED:=FALSE;
667     FOR FADECTEMP:=1TO 255DO BEGIN
668       SETPAL(FADECTEMP,FADECOL[FADECTEMP,1]-ROUND(FADECOLI[FADECTEMP,1]*FADETEMP),
669         FADECOL[FADECTEMP,2]-ROUND(FADECOLI[FADECTEMP,2]*FADETEMP),
670           FADECOL[FADECTEMP,3]-ROUND(FADECOLI[FADECTEMP,3]*FADETEMP));
671     END; {CHANGE_ALL_COLORS}
672   END; {FADE_OUT_ALL_COLORS}
673   WAITRETRACE; FOR FADECTEMP:=1TO 255DO SETPAL(FADECTEMP,0,0,0);
674 END; {FADEDOWN}
675
676 PROCEDURE FADEOUT;
677 VAR FADETEMP,FADECTEMP:INTEGER;
678     FADETMP:ARRAY[1..3]OF BYTE;
679 BEGIN {FADE_ALL_256_COLORS_BY_DECREASING_THEM_UNTIL_THEY_REACH_ZERO}
680   FOR FADETEMP:=0TO 63DO BEGIN
681     REPEAT UNTIL TIMEEXPIRED; TIMEEXPIRED:=FALSE;
682     FOR FADECTEMP:=1TO 255DO BEGIN
683       GETPAL(FADECTEMP,FADETMP[1],FADETMP[2],FADETMP[3]);
684       IF FADETMP[1]>0THEN DEC(FADETMP[1]);
685       IF FADETMP[2]>0THEN DEC(FADETMP[2]);
686       IF FADETMP[3]>0THEN DEC(FADETMP[3]);
687       SETPAL(FADECTEMP,FADETMP[1],FADETMP[2],FADETMP[3]);
688     END; {CHANGE_ALL_COLORS}
689   END; {FADE_OUT_ALL_COLORS}
690 END; {FADEOUT}
691
692 PROCEDURE PUTPIXEL(X,Y:INTEGER;COL:BYTE;WHERE:WORD);
693 BEGIN {PUTS_A_PIXEL_AT_PX,PY_COLOR_PCOL_ON_VGA_OR_VIRTUAL_SCREEN}
694   ASM
695   MOV AX,[WHERE]
696   MOV ES,AX
697   MOV BX,[X]
698   MOV DX,[Y]
699   MOV DH,DL
700   XOR DL,DL
701   ADD BX,DX
702   SHR DX,2
703   ADD BX,DX
704   MOV AL,[COL]
705   MOV ES:[BX],AL
706   END; {ASSEMBLER_VERSION}
707 END; {PUTPIXEL}
708
709 PROCEDURE PUTXPIX(X,Y:INTEGER;COL:BYTE);
710 BEGIN {PUTS_A_PIXEL_AT_PX,PY_COLOR_PCOL_ON_VGA_OR_VIRTUAL_SCREEN}
711   PORTW[$03C4]:=$100SHL(X AND 3)+2; {@SET_MAP_MASK_TO_SELECT_PROPER_PLANE}
712   MEM[VGA:Y*WIDTH+X SHR 2]:=COL;
713 {  MOV DX,03C4H
714   MOV AL,02H
715   OUT DX,AL
716   INC DX
717   MOV AL,1
718   MOV CX,[X]
719   AND CL,03H
720   SHL AL,CL
721   OUT DX,AL
722   MOV ES,[VGA]
723   MOV BX,[WIDTH]
724   MOV AX,[Y]
725   MUL BL
726   MOV BX,[X]
727   SHR BX,2
728   ADD BX,AX
729   MOV AL,[COL]
730   MOV ES:[BX],AL}
731 END; {PUTXPIX}
732
733 PROCEDURE PUTPIX(X:INTEGER;COL:BYTE;WHERE:WORD); ASSEMBLER;
734 ASM {DISPLAYS_A_PIXEL_AT_PRECALCULATED_COORDINATES}
735   MOV AX,[WHERE]
736   MOV ES,AX
737   MOV AX,[X]
738   MOV DI,AX
739   MOV AL,[COL]
740   STOSB
741 END; {PUTPIX}
742
743 PROCEDURE XPUTPIX(X:INTEGER;COL:BYTE);
744 BEGIN {PUTS_A_PIXEL_AT_PX,PY_COLOR_PCOL_ON_VGA_OR_VIRTUAL_SCREEN}
745   PORTW[$03C4]:=$100SHL(X AND 3)+2; {@SET_MAP_MASK_TO_SELECT_PROPER_PLANE}
746   MEM[VGA:X SHR 2]:=COL;
747 END; {XPUTPIX}
748
749 FUNCTION GETPIXEL(X,Y:INTEGER;WHERE:WORD):BYTE; ASSEMBLER;
750 ASM {GET_A_PIXEL_FROM_A_CHAINED_SCREEN}
751   MOV AX,[WHERE]
752   MOV ES,AX
753   MOV BX,[X]
754   MOV DX,[Y]
755   MOV DH,DL
756   XOR DL,DL
757   ADD BX,DX
758   SHR DX,1
759   SHR DX,1
760   ADD BX,DX
761   MOV AL,ES:[BX]
762 END; {GETPIXEL}
763
764 FUNCTION GETXPIX(X,Y:INTEGER;WHERE:WORD):BYTE;
765 BEGIN {PUTS_A_PIXEL_AT_PX,PY_COLOR_PCOL_ON_VGA_OR_VIRTUAL_SCREEN}
766   PORT[$03CE]:=4;
767   PORT[$03CF]:=X AND 3;
768   GETXPIX:=MEM[WHERE:WIDTH*Y+X SHR 2];
769 END; {PUTPIXEL}
770
771 PROCEDURE BLACKBAR(X1,Y1,X2,Y2:INTEGER;WHERE:WORD);
772 VAR BLB1,BLB2:INTEGER;
773 BEGIN {DRAW_A_BAR_WITH_COLOR_ZERO}
774   FOR BLB1:=Y1 TO Y2 DO FOR BLB2:=X1 TO X2 DO
775     PUTPIXEL(BLB2,BLB1,0,WHERE);
776 END; {BLACKBAR}
777
778 PROCEDURE XBLACKBAR(X1,Y1,X2,Y2:INTEGER;WHERE:WORD);
779 VAR BLB1,BLB2:INTEGER;
780 BEGIN
781   FOR BLB1:=Y1 TO Y2 DO FOR BLB2:=X1 TO X2 DO
782     PUTXPIX(BLB2,BLB1,0);
783 END; {BLACKBAR}
784
785 PROCEDURE BAR(X1,Y1,X2,Y2:INTEGER;COL:BYTE;WHERE:WORD);
786 VAR BLB1:INTEGER;
787 BEGIN {DRAWS_A_BAR_WITH_SPECIFIED_COLOR}
788   FOR BLB1:=Y1 TO Y2 DO HLINE(X1,X2,BLB1,COL,WHERE);
789 END; {BAR}
790
791 PROCEDURE XBAR(X1,Y1,X2,Y2:INTEGER;COL:BYTE);
792 VAR BLB1,BLB2:INTEGER;
793 BEGIN
794   FOR BLB1:=Y1 TO Y2 DO XHLINE(X1,X2,BLB1,COL);
795 END; {XBAR}
796
797 PROCEDURE HLINE(X,XX,Y:INTEGER;COL:BYTE;WHERE:WORD); ASSEMBLER;
798 ASM {DRAWS_A_HORIZONTAL_LINE}
799   MOV AX,[WHERE]
800   MOV ES,AX
801   MOV DX,[X]
802   MOV DI,DX
803   MOV AX,[Y]
804   MOV AH,AL
805   XOR AL,AL
806   ADD DI,AX
807   MOV AL,[COL]
808   MOV AH,AL
809   MOV CX,[XX]
810   SUB CX,DX
811   SHR CX,1
812   JNC @@1
813   STOSB
814 @@1:
815   REP STOSW
816 END; {HLINE}
817
818 PROCEDURE XHLINE(X,XX,Y:INTEGER;COL:BYTE);
819 VAR I:INTEGER;
820 BEGIN {DRAWS_A_HORIZONTAL_LINE_FROM_(X,Y)_TO_(XX,Y)_AT_COLOR_PCOL_ON_VGA}
821   FOR I:=X TO XX DO PUTXPIX(I,Y,COL);
822 END; {XHLINE}
823
824 PROCEDURE LINE(X,Y,XX,YY:INTEGER;COL:BYTE;WHERE:WORD);
825 VAR LINE1,LINE2,SX,SY,SXY,SYX,DX1,DX2,DY1,DY2:INTEGER;
826 BEGIN {JUST_A_SIMPLE_LINE_PROCEDURE}
827   SX:=XX-X; SY:=YY-Y; DX1:=SGN(SX); DX2:=DX1; DY1:=SGN(SY); DY2:=0;
828   SXY:=ABS(SX); SYX:=ABS(SY);
829   IF SYX>SXY THEN BEGIN
830     DY2:=DY1; DX2:=0; LINE1:=SXY; SXY:=SYX; SYX:=LINE1;
831   END; {VERTICAL_LINE}
832   LINE1:=SXY SHR 1;
833   FOR LINE2:=0TO SXY DO BEGIN
834     PUTPIXEL(X,Y,COL,WHERE);
835     LINE1:=LINE1+SYX;
836     IF LINE1<SXY THEN BEGIN
837       INC(X,DX2); INC(Y,DY2);
838     END {STRAIGT_AHEAD} ELSE BEGIN
839       LINE1:=LINE1-SXY;
840       INC(X,DX1); INC(Y,DY1);
841     END; {NEXT_STEP}
842   END; {DRAW_THE_LINE}
843 END; {LINE}
844
845 PROCEDURE XLINE(X,Y,XX,YY:INTEGER;COL:BYTE);
846 VAR LINE1,LINE2,SX,SY,SXY,SYX,DX1,DX2,DY1,DY2:INTEGER;
847 BEGIN
848   SX:=XX-X; SY:=YY-Y; DX1:=SGN(SX); DX2:=DX1; DY1:=SGN(SY); DY2:=0;
849   SXY:=ABS(SX); SYX:=ABS(SY);
850   IF SYX>SXY THEN BEGIN
851     DY2:=DY1; DX2:=0; LINE1:=SXY; SXY:=SYX; SYX:=LINE1;
852   END; {VERTICAL_LINE}
853   LINE1:=SXY SHR 1;
854   FOR LINE2:=0TO SXY DO BEGIN
855     PUTXPIX(X,Y,COL);
856     LINE1:=LINE1+SYX;
857     IF LINE1<SXY THEN BEGIN
858       INC(X,DX2); INC(Y,DY2);
859     END {STRAIGT_AHEAD} ELSE BEGIN
860       LINE1:=LINE1-SXY;
861       INC(X,DX1); INC(Y,DY1);
862     END; {NEXT_STEP}
863   END; {DRAW_THE_LINE}
864 END; {LINE}
865
866 PROCEDURE FLIP(SOURCE,DEST:WORD); ASSEMBLER;
867 ASM {FLIPS_AN_MCGA_SCREEN_FROM_SOURCE_TO_DEST}
868   PUSH DS
869   MOV AX,[DEST]
870   MOV ES,AX
871   MOV AX,[SOURCE]
872   MOV DS,AX
873   XOR SI,SI
874   XOR DI,DI
875   MOV CX,32000
876   REP MOVSW
877   POP DS
878 END; {FLIP}
879
880 PROCEDURE FLIPSCR(SOURCE,DEST:WORD); ASSEMBLER;
881 ASM {FLIPS_A_PART_OF_AN_MCGA_SCREEN_FROM_SOURCE_TO_DEST}
882   PUSH DS
883   MOV AX,[DEST]
884   MOV ES,AX
885   MOV AX,[SOURCE]
886   MOV DS,AX
887   MOV SI,3200
888   MOV DI,3200
889   MOV CX,25600
890   REP MOVSW
891   POP DS
892 END; {FLIP}
893
894
895 END.                                                {THAT'S_ALL_FOLKS!}