]> 4ch.mooo.com Git - 16.git/blob - 16/PCGPE10/TUT7.TXT
modified: 16/modex16/scroll.c
[16.git] / 16 / PCGPE10 / TUT7.TXT
1                    ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸\r
2                    ³         W E L C O M E         ³\r
3                    ³  To the VGA Trainer Program   ³ ³\r
4                    ³              By               ³ ³\r
5                    ³      DENTHOR of ASPHYXIA      ³ ³ ³\r
6                    ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³\r
7                      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³\r
8                        ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
9 \r
10                            --==[ PART 7 ]==--\r
11 \r
12 \r
13 \r
14 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
15 þ Introduction\r
16 \r
17 Hello! By popular request, this part is all about animation. I will be\r
18 going over three methods of doing animation on a PC, and will\r
19 concerntrate specifically on one, which will be demonstrated in the\r
20 attached sample code.\r
21 \r
22 Although not often used in demo coding, animation is usually used in\r
23 games coding, which can be almost as rewarding ;-)\r
24 \r
25 In this part I will also be a lot less stingy with assembler code :)\r
26 Included will be a fairly fast pure assembler putpixel, an asm screen\r
27 flip command, an asm icon placer, an asm partial-flip and one or two\r
28 others. I will be explaining how these work in detail, so this may also\r
29 be used as a bit of an asm-trainer too.\r
30 \r
31 By the way, I apologise for this part taking so long to be released, but\r
32 I only finished my exams a few days ago, and they of course took\r
33 preference ;-). I have also noticed that the MailBox BBS is no longer\r
34 operational, so the trainer will be uploaded regularly to the BBS lists\r
35 shown at the end of this tutorial.\r
36 \r
37 If you would like to contact me, or the team, there are many ways you\r
38 can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail\r
39                   on the ASPHYXIA BBS.\r
40             2) Write a message in the Programming conference on the\r
41                   For Your Eyes Only BBS (of which I am the Moderator )\r
42                   This is preferred if you have a general programming query\r
43                   or problem others would benefit from.\r
44             4) Write to Denthor, Eze or Livewire on Connectix.\r
45             5) Write to :  Grant Smith\r
46                            P.O.Box 270 Kloof\r
47                            3640\r
48                            Natal\r
49             6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you\r
50                   call during varsity)\r
51             7) Write to mcphail@beastie.cs.und.ac.za on InterNet, and\r
52                   mention the word Denthor near the top of the letter.\r
53 \r
54 NB : If you are a representative of a company or BBS, and want ASPHYXIA\r
55        to do you a demo, leave mail to me; we can discuss it.\r
56 NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling\r
57         quite lonely and want to meet/help out/exchange code with other demo\r
58         groups. What do you have to lose? Leave a message here and we can work\r
59         out how to transfer it. We really want to hear from you!\r
60 \r
61 \r
62 \r
63 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
64 þ  The Principals of Animation\r
65 \r
66 I am sure all of you have seen a computer game with animation at one or\r
67 other time. There are a few things that an animation sequence must do in\r
68 order to give an impression of realism. Firstly, it must move,\r
69 preferably using different frames to add to the realism (for example,\r
70 with a man walking you should have different frames with the arms an\r
71 legs in different positions). Secondly, it must not destroy the\r
72 background, but restore it after it has passed over it.\r
73 \r
74 This sounds obvious enough, but can be very difficult to code when you\r
75 have no idea of how to go about achieving that.\r
76 \r
77 In this trainer I will discuss various methods of meeting these two\r
78 objectives.\r
79 \r
80 \r
81 \r
82 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
83 þ  Frames and Object Control\r
84 \r
85 It is quite obvious that for most animation to succeed, you must have\r
86 numerous frames of the object in various poses (such as a man with\r
87 several frames of him walking). When shown one after the other, these\r
88 give the impression of natural movement.\r
89 \r
90 So, how do we store these frames? I hear you cry. Well, the obvious\r
91 method is to store them in arrays. After drawing a frame in Autodesk\r
92 Animator and saving it as a .CEL, we usually use the following code to\r
93 load it in :\r
94 \r
95 TYPE icon = Array [1..50,1..50] of byte;\r
96 \r
97 VAR tree : icon;\r
98 \r
99 Procedure LoadCEL (FileName :  string; ScrPtr : pointer);\r
100 var\r
101   Fil : file;\r
102   Buf : array [1..1024] of byte;\r
103   BlocksRead, Count : word;\r
104 begin\r
105   assign (Fil, FileName);\r
106   reset (Fil, 1);\r
107   BlockRead (Fil, Buf, 800);    { Read and ignore the 800 byte header }\r
108   Count := 0; BlocksRead := $FFFF;\r
109   while (not eof (Fil)) and (BlocksRead <> 0) do begin\r
110     BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024, BlocksRead);\r
111     Count := Count + 1024;\r
112   end;\r
113   close (Fil);\r
114 end;\r
115 \r
116 BEGIN\r
117   Loadcel ('Tree.CEL',addr (tree));\r
118 END.\r
119 \r
120 We now have the 50x50 picture of TREE.CEL in our array tree. We may access\r
121 this array in the usual manner (eg. col:=tree [25,30]). If the frame is\r
122 large, or if you have many frames, try using pointers (see previous\r
123 parts)\r
124 \r
125 Now that we have the picture, how do we control the object? What if we\r
126 want multiple trees wandering around doing their own thing? The solution\r
127 is to have a record of information for each tree. A typical data\r
128 structure may look like the following :\r
129 \r
130 TYPE Treeinfo = Record\r
131                   x,y:word;       { Where the tree is }\r
132                   speed:byte;     { How fast the tree is moving }\r
133                   Direction:byte; { Where the tree is facing }\r
134                   frame:byte      { Which animation frame the tree is\r
135                                     currently involved in }\r
136                   active:boolean; { Is the tree actually supposed to be\r
137                                     shown/used? }\r
138                 END;\r
139 \r
140 VAR Forest : Array [1..20] of Treeinfo;\r
141 \r
142 You now have 20 trees, each with their own information, location etc.\r
143 These are accessed using the following means :\r
144                   Forest [15].x:=100;\r
145 This would set the 15th tree's x coordinate to 100.\r
146 \r
147 \r
148 \r
149 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
150 þ  Restoring the Overwritten Background\r
151 \r
152 I will discuss three methods of doing this. These are NOT NECESSARILY\r
153 THE ONLY OR BEST WAYS TO DO THIS! You must experiment and decide which\r
154 is the best for your particular type of program.\r
155 \r
156 METHOD 1 :\r
157 \r
158 Step 1 : Create two virtual pages, Vaddr and Vaddr2.\r
159 Step 2 : Draw the background to Vaddr2.\r
160 Step 3 : Flip Vaddr2 to Vaddr.\r
161 Step 4 : Draw all the foreground objects onto Vaddr.\r
162 Step 5 : Flip Vaddr to VGA.\r
163 Step 6 : Repeat from 3 continuously.\r
164 \r
165 In ascii, it looks like follows ...\r
166 \r
167     +---------+           +---------+           +---------+\r
168     |         |           |         |           |         |\r
169     |  VGA    | <=======  |  VADDR  |  <======  |  VADDR2 |\r
170     |         |           | (bckgnd)|           | (bckgnd)|\r
171     |         |           |+(icons) |           |         |\r
172     +---------+           +---------+           +---------+\r
173 \r
174 The advantages of this approach is that it is straightforward, continual\r
175 reading of the background is not needed, there is no flicker and it is\r
176 simple to implement.  The disadvantages are that two 64000 byte virtual\r
177 screens are needed, and the procedure is not very fast because of the\r
178 slow speed of flipping.\r
179 \r
180 \r
181 METHOD 2 :\r
182 \r
183 Step 1 : Draw background to VGA.\r
184 Step 2 : Grab portion of background that icon will be placed on.\r
185 Step 3 : Place icon.\r
186 Step 4 : Replace portion of background from Step 2 over icon.\r
187 Step 5 : Repeat from step 2 continuously.\r
188 \r
189 In terms of ascii ...\r
190 \r
191       +---------+\r
192       |      +--|------- + Background restored (3)\r
193       |      * -|------> * Background saved to memory (1)\r
194       |      ^  |\r
195       |      +--|------- # Icon placed (2)\r
196       +---------+\r
197 \r
198 The advantages of this method is that very little extra memory is\r
199 needed. The disadvantages are that writing to VGA is slower then writing\r
200 to memory, and there may be large amounts of flicker.\r
201 \r
202 \r
203 METHOD 3 :\r
204 \r
205 Step 1 : Set up one virtual screen, VADDR.\r
206 Step 2 : Draw background to VADDR.\r
207 Step 3 : Flip VADDR to VGA.\r
208 Step 4 : Draw icon to VGA.\r
209 Step 5 : Transfer background portion from VADDR to VGA.\r
210 Step 6 : Repeat from step 4 continuously.\r
211 \r
212 In ascii ...\r
213 \r
214      +---------+           +---------+\r
215      |         |           |         |\r
216      |   VGA   |           |  VADDR  |\r
217      |         |           | (bckgnd)|\r
218      | Icon>* <|-----------|--+      |\r
219      +---------+           +---------+\r
220 \r
221 The advantages are that writing from the virtual screen is quicker then\r
222 from VGA, and there is less flicker then in Method 2. Disadvantages are\r
223 that you are using a 64000 byte virtual screen, and flickering occurs\r
224 with large numbers of objects.\r
225 \r
226 In the attached sample program, a mixture of Method 3 and Method 1 is\r
227 used. It is faster then Method 1, and has no flicker, unlike Method 3.\r
228 What I do is I use VADDR2 for background, but only restore the\r
229 background that has been changed to VADDR, before flipping to VGA.\r
230 \r
231 In the sample program, you will see that I restore the entire background\r
232 of each of the icons, and then place all the icons. This is because if I\r
233 replace the background then place the icon on each object individually,\r
234 if two objects are overlapping, one is partially overwritten.\r
235 \r
236 The following sections are explanations of how the various assembler\r
237 routines work. This will probably be fairly boring for you if you\r
238 already know assembler, but should help beginners and dabblers alike.\r
239 \r
240 \r
241 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
242 þ  The ASM Putpixel\r
243 \r
244 To begin with, I will explain a few of the ASM variables and functions :\r
245 \r
246 <NOTE THAT THIS IS AN EXTREMELY SIMPLISTIC VIEW OF ASSEMBLY LANGUAGE!\r
247 There are numerous books to advance your knowledge, and the Norton\r
248 Guides assembler guide  may be invaluable for people beginning to code\r
249 in assembler. I haven't given you the pretty pictures you are supposed\r
250 to have to help you understand it easier, I have merely laid it out like\r
251 a programming language with it's own special procedures. >\r
252 \r
253 There are 4 register variables : AX,BX,CX,DX. These are words (double\r
254 bytes) with a range from 0 to 65535. You may access the high and low\r
255 bytes of these by replacing the X with a "H" for high or "L" for low.\r
256 For example, AL has a range from 0-255.\r
257 \r
258 You also have two pointers : ES:DI and DS:SI. The part on the left is\r
259 the segment to which you are pointing (eg $a000), and the right hand\r
260 part is the offset, which is how far into the segment you are pointing.\r
261 Turbo Pascal places a variable over 16k into the base of a segment, ie.\r
262 DI or SI will be zero at the start of the variable.\r
263 \r
264 If you wish to be pointing to pixel number 3000 on the VGA screen (see\r
265 previous parts for the layout of the VGA screen), ES would be equal to\r
266 $a000 and DI would be equal to 3000.  You can quite as easily make ES or\r
267 DS be equal to the offset of a virtual screen.\r
268 \r
269 Here are a few functions that you will need to know :\r
270 \r
271       mov   destination,source       This moves the value in source to\r
272                                      destination. eg  mov ax,50\r
273       add   destination,source       This adds source to destination,\r
274                                      the result being stored in destination\r
275       mul   source                   This multiplies AX by source. If\r
276                                      source is a byte, the source is\r
277                                      multiplied by AL, the result being\r
278                                      stored in AX. If source is a word,\r
279                                      the source is multiplied by AX, the\r
280                                      result being stored in DX:AX\r
281       movsb                          This moves the byte that DS:SI is\r
282                                      pointing to into ES:DI, and\r
283                                      increments SI and DI.\r
284       movsw                          Same as movsb except it moves a\r
285                                      word instead of a byte.\r
286       stosw                          This moves AX into ES:DI. stosb\r
287                                      moves AL into ES:DI. DI is then\r
288                                      incremented.\r
289       push register                  This saves the value of register by\r
290                                      pushing it onto the stack. The\r
291                                      register may then be altered, but\r
292                                      will be restored to it's original\r
293                                      value when popped.\r
294       pop register                   This restores the value of a pushed\r
295                                      register. NOTE : Pushed values must\r
296                                      be popped in the SAME ORDER but\r
297                                      REVERSED.\r
298       rep  command                   This repeats Command by as many\r
299                                      times as the value in CX\r
300 \r
301 \r
302 SHL Destination,count      ;\r
303 and SHR Destination,count  ;\r
304 need a bit more explaining. As you know, computers think in ones and\r
305 zeroes. Each number may be represented in this base 2 operation. A byte\r
306 consists of 8 ones and zeroes (bits), and have a range from 0 to 255. A \r
307 word consists of 16 ones and zeroes (bits), and has a range from 0 to \r
308 65535. A double word consists of 32 bits.\r
309 \r
310 The number 53 may be represented as follows :  00110101.  Ask someone who\r
311 looks clever to explain to you how to convert from binary to decimal and\r
312 vice-versa.\r
313 \r
314 What happens if you shift everything to the left? Drop the leftmost\r
315 number and add a zero to the right? This is what happens :\r
316 \r
317                 00110101     =  53\r
318                  <-----\r
319                 01101010     =  106\r
320 \r
321 As you can see, the value has doubled! In the same way, by shifting one\r
322 to the right, you halve the value! This is a VERY quick way of\r
323 multiplying or dividing by 2. (note that for dividing by shifting, we\r
324 get the trunc of the result ... ie.  15 shr 1 = 7)\r
325 \r
326 In assembler the format is SHL destination,count    This shifts\r
327 destination by as many bits in count (1=*2, 2=*4, 3=*8, 4=*16 etc)\r
328 Note that a shift takes only 2 clock cycles, while a mul can take up to 133\r
329 clock cycles. Quite a difference, no? Only 286es or above may have count\r
330 being greater then one.\r
331 \r
332 This is why to do the following to calculate the screen coordinates for\r
333 a putpixel is very slow :\r
334 \r
335            mov    ax,[Y]\r
336            mov    bx,320\r
337            mul    bx\r
338            add    ax,[X]\r
339            mov    di,ax\r
340 \r
341 But alas! I hear you cry. 320 is not a value you may shift by, as you\r
342 may only shift by 2,4,8,16,32,64,128,256,512 etc.etc. The solution is\r
343 very cunning. Watch.\r
344 \r
345     mov     bx,[X]\r
346     mov     dx,[Y]\r
347     push    bx\r
348     mov     bx, dx                  {; bx = dx = Y}\r
349     mov     dh, dl                  {; dh = dl = Y}\r
350     xor     dl, dl                  {; These 2 lines equal dx*256 }\r
351     shl     bx, 1\r
352     shl     bx, 1\r
353     shl     bx, 1\r
354     shl     bx, 1\r
355     shl     bx, 1\r
356     shl     bx, 1                   {; bx = bx * 64}\r
357     add     dx, bx                  {; dx = dx + bx (ie y*320)}\r
358     pop     bx                      {; get back our x}\r
359     add     bx, dx                  {; finalise location}\r
360     mov     di, bx\r
361 \r
362 Let us have a look at this a bit closer shall we?\r
363 bx=dx=y        dx=dx*256  ;   bx=bx*64     ( Note, 256+64 = 320 )\r
364 \r
365 dx+bx=Correct y value, just add X!\r
366 \r
367 As you can see, in assembler, the shortest code is often not the\r
368 fastest.\r
369 \r
370 The complete putpixel procedure is as follows :\r
371 \r
372 Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);\r
373   { This puts a pixel on the screen by writing directly to memory. }\r
374 BEGIN\r
375   Asm\r
376     push    ds                      {; Make sure these two go out the }\r
377     push    es                      {; same they went in }\r
378     mov     ax,[where]\r
379     mov     es,ax                   {; Point to segment of screen }\r
380     mov     bx,[X]\r
381     mov     dx,[Y]\r
382     push    bx                      {; and this again for later}\r
383     mov     bx, dx                  {; bx = dx}\r
384     mov     dh, dl                  {; dx = dx * 256}\r
385     xor     dl, dl\r
386     shl     bx, 1\r
387     shl     bx, 1\r
388     shl     bx, 1\r
389     shl     bx, 1\r
390     shl     bx, 1\r
391     shl     bx, 1                   {; bx = bx * 64}\r
392     add     dx, bx                  {; dx = dx + bx (ie y*320)}\r
393     pop     bx                      {; get back our x}\r
394     add     bx, dx                  {; finalise location}\r
395     mov     di, bx                  {; di = offset }\r
396     {; es:di = where to go}\r
397     xor     al,al\r
398     mov     ah, [Col]\r
399     mov     es:[di],ah              {; move the value in ah to screen\r
400                                        point es:[di] }\r
401     pop     es\r
402     pop     ds\r
403   End;\r
404 END;\r
405 \r
406 Note that with DI and SI, when you use them :\r
407       mov   di,50      Moves di to position 50\r
408       mov   [di],50    Moves 50 into the place di is pointing to\r
409 \r
410 \r
411 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
412 þ  The Flip Procedure\r
413 \r
414 This is fairly straightforward. We get ES:DI to point to the start of\r
415 the destination screen, and DS:SI to point to the start of the source\r
416 screen, then do 32000 movsw (64000 bytes).\r
417 \r
418 procedure flip(source,dest:Word);\r
419   { This copies the entire screen at "source" to destination }\r
420 begin\r
421   asm\r
422     push    ds\r
423     mov     ax, [Dest]\r
424     mov     es, ax                  { ES = Segment of source }\r
425     mov     ax, [Source]\r
426     mov     ds, ax                  { DS = Segment of source }\r
427     xor     si, si                  { SI = 0   Faster then mov si,0 }\r
428     xor     di, di                  { DI = 0 }\r
429     mov     cx, 32000\r
430     rep     movsw                   { Repeat movsw 32000 times }\r
431     pop     ds\r
432   end;\r
433 end;\r
434 \r
435 The cls procedure works in much the same way, only it moves the color\r
436 into AX then uses a rep stosw (see program for details)\r
437 \r
438 The PAL command is almost exactly the same as it's Pascal equivalent\r
439 (see previous tutorials). Look in the sample code to see how it uses the\r
440 out and in commands.\r
441 \r
442 \r
443 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\r
444 þ  In Closing\r
445 \r
446 The assembler procedures presented to you in here are not at their best.\r
447 Most of these are procedures ASPHYXIA abandoned for better ones after\r
448 months of use. But, as you will soon see, they are all MUCH faster then\r
449 the original Pascal equivalents I originally gave you. In future, I\r
450 hope to give you more and more assembler procedures for your ever\r
451 growing collections. But, as you know, I am not always very prompt with\r
452 this series (I don't know if even one has been released within one week\r
453 of the previous one), so if you want to get any stuff done, try do it\r
454 yourself. What do you have to lose, aside from your temper and a few\r
455 rather inventive reboots ;-)\r
456 \r
457 What should I do for the next trainer? A simple 3-d tutorial? You may\r
458 not like it, because I would go into minute detail of how it works :)\r
459 Leave me suggestions for future trainers by any of the means discussed\r
460 at the top of this trainer.\r
461 \r
462 After the customary quote, I will place a listing of the BBSes I\r
463 currently know that regularly carry this Trainer Series. If your BBS\r
464 receives it regularly, no matter where in the country you are, get a\r
465 message to me and I'll add it to the list. Let's make it more convenient\r
466 for locals to grab a copy without calling long distance ;-)\r
467 \r
468             [  There they sit, the preschooler class encircling their\r
469                   mentor, the substitute teacher.\r
470                "Now class, today we will talk about what you want to be\r
471                   when you grow up. Isn't that fun?" The teacher looks\r
472                   around and spots the child, silent, apart from the others\r
473                   and deep in thought. "Jonny, why don't you start?" she\r
474                   encourages him.\r
475                Jonny looks around, confused, his train of thought\r
476                   disrupted. He collects himself, and stares at the teacher\r
477                   with a steady eye. "I want to code demos," he says,\r
478                   his words becoming stronger and more confidant as he\r
479                   speaks. "I want to write something that will change\r
480                   peoples perception of reality. I want them to walk\r
481                   away from the computer dazed, unsure of their footing\r
482                   and eyesight. I want to write something that will\r
483                   reach out of the screen and grab them, making\r
484                   heartbeats and breathing slow to almost a halt. I want\r
485                   to write something that, when it is finished, they\r
486                   are reluctant to leave, knowing that nothing they\r
487                   experience that day will be quite as real, as\r
488                   insightful, as good. I want to write demos."\r
489                Silence. The class and the teacher stare at Jonny, stunned. It\r
490                   is the teachers turn to be confused. Jonny blushes,\r
491                   feeling that something more is required.  "Either that\r
492                   or I want to be a fireman."\r
493                                                                      ]\r
494                                                        - Grant Smith\r
495                                                             14:32\r
496                                                                21/11/93\r
497 \r
498 See you next time,\r
499   - DENTHOR\r
500 \r
501 These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical)\r
502 \r
503 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍËÍÍÍËÍÍÍÍËÍÍÍÍ»\r
504 ºBBS Name                  ºTelephone No.   ºOpen ºMsgºFileºPastº\r
505 ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÎÍÍÍÎÍÍÍÍÎÍÍÍ͹\r
506 ºASPHYXIA BBS #1           º(031) 765-5312  ºALL  º * º *  º *  º\r
507 ºASPHYXIA BBS #2           º(031) 765-6293  ºALL  º * º *  º *  º\r
508 ºConnectix BBS             º(031) 266-9992  ºALL  º * º *  º *  º\r
509 ºFor Your Eyes Only BBS    º(031) 285-318   ºA/H  º * º *  º *  º\r
510 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÊÍÍÍÊÍÍÍÍÊÍÍÍͼ\r
511 \r
512 Open = Open at all times or only A/H\r
513 Msg  = Available in message base\r
514 File = Available in file base\r
515 Past = Previous Parts available\r
516 \r
517 \r
518 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\r
519 ³ TUTPROG7.PAS ³\r
520 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
521 \r
522 {$X+}\r
523 USES crt;\r
524 \r
525 CONST VGA = $a000;\r
526 \r
527 Type Toastinfo = Record                 { This is format of of each of our }\r
528                  x,y:integer;              { records for the flying toasters }\r
529                  speed,frame:integer;\r
530                  active:boolean;\r
531                END;\r
532 \r
533      icon = Array [1..30*48] of byte;  { This is the size of our pictures }\r
534 \r
535      Virtual = Array [1..64000] of byte;  { The size of our Virtual Screen }\r
536      VirtPtr = ^Virtual;                  { Pointer to the virtual screen }\r
537 \r
538 CONST frame1 : icon = (\r
539 0,0,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,\r
540 7,7,7,7,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,\r
541 5,7,7,7,7,7,7,7,8,8,7,7,7,7,7,7,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,\r
542 0,0,0,0,0,5,5,7,7,7,7,7,8,8,7,8,8,7,8,7,8,7,7,7,5,8,8,8,8,5,5,5,5,5,5,5,5,5,5,5,\r
543 5,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,8,7,7,7,8,7,7,7,7,7,7,0,0,0,0,0,0,8,5,5,5,\r
544 5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,5,7,7,8,8,7,7,8,7,7,8,7,7,7,7,7,0,0,0,0,0,\r
545 0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,5,7,8,8,8,7,7,8,7,7,8,7,7,7,\r
546 7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,5,7,8,8,8,7,7,\r
547 8,8,8,8,8,8,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,\r
548 9,5,7,8,8,8,8,8,7,7,8,8,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,\r
549 1,1,1,1,9,9,9,9,5,7,7,8,8,8,8,7,7,8,8,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,\r
550 1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,5,7,8,8,7,7,8,8,7,8,8,8,7,0,0,0,0,0,0,0,0,0,0,0,0,\r
551 0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,5,7,8,8,7,7,7,7,8,8,7,7,7,0,0,0,0,\r
552 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,7,8,8,8,8,8,8,8,7,\r
553 7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,7,\r
554 7,7,7,7,7,7,7,7,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,\r
555 1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,\r
556 1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
557 0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,\r
558 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,\r
559 2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,\r
560 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,\r
561 1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,\r
562 4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
563 0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,\r
564 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,\r
565 9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,\r
566 9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,\r
567 1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
568 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
569 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
570 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
571 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
572 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
573 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
574 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
575 );\r
576       frame2 : icon = (\r
577 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
578 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
579 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
580 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
581 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
582 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
583 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
584 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
585 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,\r
586 9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,\r
587 1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,\r
588 1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,\r
589 0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,\r
590 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,\r
591 2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,5,\r
592 5,5,5,5,5,5,5,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,\r
593 1,1,1,2,2,2,2,2,5,5,5,5,5,5,5,5,5,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,\r
594 1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
595 0,0,0,0,0,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,\r
596 0,0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,5,5,5,5,\r
597 5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,\r
598 2,2,2,2,2,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,1,1,1,1,1,0,0,0,1,1,1,\r
599 1,1,1,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,7,1,4,\r
600 4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,\r
601 0,0,0,5,5,1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5,5,5,5,0,0,\r
602 0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,5,5,\r
603 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,\r
604 9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,\r
605 1,1,1,1,9,9,9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,\r
606 1,7,7,1,7,1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,\r
607 0,0,0,0,0,0,0,5,5,1,7,7,7,1,1,5,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,0,\r
608 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,5,5,5,5,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,\r
609 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,\r
610 0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
611 0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
612 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
613 );\r
614       frame3 : icon = (\r
615 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
616 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
617 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
618 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
619 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
620 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
621 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
622 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
623 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,\r
624 9,9,9,9,9,9,9,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,1,1,1,1,1,1,1,1,1,1,1,\r
625 1,1,1,1,9,9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,7,1,1,1,1,1,\r
626 1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,\r
627 0,7,1,1,7,7,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,1,7,7,7,7,5,5,5,5,5,5,\r
628 5,0,0,0,0,0,0,0,7,1,7,7,7,1,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,5,5,1,1,1,7,7,\r
629 1,1,7,5,5,5,5,5,5,5,0,0,0,0,0,0,1,1,7,1,1,7,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,\r
630 2,1,7,7,7,1,7,7,7,7,7,5,5,5,5,5,5,5,5,0,0,0,0,0,1,7,7,7,7,1,1,1,1,1,0,0,0,1,1,1,\r
631 1,1,1,2,2,2,2,2,2,1,7,7,7,7,7,7,7,1,1,5,5,5,5,5,5,5,5,5,0,0,0,0,7,7,1,7,1,7,1,1,\r
632 1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,5,5,5,5,5,5,5,5,5,5,5,0,0,0,\r
633 7,7,7,7,7,1,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,\r
634 5,5,5,5,5,0,0,0,7,7,0,0,7,7,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,\r
635 2,2,5,5,0,0,5,5,0,5,5,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,\r
636 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,\r
637 1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,\r
638 4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
639 0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,\r
640 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,\r
641 9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,\r
642 9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,\r
643 1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
644 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
645 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
646 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
647 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
648 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
649 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\r
650 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
651 );\r
652 \r
653 \r
654 VAR Virscr : VirtPtr;                      { Our first Virtual screen }\r
655     VirScr2 : VirtPtr;                     { Our second Virtual screen }\r
656     Vaddr  : word;                      { The segment of our virtual screen}\r
657     Vaddr2 : Word;                      { The segment of our 2nd virt. screen}\r
658     ourpal : Array [0..255,1..3] of byte; { A virtual pallette }\r
659     toaster : Array [1..10] of toastinfo; { The toaster info }\r
660 \r
661 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
662 Procedure SetMCGA;  { This procedure gets you into 320x200x256 mode. }\r
663 BEGIN\r
664   asm\r
665      mov        ax,0013h\r
666      int        10h\r
667   end;\r
668 END;\r
669 \r
670 \r
671 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
672 Procedure SetText;  { This procedure returns you to text mode.  }\r
673 BEGIN\r
674   asm\r
675      mov        ax,0003h\r
676      int        10h\r
677   end;\r
678 END;\r
679 \r
680 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
681 Procedure Cls (Col : Byte; Where:word);\r
682    { This clears the screen to the specified color }\r
683 BEGIN\r
684      asm\r
685         push    es\r
686         mov     cx, 32000;\r
687         mov     es,[where]\r
688         xor     di,di\r
689         mov     al,[col]\r
690         mov     ah,al\r
691         rep     stosw\r
692         pop     es\r
693      End;\r
694 END;\r
695 \r
696 \r
697 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
698 Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);\r
699   { This puts a pixel on the screen by writing directly to memory. }\r
700 BEGIN\r
701   Asm\r
702     push    ds\r
703     push    es\r
704     mov     ax,[where]\r
705     mov     es,ax\r
706     mov     bx,[X]\r
707     mov     dx,[Y]\r
708     push    bx                      {; and this again for later}\r
709     mov     bx, dx                  {; bx = dx}\r
710     mov     dh, dl                  {; dx = dx * 256}\r
711     xor     dl, dl\r
712     shl     bx, 1\r
713     shl     bx, 1\r
714     shl     bx, 1\r
715     shl     bx, 1\r
716     shl     bx, 1\r
717     shl     bx, 1                   {; bx = bx * 64}\r
718     add     dx, bx                  {; dx = dx + bx (ie y*320)}\r
719     pop     bx                      {; get back our x}\r
720     add     bx, dx                  {; finalise location}\r
721     mov     di, bx\r
722     {; es:di = where to go}\r
723     xor     al,al\r
724     mov     ah, [Col]\r
725     mov     es:[di],ah\r
726     pop     es\r
727     pop     ds\r
728   End;\r
729 END;\r
730 \r
731 \r
732 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
733 procedure WaitRetrace; assembler;\r
734   {  This waits for a vertical retrace to reduce snow on the screen }\r
735 label\r
736   l1, l2;\r
737 asm\r
738     mov dx,3DAh\r
739 l1:\r
740     in al,dx\r
741     and al,08h\r
742     jnz l1\r
743 l2:\r
744     in al,dx\r
745     and al,08h\r
746     jz  l2\r
747 end;\r
748 \r
749 \r
750 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
751 Procedure Pal(Col,R,G,B : Byte);\r
752   { This sets the Red, Green and Blue values of a certain color }\r
753 Begin\r
754    asm\r
755       mov    dx,3c8h\r
756       mov    al,[col]\r
757       out    dx,al\r
758       inc    dx\r
759       mov    al,[r]\r
760       out    dx,al\r
761       mov    al,[g]\r
762       out    dx,al\r
763       mov    al,[b]\r
764       out    dx,al\r
765    end;\r
766 End;\r
767 \r
768 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
769 Procedure GetPal(Col : Byte; Var R,G,B : Byte);\r
770   { This gets the Red, Green and Blue values of a certain color }\r
771 Var\r
772    rr,gg,bb : Byte;\r
773 Begin\r
774    asm\r
775       mov    dx,3c7h\r
776       mov    al,col\r
777       out    dx,al\r
778 \r
779       add    dx,2\r
780 \r
781       in     al,dx\r
782       mov    [rr],al\r
783       in     al,dx\r
784       mov    [gg],al\r
785       in     al,dx\r
786       mov    [bb],al\r
787    end;\r
788    r := rr;\r
789    g := gg;\r
790    b := bb;\r
791 end;\r
792 \r
793 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
794 Procedure SetUpVirtual;\r
795    { This sets up the memory needed for the virtual screen }\r
796 BEGIN\r
797   GetMem (VirScr,64000);\r
798   vaddr := seg (virscr^);\r
799   GetMem (VirScr2,64000);\r
800   vaddr2 := seg (virscr2^);\r
801 END;\r
802 \r
803 \r
804 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
805 Procedure ShutDown;\r
806    { This frees the memory used by the virtual screen }\r
807 BEGIN\r
808   FreeMem (VirScr,64000);\r
809   FreeMem (VirScr2,64000);\r
810 END;\r
811 \r
812 \r
813 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
814 procedure flip(source,dest:Word);\r
815   { This copies the entire screen at "source" to destination }\r
816 begin\r
817   asm\r
818     push    ds\r
819     mov     ax, [Dest]\r
820     mov     es, ax\r
821     mov     ax, [Source]\r
822     mov     ds, ax\r
823     xor     si, si\r
824     xor     di, di\r
825     mov     cx, 32000\r
826     rep     movsw\r
827     pop     ds\r
828   end;\r
829 end;\r
830 \r
831 \r
832 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
833 Procedure putico(X,Y:Word;VAR sprt : icon;Where:Word); ASSEMBLER;\r
834   { This puts an icon, EXCEPT it's color 0 (black) pixels, onto the screen\r
835     "where", at position X,Y }\r
836 label\r
837   _Redraw, _DrawLoop, _Exit, _LineLoop, _NextLine, _Store, _NoPaint;\r
838 \r
839 asm\r
840     push  ds\r
841     push  es\r
842     lds   si,Sprt\r
843     mov   ax,X     { ax = x }\r
844     mov   bx,Y     { bx = y }\r
845 _Redraw:\r
846     push    ax\r
847     mov     ax,[where]\r
848     mov     es,ax\r
849 \r
850     mov     ax, bx                  {; ax = bx  x = y}\r
851     mov     bh, bl                  {; y = y * 256  bx = bx * 256}\r
852     xor     bl, bl\r
853     shl     ax, 1\r
854     shl     ax, 1\r
855     shl     ax, 1\r
856     shl     ax, 1\r
857     shl     ax, 1\r
858     shl     ax, 1                   {; y = y * 64   ax = ax * 64}\r
859     add     bx, ax                  {; y = (y*256) + (Y*64)  bx = bx + ax (ie y*320)}\r
860 \r
861     pop     ax                      {; get back our x}\r
862 \r
863 \r
864     add     ax, bx                  {; finalise location}\r
865     mov     di, ax\r
866 \r
867     mov   dl,30    { dl = height of sprite }\r
868     xor   ch,ch\r
869     mov   cl,48     { cx = width of sprite }\r
870     cld\r
871     push  ax\r
872     mov   ax,cx\r
873 _DrawLoop:\r
874     push  di            { store y adr. for later }\r
875     mov   cx,ax          { store width }\r
876 _LineLoop:\r
877     mov   bl,byte ptr [si]\r
878     or    bl,bl\r
879     jnz   _Store\r
880 _NoPaint:\r
881     inc    si\r
882     inc    di\r
883     loop   _LineLoop\r
884     jmp    _NextLine\r
885 _Store:\r
886     movsb\r
887     loop  _LineLoop\r
888 _NextLine:\r
889     pop   di\r
890     dec   dl\r
891     jz    _Exit\r
892     add   di,320        { di = next line of sprite }\r
893     jmp   _DrawLoop\r
894 _Exit:\r
895     pop   ax\r
896     pop   es\r
897     pop   ds\r
898 end;\r
899 \r
900 \r
901 \r
902 \r
903 \r
904 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
905 Procedure Funny_line(a,b,c,d:integer;where:word);\r
906   { This procedure draws a line from a,b to c,d on screen "where". After\r
907     each pixel it plots, it increments a color counter for the next pixel.\r
908     you may easily alter this to be a normal line procedure, and it will\r
909     be quite a bit faster than the origional one I gave you. This is\r
910     because I replaced all the reals with integers. }\r
911 \r
912   function sgn(a:real):integer;\r
913   begin\r
914        if a>0 then sgn:=+1;\r
915        if a<0 then sgn:=-1;\r
916        if a=0 then sgn:=0;\r
917   end;\r
918 var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer;\r
919     count:integer;\r
920 begin\r
921      count:=50;\r
922      u:= c - a;\r
923      v:= d - b;\r
924      d1x:= SGN(u);\r
925      d1y:= SGN(v);\r
926      d2x:= SGN(u);\r
927      d2y:= 0;\r
928      m:= ABS(u);\r
929      n := ABS(v);\r
930      IF NOT (M>N) then\r
931      BEGIN\r
932           d2x := 0 ;\r
933           d2y := SGN(v);\r
934           m := ABS(v);\r
935           n := ABS(u);\r
936      END;\r
937      s := m shr 1;\r
938      FOR i := 0 TO m DO\r
939      BEGIN\r
940           putpixel(a,b,count,where);\r
941           inc (count);\r
942           if count=101 then count:=50;\r
943           s := s + n;\r
944           IF not (s<m) THEN\r
945           BEGIN\r
946                s := s - m;\r
947                a:= a + d1x;\r
948                b := b + d1y;\r
949           END\r
950           ELSE\r
951           BEGIN\r
952                a := a + d2x;\r
953                b := b + d2y;\r
954           END;\r
955      end;\r
956 END;\r
957 \r
958 \r
959 \r
960 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
961 Procedure SetUpScreen;\r
962   { This procedure sets up the static background to be used in the program }\r
963 \r
964 CONST circ : Array [1..5,1..5] of byte =\r
965         ((0,10,10,10,0),\r
966          (10,13,12,11,10),\r
967          (10,12,12,11,10),\r
968          (10,11,11,11,10),\r
969          (0,10,10,10,0));\r
970 \r
971 VAR x,y:integer;\r
972     loop1,loop2,loop3:integer;\r
973 \r
974 BEGIN\r
975   pal (1,22,22,22);\r
976   pal (2,45,45,45);\r
977   pal (3,59,59,59);\r
978   pal (4,63,63,27);\r
979   pal (5,39,63,3);\r
980   pal (6,51,39,3);\r
981   pal (7,3,27,3);\r
982   pal (8,15,39,15);\r
983   pal (9,35,35,35);\r
984   pal (10, 0, 0,40);\r
985   pal (11,10,10,50);\r
986   pal (12,20,20,60);\r
987   pal (13,30,30,63);\r
988 \r
989   For loop1:=50 to 100 do\r
990     pal (loop1,0,0,loop1-36);\r
991 \r
992   For loop1:=0 to 255 do\r
993      getpal (loop1,OurPal[loop1,1],OurPal[loop1,2],OurPal[loop1,3]);\r
994 \r
995   For loop1:=0 to 319 do\r
996     Funny_line (0,199,loop1,0,vaddr);\r
997   For loop1:=0 to 199 do\r
998     Funny_line (0,199,319,loop1,vaddr);\r
999 \r
1000   For loop1:=1 to 200 do BEGIN\r
1001     x:=random (315);\r
1002     y:=random (195);\r
1003     For loop2:=1 to 5 do\r
1004       For loop3:=1 to 5 do\r
1005         if circ [loop2,loop3]<>0 then\r
1006           putpixel (x+loop2,y+loop3,circ [loop2,loop3],vaddr);\r
1007   END;\r
1008   flip (vaddr,vga);  { Copy the entire screen at vaddr, our virtual screen }\r
1009                      { on which we have done all our graphics, onto the    }\r
1010                      { screen you see, VGA }\r
1011   flip (vaddr,vaddr2);\r
1012 END;\r
1013 \r
1014 \r
1015 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
1016 Procedure rotatepal;\r
1017   { This procedure rotates the colors between 50 and 100 }\r
1018 VAR temp : Array [1..3] of byte;\r
1019     loop1:integer;\r
1020 BEGIN\r
1021   Move(OurPal[100],Temp,3);\r
1022   Move(OurPal[50],OurPal[51],50*3);\r
1023   Move(Temp,OurPal[50],3);\r
1024   For loop1:=50 to 100 do\r
1025     pal (loop1,OurPal[loop1,1],OurPal[loop1,2],OurPal[loop1,3]);\r
1026 END;\r
1027 \r
1028 \r
1029 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
1030 Procedure ScreenTrans (x,y:word);\r
1031   { This is a small procedure to copy a 30x30 pixel block from coordinates\r
1032     x,y on the virtual screen to coordinates x,y on the true vga screen }\r
1033 BEGIN\r
1034   asm\r
1035     push    ds\r
1036     push    es\r
1037     mov     ax,vaddr\r
1038     mov     es,ax\r
1039     mov     ax,vaddr2\r
1040     mov     ds,ax\r
1041     mov     bx,[X]\r
1042     mov     dx,[Y]\r
1043     push    bx                      {; and this again for later}\r
1044     mov     bx, dx                  {; bx = dx}\r
1045     mov     dh, dl                  {; dx = dx * 256}\r
1046     xor     dl, dl\r
1047     shl     bx, 1\r
1048     shl     bx, 1\r
1049     shl     bx, 1\r
1050     shl     bx, 1\r
1051     shl     bx, 1\r
1052     shl     bx, 1                   {; bx = bx * 64}\r
1053     add     dx, bx                  {; dx = dx + bx (ie y*320)}\r
1054     pop     bx                      {; get back our x}\r
1055     add     bx, dx                  {; finalise location}\r
1056     mov     di, bx                  {; es:di = where to go}\r
1057     mov     si, di\r
1058     mov     al,60\r
1059     mov     bx, 30         { Hight of block to copy }\r
1060 @@1 :\r
1061     mov     cx, 24         { Width of block to copy divided by 2 }\r
1062     rep     movsw\r
1063     add     di,110h        { 320 - 48 = 272 .. or 110 in hex }\r
1064     add     si,110h\r
1065     dec     bx\r
1066     jnz     @@1\r
1067 \r
1068     pop     es\r
1069     pop     ds\r
1070   end;\r
1071   { I wrote this procedure late last night, so it may not be in it's\r
1072     most optimised state. Sorry :-)}\r
1073 END;\r
1074 \r
1075 \r
1076 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
1077 Procedure NewToaster;\r
1078   { This adds a new toaster to the screen }\r
1079 VAR loop1:integer;\r
1080 BEGIN\r
1081   loop1:=0;\r
1082   repeat\r
1083     inc (loop1);\r
1084     if not (toaster[loop1].active) then BEGIN\r
1085       toaster[loop1].x:=random (200)+70;\r
1086       toaster[loop1].y:=0;\r
1087       toaster[loop1].active:=true;\r
1088       toaster[loop1].frame:=1;\r
1089       toaster[loop1].speed:=Random (3)+1;\r
1090       loop1:=10;\r
1091     END;\r
1092   until loop1=10;\r
1093 END;\r
1094 \r
1095 \r
1096 {ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}\r
1097 Procedure Fly;\r
1098   { This is the procedure where we move and put the toasters }\r
1099 VAR loop1,loop2:integer;\r
1100     ch:char;\r
1101 BEGIN\r
1102   For loop1:=1 to 10 do\r
1103     toaster[loop1].active:=FALSE;\r
1104   ch:=#0;\r
1105   NewToaster;\r
1106   Repeat\r
1107     if keypressed then BEGIN\r
1108       ch:=readkey;\r
1109       if ch='+' then NewToaster;      { If '+' is pressed, add a toaster }\r
1110       if ch='-' then BEGIN            { if '-' is pressed, remove a toaster }\r
1111         loop1:=0;\r
1112         repeat\r
1113           inc (loop1);\r
1114           if toaster[loop1].active then BEGIN\r
1115             screentrans (toaster[loop1].x,toaster[loop1].y);\r
1116             toaster [loop1].active:=FALSE;\r
1117             loop1:=10;\r
1118           END;\r
1119         until loop1=10;\r
1120       END;\r
1121     END;\r
1122     for loop1:=1 to 10 do\r
1123       if toaster[loop1].active then BEGIN\r
1124         screentrans (toaster[loop1].x,toaster[loop1].y);\r
1125           { Restore the backgrond the toaster was over }\r
1126         dec (toaster[loop1].x,toaster[loop1].speed);\r
1127         inc (toaster[loop1].y,toaster[loop1].speed);\r
1128           { Move the toaster }\r
1129         if (toaster[loop1].x<1) or (toaster[loop1].y>170) then BEGIN\r
1130           toaster[loop1].active:=FALSE;\r
1131           NewToaster;\r
1132         END;\r
1133           { When toaster reaches the edge of the screen, render it inactive\r
1134             and bring a new one into existance. }\r
1135       END;\r
1136     for loop1:=1 to 10 do\r
1137       if toaster[loop1].active then BEGIN\r
1138         CASE toaster [loop1].frame of\r
1139            1   : putico (toaster[loop1].x,toaster[loop1].y,frame1,vaddr);\r
1140            3   : putico (toaster[loop1].x,toaster[loop1].y,frame2,vaddr);\r
1141            2,4 : putico (toaster[loop1].x,toaster[loop1].y,frame3,vaddr);\r
1142         END;\r
1143         toaster[loop1].frame:=toaster[loop1].frame+1;\r
1144         if toaster [loop1].frame=5 then toaster[loop1].frame:=1;\r
1145           { Draw all the toasters on the VGA screen }\r
1146       END;\r
1147     waitretrace;\r
1148     flip (vaddr,vga);\r
1149     rotatepal;\r
1150   Until ch=#27;\r
1151 END;\r
1152 \r
1153 \r
1154 BEGIN\r
1155   Randomize;       { Make sure that the RANDOM funcion really is random }\r
1156   SetupVirtual;    { Set up virtual page, VADDR }\r
1157   ClrScr;\r
1158   writeln ('Hello! This program will demonstrate the principals of animation.');\r
1159   writeln ('The program will firstly generate an arb background screen to a');\r
1160   writeln ('virtual page, then flip it to the VGA. A toaster will then start');\r
1161   writeln ('to move across the screen. Note that the background will be restored');\r
1162   writeln ('after the toaster has passed over it. You may add or remove toasters');\r
1163   writeln ('by hitting "+" or "-" respectively. Note that the more frames you');\r
1164   writeln ('use, usually the better the routine looks. Because of space');\r
1165   writeln ('restrictions, we only had room for three frames.');\r
1166   writeln;\r
1167   writeln ('The toasters were drawn by Fubar (Pieter Buys) in Autodesk Animator.');\r
1168   writeln ('I wrote a small little program to convert them into CONSTANTS. See');\r
1169   writeln ('the main text to find out how to load up AA CEL files directly.');\r
1170   writeln;\r
1171   writeln;\r
1172   Write ('  Hit any key to contine ...');\r
1173   Readkey;\r
1174   SetMCGA;\r
1175   SetupScreen;     { Draw the background screen to VADDR, then flip it to\r
1176                      the VGA screen }\r
1177   Fly;             { Make the toasters fly around the screen }\r
1178   SetText;\r
1179   ShutDown;        { Free the memory taken up by virtual page }\r
1180   Writeln ('All done. This concludes the seventh sample program in the ASPHYXIA');\r
1181   Writeln ('Training series. You may reach DENTHOR under the names of GRANT');\r
1182   Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid');\r
1183   Writeln ('Connectix BBS user, which is unfortunatly offline for the moment.');\r
1184   Writeln ('For discussion purposes, I am also the moderator of the Programming');\r
1185   Writeln ('newsgroup on the For Your Eyes Only BBS.');\r
1186   Writeln ('The numbers are available in the main text. You may also write to me at:');\r
1187   Writeln ('             Grant Smith');\r
1188   Writeln ('             P.O. Box 270');\r
1189   Writeln ('             Kloof');\r
1190   Writeln ('             3640');\r
1191   Writeln ('I hope to hear from you soon!');\r
1192   Writeln; Writeln;\r
1193   Write   ('Hit any key to exit ...');\r
1194   Readkey;\r
1195 END.\r