Asm and Fire Code

                    嬪様様様様様様様様様様様様様様様
                             W E L C O M E         
                      To the VGA Trainer Program    
                                  By                
                          DENTHOR of ASPHYXIA        
                    塒様様様様様様様様様様様様様様様  
                      陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳 
                        陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳

                            --==[ PART 19 ]==--

 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  Introduction

 Hi there. As promised in Tut 18, this trainer is on assembler. For those
 people who already know assembler quite well, this tut is also on the flame
 effect.

 Okay, here is the total list of ways to get my trainers :

 http://goth.vironix.co.za/~denthor                     (WWW)
 ftp.eng.ufl.edu pub/msdos/demos/code/graph/tutor       (FTP)
 denthor@beastie.cs.und.ac.za  Subject : request-list   (EMAIL)

 As well as the BBS numbers shown at the end ... I will add a few ftp sits
 to that list (x2ftp.oulu.fi etc.)

 Tut 20? How about 3d shading, hidden surface removal etc? Mail me :)

 If you would like to contact me, or the team, there are many ways you
 can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
                   on the ASPHYXIA BBS.
             2) Write to :  Grant Smith
                            P.O.Box 270 Kloof
                            3640
                            Natal
                            South Africa
             3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
                   call during varsity). Call +27-31-73-2129 if you call
                   from outside South Africa. (It's YOUR phone bill ;-))
             4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
             5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
                us at once.

 NB : If you are a representative of a company or BBS, and want ASPHYXIA
        to do you a demo, leave mail to me; we can discuss it.
 NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
         quite lonely and want to meet/help out/exchange code with other demo
         groups. What do you have to lose? Leave a message here and we can work
         out how to transfer it. We really want to hear from you!

 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
   Assembler - the short version

 Okay, there are many assembler trainers out there, many of which are
 probably better then this one. I will focus on the areas of assembler that
 I find important ... if you want more, go buy a book (go for the Michael
 Abrash ones), or scour the 'net for others.

 First, let us start off with the basic set up of an assembler program.

 DOSSEG

 This tells your assembler program to order your segments in the same manner
 that high level languages do.

 .MODEL

  can be : Tiny       Code + Data < 64k   (Can be made a COM file)
                  Small      Code < 64k          Data < 64k
                  Medium     Code > 64k          Data < 64k
                  Compact    Code < 64k          Data > 64k
                  Large      Code > 64k          Data > 64k
                  Huge       Arrays > 64k

 .286

 Enable 286 instructions ... can be .386 ; .386P etc.

 .STACK

  will be the size of your stack. I usually use 200h

 .DATA

 Tells the program that the data is about to follow. (Everything after this
 will be placed in the data segment)

 .CODE

 Tells the program that the code is about to follow. (Everything after this
 will be placed in the code segment)

 START :

 Tells the program that this is where the code begins.

 END START

 Tells the program that this is where the code ends.

 To compile and run an assembler file, we run
 tasm bob
 tlink bob

 I personally use tasm, you will have to find out how your assembler works.

 Now, if we ran the above file as follows :

 DOSSEG
 .MODEL SMALL
 .286
 .STACK 200h
 .DATA
 .CODE

 START
 END START

 You would think that is would just exit to dos immediately, right? Wrong.
 You have to specifically give dos back control, by doing the following :

 START
         mov     ax,4c00h
         int     21h
 END START

 Now if you compiled it, it would run and do nothing.

 Okay, let us kick off with registers.

 Firstly : A bit is a value that is either 1 or 0

 This is obviously quite limited, but if we start counting in them, we can
 get larger numbers. Counting with ones and zeros is known as binary, and we
 call it base 2. Counting in normal decimal is known as base 10, and
 counting in hexidecimal is known as base 16.

     Base 2 (Binary)     Base 10 (Decimal)    Base 16 (Hexidecimal)
          0                      0                       0
          1                      1                       1
          10                     2                       2
          11                     3                       3
          100                    4                       4
          101                    5                       5
          110                    6                       6
          111                    7                       7
          1000                   8                       8
          1001                   9                       9
          1010                   10                      A
          1011                   11                      B
          1100                   12                      C
          1101                   13                      D
          1110                   14                      E
          1111                   15                      F

 As you can see, you need four bits to count up to 15, and we call this a
 nibble. With eight bits, we can count up to 255, and we call this a byte.
 With sixteen bits, we can count up to 65535, and we call this a word. With
 thirty two bits, we can count up to lots, and we call this a double word. :)

 A quick note : Converting from binary to hex is actually quite easy. You
 break up the binary into groups of four bits, starting on the right, and
 convers these groups of four to hex.

       1010 0010 1111 0001
   =      A    2    F    1

 Converting to decimal is a bit more difficult. What you do, is you multiply
 each number by it's base to the power of it's index ...

   A2F1 hex
 = (A*16^3) + (2*16^2) + (F*16^1) + (1*16^0)
 = (10*4096) + (2*256) + (15*16) + (1)
 = 40960 + 512 + 240 + 1
 = 41713 decimal

 The same system can be used for binary.

 To convert from decimal to another base, you divide the decimal value by the
 desired base, keeping a note of the remainders, and then reading the results
 backwards.

                16   |   41713
                16   |   2607    r   1       (41713 / 16 = 2607 r 1)
                16   |   162     r   F       (2607 / 16 = 162 r 15)
                16   |   10      r   2       (162 / 16 = 10 r 2)
                     |   0       r   A       (10 / 16 = 0 r 10)

 Read the remainders bacckwards, our number is : A2F1 hex. Again, the same
 method can be used for binary.

 The reason why hex is popular is obvious ... using bits, it is impossible
 to get a reasonable base 10 (decimal) system going, and binary get's unwieldly
 at high values. Don't worry too much though : most assemblers (like Tasm)
 will convert all your decimal values to hex for you.

 You have four general purpose registers : AX, BX, CX and DX
 Think of them as variables that you will always have. On a 286, these
 registers are 16 bytes long, or one word.

 As you know, a word consists of two bytes, and in assembler you can access
 these bytes individualy. They are separated into high bytes and low bytes per
 word.

    High Byte |  Low Byte
    0000 0000 | 0000 0000  bits
    [--------Word-------]

 The method of access is easy. The high byte of AX is AH, and the low byte is
 AL ... you can also access BH, BL, CH, CL, DH and DL.

 A 386 has extended registers : EAX, EBX, ECX, EDX ... you can access the
 lower word normally (as AX, with bytes AH and AL), but you cannot access the
 high word directly ... you must ror EAX,16 (rotate the binary value through
 16 bits), after which the high word and low word swap ... do it again to
 return them. Acessing EAX as a whole is no problem ... mov eax,10 ;
 add eax,ebx ... these are all vaild.

 Next come segments. As you have probably heard, computer memory is divided
 into various 64k segments (note : 64k = 65536 bytes, sound familiar?) A
 segment register points to which segment you are looking at. An offset
 register points to how far into that segment you are looking. One way
 of looking at it is like looking at a 2d array ... the segments are your
 columns and your offsets are your rows. Segments and offsets are displayed
 as Segment:Offset ... so $a000:50 would mean the fiftieth byte in segment
 $a000.

 The segment registers are ES, DS, SS and CS. A 386 also has FS an GS.
 These values are words (0-65535), and you cannot access the high or low bytes
 separately. CS points to you your code segment, and usually if you touch this
 your program will explode. SS points to your stack segment, again, this
 baby is dangerous. DS points to your data segment, and can be altered, if
 you put it back after you use it, and don't use any global variables while
 it is altered. ES is your extra segment, and you can do what you want with
 it.

 The offset registers are DI, SI, IP, SP, BP. Offset registers are generally
 asscociated with specific segment registers, as follows :
 ES:DI  DS:SI  CS:IP  SS:SP ... On a 286, BX can be used instead of the above
 offset registers, and on a 386, any register may be used. DS:BX is therefore
 valid.

 If you create a global variable (let's say bob), when you access that
 variable, the compiler will actually look for it in the data segment.
 This means that the statement :

 ax = bob
 could be
 ax = ds:[15]

 A quick note : A value may be signed or unsigned. An unsigned word has a
 range from 0 to 65535. A signed word is called an integer and has a range
 -32768 to 32767. With a signed value, if the leftmost bit is equal to 1,
 the value is in the negative.

 Next, let us have a look at the stack. Let us say that you want to save the
 value in ax, use ax to do other things, then restore it to it's origional
 value afterwards. This is done by utilising the stack. Have a look at the
 following code :

 mov   ax, 50      ; ax is equal to 50
 push  ax          ; push ax onto the stack
 mov   ax, 27      ; ax is equal to 27
 pop   ax          ; pop ax off the stack
 At this point, ax is equal to 50.

 Remember we defined the stack to be 200h further up? This is part of the
 reason we have it. When you push a value onto the stack, that value is
 recorded on the stack heap (referenced by SS:SP, SP is incremented) When you
 pop a value off the stack, the value is placed into the variable you are
 poping it back in to, SP is decremented and so forth. Note that the computer
 does not care what you pop the value back in to ...

 mov   ax, 50
 push  ax
 pop   bx

 Would set the values of both ax and bx to 50. (there are faster ways of doing
 this, pushing and poping are fairly fast though)

 push ax
 push bx
 pop  ax
 pop  bx

 would swap the values of ax and bx. As you can see, to pop the values back
 in to the origional variables, you must pop them back in the opposite
 direction to which you pushed them.

 push ax
 push bx
 push cx

 pop cx
 pop bx
 pop ax

 would result in no change for any of the registers.

 When a procedure is called, all the parameters for that procedure are pushed
 onto the stack. These can actually be read right off the stack, if you want
 to.

 As you have already seen, the mov command moves a value...

 mov  ,

 Note that dest and source must be the same number of bits long...

 mov  ax, dl

 would not work, and neither would

 mov  cl,bx

 However, mov  cx,dx
          mov  ax,50
          mov  es,ax
 are all valid.

 Shl I have explained before, it is where all the bits in a register are
 shifted one to the left and a zero added on to the right. This is the
 eqivalent of multiplying the value by two. Shr works in the opposite
 direction.

 Rol does the same, except that the bit that is removed from the left is
 replaced on the right hand side. Ror works in the opposite direction.

 div  divides the value in ax by value and returns the result in
 al if value is a byte, placing the remainder in ah. If value is a word,
 the double word DX:AX is divided by value, the result being placed in ax
 and the remainder in dx. Note that this only works for unsigned values.

 idiv  does the same as above, but for signed variables.

 mul   If value is a byte, al is multiplied by value and the result
 is stored in ax. If value is a word, ax is multiplied by value and the
 result is stored in the double word DX:AX

 imul  does the same as above, but for signed variables.

 The j* commands are fairly simple : if a condition is met, jump to a certain
 lable.

 jz     Jump if zero
 ja     Jump above     (unsigned)
 jg     Jump greater   (signed)

 and so forth.

 An example ...

 cmp  ax,50    ; Compare ax to 50
 je   @Equal   ; If they are equal, jump to label @equal

 call MyProc   Runs procedure MyProc and then returns to the next line of code.

 Procedures are declared as follows :

 MyProc   proc near
            ret    ; Must be here to return from where it was called
 MyProc   endp

 Variables are also easy :

 bob  db 50

 creates a variable bob, a byte, with an initial value of 50.

 bob2 dw 50

 creates a variable bob2, a word, with an initial value of 50.

 bob3 db 1,2,3,4,5,65,23

 creates bob3, an array of 7 bytes.

 bob4 db 100 dup (?)

 creates bob4, an array of 100 bytes, with no starting value.

 Go back and look at tut 7 for a whole lot more assembler commands, and get
 some sort of reference guide to help you out with others. I personally use
 the Norton Guides help file to program assembler.

 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
   Fire Routines

 To demonstrate how to write an assembler program, we will write a fire
 routine in 100% assembler. The theory is simple...

 Set the pallette to go from white to yellow to red to blue to black.
 Create a 2d array representing the screen on the computer.
 Place high values at the bottom of the array (screen)
 for each element, do the following :
   Take the average of the four elements under it

                          * Current element
                         123
                          4  Other elements
   Get the average of the four elements, and place the result in the current
   element.
 Repeat

 Easy, no? I first saw a fire routine in the Iguana demo, and I just had to
 do one ;) ... it looks very effective.

 With the sample file, I have created a batch file, make.bat ... it basically
 says :
         tasm fire
         tlink fire

 So to build and run the fire program, type :
 make
 fire

 The source file is commented quite well, so there shouldn't be any problems.

 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
   In closing

 As you can see, the sample program is in 100% assembler. For the next tut
 I will return to Pascal, and hopefully your new found assembler skills will
 help you there too.

 Byeeeee....
   - Denthor

 The following are official ASPHYXIA distribution sites :

 浜様様様様様様様様様様様様曜様様様様様様様様僕様様
 BBS Name                  Telephone No.   Open 
 麺様様様様様様様様様様様様洋様様様様様様様様陵様様
 ASPHYXIA BBS #1           +27-31-765-5312 ALL  
 ASPHYXIA BBS #2           +27-31-765-6293 ALL  
 C-Spam BBS                410-531-5886    ALL  
 POP!                      +27-12-661-1257 ALL  
 Soul Asylum               +358-0-5055041  ALL  
 Wasted Image              407-838-4525    ALL  
 Reckless Life             351-01-716 67 58ALL  
 Mach 5 BBS                +1 319-355-7336 ALL  
 House of Horror           +1 513-734-6470 ALL  
 Zero Level                +39 6-810-9934  ALL  
 藩様様様様様様様様様様様様擁様様様様様様様様瞥様様

 Leave me mail if you want to become an official Asphyxia BBS
 distribution site.
 USES crt,dos;

 VAR source,dest:string;

 function Exist(FileName: String): Boolean;
 { Boolean function that returns True if the file exists;otherwise,
  it returns False. Closes the file if it exists. }
 var
  F: file;
 begin
  {$I-}
  Assign(F, FileName);
  FileMode := 0;  { Set file access to read only }
  Reset(F);
  Close(F);
  {$I+}
  Exist := (IOResult = 0) and (FileName <> '');
 end;

 Procedure GetNames;
 BEGIN
   writeln;
   writeln ('Conversion from binary to db...');
   writeln;
   Write ('Enter name of binary file --> ');
   Readln (source);
   if not exist (source) then BEGIN
     Writeln (source,' not found! Exiting ...');
     writeln;
     halt;
   END;
   Write ('Enter name of desination text file --> ');
   Readln (dest);
   writeln;
   writeln ('Working ...');
 END;

 Procedure Convert;
 VAR f:text;
     f2:file;
     loop1,loop2,loop3:integer;
     no:byte;
     msg:string;
     dir:dirstr;
     name:namestr;
     ext:extstr;
 BEGIN
   assign (f2,source);
   reset (f2,1);
   assign (f,dest);
   rewrite (f);

   fsplit (dest, dir, name, ext);
   while length (name)<8 do name:=name+' ';

   write (f,name,'  db ');
   loop1:=0;
   loop3:=filesize (f2);
   loop2:=0;
   While not EOF (f2) do BEGIN
     blockread (f2,no,1);
     str (no:3,msg);
     write (f,msg);
     inc (loop1);
     inc (loop2);
     gotoxy (1,wherey);
     write (loop2,'/',loop3);
     if (loop1=16) and (not (eof(f2))) then BEGIN
       loop1:=0;
       writeln(f);
       write (f,'          db ');
     END else
     if not (eof(f2)) then write (f,',');
   END;

   close (f);
   close (f2);
   writeln;

   writeln ('Done.');
 END;

 BEGIN
   Getnames;
   Convert;
 END.    DOSSEG          ; Order the program to order it's segments in the
                     ; same way that high level languages do.

     .MODEL SMALL    ; Different models :
                     ;     Tiny   : Code + Data < 64k  (can be made a COM file)
                     ;     Small  : Code < 64k ;  Data < 64k
                     ;     Medium : Code > 64k ;  Data < 64k
                     ;     Compact: Code < 64k ;  Data > 64k
                     ;     Large  : Code > 64k ;  Data > 64k
                     ;     Huge   : Arrays > 64k

     .286            ; Enable 286 instructions

     .STACK 200h

     .DATA           ; Tells compiler that data is to follow.

 endmessage db "This was the Fire Effect       - denthor@beastie.cs.und.ac.za$"
                     ; This is our end message. Must be terminated with a "$"
 xsize    =  80      ; The x-width of our screen in pixels
 ysize    =  112      ; The y-height of our screen in pixels, plus a few extra
 randseed dw ?       ; any number for randomness

 pallette db  0, 0, 0, 0, 0, 6, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 8, 0, 0, 9, 0, 0,10
          db  2, 0,10, 4, 0, 9, 6, 0, 9, 8, 0, 8,10, 0, 7,12, 0, 7,14, 0, 6,16, 0, 5
          db 18, 0, 5,20, 0, 4,22, 0, 4,24, 0, 3,26, 0, 2,28, 0, 2,30, 0, 1,32, 0, 0
          db 32, 0, 0,33, 0, 0,34, 0, 0,35, 0, 0,36, 0, 0,36, 0, 0,37, 0, 0,38, 0, 0
          db 39, 0, 0,40, 0, 0,40, 0, 0,41, 0, 0,42, 0, 0,43, 0, 0,44, 0, 0,45, 0, 0
          db 46, 1, 0,47, 1, 0,48, 2, 0,49, 2, 0,50, 3, 0,51, 3, 0,52, 4, 0,53, 4, 0
          db 54, 5, 0,55, 5, 0,56, 6, 0,57, 6, 0,58, 7, 0,59, 7, 0,60, 8, 0,61, 8, 0
          db 63, 9, 0,63, 9, 0,63,10, 0,63,10, 0,63,11, 0,63,11, 0,63,12, 0,63,12, 0
          db 63,13, 0,63,13, 0,63,14, 0,63,14, 0,63,15, 0,63,15, 0,63,16, 0,63,16, 0
          db 63,17, 0,63,17, 0,63,18, 0,63,18, 0,63,19, 0,63,19, 0,63,20, 0,63,20, 0
          db 63,21, 0,63,21, 0,63,22, 0,63,22, 0,63,23, 0,63,24, 0,63,24, 0,63,25, 0
          db 63,25, 0,63,26, 0,63,26, 0,63,27, 0,63,27, 0,63,28, 0,63,28, 0,63,29, 0
          db 63,29, 0,63,30, 0,63,30, 0,63,31, 0,63,31, 0,63,32, 0,63,32, 0,63,33, 0
          db 63,33, 0,63,34, 0,63,34, 0,63,35, 0,63,35, 0,63,36, 0,63,36, 0,63,37, 0
          db 63,38, 0,63,38, 0,63,39, 0,63,39, 0,63,40, 0,63,40, 0,63,41, 0,63,41, 0
          db 63,42, 0,63,42, 0,63,43, 0,63,43, 0,63,44, 0,63,44, 0,63,45, 0,63,45, 0
          db 63,46, 0,63,46, 0,63,47, 0,63,47, 0,63,48, 0,63,48, 0,63,49, 0,63,49, 0
          db 63,50, 0,63,50, 0,63,51, 0,63,52, 0,63,52, 0,63,52, 0,63,52, 0,63,52, 0
          db 63,53, 0,63,53, 0,63,53, 0,63,53, 0,63,54, 0,63,54, 0,63,54, 0,63,54, 0
          db 63,54, 0,63,55, 0,63,55, 0,63,55, 0,63,55, 0,63,56, 0,63,56, 0,63,56, 0
          db 63,56, 0,63,57, 0,63,57, 0,63,57, 0,63,57, 0,63,57, 0,63,58, 0,63,58, 0
          db 63,58, 0,63,58, 0,63,59, 0,63,59, 0,63,59, 0,63,59, 0,63,60, 0,63,60, 0
          db 63,60, 0,63,60, 0,63,60, 0,63,61, 0,63,61, 0,63,61, 0,63,61, 0,63,62, 0
          db 63,62, 0,63,62, 0,63,62, 0,63,63, 0,63,63, 1,63,63, 2,63,63, 3,63,63, 4
          db 63,63, 5,63,63, 6,63,63, 7,63,63, 8,63,63, 9,63,63,10,63,63,10,63,63,11
          db 63,63,12,63,63,13,63,63,14,63,63,15,63,63,16,63,63,17,63,63,18,63,63,19
          db 63,63,20,63,63,21,63,63,21,63,63,22,63,63,23,63,63,24,63,63,25,63,63,26
          db 63,63,27,63,63,28,63,63,29,63,63,30,63,63,31,63,63,31,63,63,32,63,63,33
          db 63,63,34,63,63,35,63,63,36,63,63,37,63,63,38,63,63,39,63,63,40,63,63,41
          db 63,63,42,63,63,42,63,63,43,63,63,44,63,63,45,63,63,46,63,63,47,63,63,48
          db 63,63,49,63,63,50,63,63,51,63,63,52,63,63,52,63,63,53,63,63,54,63,63,55
          db 63,63,56,63,63,57,63,63,58,63,63,59,63,63,60,63,63,61,63,63,62,63,63,63
            ; Our pallette ... generated elsewhere and brought in

 screen   db xsize*ysize dup (?) ; Virtual screen

     .CODE           ; Tells compiler that code is to follow.

 Random          proc near

     mov     ax,[RandSeed]
     mov     dx,8405h
     mul     dx     ; ax*dx with result in dx:ax
     inc     ax
     mov     [RandSeed],ax
     ret            ; Return back to main section

 Random          endp

 SetUpScreen     proc near

     mov     ax,0013h
     int     10h       ; Get into 320x200x256 MCGA mode.

     mov     ax,0a000h
     mov     es,ax
     xor     di,di     ; ES:DI is now pointing to the top left hand of the screen

     cli
     cld
     mov     dx,3c4h
     mov     ax,604h   ; Enter unchained mode
     out     dx,ax
     mov     ax,0F02h  ; All planes
     out     dx,ax
     xor     ax,ax
     mov     cx,32767
     rep     stosw     ; Clear the screen
     mov     dx,3D4h
     mov     ax,14h    ; Disable dword mode
     out     dx,ax
     mov     ax,0E317h ; Enable byte mode.
     out     dx,ax
     out     dx,ax
     mov     ax,00409h ; Cell height
     out     dx,ax

     mov     si, offset [pallette]
     mov     dx, 3c8h  ; Pallette write register
     mov     al, 0
     out     dx, al    ; Start at color zero
     inc     dx
     mov     cx, 768
 @PalLoop :
     outsb             ; Write value to port; inc DI
     dec     cx
     jnz     @PalLoop
     ret

 SetUpScreen    endp

 START:
     mov     ax,@DATA
     mov     ds,ax     ; Moves the segment of the data into DS.

     call    SetUpScreen

     mov     randseed,1234h
     mov     si,offset [screen]
     mov     cx,xsize*ysize
     xor     ax,ax
     rep     stosb     ; Clear our virtual screen.

 @MainLoop :

                       ;
                       ; This next bit puts either 0 or 255 along the very
                       ; bottom row of our virtual screen.
                       ;

     mov     si,offset [screen]
     add     si,xsize*ysize
     sub     si,xsize  ; si=ofs(screen)+xsize*ysize-xsize ie. start of last row
     mov     cx,xsize  ; loop the entire last row
     xor     dx,dx
 @Newline :
     call    random
     mov     ds:[si],dl
     inc     si
     dec     cx
     jnz     @Newline

                       ;
                       ; This "softens" the values in the virtual array,
                       ; creating a fire effect.
                       ;
     mov     cx,xsize*ysize
     sub     cx,xsize
     mov     si,offset [screen]
     add     si,xsize
 @FileLoop :
     xor     ax,ax
     mov     al,ds:[si]
     add     al,ds:[si+1]
     adc     ah,0
     add     al,ds:[si-1]
     adc     ah,0
     add     al,ds:[si+xsize]
     adc     ah,0
     shr     ax,2
     jz      @zero
     dec     ax
 @Zero :
                       ; al = ((pos)+(pos+1)+(pos-1)+(pos+80))/4 - 1
     mov     ds:[si-xsize],al
     inc     si
     dec     cx
     jnz     @FileLoop

                       ;
                       ; This dumps our virtual screen to the VGA screen.
                       ;
     mov     dx, 3dah
 l1:
     in      al, dx
     and     al, 8h
     jnz     l1
 l2:
     in      al, dx
     and     al, 8h
     jz      l2

     mov     cx,xsize*ysize
     shr     cx,1
     mov     si,offset [screen]
     xor     di,di
     rep     movsw

     mov     ah,01
     int     16h       ; Has a key been pressed?
     jz      @MainLoop ; If not, carry on.

     mov     ah,0
     int     16h       ;get a key, returned in AX
                       ;this is just to clear the keyboard buffer of the key
                       ;press.

     mov     ax,0003h
     int     10h       ; Get into 80x25 text mode

     mov     dx,offset [endmessage]
     mov     ah,09h
     int     21h       ; Dos interrupt 21, subfunction 09 ... print string.
                       ; DS:DX must be pointing to start of string.

     mov     ax,4c00h  ; This function exits the program
     int     21h       ; and returns control to DOS.
 END START

 fire      db   0,  0,  0,  0,  0,  6,  0,  0,  6,  0,  0,  7,  0,  0,  8,  0
           db   0,  8,  0,  0,  9,  0,  0, 10,  2,  0, 10,  4,  0,  9,  6,  0
           db   9,  8,  0,  8, 10,  0,  7, 12,  0,  7, 14,  0,  6, 16,  0,  5
           db  18,  0,  5, 20,  0,  4, 22,  0,  4, 24,  0,  3, 26,  0,  2, 28
           db   0,  2, 30,  0,  1, 32,  0,  0, 32,  0,  0, 33,  0,  0, 34,  0
           db   0, 35,  0,  0, 36,  0,  0, 36,  0,  0, 37,  0,  0, 38,  0,  0
           db  39,  0,  0, 40,  0,  0, 40,  0,  0, 41,  0,  0, 42,  0,  0, 43
           db   0,  0, 44,  0,  0, 45,  0,  0, 46,  1,  0, 47,  1,  0, 48,  2
           db   0, 49,  2,  0, 50,  3,  0, 51,  3,  0, 52,  4,  0, 53,  4,  0
           db  54,  5,  0, 55,  5,  0, 56,  6,  0, 57,  6,  0, 58,  7,  0, 59
           db   7,  0, 60,  8,  0, 61,  8,  0, 63,  9,  0, 63,  9,  0, 63, 10
           db   0, 63, 10,  0, 63, 11,  0, 63, 11,  0, 63, 12,  0, 63, 12,  0
           db  63, 13,  0, 63, 13,  0, 63, 14,  0, 63, 14,  0, 63, 15,  0, 63
           db  15,  0, 63, 16,  0, 63, 16,  0, 63, 17,  0, 63, 17,  0, 63, 18
           db   0, 63, 18,  0, 63, 19,  0, 63, 19,  0, 63, 20,  0, 63, 20,  0
           db  63, 21,  0, 63, 21,  0, 63, 22,  0, 63, 22,  0, 63, 23,  0, 63
           db  24,  0, 63, 24,  0, 63, 25,  0, 63, 25,  0, 63, 26,  0, 63, 26
           db   0, 63, 27,  0, 63, 27,  0, 63, 28,  0, 63, 28,  0, 63, 29,  0
           db  63, 29,  0, 63, 30,  0, 63, 30,  0, 63, 31,  0, 63, 31,  0, 63
           db  32,  0, 63, 32,  0, 63, 33,  0, 63, 33,  0, 63, 34,  0, 63, 34
           db   0, 63, 35,  0, 63, 35,  0, 63, 36,  0, 63, 36,  0, 63, 37,  0
           db  63, 38,  0, 63, 38,  0, 63, 39,  0, 63, 39,  0, 63, 40,  0, 63
           db  40,  0, 63, 41,  0, 63, 41,  0, 63, 42,  0, 63, 42,  0, 63, 43
           db   0, 63, 43,  0, 63, 44,  0, 63, 44,  0, 63, 45,  0, 63, 45,  0
           db  63, 46,  0, 63, 46,  0, 63, 47,  0, 63, 47,  0, 63, 48,  0, 63
           db  48,  0, 63, 49,  0, 63, 49,  0, 63, 50,  0, 63, 50,  0, 63, 51
           db   0, 63, 52,  0, 63, 52,  0, 63, 52,  0, 63, 52,  0, 63, 52,  0
           db  63, 53,  0, 63, 53,  0, 63, 53,  0, 63, 53,  0, 63, 54,  0, 63
           db  54,  0, 63, 54,  0, 63, 54,  0, 63, 54,  0, 63, 55,  0, 63, 55
           db   0, 63, 55,  0, 63, 55,  0, 63, 56,  0, 63, 56,  0, 63, 56,  0
           db  63, 56,  0, 63, 57,  0, 63, 57,  0, 63, 57,  0, 63, 57,  0, 63
           db  57,  0, 63, 58,  0, 63, 58,  0, 63, 58,  0, 63, 58,  0, 63, 59
           db   0, 63, 59,  0, 63, 59,  0, 63, 59,  0, 63, 60,  0, 63, 60,  0
           db  63, 60,  0, 63, 60,  0, 63, 60,  0, 63, 61,  0, 63, 61,  0, 63
           db  61,  0, 63, 61,  0, 63, 62,  0, 63, 62,  0, 63, 62,  0, 63, 62
           db   0, 63, 63,  0, 63, 63,  1, 63, 63,  2, 63, 63,  3, 63, 63,  4
           db  63, 63,  5, 63, 63,  6, 63, 63,  7, 63, 63,  8, 63, 63,  9, 63
           db  63, 10, 63, 63, 10, 63, 63, 11, 63, 63, 12, 63, 63, 13, 63, 63
           db  14, 63, 63, 15, 63, 63, 16, 63, 63, 17, 63, 63, 18, 63, 63, 19
           db  63, 63, 20, 63, 63, 21, 63, 63, 21, 63, 63, 22, 63, 63, 23, 63
           db  63, 24, 63, 63, 25, 63, 63, 26, 63, 63, 27, 63, 63, 28, 63, 63
           db  29, 63, 63, 30, 63, 63, 31, 63, 63, 31, 63, 63, 32, 63, 63, 33
           db  63, 63, 34, 63, 63, 35, 63, 63, 36, 63, 63, 37, 63, 63, 38, 63
           db  63, 39, 63, 63, 40, 63, 63, 41, 63, 63, 42, 63, 63, 42, 63, 63
           db  43, 63, 63, 44, 63, 63, 45, 63, 63, 46, 63, 63, 47, 63, 63, 48
           db  63, 63, 49, 63, 63, 50, 63, 63, 51, 63, 63, 52, 63, 63, 52, 63
           db  63, 53, 63, 63, 54, 63, 63, 55, 63, 63, 56, 63, 63, 57, 63, 63
           db  58, 63, 63, 59, 63, 63, 60, 63, 63, 61, 63, 63, 62, 63, 63, 63

 [BACK] Back

Discuss this article in the forums


Date this article was posted to GameDev.net: 7/16/1999
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
Denthor's Asphyxia Tutorials

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!