unit LevelSys;
//----------------------------------------------------------------------------------------------------------------------
// Alex 'Shirson' Nevskiy 2012-08
//----------------------------------------------------------------------------------------------------------------------
interface

uses SysUtils, _render, classes;

type
  TCell = record
    Block: byte;   // Walls and floors (passability)
    WarFog: byte;  // Last seen
    Visible:byte;  // Cell is visible
    Blood: byte;   // Blood on the floor
    Entity: word;  // Who is in cell
    Item: byte;    // Item on the floor   2..50=$
    ID: word;      // RoomID;
  end;

  TLevel = array of array of TCell;

  TPoint = record
    X, Y:integer;
  end;

  TPointsAr= array of TPoint;

  TNear=record
    wl, no: byte;
  end;

  TRegion = record
    Area: cardinal;
    x, y: integer;
    Coord: TPointsAr;
  end;

const
  dirUp=			  $01;
  dirUpRight=		$02;
  dirRight=		  $04;
  dirDownRight=	$08;
  dirDown=		  $10;
  dirDownLeft=	$20;
  dirLeft=		  $40;
  dirUpLeft=		$80;
  dirAll =      $FF;
  dirCross = dirUp + dirRight + dirDown + dirLeft;

  blRight =12;
  blLeft  =13;
  blUp    =14;
  blDown  =15;
  blNone= 183;
  blNoneWF= 183-1;
  itmLife = 3;
  itmArmor = 4;
  itmAmmo =61; //+0 ShotGun; +1 MG; +2 Rocket;
  itmGuns = 50;//+0 ShotGun; +1 MG; +2 Rocket;
  itmInvul=2;

  blWall= 129;
  blWallWF= 129-1;
  blBedRock=130;

var
  Rooms : array of TRegion;
  Walls : array of TRegion;


procedure InitLevelGeometry(w,h:integer; Proportion:string; var Level:Tlevel );
procedure FractalZoom(grow:integer; OldLevel:TLevel; var NewLevel:Tlevel; var LevelW, LevelH:integer);
procedure RemoveNoiseEx(var Level:Tlevel);
procedure RemoveX(var Level:TLevel);
procedure ApplyDataLevel(var Level:TLevel);
procedure CreateLevel(var Width, Heigh: integer; ZoomStep, ZoomCount: integer; Proportion:string; var Level: TLevel);
function isValidCell(x, y :integer; var Level: TLevel):boolean;
function FoundDZ(var Level:TLevel):Tpoint;
function FoundEnd(var Level:TLevel):Tpoint;
function DeployItems(WallClose: byte; var Level:TLevel):Tpoint;
function DeployItemsEmp(var Level:TLevel):Tpoint;
procedure GetAround(x, y: integer; var Level:TLevel; out Square: TPointsAr; forMove:boolean=true);

function DeployEntity(AvoidX, AvoidY: integer; Distantion:integer; var Level:TLevel):Tpoint;
function BigestArea:cardinal;

function CoordEqual(Coord1, Coord2:Tpoint):boolean;
//procedure SaveArr(f:string; Level:Tlevel);

implementation
uses _math;


//----------------------------------------------------------------------------------------------------------------------

procedure GetAround(x, y: integer; var Level:TLevel; out Square: TPointsAr; forMove:boolean=true);

    procedure AddPoint(x0,y0:integer; var Square: TPointsAr);
    begin
      SetLength(Square, High(Square)+2);
      Square[High(Square)].X:=x0;
      Square[High(Square)].y:=y0;
    end;

    procedure CheckCell(x,y:integer);
    begin
      if (x<0) or (y<0) or (y>High(Level[0])) or (x>High(Level)) then exit;
      if (Level[x, y].Block in [blWall, blBedRock]) and forMove then exit;
      if (Level[x, y].Entity<>0) and forMove then exit;
      AddPoint(x,y, Square);
    end;

begin
  SetLength(Square,0);
  CheckCell(x  , y-1);
  CheckCell(x+1, y-1);
  CheckCell(x+1, y  );
  CheckCell(x+1, y+1);
  CheckCell(x  , y+1);
  CheckCell(x-1, y+1);
  CheckCell(x-1, y  );
  CheckCell(x-1, y-1);
end;

//----------------------------------------------------------------------------------------------------------------------

function GetCell(x, y: integer; var Level:TLevel; var res:TNear):boolean; overload;
begin
	result:=false;
  if (x<0) or (y<0) or (y>High(Level[0])) or (x>High(Level)) then exit;
  if (Level[x,y].Block=0) or (Level[x,y].Block=blNone) then
    inc(res.no)
  else
    inc(res.wl);
end;

//----------------------------------------------------------------------------------------------------------------------

function GetNear(x, y: integer; var Level:TLevel; Directions:byte=255):TNear;
begin
	result.wl:=0;
	result.no:=0;
  if Directions and dirUpLeft <>0   then GetCell(x-1, y-1, Level, result);
  if Directions and dirUp <>0       then GetCell(x,   y-1, Level, result);
  if Directions and dirUpRight <>0  then GetCell(x+1, y-1, Level, result);
  if Directions and dirLeft <>0     then GetCell(x-1, y  , Level, result);
  if Directions and dirRight <>0    then GetCell(x+1, y  , Level, result);
  if Directions and dirDownLeft <>0 then GetCell(x-1, y+1, Level, result);
  if Directions and dirDown <>0     then GetCell(x,   y+1, Level, result);
  if Directions and dirDownRight <>0then GetCell(x+1, y+1, Level, result);
end;


//----------------------------------------------------------------------------------------------------------------------

procedure InitLevelGeometry(w,h:integer; Proportion:string; var Level:Tlevel );
var a,b:integer;
const border=1;
begin
  SetLength(Level, w, h);
  FillChar(Level[0,0], SizeOf(Level), 0);

	for a:=0 to	w-1 do
    for b:=0 to h-1 do
   	begin
      if ((a<border) or (a>w-border-1)) or ((b<border) or (b>h-border-1)) then
      begin
        if a<border then Level[a, b].Block:=1;
        if a>w-border-1 then Level[a, b].Block:=1;
        if b<border then Level[a, b].Block:=1;
        if b>h-border-1 then Level[a, b].Block:=1;
      end
      else
      Level[a, b].Block:=strtoint(Proportion[random(length(proportion))+1]);
//      if random(cLnd)>=(cSpc) then
//        Level[a, b].Block:=1
//      else
//        Level[a, b].Block:=0;

    end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure FractalZoom(grow:integer; OldLevel:TLevel; var NewLevel:Tlevel; var LevelW, LevelH:integer);
var x_Old, y_old, x_new, y_new:integer;
	  tmp_fld:TLevel;
    res:TNear;
    h,w:integer;
begin
  LevelW:=LevelW*2;
  LevelH:=LevelH*2;

	w:=grow * (High(OldLevel)+1);
	h:=grow * (High(OldLevel[0])+1);

	setlength(NewLevel, w, h);
  setlength(tmp_fld, w, h);

  for x_New:=0 to High(NewLevel) do
    for y_New:=0 to High(NewLevel[0]) do
    begin
      x_old:=x_new div grow;
      y_old:=y_new div grow;
      tmp_fld[x_new, y_new]:=OldLevel[x_old, y_old];
    end;

  for x_New:=0 to High(NewLevel) do
    for y_New:=0 to High(NewLevel[0]) do
    begin
      res:=GetNear(x_new, y_new, tmp_fld);
      if tmp_fld[x_new, y_new].Block=0 then
        if random(12)+2<=res.wl then
          NewLevel[x_new, y_new].Block:=1
        else
          NewLevel[x_new, y_new].Block:=0;
      if tmp_fld[x_new, y_new].Block=1 then
       if random(12)+2<=res.no then
         NewLevel[x_new, y_new].Block:=0
       else
         NewLevel[x_new, y_new].Block:=1;
    end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure RemoveNoiseEx(var Level:Tlevel);
var x_new, y_new:integer;
	res:TNear;
	isDoAgain:boolean;
begin
  isDoAgain:=true;
  //pb.MaxValue:=High(lfld);
  while isDoAgain do
 	begin
    isDoAgain:=false;
    for x_New:=0 to High(Level) do
    begin
      //pb.Progress:=x_New;
      for y_New:=0 to High(Level[0]) do
      begin
//        res:=GetNeib(x_new, y_new, Level);
//        if (Level[x_new, y_new].Block=1) and (res.wl<=2) then  // Old version. Dont removes
//        begin                                                  //          ...
//          Level[x_new, y_new].Block:=0;                        //          .#.
//          isDoAgain:=true;                                     //          ###
//        end;
//        if (Level[x_new, y_new].Block=0) and (res.no<=2) then
//        begin
//          Level[x_new, y_new].Block:=1;
//          isDoAgain:=true;
//        end;

        res:=GetNear(x_new, y_new, Level);
        if (Level[x_new, y_new].Block=1) then                   // New version.
          if (res.wl <= 1) or ((res.no >=5) and (res.wl >=2)) then                 // $%#$@@%$!!! It's amazing! :)
          begin
            Level[x_new, y_new].Block:=0;
            isDoAgain:=true;
          end;

        if (Level[x_new, y_new].Block=0) then
          if (res.no <= 1) or ((res.wl >=5) and (res.no >=2)) then
          begin
            Level[x_new, y_new].Block:=1;
            isDoAgain:=true;
          end;
      end;
    end;
  end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure RemoveX(var Level:TLevel);            //
var res:TNear;                                  //  #.    .#    ..
    x,y :integer;                               //  .# or #. -> ..
begin                                           //
//	pb2.MaxValue:=High(TerrTypeAr);
  for x:=0 to High(Level) do
  begin
    //pb2.Progress:=x;
   	for y:=0 to High(Level[0]) do
    begin
      if Level[x,y].Block=1 then
      begin
        res:=GetNear(x,y, Level, dirRight + dirDown);
        if res.no=2 then
          begin
            res:=GetNear(x,y, Level, dirDownRight);
            if res.wl=1 then
            begin
              Level[x, y].Block:=0;
              Level[x+1,y+1].Block:=0;
            end;
          end;
      end;

      if Level[x,y].Block=0 then
      begin
        res:=GetNear(x,y, Level, dirRight + dirDown);
        if res.wl=2 then
          begin
            res:=GetNear(x,y, Level, dirDownRight);
            if res.no=1 then
            begin
              Level[x+1, y].Block:=0;
              Level[x,y+1].Block:=0;
            end;
          end;
      end;
    end;
  end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure ApplyDataLevel(var Level:TLevel);
var x,y:integer;
begin
  for x:=0 to High(Level) do
    for y:=0 to High(Level[0]) do
    case Level[x,y].Block of
      0: Level[x,y].Block:=blNone;
      1: Level[x,y].Block:=blWall;
      2: Level[x,y].Block:=blBedRock;
    end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure MakeBorder(var Level:TLevel);
var a, LevelW, LevelH :integer;
begin
  LevelW:=High(Level);
  LevelH:=High(Level[0]);
  for a:=0 to LevelW-1 do
  begin
    Level[a, 0].Block:=blBedRock;
    Level[a, LevelH-1].Block:=blBedRock;
  end;

  for a:=0 to LevelH-1 do
  begin
    Level[LevelW-1, a].Block:=blBedRock;
    Level[0, a].Block:=blBedRock;
  end;
end;

//----------------------------------------------------------------------------------------------------------------------

//procedure _MarkRooms(var Level:TLevel);
//var x, y, LevelW, LevelH :integer;
//    rGID, wGID, Area : integer;
//
////    procedure FillCell(x, y, block, ID:integer; var Area: integer; var Coord: TPointsAr);
////    begin
////      if (x>=0) and (y>=0) and (x<=LevelW) and (y<=LevelH) then
////        if (Level[x,y].Block=block) and (Level[x,y].ID=0) then
////        begin
////          Level[x,y].ID:=ID;
////          inc(Area);
////          SetLength(Coord, Area);
////          Coord[High(Coord)].x:=x;
////          Coord[High(Coord)].y:=y;
////          FillCell(x,y-1, block, ID, Area, Coord);
////          FillCell(x+1,y, block, ID, Area, Coord);
////          FillCell(x,y+1, block, ID, Area, Coord);
////          FillCell(x-1,y, block, ID, Area, Coord);
////        end;
////    end;
//
//    procedure FillCell(x, y, block, ID:integer; var Area: integer; var Coord: TPointsAr);
//    type  TFill = record
//            X, Y:integer;
//            toRemove:boolean;
//          end;
//    var FillAr: array of TFill;
//        var a, b, c:integer;
//    begin
//      SetLength(FillAr, 1);
//      FillAr[0].X:=x;
//      FillAr[0].Y:=y;
//      FillAr[0].toRemove:=false;
//      Level[FillAr[0].x, FillAr[0].y].ID:=ID;
//      while High(FillAr)>=0 do
//      begin
//        c:= High(FillAr);
//        for a:=0 to c do
//        begin
//          FillAr[a].toRemove:=true;
//          inc(Area);
//          SetLength(Coord, Area);
//          Coord[High(Coord)].x:=FillAr[a].x;
//          Coord[High(Coord)].y:=FillAr[a].y;
//          if isValidCell(FillAr[a].x, FillAr[a].y-1, Level) then
//            if (Level[FillAr[a].x, FillAr[a].y-1].Block = Block) and (Level[FillAr[a].x, FillAr[a].y-1].ID = 0) then
//            begin
//              Level[FillAr[a].x, FillAr[a].y-1].ID:=ID;
//              SetLength(FillAr, High(FillAr)+2);
//              FillAr[High(FillAr)].X:=FillAr[a].x;
//              FillAr[High(FillAr)].Y:=FillAr[a].y-1;
//              FillAr[High(FillAr)].toRemove:=false;
//            end;
//
//          if isValidCell(FillAr[a].x+1, FillAr[a].y, Level) then
//            if (Level[FillAr[a].x+1, FillAr[a].y].Block = Block) and (Level[FillAr[a].x+1, FillAr[a].y].ID = 0) then
//            begin
//              Level[FillAr[a].x+1, FillAr[a].y].ID:=ID;
//              SetLength(FillAr, High(FillAr)+2);
//              FillAr[High(FillAr)].X:=FillAr[a].x+1;
//              FillAr[High(FillAr)].Y:=FillAr[a].y;
//              FillAr[High(FillAr)].toRemove:=false;
//            end;
//
//          if isValidCell(FillAr[a].x, FillAr[a].y+1, Level) then
//            if (Level[FillAr[a].x, FillAr[a].y+1].Block = Block) and (Level[FillAr[a].x, FillAr[a].y+1].ID = 0) then
//            begin
//              Level[FillAr[a].x, FillAr[a].y+1].ID:=ID;
//              SetLength(FillAr, High(FillAr)+2);
//              FillAr[High(FillAr)].X:=FillAr[a].x;
//              FillAr[High(FillAr)].Y:=FillAr[a].y+1;
//              FillAr[High(FillAr)].toRemove:=false;
//            end;
//
//          if isValidCell(FillAr[a].x-1, FillAr[a].y, Level) then
//            if (Level[FillAr[a].x-1, FillAr[a].y].Block = Block) and (Level[FillAr[a].x-1, FillAr[a].y].ID = 0) then
//            begin
//              Level[FillAr[a].x-1, FillAr[a].y].ID:=ID;
//              SetLength(FillAr, High(FillAr)+2);
//              FillAr[High(FillAr)].X:=FillAr[a].x-1;
//              FillAr[High(FillAr)].Y:=FillAr[a].y;
//              FillAr[High(FillAr)].toRemove:=false;
//            end;
//        end;
//        b:=0;
//        for a:=0 to high(FillAr) do
//          if not FillAr[a].toRemove then
//          begin
//            FillAr[b]:=FillAr[a];
//            inc(b);
//          end;
//        setlength(FillAr,b);
//      end;
//    end;
//
//
//begin
//  LevelW:=High(Level);
//  LevelH:=High(Level[0]);
//  rGID:=1;
//  wGID:=1;
//  for x:=0 to LevelW do
//    for y:=0 to LevelH do
//    begin
//      if (Level[x,y].Block=0) and (Level[x,y].ID=0) then
//      begin
//        Area:=0;
//        SetLength(Rooms, rGID);
//        FillCell(x,y, 0, rGID, Area, Rooms[High(Rooms)].Coord);
//        Rooms[rGID].Area:= Area;
//        Rooms[rGID].x:= x;
//        Rooms[rGID].y:= y;
//        inc(rGID);
//      end;
//
//      if (Level[x,y].Block=1) and (Level[x,y].ID=0) then
//      begin
//        Area:=0;
//        SetLength(Walls, wGID);
//        FillCell(x,y, 1, wGID, Area, Walls[High(Walls)].Coord);
//        Walls[wGID].Area:= Area;
//        Walls[wGID].x:= x;
//        Walls[wGID].y:= y;
//        inc(wGID);
//      end;
//    end;
//end;


procedure MarkRooms(var Level:TLevel);
var x,y :integer;
    rGID, wGID, Area : integer;
    LevelW, LevelH:integer;

//    procedure FillCell(x, y, block, ID:integer; var Coord:  TPointsAr);
//    begin
//      if (x>=0) and (y>=0) and (x<LevelW) and (y<LevelH) then
//      if (Level[x,y].Block=block) and (Level[x,y].ID=0) then
//      begin
//        Level[x,y].ID:=ID;
//        inc(Area);
//        SetLength(Coord, Area);
//        Coord[Area-1].x:=x;
//        Coord[Area-1].y:=y;
//        FillCell(x,y-1, block, ID, Coord);
//        FillCell(x+1,y, block, ID, Coord);
//        FillCell(x,y+1, block, ID, Coord);
//        FillCell(x-1,y, block, ID, Coord);
//      end;
//    end;
    procedure FillCell(x, y, block, ID:integer; var Coord: TPointsAr);
    type  TFill = record
            X, Y:integer;
            toRemove:boolean;
          end;
    var FillAr: array of TFill;
        var a, b, c:integer;
    begin
      SetLength(FillAr, 1);
      FillAr[0].X:=x;
      FillAr[0].Y:=y;
      FillAr[0].toRemove:=false;
      Level[FillAr[0].x, FillAr[0].y].ID:=ID;
      while High(FillAr)>=0 do
      begin
        c:= High(FillAr);
        for a:=0 to c do
        begin
          FillAr[a].toRemove:=true;
          inc(Area);
          SetLength(Coord, Area);
          Coord[High(Coord)].x:=FillAr[a].x;
          Coord[High(Coord)].y:=FillAr[a].y;
          if isValidCell(FillAr[a].x, FillAr[a].y-1, Level) then
            if (Level[FillAr[a].x, FillAr[a].y-1].Block = Block) and (Level[FillAr[a].x, FillAr[a].y-1].ID = 0) then
            begin
              Level[FillAr[a].x, FillAr[a].y-1].ID:=ID;
              SetLength(FillAr, High(FillAr)+2);
              FillAr[High(FillAr)].X:=FillAr[a].x;
              FillAr[High(FillAr)].Y:=FillAr[a].y-1;
              FillAr[High(FillAr)].toRemove:=false;
            end;

          if isValidCell(FillAr[a].x+1, FillAr[a].y, Level) then
            if (Level[FillAr[a].x+1, FillAr[a].y].Block = Block) and (Level[FillAr[a].x+1, FillAr[a].y].ID = 0) then
            begin
              Level[FillAr[a].x+1, FillAr[a].y].ID:=ID;
              SetLength(FillAr, High(FillAr)+2);
              FillAr[High(FillAr)].X:=FillAr[a].x+1;
              FillAr[High(FillAr)].Y:=FillAr[a].y;
              FillAr[High(FillAr)].toRemove:=false;
            end;

          if isValidCell(FillAr[a].x, FillAr[a].y+1, Level) then
            if (Level[FillAr[a].x, FillAr[a].y+1].Block = Block) and (Level[FillAr[a].x, FillAr[a].y+1].ID = 0) then
            begin
              Level[FillAr[a].x, FillAr[a].y+1].ID:=ID;
              SetLength(FillAr, High(FillAr)+2);
              FillAr[High(FillAr)].X:=FillAr[a].x;
              FillAr[High(FillAr)].Y:=FillAr[a].y+1;
              FillAr[High(FillAr)].toRemove:=false;
            end;

          if isValidCell(FillAr[a].x-1, FillAr[a].y, Level) then
            if (Level[FillAr[a].x-1, FillAr[a].y].Block = Block) and (Level[FillAr[a].x-1, FillAr[a].y].ID = 0) then
            begin
              Level[FillAr[a].x-1, FillAr[a].y].ID:=ID;
              SetLength(FillAr, High(FillAr)+2);
              FillAr[High(FillAr)].X:=FillAr[a].x-1;
              FillAr[High(FillAr)].Y:=FillAr[a].y;
              FillAr[High(FillAr)].toRemove:=false;
            end;
        end;
        b:=0;
        for a:=0 to high(FillAr) do
          if not FillAr[a].toRemove then
          begin
            FillAr[b]:=FillAr[a];
            inc(b);
          end;
        setlength(FillAr,b);
      end;
    end;

begin
  rGID:=1;
  wGID:=1;
  LevelW:=High(Level)+1;
  LevelH:=High(Level[0])+1;
  for x:=0 to LevelW-1 do
    for y:=0 to LevelH-1 do
    begin
      if (Level[x,y].Block=0) and (Level[x,y].ID=0) then
      begin
        Area:=0;
        SetLength(Rooms, rGID+1);
        FillCell(x,y, 0, rGID, Rooms[rGID].Coord);
        Rooms[rGID].Area:= Area;
        Rooms[rGID].x:= x;
        Rooms[rGID].y:= y;
        inc(rGID);
      end;

      if (Level[x,y].Block=1) and (Level[x,y].ID=0) then
      begin
        Area:=0;
        SetLength(Walls, wGID+1);
        FillCell(x,y, 1, wGID, Walls[wGID].Coord);
        Walls[wGID].Area:= Area;
        Walls[wGID].x:= x;
        Walls[wGID].y:= y;
        inc(wGID);
      end;
    end;
end;

//----------------------------------------------------------------------------------------------------------------------

function FindLarger(Areal: array of TRegion): integer;
var Cnt, MaxArea: cardinal;
begin
  MaxArea:=0;
  result:=0;
  for Cnt:=0 to High(Areal) do
    if MaxArea < Areal[Cnt].Area then
    begin
      MaxArea:= Areal[Cnt].Area;
      result:=Cnt;
    end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure RenameBlocks (var Level:TLevel);
var x,y:integer;
begin
  for x:=0 to High(Level) do
    for y:=0 to High(Level[0]) do
    case Level[x,y].Block of
      0: Level[x,y].Block:=blNone;
      1: Level[x,y].Block:=blWall;
      2: Level[x,y].Block:=blBedRock;
    end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure CreateLevel(var Width, Heigh: integer; ZoomStep, ZoomCount: integer; Proportion:string; var Level: TLevel);
var a:integer;
begin
  InitLevelGeometry(Width, Heigh, Proportion, Level);
  for a:=1 to ZoomCount do
    FractalZoom(ZoomStep, Level, Level, Width, Heigh);
  RemoveNoiseEx(Level);
  RemoveX(Level);
  RemoveNoiseEx(Level);
  MakeBorder(Level);
  //SaveArr('Test', Level);
  MarkRooms(Level);
  RenameBlocks(Level);
  //SaveArr('Test', Level);

end;

//----------------------------------------------------------------------------------------------------------------------

function isValidCell(x, y :integer; var Level: TLevel):boolean;
begin
  result:=false;
  if x < 0 then exit;
  if y < 0 then exit;
  if x > High(Level) then exit;
  if y > High(Level[0]) then exit;
  result:=true;
end;

//----------------------------------------------------------------------------------------------------------------------

function FoundDZ(var Level:TLevel):Tpoint;
var Idx, Target:integer;
begin
  Idx:=FindLarger(Rooms);
  //Target:=random(Rooms[Idx].Area);
  Target:=0;
  result:=Rooms[Idx].Coord[Target];
end;

//----------------------------------------------------------------------------------------------------------------------

function FoundEnd(var Level:TLevel):Tpoint;
var Idx, Target:integer;
begin
  Idx:=FindLarger(Rooms);
  //Target:=random(Rooms[Idx].Area);
  Target:=High(Rooms[Idx].Coord);
  result:=Rooms[Idx].Coord[Target];
end;

//----------------------------------------------------------------------------------------------------------------------

function BigestArea:cardinal;
var Idx: integer;
begin
  Idx:=FindLarger(Rooms);
  result:=Rooms[Idx].Area;
end;

//----------------------------------------------------------------------------------------------------------------------

function DeployItems(WallClose: byte; var Level:TLevel):Tpoint;
var Idx, Target:integer;
    res:TNear;
begin
  Idx:=FindLarger(Rooms);
  repeat
    Target:=random(Rooms[Idx].Area);
    res:=GetNear(Rooms[Idx].Coord[Target].X, Rooms[Idx].Coord[Target].Y, Level);
    if Level[Rooms[Idx].Coord[Target].X, Rooms[Idx].Coord[Target].Y].Item <> 0 then continue;
  until res.wl >= WallClose;
  result:=Rooms[Idx].Coord[Target];
end;

//----------------------------------------------------------------------------------------------------------------------

function DeployItemsEmp(var Level:TLevel):Tpoint;
var Idx, Target:integer;
    res:TNear;
begin
  Idx:=FindLarger(Rooms);
  repeat
    Target:=random(Rooms[Idx].Area);
    res:=GetNear(Rooms[Idx].Coord[Target].X, Rooms[Idx].Coord[Target].Y, Level);
    if Level[Rooms[Idx].Coord[Target].X, Rooms[Idx].Coord[Target].Y].Item <> 0 then continue;
  until res.wl = 0;
  result:=Rooms[Idx].Coord[Target];
end;

//----------------------------------------------------------------------------------------------------------------------

function DeployEntity(AvoidX, AvoidY: integer; Distantion:integer; var Level:TLevel):Tpoint;
var Idx, Target:integer;
    //res:TNear;
    D:single;
    Ent:integer;
begin
  Idx:=FindLarger(Rooms);
  repeat
    Target:=random(Rooms[Idx].Area);
//    res:=GetNear(Rooms[Idx].Coord[Target].X, Rooms[Idx].Coord[Target].Y, Level);
    //if Level[Rooms[Idx].Coord[Target].X, Rooms[Idx].Coord[Target].Y].Entity <> 0 then continue;
    ent:=Level[Rooms[Idx].Coord[Target].X, Rooms[Idx].Coord[Target].Y].Entity;
    D:=Dist(AvoidX, AvoidY, Rooms[Idx].Coord[Target].X, Rooms[Idx].Coord[Target].y);
  until (D>=Distantion) and (ent=0);
  result:=Rooms[Idx].Coord[Target];
end;

//----------------------------------------------------------------------------------------------------------------------

procedure SaveArr(f:string; Level:Tlevel);
var x,y :integer;
	TSL:TStringList;
    s:string;
begin
	TSL:=TStringList.Create;
  	for y:=0 to High(Level[0]) do
    begin
      s:='';
      for x:=0 to  High(Level) do
				if (Level[x,y].Block<>blNone) and (Level[x,y].Block<>0)  then s:=s+'#' else s:=s+'.';
        TSL.Add(s);
    end;
//    if High(Rooms)>0 then
//    for x:=0 to High(Rooms) do
//      TSL.Add(Chr(x+48)+' Area:'+ inttostr(Rooms[x].Area)+' Coord:'+inttostr(Rooms[x].x)+':'+inttostr(Rooms[x].y));
//    TSL.Add('');
//    if High(Walls)>0 then
//
//    for x:=0 to High(Walls) do
//      TSL.Add(Chr(x+192)+' Area:'+ inttostr(Walls[x].Area)+' Coord:'+inttostr(Walls[x].x)+':'+inttostr(Walls[x].y));

//  for y:=0 to TotalH-1 do
//  begin
//    s:='';
//    for x:=0 to TotalW-1 do
//    begin
//      s:=s+chr(GUIMatrix[x,y].Ch);
//    end;
//    TSL.Add(s);
//  end;

    TSL.SaveToFile(f);
    TSL.free;
end;

//----------------------------------------------------------------------------------------------------------------------

function CoordEqual(Coord1, Coord2:Tpoint):boolean;
begin
  result:=(Coord1.X = Coord2.X) and (Coord1.Y = Coord2.Y);
end;

//----------------------------------------------------------------------------------------------------------------------


end.

