anchor.diff:    MIN_SCAN_DIST_FROM_HOUSE = 2; // Houses must have at least 1 tile of space between them
   
   var
  -  GA_EYE_GetForests_SPRndOwnLimMin : Single = 52.91167;
  -  GA_EYE_GetForests_SPRndOwnLimMax : Single = 237.3961;
  -  GA_EYE_GetForests_AddRndPosition : Single = 15.86685;
  -  GA_EYE_GetForests_RndCount       : Single = 10;
  -  GA_EYE_GetForests_RndLimit       : Single = 0.62351;
  -  GA_EYE_GetForests_InflLimit      : Single = 220.5552;
  -  GA_EYE_GetForests_MinTrees       : Single = 3.11;
  -  GA_EYE_GetForests_Radius         : Single = 5.0698;
  -  GA_EYE_GetForests_MinRndSoil     : Single = 15.969; //0<->25
  +  GA_EYE_GetForests_SPRndOwnLimMin : Single = 50.40101;
  +  GA_EYE_GetForests_SPRndOwnLimMax : Single = 239.6274;
  +  GA_EYE_GetForests_AddRndPosition : Single = 18.87446;
  +  GA_EYE_GetForests_RndCount       : Single = 8.2571;
  +  GA_EYE_GetForests_RndLimit       : Single = 0.841865;
  +  GA_EYE_GetForests_InflLimit      : Single = 204.4068;
  +  GA_EYE_GetForests_MinTrees       : Single = 3.1580;
  +  GA_EYE_GetForests_Radius         : Single = 5.2813;
  +  GA_EYE_GetForests_MinRndSoil     : Single = 16.66946; //0<->25
   
   
   type
  
positive.code: begin
    inherited Create();
    fUpdateTick := 0;
    fLocs := TKMPointList.Create();
  end;
  
  
negative.code: begin
    LoadStream.ReadAssert('Eye');
    LoadStream.Read(fOwner);
    LoadStream.Read(fMapX);
    LoadStream.Read(fMapY);
  
    fGoldMines.LoadFromStream(LoadStream);
    fIronMines.LoadFromStream(LoadStream);
    fStoneMiningTiles.LoadFromStream(LoadStream);
  
    LoadByteArr(fSoil);
    LoadByteArr(fRoutes);
    LoadByteArr(fFlatArea);
    LoadByteArr(fCoalPolygons);
  
    fArmyEvaluation.Load(LoadStream);
  end;
  
  
  function TKMEye.GetSoil(const aY,aX: Word): Byte;
  begin
    Result := fSoil[aY*fMapX + aX];
  end;
  procedure TKMEye.SetSoil(const aY,aX: Word; const aValue: Byte);
  begin
    fSoil[aY*fMapX + aX] := aValue;
  end;
  
  function TKMEye.GetRoutes(const aY,aX: Word): Byte;
  begin
    Result := fRoutes[aY*fMapX + aX];
  end;
  procedure TKMEye.SetRoutes(const aY,aX: Word; const aValue: Byte);
  begin
    fRoutes[aY*fMapX + aX] := aValue;
  end;
  
  function TKMEye.GetFlatArea(const aY,aX: Word): Byte;
  begin
    Result := fFlatArea[aY*fMapX + aX];
  end;
  procedure TKMEye.SetFlatArea(const aY,aX: Word; const aValue: Byte);
  begin
    fFlatArea[aY*fMapX + aX] := aValue;
  end;
  
  
  procedure TKMEye.AfterMissionInit();
    procedure GeneralizeArray(var aArr: TKMByteArray);
    const
      RADIUS = 4;
    var
      X,Y,Y2,X2,Idx: Integer;
      CopyArr: TKMByteArray;
    begin
      SetLength(CopyArr, Length(aArr));
      Move(aArr[0],CopyArr[0],Sizeof(aArr[0])*Length(aArr));
  
      for Y := 1 to fMapY - 1 do
      for X := 1 to fMapX - 1 do
      begin
        Idx := Y*fMapX + X;
        for Y2 := Max(1, Y-RADIUS) to Min(fMapY-1, Y+RADIUS) do
        for X2 := Y2*fMapX + Max(1, X-RADIUS) to Y2*fMapX + Min(fMapX-1, X+RADIUS) do
          Inc(aArr[Idx], CopyArr[X2]);
      end;
  
    //  for Y := 1 to 1+RADIUS-1 do
    //  for X := 1 to 1+RADIUS do
    //    Inc(aArr[1*fMapX + 1], CopyArr[Y*fMapX + X]);
    //  for Y := 1 to fMapY - 1 do
    //  begin
    //    Idx := Y*fMapX + 1;
    //    aArr[Idx] := aArr[Max(Y-1,1)*fMapX + 1];
    //    if (Y-RADIUS-1 > 0) then
    //      for X := 1 to 1+RADIUS do
    //        Dec(aArr[Idx], CopyArr[(Y-RADIUS-1)*fMapX + X]);
    //    if (Y+RADIUS < fMapY) then
    //      for X := 1 to 1+RADIUS do
    //        Inc(aArr[Idx], CopyArr[(Y+RADIUS)*fMapX + X]);
    //
    //    for X := 2 to fMapX - 1 do
    //    begin
    //      Idx := Y*fMapX + X;
    //      aArr[Idx] := aArr[Idx-1];
    //      if (X-RADIUS-1 > 0) then
    //        for Y2 := Max(1,Y-RADIUS) to Min(fMapY-1,Y+RADIUS) do
    //          Dec(aArr[Idx], CopyArr[Y2*fMapX + X-RADIUS-1]);
    //      if (X+RADIUS < fMapY) then
    //        for Y2 := Max(1,Y-RADIUS) to Min(fMapY-1,Y+RADIUS) do
    //          Inc(aArr[Idx], CopyArr[Y2*fMapX + X+RADIUS]);
    //    end;
    //  end;
    end;
  var
    X,Y: Integer;
    Time: Cardinal;
    Loc: TKMPoint;
  begin
    Time := TimeGet();
    fMapX := gTerrain.MapX;
    fMapY := gTerrain.MapY;
    SetLength(fCoalPolygons, Length(gAIFields.NavMesh.Polygons));
    FillChar(fCoalPolygons[0], SizeOf(fCoalPolygons[0]) * Length(fCoalPolygons), #0);
  
    SetLength(fSoil, fMapX * fMapY);
    SetLength(fRoutes, fMapX * fMapY);
    SetLength(fFlatArea, fMapX * fMapY);
    FillChar(fSoil, fSoil[0] * Length(fSoil), #0);
    FillChar(fRoutes, fRoutes[0] * Length(fRoutes), #0);
    FillChar(fFlatArea, fFlatArea[0] * Length(fFlatArea), #0);
  
    for Y := 1 to fMapY - 1 do
    for X := 1 to fMapX - 1 do
    begin
      Loc := KMPoint(X,Y);
      FlatArea[Y,X] := Byte(gTerrain.TileIsWalkable(Loc));
      if gTerrain.TileIsSoil(X,Y) then
        Soil[Y,X] := 1
      else if (gTerrain.TileIsCoal(X,Y) > 1) then
      begin
        Inc(fCoalPolygons[  gAIFields.NavMesh.KMPoint2Polygon[ Loc ]  ]);
      end
      else if gTerrain.TileHasStone(X,Y) then
      begin
        if (Y < fMapY - 1) AND (tpWalk in gTerrain.Land[Y+1,X].Passability) then
          fStoneMiningTiles.Add(KMPoint(X,Y));
      end
      else if CanAddHousePlan(Loc, htGoldMine, True, False) then
      begin
        if CheckResourcesNearMine(Loc, htGoldMine) then
          fGoldMines.Add(Loc);
      end
      else if CanAddHousePlan(Loc, htIronMine, True, False) then
      begin
        if CheckResourcesNearMine(Loc, htIronMine) then
          fIronMines.Add(Loc);
      end;
    end;
    GeneralizeArray(fSoil);
    GeneralizeArray(fFlatArea);
    Time := TimeGet() - Time;
  end;
  
  
  