
{$G+}
{- FUEGO.PAS
                              Fuego - Flames
                             ----------------
                           tlaure@lsa.lsa.com.uy
                           Tomas Laurenzo - 1997
                            Montevideo - Uruguay
 ----------------------------------------------------------------------------
 
  DISCLAIMER: Same as usual, use it at your own risk.
 
  COPYRIGHT: Use it freely, just remember _I_ coded it :)
 
 
  DESCRIPTION:
  This is a simple flames routine, with two fades at the end
  I do use some routines that i've collected for quite awhile.
  I think most of'em are from the SWAG files, and from the Asphyxia VGA
  Trainer by Denthor... which helped me a lot, (not very long :) time ago.
 
  Sorry, it's not optimized, but as long as it uses no ASM (appart from
  plotting dots and the palette stuff, wich is not "Fire code"), it's really
  easy to follow the code.
 
  Once the program is running, with the keys '4','5','1' and '2', you can
  move the limits of the fire.
 
  Any comments, suggestions, whatever, _please_ mail.
 
  Sal£,
    Tom.
 
^`§:;,.,;:§'^`§:;,.,;:§'^`§:;,.,;:§'^`§:;,.,;:§'^`§:;,.,;:§'^`§:;,.,;:§'^`§:;,.
}
 
 
 
PROGRAM Fuego;
 
 USES
   Crt;
 
 
 CONST Alt  = 100;    { The line from where we start redrawing the screen }
       VGA  = $A000;
 
 TYPE
      Tcolor  = RECORD                      { Las componentes RGB de un color}
                 R,G,B : Byte;
               END;
 
 
     Tpaleta = ARRAY [0..255] of Tcolor;
 
 
 VAR Y,
     X     : Word;
     Scr   : ARRAY [0..319, Alt-1..199] OF BYTE; { This will store the colors }
     MinX,                                       { of every dot in the screen }
     MaxX  : Word;                  { The limits of the fire }
     Sigue : Boolean;
     Tecla : Char;
 
 
{............................................................................}
 
 PROCEDURE Retraso; Assembler;   { Waits for the vertical retrace }
  ASM
      mov   dx,3DAh
  @@1:
      in    al,dx
      and   al,08h
      jnz   @@1
  @@2:
      in    al,dx
      and   al,08h
      jz    @@2
  END;
 
{............................................................................}
 
 PROCEDURE SeteaColor (Col : Byte; Color : Tcolor);
   { Sets a color of the palette}
  VAR R,G,B : Byte;
 
  BEGIN
    R := Color.R;
    G := Color.G;
    B := Color.B;
 
   ASM
     mov    dx,3c8h
     mov    al,[col]
     out    dx,al
     inc    dx
     mov    al,[r]
     out    dx,al
     mov    al,[g]
     out    dx,al
     mov    al,[b]
     out    dx,al
   END;
  END;
 
{............................................................................}
 
 PROCEDURE CargaColor (Col : Byte; VAR Color : Tcolor);
   { Loads a color from the palette }
 
  VAR
    rr,gg,bb : Byte;
 
  BEGIN
    ASM
       mov    dx,3c7h
       mov    al,col
       out    dx,al
 
       add    dx,2
 
       in     al,dx
       mov    [rr],al
       in     al,dx
       mov    [gg],al
       in     al,dx
       mov    [bb],al
    END;
    Color.r := rr;
    Color.g := gg;
    Color.b := bb;
  END;
 
{............................................................................}
 
 PROCEDURE FadeOut (Ret : Boolean); { Fades the screen out }
  VAR I       : Byte;
      ColTemp : tColor;
      Paleta  : tPaleta;
 
  FUNCTION Hay : Boolean;
    VAR I       : Byte;
        ColTemp : tColor;
        Paleta  : tPaleta;
        H       : Boolean;
 
    BEGIN
     FOR I := 0 TO 255 DO CargaColor (I,Paleta[I]);
     H := False;
     FOR I := 0 TO 255 DO BEGIN
           IF Paleta[I].R > 0 THEN H := True;
           IF Paleta[I].G > 0 THEN H := True;
           IF Paleta[I].B > 0 THEN H := True;
           IF H = True THEN Exit;
     END;
     Hay := H;
    END;
 
  BEGIN
   WHILE Hay DO BEGIN
    FOR I := 0 TO 255 DO CargaColor (I,Paleta[I]);
    FOR I := 0 TO 255 DO BEGIN
          IF Paleta[I].R > 0 THEN Dec (Paleta[I].R);
          IF Paleta[I].G > 0 THEN Dec (Paleta[I].G);
          IF Paleta[I].B > 0 THEN Dec (Paleta[I].B);
    END;
    FOR I := 255 DownTO 0 DO SeteaColor (I,Paleta[I]);
    IF Ret = True THEN Retraso;
   END;
  END;
 
{............................................................................}
 
 PROCEDURE FadeWhite (Ret : Boolean);  { Fade the screens to white }
  VAR J,
      I       : Byte;
      ColTemp : tColor;
      Paleta  : tPaleta;
 
  BEGIN
   FOR J := 0 TO 64 DO BEGIN
    FOR I := 0 TO 255 DO CargaColor (I,Paleta[I]);
    FOR I := 0 TO 255 DO BEGIN
          IF Paleta[I].R < 63 THEN Inc (Paleta[I].R)
                               ELSE Paleta[I].R := 63;
          IF Paleta[I].G < 63 THEN Inc (Paleta[I].G)
                               ELSE Paleta[I].G := 63;
          IF Paleta[I].B < 63 THEN Inc (Paleta[I].B)
                               ELSE Paleta[I].B := 63;
    END;
    FOR I := 255 DownTO 0 DO SeteaColor (I,Paleta[I]);
    IF Ret = True THEN Retraso;
   END;
  END;
 
{............................................................................}
 
  PROCEDURE Cls (Col : Byte; Where:word); assembler;  { Clears the screen }
   ASM                                                { to the color #col }
    push    es
    mov     cx, 32000;
    mov     es,[where]
    xor     di,di
    mov     al,[col]
    mov     ah,al
    rep     stosw
    pop     es
   END;
 
 
{............................................................................}
 
  PROCEDURE Modo13h; Assembler;   { Goes into 13h VGA mode }
   ASM
    MOV AX, 13h
    INT 10h
   END;
 
{............................................................................}
 { Plots a dot to the screen }
 PROCEDURE PutDot (X,Y : Integer; Color : Byte; SegDes:word); assembler;
  ASM
   cmp  X,0
   jl   @@END
   cmp  Y,0
   jl   @@END
   cmp  X,319
   jg   @@END
   cmp  Y,199
   jg   @@END
   mov  ax,SegDes
   mov  es,ax
   mov  al,Color
   mov  di,Y
   mov  bx,X
   mov  dx,di
   xchg dh,dl
   shl  di,6
   add  di,dx
   add  di,bx
   mov  es:[di],al
 @@END:
 END;
 
{............................................................................}
 
 PROCEDURE Promedio;       { Averages the screen dots }
  VAR X, Y : Word;
  BEGIN
   FOR X := MinX+1 TO MaxX-1 DO FOR Y := Alt TO 199 DO
     Scr [X,Y] := (Scr[X,Y+1] + Scr [X,Y+1] + Scr[X+1,Y+1] + Scr [X-1,Y-1]) div 4
  END;
 
 
{............................................................................}
 
 PROCEDURE Escribo;        { This plots the dots to the screen }
  VAR X, Y : Word;
  BEGIN
   FOR X := MinX TO MaxX DO FOR Y := Alt TO 198 DO IF Scr[X,Y] > 0 THEN PutDot (X,Y,Scr[X,Y],VGA);
  END;
 
{............................................................................}
 
 PROCEDURE CreoPaleta;    {  Creates the palette }
  VAR Paleta  : tPaleta;
      ColTemp : tColor;
      I       : Byte;
 
  BEGIN
    FOR I := 1 TO 64 DO BEGIN
      ColTemp.R := I;
      ColTemp.G := 0;
      ColTemp.B := 0;
      Paleta[I] := ColTemp;
    END;
    FOR I := 64 TO 128 DO BEGIN
      ColTemp.R := 255;
      ColTemp.G := I;
      ColTemp.B := 0;
      Paleta[I] := ColTemp;
    END;
    FOR I := 118 TO 150 DO BEGIN
      ColTemp.R := 255;
      ColTemp.G := 128;
      ColTemp.B := 0;
      Paleta[I] := ColTemp;
    END;
    FOR I := 1 TO 150 DO SeteaColor (I,Paleta[I])
  END;
 
{............................................................................}
                               { Main }
 BEGIN
   Modo13h;
   CreoPaleta;
   Cls (0,VGA);
   MinX := 0;
   MaxX := 319;
   Sigue := True;
   FOR X := MinX TO MaxX DO BEGIN       { Initialize the Scr array to 0 }
     FOR Y := Alt-1 TO 199 DO BEGIN
       Scr [X,Y] := 0;
     END;
   END;
   WHILE Sigue DO BEGIN
    FOR X := MinX TO MaxX DO Scr [X,199] := Random (100)+40; { The first line }
    Promedio;
    Escribo;
 
    IF KeyPressed THEN BEGIN
      Tecla := ReadKey;
      CASE Tecla OF
        '4' : IF (MaxX > 0) AND (MaxX > MinX+10) THEN BEGIN
                Dec (MaxX,10);
                FOR X := MaxX to 319 DO
                    FOR Y := Alt-1 to 199 DO PutDot (X,Y,0,VGA);
              END;
 
        '5' : IF MaxX < 319 THEN Inc (MaxX,10);
        '1' : IF MinX > 0 THEN Dec (MinX,10);
        '2' : IF (MinX < 319) AND (MinX < MaxX-10) THEN BEGIN
                Inc (MinX,10);
                FOR X := 0 to MinX DO
                    FOR Y := Alt-1 to 199 DO PutDot (X,Y,0,VGA);
              END;
      ELSE Sigue := False;
      END;
     END;
    END;
   FadeWhite (True);
   Cls (53,VGA);
   FadeOut (True);
 END.
