{--------------------------------------------------------------}
{                           Bomber                             }
{                                                              }
{            Extended graphics demonstration program           }
{                                                              }
{                             by Jeff Duntemann                }
{                             Turbo Pascal V3.0                }
{                             Last update 4/13/86              }
{                                                              }
{    From the book, COMPLETE TURBO PASCAL, by Jeff Duntemann   }
{    Scott, Foresman & Co. (c) 1986,1987  ISBN 0-673-18600-8   }
{--------------------------------------------------------------}

PROGRAM Bomber;

{$I \turbo\GRAPH.P}

CONST
  MissileSize = 39;
  Hatch       = True;
  NoHatch     = False;

TYPE
  PatternArray = ARRAY[0..7] OF Byte;

  MissileRec = RECORD
                 ModeCode,Width,Height : Integer;
                 Pixels : ARRAY[0..MissileSize] OF Byte
               END;

  TargetRec  = RECORD
                 ModeCode,Width,Height : Integer;
                 Pixels : ARRAY[0..511] OF Byte
               END;

  TargetArray  = ARRAY[0..7] OF INTEGER;


CONST
  Lines : PatternArray =
          ($44,$88,$11,$22,$44,$88,$11,$22);

 { Note well that PutPic images are displayed "upside-down" }
 { from the orientation in which you code them.  The bomb   }
 { below points "up" in the listing but will be nose-down   }
 { when PutPic shows it on the screen! }

  Bomb : MissileRec =
         (ModeCode : 2;   { 2 = Color Graphics; 1 = HiRes }
          Width    : 8;   { Remember...2 bits per pixel!  }
          Height   : 20;
          Pixels   : ($0F,$F0,    {    ********    }
                      $3F,$FC,    {  ************  }
                      $FF,$FF,    {****************}
                      $FF,$FF,    {****************}
                      $FF,$FF,    {****************}
                      $FF,$FF,    {****************}
                      $FF,$FF,    {****************}
                      $FF,$FF,    {****************}
                      $FF,$FF,    {****************}
                      $FF,$FF,    {****************}
                      $FF,$FF,    {****************}
                      $3F,$FC,    {  ************  }
                      $0F,$F0,    {    ********    }
                      $03,$C0,    {      ****      }
                      $0F,$F0,    {    ********    }
                      $3F,$FC,    {  ************  }
                      $FC,$3F,    {******    ******}
                      $FC,$3F,    {******    ******}
                      $FC,$3F,    {******    ******}
                      $FC,$3F));  {******    ******}

VAR
  I             : Integer;
  NoBomb        : MissileRec;    { "Black" bomb that erases visible bomb }
  X,XNose,YNose : Integer;
  BombX         : Integer;       { Column from which bomb is dropped }
  TargetFigure  : TargetRec;     { The target itself, replicated by PutPic }
  Targets       : TargetArray;   { Array of flags showing which targets hit }
  DetonateX,DetonateY : Integer; { Point at which bomb encountered target }


{$I PULL.SRC }   { Described in Section 16.10 }


PROCEDURE GBAR(X,Y,Width,Height,EdgeColor,FillerColor : Integer;
               Hatch : Boolean;
               HatchPattern : PatternArray);

BEGIN
  Draw(X,Y,X+Width,Y,EdgeColor);
  Draw(X,Y+Height,X+Width,Y+Height,EdgeColor);
  Draw(X,Y,X,Y+Height,EdgeColor);
  Draw(X+Width,Y,X+Width,Y+Height,EdgeColor);
  IF Hatch THEN
    BEGIN
      Pattern(HatchPattern);
      FillPattern(X+1,Y+1,X+Width-1,Y+Height-1,FillerColor)
    END
  ELSE
    FillShape(X+1,Y+1,FillerColor,EdgeColor);
END;


FUNCTION AllClear(Targets : TargetArray) : Boolean;

VAR
  I : Integer;

BEGIN
  AllClear := True;   { Start by assuming all targets have been hit... }
  FOR I := 0 TO 7 DO
                      { ...but if any haven't, return FALSE }
    IF Targets[I] <> 0 THEN AllClear := False
END;


PROCEDURE ClearTarget(DetonateX,DetonateY : Integer;
                      VAR Targets : TargetArray);

VAR
  I : Integer;

BEGIN        { Erase the target by drawing a "black" bar over it }
  GBar((DetonateX DIV 40)*40,DetonateY,40,10,0,0,NoHatch,Lines);
  Targets[DetonateX DIV 40] := 0;
END;


PROCEDURE DropBomb(StartX,StartY : Integer;
                   VAR DetonateX,DetonateY : Integer);

VAR
  YNose : Integer;

BEGIN
  YNose := StartY;
  REPEAT
    PutPic(Bomb,StartX,YNose);       { Draw the bomb }
    PutPic(NoBomb,StartX,YNose);     { Erase the bomb }
    YNose := Succ(YNose);            { Prepare to draw it one pixel down }
  UNTIL (GetDotColor(StartX+4,YNose+1) <> 0) OR (YNose+1 >= 199);
  { Bombs travel downward until they hit a target or hit the screen bottom }
  DetonateX := StartX;  DetonateY := YNose + 1;
END;



BEGIN
  Randomize;               { Randomization: the spice of life... }
  FillChar(NoBomb,Sizeof(NoBomb),Chr(0));  { Blacken the bomb-blanker... }
  WITH NoBomb DO                           { ...and fill its header }
    BEGIN
      ModeCode := Bomb.ModeCode;
      Height := Bomb.Height;
      Width  := Bomb.Width
    END;
  GraphColorMode;
                           { Pull random vertical positions for the targets }
  FOR X := 0 TO 7 DO Targets[X] := Pull(85,180);
                           { Draw a target for the intro and "lift" it }
  GBar(140,120,40,10,1,2,NoHatch,Lines);
  GetPic(TargetFigure,140,120,180,130);
                           { Do the animated intro }
  DropBomb(156,24,DetonateX,DetonateY);
  GotoXY(16,18); Write('Bombs Away!');
  GotoXY(12,19); Write('Press (CR) to begin:');
  Readln;
                           { Blank the screen again and begin }
  GraphColorMode;

  { Now we lay down the targets, each of which is 40 pixels wide.  The }
  { vertical (Y) position of each target is stored in array Targets. }
  { The elements of Targets also function as collission flags, which }
  { are set to zero when a given target is struck by a bomb.  When all }
  { elements in Targets are zeroed, the game is over. }
  FOR I := 1 TO 8 DO PutPic(TargetFigure,(I-1)*40,Targets[I]);
  YNose := 24;
  XNose := Pull(5,300);
  REPEAT                   { Drop bombs until all the targets are gone }
    { The following statement ensures that bombs will not "graze" the next }
    { target to the right by making sure each bomb is dropped from a point }
    { at least eight pixels from the right edge of each target position }
    REPEAT BombX := Pull(5,310) UNTIL (BombX MOD 40) < 32;
    DropBomb(BombX,24,DetonateX,DetonateY);
    ClearTarget(DetonateX,DetonateY,Targets);
    IF KeyPressed THEN Halt    { To stop things early }
  UNTIL AllClear(Targets);
  GotoXY(1,23); Write('Press (CR) to continue: ');
  Readln;
  TextMode;    { Don't ever leave the user in graphics mode! }
END.
