program SpaceShip;

        { Spaceship by Phil Spencer
          keys: up: a Down: z forward: c Back: x Fire!: s
          Exit: 0}

         { Friday Nov 19th -> User Interface complete basic
           Ship Movement and Firing Work }

         { Tuesday Nov 23rd -> Asteriod Explosion Completed, very
  				 annoyed with outtext on the scoring part. Only 1 Asteroid
	  			 at the moment }

         { Wednesday Nov 24th -> Scoring Complete, Multiple asteriods
				   began to exceed 486 limitations, User Death has been met with
				   limited success }

         { Wednesday 24th Evening -> Got User Death working , Asteroid Explosion
           is still QUITE buggy, but im done now code is to sloppy an game
           is slow }

uses crt,spence,graph;

const
    max 				= 5;
    RockColour  = LightGreen;

type
  Baroo   = file of integer;
	images  = array[1..2] of pointer;
  Rocked  = record
  						Rock   : integer;
              RockX  : integer;
              RockY  : integer;
              Speed  : integer;
            end;

  User    = record
          		Lives  : integer;
              Score  : word;
              Move   : char;
            end;

  Fired   = record
  						Fire  : boolean;
              FireX : boolean;
		  				Firey : boolean;
            end;

  HighScore = record
  							Name  : String[10];
                Score : word;
              end;

var
  i,x,y     : integer;
  Sprite    : images;
  Exit      : boolean;
  Fire      : boolean;
  FireX     : integer;
  FireY     : integer;
  CheckHit 	: integer;
  TargetHit : boolean;
  Player    : User;
  Asteroid  : array[1..max] of Rocked;
  OutScore  : String[10];
  NextRock  : integer;
  loop      : integer;
  Dead      : boolean;
  OutLives  : String[1];
  FResult   : boolean;
  fh        : baroo;
  FWriter   : HighScore;

procedure Sprites(var image :images);
var
	size  : integer;

begin
  setcolor(white);
	line(100,100,170,130);
	line(170,130,80,150);
	line(80,150,110,130);                             { Draws Ship }
	line(110,130,100,100);
  Size := ImageSize(99, 99, 201, 201);              { Gets Size of Ship }
	GetMem(image[1], Size);                              { Allocates memory }
  getimage(75,95,175,155,image[1]^);                   { Saves Ship in Memory }
  setcolor(RockColour);
  line(100,200,150,230);                              { Draws Asteroid }
  line(150,230,140,240);
  line(140,240,105,243);
  line(105,243,103,210);
  line(103,210,100,200);
  Size := ImageSize(98,198,156,246);                  { Gets Size of rock }
	GetMem(image[2], Size);                             { Allocates memory }
	Getimage(98,198,156,246,image[2]^);                 { Saves it in memory }
end;

procedure DrawShip(image : pointer ; x,y :integer);

begin
  putimage(x,y,image^,normalput);       { Draws Ship Wherever X an Y are }
end;

procedure EraseRock(x,y:integer);
begin
  setcolor(black);
  for i := x to x+52 do            { This Erases asteroids after they leave the screen }
  	line(i,y,i,y+47);
end;

Procedure DrawRock(x,y :integer ; image :pointer );
begin
	putimage(x,y,image^,NormalPut);    { Draws Rocks }
end;

function DoesItExist(var FileH: baroo) :boolean;
var
	result :integer;

begin
  {$I-}
  reset(FileH);
  {$I+}
  result := IOresult;
  if result = 0 then DoesItExist := True
  else
		DoesItExist := False;
end;

begin
  StartGraph;         { Graphics init(Vga 640x480 16 colours) }
  sprites(sprite);
  SpenceLogo(true);
  cleardevice;
  StarStart;         { Init Stars }
  x := 78;
  y := 98;           { Start x,y cord.}
  Player.Lives := 3; { Players Lives }
  randomize;
  for i := 1 to max do begin
 	 with Asteroid[i] do begin
  		 Rock := random(200)+1;
  		 RockX := 600;
  		 RockY := random(330)+30;
 	 	 Speed := random(5)+2;
 	 end;
  end;
  Player.Score := 0;
  Dead := false;
  repeat
    StarMove;        { Move Stars }
    DrawShip(sprite[1],x,y);

    {Checks Asteroid hit }
   loop := 0;
   while (Dead <> true) and ( loop < 3 ) do begin
    loop := loop + 1;
    with Asteroid[loop] do begin
         if (RockX - x+70 < 70 ) then begin
            if (Rocky > y) then
              if (Rocky - y < 30) then
                 Dead := true;
             if y > RockY then
                if (y+30 - rocky < 30) then
                   Dead := true;
          end;
         end;
    end;

    { Checks Users Movement }

    if keypressed = true then begin        { if a key is pressed Check Move}
      Player.Move := readkey;
    	if Player.Move = '0' then exit := true;     { exit key }
      if Player.Move = 'z' then begin
        if y < 330 then	y := y + 5;
        DrawShip(sprite[1],x,y);               { Moves Ship Down }
      end;
      if Player.Move = 'a' then begin
        if y > 5 then y := y - 5;
        DrawShip(sprite[1],x,y);               { Moves Ship Up }
     	end;
      if Player.Move = 'c' then begin
        if x < 240 then x := x + 5;
        DrawShip(sprite[1],x,y);               { Moves Ship Forward }
      end;
      if Player.Move = 'x' then begin
        if x > 5 then x := x - 5;
        DrawShip(sprite[1],x,y);               { Moves Ship Forward }
        end;
      if Player.Move = 's' then begin
         if fire <> true then begin
            Fire    := true;               { Fire! }
            FireX   := x + 80;
            FireY   := y + 35;
         end;
      end;
    end;

    { Detects Rocks Location }

    for loop := 1 to max do begin
     with Asteroid[loop] do begin
    	if  Rock > 200 then begin       { If Rocks are activethen -> }
    		if  RockX < 5 then begin
    	      EraseRock( RockX, RockY);        {If X less than 5, Erase it }
    	      Rock := Random(200)+1;
    	      RockX := 600;
    	      RockY := random(300)+30;
    	      Speed := random(5)+2;
    	  end;
   	   if  RockY < 5 then begin         { If Y less than 5 Erase it }
    	    EraseRock( RockX, RockY);
    		  Rock := random(200)+1;
    	    RockX := 600;
     	    RockY := random(300)+30;
     	    Speed := random(5)+2;
     	 end;
     	 if  RockY > 480 then begin     { If Y > 480 then Erase it }
     	    EraseRock( RockX, RockY);
    	    Rock := random(200)+1;
          RockX := 600;
          RockY := random(300)+30;
          Speed := random(5)+2;
       end;
        RockX :=  RockX -  Speed;
       DrawRock( RockX, RockY,sprite[2]);
      end;
    end;
   end;

     { Fire Code Begins Here }
     if Fire = true then begin
       if (FireX < 640) and (targethit <> true) then begin
          for i := 1 to 10 do begin
              FireX := FireX + 1;
              setcolor(red);
              line(FireX,FireY,FireX+30,FireY);
              setcolor(black);                        { Fireing Code }
              line(FireX-1,FireY,FireX-1,FireY);
              CheckHit := GetPixel(FireX+31,FireY);
              if CheckHit = RockColour then begin
              			targethit:= true;
               			Fire := False;
              end;
           end;
       end else
           Fire := false
    end;

    { Sprite Hit }

  for loop := 1 to max do begin
   with asteroid[loop] do begin
    if targethit = true then begin
     if RockX - Firex < 10 then
      if (RockY - FireY < 10) or ( FireY - RockX < 10) then begin
    	setcolor(black);
      line(FireX,FireY,FireX+30,FireY);
      for i := 1 to 50 do begin
            setcolor(yellow);
         		circle( RockX+20, RockY+20,i);
            setcolor(black);
            circle( RockX+20, RockY+20,i);
      end;
      Player.Score := Player.Score + 50;
      circle( RockX+20, RockY+20,i);
       Rock := random(200)+1;
      EraseRock( RockX, RockY);
       RockX := 600;
       RockY := Random(330)+30;
      setcolor(black);
      outtextxy(220,430,OutScore);
      targethit := false;
      end;
   end;
   Rock :=  Rock + 1; { increase everytime until it hits 200 , then a rock happens }
   end;
   end;

      {death code }
    if dead = true then begin
       for i := 1 to 50 do begin
           setcolor(yellow);
           circle(x+30,y+30,i);
       end;
       for i := 1 to 50 do begin
           setcolor(black);
           circle(x+30,y+30,i);
       end;
       delay(500);
       cleardevice;
       Player.lives := Player.lives - 1;
       setcolor(Lightgreen);
       if Player.lives > 0 then begin
          outtextxy(320,240,'Ready?');
          readkey;
          setcolor(black);
          outtextxy(320,240,'Ready?');
          dead := false;
          x := 78;
          y := 98;
          for i := 1 to max do begin
 	            with Asteroid[i] do begin
  		           Rock := random(200)+1;
  		             RockX := 600;
  		              RockY := random(330)+30;
 	 	               Speed := random(5)+2;
 	             end;
          end;
      end;
     end;

    {	Score Drawing }

    settextstyle(TripleXfont,Horizdir,3);
    setcolor(lightblue);
    outtextxy(100,430,'Score: ');
    str(Player.Score,OutScore);
    outtextxy(220,430,OutScore);
    Outtextxy(300,430,'Lives:');
    line(0,400,640,400); { Bottom of screen}
    str(Player.Lives,OutLives);
    Outtextxy(360,430,OutLives);
  until (exit = true) or (Player.Lives = 0);               {exit if 0 is pressed}
  closegraph;
  assign(fh,'Score.Dat');
  FResult := DoesItExist(fh);
  if FResult = false then rewrite(fh);
  close(fh);
  ClearMenu;
  menu(20,13,60,17,'Game Over',red);
  writelnmenu(1,'');
  writemenu(1,' Final Score:');
  gotoxy(35,15);
  write(Player.score);
  readkey;
end.
