[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]