program a2mview;
uses dos,mouse,crt; {Unit mouse is the same as the unit 02mouse}

type PArea=^TArea;
     TArea=object {This is an object on which is the whole program based}
      X1,Y1,X2,Y2:word;
      nextA:PArea; {This points to the next area which is in the same region}
      color:byte;
      constructor Init(Ax1,Ay1,Ax2,Ay2:word;Acolor:byte);
      function Inside(x,y:word):boolean; {This checks whether the point is
                                          inside the area}
      procedure Show;                    {This shows the area on the screen}
      procedure SBorder(scroll:byte);    {This draws the border of the area}
      destructor Done;
     end;

     PRegion=^TRegion;
     TRegion=object
      index:byte;
      FirstA:PArea;     {Pointer to the first area of all which are owned by
                         region}
      nextR:PRegion;    {Points to the next region in the map}
      constructor Init(Aindex:byte);
      procedure Insert(Ap:PArea); {Here is an area assigned to the region}
      procedure Show;             {Draws the whole region (all the areas)}
      procedure SBorder(scroll:byte);{Draws the border of the region}
      function Inside(x,y:word):boolean;{This is similar as the previous one}
      destructor Done;
     end;

    TMap=object
      Level:byte;  {This is here just to keep the form, but it isn't used
                    in this program. The program uses all the data in the
                    same way.}
      firstR:PRegion; {Points to the first region of all which are owned by
                       Map.}
      constructor Load(var f:text);
      procedure Show;
      function Where(x,y:word):PRegion;{Returns the pointer of region which
                                        contains point [x,y].}
      destructor Done;
     end;

{Methods of TMap}
{*****************************************}
constructor TMap.Load;
var HlpLine:string;
    c:integer;     {some helping variable}
    l:array[1..4] of word;{hlp. var.}
    ind,i,ii,r:byte;      {-||-}
    p:PRegion;            {-||-}
begin
 FirstR:=nil;
 ReadLn(f,HlpLine);
 if copy(HlpLine,1,4)<>'MDF/' then
  begin writeln('There is an error in the file');exit end else
                                            {I think we could suppose that
                                             the bad files will not be used}
 val(HlpLine[5],Level,c);
 while not eof(f) do
  begin


   ReadLn(f,HlpLine);
   i:=2;
   while HlpLine[i]<>' ' do
    inc(i);
   val(copy(HlpLine,1,i-1),ind,c); {We have to check the index}

   for r:=1 to 4 do
    begin
     inc(i);
     ii:=i;
     while (HlpLine[i]<>' ') and (i<=length(HlpLine)) do
      inc(i);
     val(copy(HlpLine,ii,i-ii),l[r],c);
    end;

  if FirstR=nil then begin
                      FirstR:=new(PRegion,Init(ind));
                      p:=FirstR;
                     end
              else
   begin
    p:=FirstR;
    while (p^.index<>ind) and (p^.nextR<>nil) do
     p:=p^.nextR;
   end;
   if p^.index<>ind then begin
                          p^.nextR:=new(PRegion,Init(ind));
                          p:=p^.nextR;
                         end;
   if p^.index=ind then p^.Insert(New(PArea,Init(l[1],l[2],l[3],l[4],p^.index)));
 end; {of while}
end;

procedure TMap.Show;
var p:PRegion;
begin
 p:=firstR;
 while p<>nil do
  begin
   P^.show;
   p:=p^.nextR;
  end;
end;

function TMap.Where;
var p:PRegion;
begin
 p:=firstR;
 while (p<>nil) and (not p^.Inside(x,y)) do
  p:=p^.nextR;
 Where:=p;
end;

destructor TMap.Done;
var p,c:PRegion;
begin
 p:=firstR;
 while P<>nil do
  begin
   c:=p;
   P:=p^.nextR;
   dispose(c,done);
  end;
end;


{Methods of TArea}
{*************************************************}
constructor TArea.Init;
begin
 {if Ax1<320 then}
  X1:=Ax1;
 {if Ay1<200 then}
  Y1:=Ay1;
{ if Ax2<=X1 then}
  X2:=Ax2;
{ if Ay2<=y1 then}
  Y2:=Ay2;
 color:=Acolor;
 nextA:=nil;
end;

procedure TArea.Show;
var columns:word;
    i:byte;
begin
 columns:=X2-X1+1;
 for i:=Y1 to Y2 do
  fillchar(mem[$A000:i*320+x1],columns,color);
end;

procedure TArea.SBorder;
var i,ii:word;
begin
 for i:=x1 to x2 do
  begin
   ii:=scroll+i;
   if (mem[$A000:(y1-1)*320+i]<>color)  and
      not (mem[$A000:(y1-1)*320+i] in[240..255]) then
   mem[$A000:y1*320+i]:=ii mod 14+240;
  end;
 for i:=y1 to y2 do
  begin
   ii:=scroll+i;
   if (mem[$A000:i*320+x2+1]<>color) and
      not (mem[$A000:i*320+x2+1] in[240..254])  then
   mem[$A000:i*320+x2]:=ii mod 14+240;
  end;
 for i:=x2 downto x1 do
  begin
   ii:=scroll+i;
   if (mem[$A000:(y2+1)*320+i]<>color)  and
      not (mem[$A000:(y2+1)*320+i] in[240..254]) then
   mem[$A000:y2*320+i]:=ii mod 14+240;
  end;
 for i:=y2 downto y1 do
  begin
   ii:=scroll+i;
   if (mem[$A000:i*320+x1-1]<>color) and
      not (mem[$A000:i*320+x1-1] in[240..255]) then
   mem[$A000:i*320+x1]:=ii mod 14+240;
  end;
end;

function TArea.Inside;
begin
 Inside:=false;
 if (x>=X1) and (x<=X2) and
    (y>=Y1) and (y<=Y2) then
   Inside:=true
end;

destructor TArea.Done;
begin
end;


{Methods of TRegion}
{**********************************************}
constructor TRegion.Init;
begin
 Index:=AIndex;
 nextR:=nil;
 firstA:=nil;
end;

destructor TRegion.Done;
var p,c:PArea;
begin
 p:=firstA;
 while p<>nil do
  begin
   c:=p;
   p:=p^.nextA;
   dispose(p,done);
  end;
end;



procedure TRegion.Insert;
var p:PArea;
begin
 if firstA=nil then firstA:=Ap else
  begin
   p:=firstA;
    while p^.nextA<>nil do
     p:=p^.nextA;
   p^.nextA:=Ap;
  end
end;


procedure TRegion.Show;
var p:PArea;
begin
 p:=firstA;
 while p<>nil do
  begin
   p^.Show;
   p:=p^.nextA;
  end;
end;

procedure TRegion.SBorder;
var p:PArea;
begin
 p:=firsta;
 while p<>nil do
  begin
   p^.SBorder(scroll);
   p:=p^.nextA;
  end;
end;

function TRegion.Inside;
var p:PArea;
    result:boolean;
begin
 p:=firstA;
 while (p<>nil) and (not result) do
  begin
   result:=p^.Inside(x,y);
   p:=p^.nextA;
  end;
 Inside:=result;
end;
{********************************************}


var df:text;
    Map:TMap;
    Pal:Array[0..255] of record
                           r,g,b:byte;
                          end;
    i:byte;
    r:registers;
    k:char;
    mx,my:word;
    leftbut:boolean;
    Region:PRegion;
begin
  if ParamCount<>1 then writeln('Usage : 02mview file.mfd');
 {$I-}
  assign(df,ParamStr(1));
  reset(df);
  if IOResult<>0 then
   begin
    writeln('Error: You have written bad name of map file.');
    exit;
   end;
 {$I+}
 Map.Load(df);
 close(df);

 asm
  mov ah,0
  mov al,19
  int 10h
 end;
 Pal[0].r:=0;
 Pal[0].g:=0;
 Pal[0].b:=0;
 Pal[255].r:=255;
 Pal[255].g:=255;
 Pal[255].b:=255;
 for i:=1 to 239 do
  begin
   Pal[i].r:=((i shr 5)*255) div 7;
   Pal[i].g:=(((i shr 2) and 7)*255) div 7;
   Pal[i].b:=(i and 3) *255 div 3;
  end;
 for i:=240 to 254 do
  begin
   Pal[i].r:=(i-239)*17;
   Pal[i].g:=(i-239)*17;
   Pal[i].b:=(i-239)*17;
  end;
  r.ax:=$1012;
  r.bx:=0;
  r.cx:=256;
  r.es:=seg(Pal);
  r.dx:=ofs(Pal);
  intr($10,r);


 Map.Show;
 COn;
 i:=0;
 region:=nil;
 repeat
  inc(i);
  MStatus(mx,my,leftbut);
  if leftbut then
   begin
    COff;
    if Region<>nil then Region^.show;
    COn;
    Region:=nil;
    Region:=Map.Where(mx div 2,my);
   end;
  if Region<>nil then begin COff;Region^.SBorder(i);COn;end;

  if keypressed then k:=readkey;
 until k=#27;
 Map.Done;
{I have to excuse me that I didn't keep the object structure of the program
 to the end, but I think it doesn't influence the function of the program.}
end.