
uses crt, dos;  {$R-}
(****************************************************************************)
(*           TPONG-1.PAS        Glenn A. Reiff    74035,400     4/5/85      *)
(*                                                                          *)
(*  Note:  While this program is usable and will provide some fun, the      *)
(*         Paddle control is not as responsive as it is in the original     *)
(*         Basic program.  Also, the side bounces could be better.  If      *)
(*         you are able to make any improvements I'd appreciate knowing     *)
(*         about them.                                                      *)
(****************************************************************************)
type Str80 = string[80];
procedure CENTER(Y:integer; Bt:Str80);
BEGIN gotoXY((80-Length(Bt)) div 2, Y); write(Bt) END;

procedure INTRODUCTION;
BEGIN
     clrscr;                    CENTER(5,'TURBO PONG');
     CENTER(8,'This is an adaption to Turbo Pascal of the Basic program  ');
     CENTER(9,'called PChallenge written by Karl Koessel and published in');
     CENTER(10,'a 1982 issue of PC Magazine.                              ');
     CENTER(12,'His was a simplification of Pong, the orignial video game.');
     CENTER(13,'Pong was developed in the early 1970''s by Nolan Bushnell. ');
     CENTER(20,'Tap a Key to Continue');
     writeln; gotoXY(80,25);
     repeat until keypressed;
END; { INTRODUCTION }


type       CharSet = set of Char;
           Str9    = string[9];

var        Paddle  : Str9;
           StartTime,
           EndTime,
           CurTime,
           BestTime,
           Drag : integer;
           Ch: char;


Procedure TEXTBORDER (color: integer);
  var regs: registers;
BEGIN
  With regs do begin
    AH := 11; BH := 0; BL := color end;
  Intr($10,regs)
END; { TEXTBORDER }

Procedure BEEP(N : Integer);
BEGIN   Sound(n);  Delay(100);  NoSound; END;

function GET_TIME: integer;
var regs: registers;
BEGIN
  with regs do begin
    ax := $2C * 256;
    MsDos(regs);
    GET_TIME := 3600 * ch + 60 * cl + dh
  end
END;  { GET_TIME }

procedure CHOOSE(    X,Y    : integer;
                     Prompt : Str80;
                     Term   : CharSet;
                 var TC     : Char    );
var   I  : integer;
      Ch : char;
BEGIN
  lowvideo; gotoXY(X,Y);
  for I:=1 to length(Prompt) do begin
      Ch:=Prompt[I];
      if I>4 then begin
        lowvideo;
        if (Prompt[I-2]=' ') and (Prompt[I-1]=' ') then highvideo;
        if (Prompt[I-1]='<') or  (Prompt[I-1]='/') then highvideo;
      end; { if I>3 }
      write(Ch)
  end; { for I }
  repeat
    TC := Upcase(ReadKey);
    if not (TC in Term) then BEEP(1000)
  until TC in Term
END; { CHOOSE }

procedure RESET(var Drag: integer;  var Paddle: Str9);
BEGIN
     TEXTBORDER(Black); textbackground(Black); clrscr;
     CENTER(10,'Left and right cursor keys move paddle.');
     textcolor(LightCyan);
     CENTER(12,'Input drag factor: (100 is Medium...0 is FAST!)  ');
read(Drag);     CHOOSE(17,14,'Pick a paddle size:  Small,  Medium or
Large',['S','M','L'],Ch);     if Ch = 'S' then Paddle := ' '+chr(27)+'
'+chr(26)+' '       else if Ch = 'M' then Paddle := ' '+chr(27)+'
'+chr(26)+' '          else if Ch = 'L' then Paddle := ' '+chr(27)+'
'+chr(26)+' 'END; { RESET }

procedure RUN;
label NewBall;
var   Used                                 :   array[1..10] of integer;
var   X,dX,Xpad,Y,dY,B,C,I,J,BallNr,Xstart :   integer;
      Flag                                 :   boolean;

  procedure RANDOMIZE;
  BEGIN
    dx := random(7)- integer (random(7));
    if dX < 0  then
      repeat
        dX := random(7) - integer (random(7));
        if dX=0 then dX:=-1;
      until (X-6)/dX=trunc((X-6)/dX);
    if dX > 0  then
      repeat
        dX := random(7) - integer (random(7));
        if dX=0 then dX:=1;
      until (59-X)/dX=trunc((59-X)/dX)
  END; { RANDOMIZE }

  procedure POSITION_PADDLE;
  BEGIN
    gotoXY(Xpad,22); textbackground(LightGray);
    textcolor(DarkGray); write(Paddle); textbackground(C);
  END; { POSITION_PADDLE }

  procedure ONKEY;
  BEGIN
    Ch := ReadKey;
    if Ch = #27 then  { it must be a function key }
      Ch := ReadKey;
    case Ch of
      'K':   if Xpad > 7 then begin
        Xpad:=Xpad-3; POSITION_PADDLE;
        gotoXY(Xpad+length(Paddle),22); write('   '); end;
      'M':   if Xpad + length(Paddle) < 60 then begin
        Xpad:=Xpad+2; POSITION_PADDLE;
        gotoXY(Xpad-3,22); write('   '); end;
    end;   { case }
  END; { ONKEY }


BEGIN
     J := 11; Xpad := 29; C := random(16);
     if c in [0, 1, 6..9, 12, 15] then C := 2;
     textbackground(C); clrscr; TEXTBORDER(C);

     for X:=8 to 17 do begin   { Setup  10 Balls }
         J := J + 4; textbackground(red); textcolor(white);
         gotoXY(J,2); write(#2); textbackground(C);
     end; { for X }
     textcolor(Blue);
     GotoXY (5, 3);
     for X:=5 to 59 do write(#219);  { Draw Backboard }
     for Y:=3 to 21 do begin         { Draw Walls  }
        gotoXY  (5,Y); write (#219#219);
        gotoXY (59,Y); write (#219#219);
     end;
     POSITION_PADDLE; textcolor(Black);
     gotoXY(5,24); write('Best Time so far is ',BestTime,' seconds.');
     gotoXY(66,3); write('TURBOPONG');
     gotoXY(63,6); write('Initial Drag ',Drag);
     FillChar (Used, 20, 0);
     BallNr := 10;
     StartTime := GET_TIME;

     while BallNr > 0 do begin
       repeat
         Xstart := 1 + random(10); Flag:=false;
         for I:=1 to 10 do if Used[I] = Xstart then Flag:=true;
       until not Flag;
       Used[BallNr]:=Xstart;
       Xstart := 11 + 4 * Xstart;
       gotoXY(Xstart,2); write(' ');
       X := Xstart; Y := 4; dY := 1; Flag := false;
       RANDOMIZE;
       while Y < 23 do begin
         if keypressed then ONKEY;
         textbackground(C);
         if (Y > 4)  and (X in [7..58]) then     { Erase Previous Ball Below }
           begin gotoXY(X,Y-1); write(' '); end;
         if (Y < 21) and (X in [7..58]) then
           begin gotoXY(X,Y+1); write(' '); end; { Erase Previous Ball Above }
         if (Y=21) and (X-Xpad in [0..length (Paddle)]) then
           begin gotoXY(X,Y); write(' '); end;   { Erase Ball On Paddle      }

         X:=X + dX;

         textbackground(red); textcolor(white);
         if X in [7..58] then begin
           gotoXY(X,Y); write(#1)         { Print New Ball Position }
         end;
         gotoXY(80,25);
         if not (x in [8..57]) then begin
           BEEP(300+random(80*BallNr)); dX:=-dX;
         end;    { Side Wall Bounce        }
         if keypressed then ONKEY;

         if (Y=21) and (X-Xpad in [0..length(Paddle)]) then begin
           dY := -dY; BEEP(700);      { Bounce Off Of Paddle }
           if dX = 0 then RANDOMIZE;
         end; { if Y=21 }

         if Y = 22 then begin
           textbackground(C); gotoXY(X,Y); write(' ');
           textbackground(red); textcolor(white);      { Park Used Ball }
           gotoXY(25+Xstart,Y+2); write(#1); gotoXY(80,25);
         end;
         if keypressed then ONKEY;

         if (Y = 4) and Flag then begin   { Bounce Off of Top Backboard }
           BEEP(300+random(80*BallNr));
           Drag := Drag - 5;  { Reduce Amout of Drag    }
           if dX = 0 then RANDOMIZE;
           inc (dX); dY := -dY; Y := Y + dY
         end else begin Y := Y + dY; Flag := true end;
         if Drag <0 then Drag := 0;
         delay(50+Drag);
       end; { while Y }
       BallNr := BallNr - 1; textbackground(C);
     end; { while BallNr }
     gotoXY(1,22); clreol;
     textcolor(Black); gotoXY(63,8); if Drag < 0 then Drag := 0;
     write('Final Drag   ',Drag);
     EndTime := GET_TIME;
     CurTime := EndTime - StartTime;
     if CurTime > BestTime then BestTime := CurTime;
     gotoXY  (5,24); write('Best Time so far is ',BestTime,' seconds.');
     gotoXY (63,11); write('This Run ', CurTime, ' sec.');
END; { RUN }

{MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
BEGIN
          BestTime := 0; Drag := 0; Paddle := '';
          INTRODUCTION;
          RESET(Drag,Paddle);
          repeat
            RUN;
            CHOOSE(19,22,'    Quit  Reset  Continue   ',['Q','R','C'],Ch);
            if Ch = 'R' then RESET(Drag,Paddle);
          until Ch = 'Q';
          TEXTBORDER(Black); textbackground(Black); clrscr;
END.

