[Back to GRAPHICS SWAG index] [Back to Main SWAG index] [Original]

    {
    AC>I got my hands on Jare's fire code and thought it was pretty cool,
    AC>so I made my own fire program. Although it didn't turn out like I
    AC>thought it would (like Jare's) what I have is (at least I think so)
    AC>something that looks more realistic.

    This is kinda funny... just the other day I was looking at Jare's fire
    code, and did an 80x50 textmode version of it in C.  I did a quick and
    dirty conversion of it to Pascal so I could post it here for you
    (don't you feel special? <G>).  The pascal version came out a bit
    slower then my C version, although they are very similar. I haven't
    figured out why though... most times I try this, both come out close
    to the same speed.

    (********************************************************************
     Fire by Eric Coolman (aka. Digitar/SKP), Simple Minded Software
     Much like Jare's (VangelisTeam) fire, but uses 80x50x16 text mode
     rather than 320x200x256 (which was "tweaked" to look like 80x50
     text mode).  Reference : FIRE.TXT by Phil Carlisle (aka Zoombapup,
     CodeX) from PC Game Programmer's Encyclopedia (PCGPE10.ZIP) by Mark
     Feldman and contributers (thanks for the great reads guys!).
     Compiler : Turbo Pascal 6.0
     Released to public domain, July 30, 1994.

     NOTE: FirePalette will not get loaded if running under DESQview
           with "VIRTUALIZE TEXTMODE" on (which will stop any palette
           manipulation).  To fix, go into setup for the DOSBOX, and
           under "VIRTUALIZE TEXT/GRAPHICS" mode, and set it to "N".
           Also for DV, set "WRITES DIRECT TO SCREEN" to "Y"es.
    ********************************************************************)
    }

    Program tFire;

    const
        MAXX = 80;
        MAXY = 50;
        { Our gradient firepalette (white/yellow/red/orange/slate/black) }
        FirePal : array[0..3*16-1] of byte =
          {       [ HUES ]       }
          {  RED    GREEN   BLUE }
          {  ===    =====   ==== }
          (                                               { Normal Color }
             0,     0,      0,                            { BLACK        }
             0,     5,      3,                            { BLUE         }
             0,     6,      7,                            { GREEN        }
             0,     7,      9,                            { CYAN         }
             0,     8,      11,                           { RED          }
             0,     9,      12,                           { MAGENTA      }
             63,    13,     0,                            { BROWN        }
             60,    4,      4,                            { LIGHTGRAY    }
             63,    58,     21,                           { DARKGRAY     }
             63,    59,     0,                            { LIGHTBLUE    }
             63,    60,     0,                            { LIGHTGREEN   }
             63,    60,     0,                            { LIGHTCYAN    }
             63,    61,     30,                           { LIGHTRED     }
             63,    55,     42,                           { LIGHTMAGENTA }
             63,    60,     55,                           { YELLOW       }
             63,    63,     63                            { WHITE        }
         );

    type
         ColorArray = array [0..MAXX+1, 0..MAXY] of Byte;
    var
        FireImage : ColorArray;
        CUR       : Word;                                { working color }
        x, y      : Byte;                             { general counters }

    (*
     Sets video mode.  If mode is 64d (40h), 8x8 ROM font will be loaded
     and 80x50 textmode will be activated.  Any other value will set
     mode normally.
    *)
    procedure VidMode(mode : byte); assembler;
    asm
         cmp  mode, 40h                      { (64d) want 80x50/43 mode? }
         jnz  @normalset
         mov  ax,1112h                { set 8 point font as current font }
         mov  bl,00h
         jmp  @MakeItSo                                            { ;-) }
       @normalset:
         mov  ah, 00h
         mov  al, mode
       @MakeItSo:
         int  10h
    end;

    { grabs and dumps keypress...returns 1 if a key was hit, else 0 }
    function KbGrab : boolean;
    var
        WasHit : boolean;
    begin
        WasHit := False;

        asm
            mov ax, 0100h
            int 16h
            lahf
            test ah, 40h
            jnz @done
            inc WasHit
            mov ax, 0000h                  { grab the key they hit .... }
            int 16h
          @done:
        end;
        KbGrab := WasHit;
    end;

    (*********************************************************************
     sets only color indexes normally used in textmode (16 of 'em).
     Note the heavy use of ternary operator there... what that means
     is - indexes 7 to 15 (dark gray to white) are actually indexes
     55 to 63, and index 6 (dark brown) is actually 20d (14h) because
     it uses the secondary hues so that it doesn't look too much like
     red.  The rest (0,1,2,4,5,7) are as expected.
    *********************************************************************)
    procedure SetFirePal;
    var
      i, j : Byte;
    begin
       for i:= 0 to 16 do                               { for each index }
         begin
           if i <= 7 then begin if i = 6 then j := 20 else j := i; end
           else j := i+48;
           port[$3c8] := j;                             { Send the index }
           port[$3c9] := FirePal[i*3];                    { Send the red }
           port[$3c9] := FirePal[i*3+1];                { Send the green }
           port[$3c9] := FirePal[i*3+2];                 { Send the blue }
        end;
    end;

    (*********************************************************************
      +----+-----+----+ Table to left are screen ofs's surrounding CUR(0).
      |-81 | -80 |-79 | That we will take average of. 80 is for width of
      +----+-----+----+ screen in chars in textmode (also width of our
      | -1 | CUR | +1 | screen buffer).  The calculated average will be
      +----+-----+----+ assigned to spot '-80' to move the fire upwards,
      |+79 | +80 |+81 | and decremented to fade it out (like a plasma
      +----+-----+----+ effect somewhat).
    *********************************************************************)
    procedure DoFire;
    begin;
        { start at [1,1] or above because 0,0 doesn't have 8 surrounding }
        { stop x at 78 or less for the same reason (ending y doesn't     }
        { matter cause we are setting max y randomly anyways).           }
        { (starting y can be set to 8 to give room for a scroller).      }
         for y := 1 to MAXY do
           for x := 1 to MAXX-1 do
             begin
              { get average of 8 surrounding colors              (-ofs-) }
              CUR := (  FireImage[x-1][y]         { direct to left  (-1) }
                      + FireImage[x+1][y]         { direct to right (+1) }
                      + FireImage[x][y-1]         { direct above   (-80) }
                      + FireImage[x][y+1]         { direct below   (+80) }
                      + FireImage[x-1][y-1]       { above to left  (-81) }
                      + FireImage[x+1][y+1]       { below to right (+81) }
                      + FireImage[x+1][y-1]       { above to right (-79) }
                      + FireImage[x-1][y+1]       { below to left  (+79) }
                    ) shr 3;                      { divide by 8          }
             Dec(CUR);                            { make fire fade out   }
             { notice below is assigning the average CUR to (CUR-1 line) }
             { ... this keeps fire moving in upward direction.           }
             FireImage[x][y-1] := CUR;                       { set color }
             mem[$b800:y*160+(x shl 1)+1] := FireImage[x][y];
           end;

           { Randomly set last line of fire... This keeps the fire going }
          for x := 0 to 80 do
             FireImage[x][49] := (random(255)+1);
          { second last line also to give fire some more height. }
          for x := 0 to 80 do
             FireImage[x][48] := (random(255)+1);
    end;

    begin
       VidMode($03);                     { 80x25 mode (to clear screen) }
       VidMode($40);                                       { 80x50 mode }

       SetFirePal;

      { change to hi-intense background so we have 16 bg colors to }
      { work with.                                                 }
      asm
          mov ax, 1003h                                 { blinking attr }
          mov bx, 0000h            { 0=HiIntBackground, 1=Blinking Attr }
          int 10h
      end;

      { clear fire image }
      fillchar(FireImage, sizeof(FireImage), 63);     { fill with white }

      for x := 0 to 80 do          { set up last line to start the fire }
        FireImage[x][49] := (random(255)+1);

      repeat DoFire; until KbGrab;

      VidMode($03);                                        { 80x25 mode }
    end.

[Back to GRAPHICS SWAG index] [Back to Main SWAG index] [Original]