anchor.diff:  //Render debug symbols
   procedure TKMInfluences.Paint(aRect: TKMRect);
   var
  -  I, K, J: Integer;
  +  PL, WatchedPL: TKMHandIndex;
  +  I, Cnt: Word;
  +  X,Y: Integer;
  +  PolyArr: TPolygonArray;
  +  NodeArr: TNodeArray;
     Col: Cardinal;
   begin
  -  if not AI_GEN_INFLUENCE_MAPS then Exit;
  -
  -  if OVERLAY_INFLUENCE then
  -    for I := aRect.Top to aRect.Bottom do
  -    for K := aRect.Left to aRect.Right do
  +  if not AI_GEN_NAVMESH OR not AI_GEN_INFLUENCE_MAPS then
  +    Exit;
  +
  +  if OVERLAY_AVOID then
  +    for Y := aRect.Top to aRect.Bottom do
  +    for X := aRect.Left to aRect.Right do
       begin
  -      Col := $80000000;
  -      J := GetBestOwner(K,I);
  -      if J <> PLAYER_NONE then
  -        Col := (gHands[J].FlagColor and $FFFFFF) or (Influence[J,I,K] shl 24);
  -      gRenderAux.Quad(K, I, Col);
  +      Col := AvoidBuilding[Y,X] * 65793 OR $80000000;
  +      gRenderAux.Quad(X, Y, Col);
       end;
   
  -  if OVERLAY_OWNERSHIP then
  -    for I := aRect.Top to aRect.Bottom do
  -    for K := aRect.Left to aRect.Right do
  +  if OVERLAY_INFLUENCE OR OVERLAY_OWNERSHIP then
  +  begin
  +    PolyArr := fNavMesh.Polygons;
  +    NodeArr := fNavMesh.Nodes;
  +    for I := 0 to fPolygons - 1 do
       begin
  -      Col := $80000000;
  -      J := GetBestOwner(K,I);
  -      if J <> PLAYER_NONE then
  -        Col := (gHands[J].FlagColor and $FFFFFF)
  -                or (Ownership[J,I,K] shl 24)
  -                or ((Byte(InRange(Ownership[J,I,K], OWN_THRESHOLD, OWN_MARGIN)) * 255) shl 24);
  -      gRenderAux.Quad(K, I, Col);
  +      PL := GetBestOwner(I);
  +      if (PL = PLAYER_NONE) then
  +        continue
  +      else
  +        Col := (gHands[PL].FlagColor AND $FFFFFF) OR (OwnPoly[PL,I] shl 24);
  +
  +      //NavMesh polys coverage
  +      gRenderAux.TriangleOnTerrain(
  +        NodeArr[PolyArr[I].Indices[0]].Loc.X,
  +        NodeArr[PolyArr[I].Indices[0]].Loc.Y,
  +        NodeArr[PolyArr[I].Indices[1]].Loc.X,
  +        NodeArr[PolyArr[I].Indices[1]].Loc.Y,
  +        NodeArr[PolyArr[I].Indices[2]].Loc.X,
  +        NodeArr[PolyArr[I].Indices[2]].Loc.Y, Col);
       end;
  -
  -  if OVERLAY_AVOID then
  -    for I := aRect.Top to aRect.Bottom do
  -    for K := aRect.Left to aRect.Right do
  +  end;
  +
  +  if OVERLAY_AI_COMBAT then
  +  begin
  +    WatchedPL := gMySpectator.HandIndex;
  +    if (WatchedPL = PLAYER_NONE) then
  +      Exit;
  +
  +    PolyArr := fNavMesh.Polygons;
  +    NodeArr := fNavMesh.Nodes;
  +
  +    for PL := 0 to gHands.Count - 1 do
       begin
  -      Col := AvoidBuilding[I,K] * 65793 or $80000000;
  -      gRenderAux.Quad(K, I, Col);
  +      if (WatchedPL = PL) then
  +        Col := $0000FF00 // Green
  +      else if (gHands[WatchedPL].Alliances[PL] = at_Ally) then
  +        Col := $00FF0000 // Blue
  +      else
  +        Col := $000000FF; // Red
  +
  +      for I := 0 to fPolygons - 1 do
  +      begin
  +        Cnt := PresenceAllGroups[PL,I];
  +        if (Cnt > 0) then
  +        begin
  +          Cnt := Min(Cnt,$5F);
  +          //NavMesh polys coverage
  +          gRenderAux.TriangleOnTerrain(
  +            NodeArr[PolyArr[I].Indices[0]].Loc.X,
  +            NodeArr[PolyArr[I].Indices[0]].Loc.Y,
  +            NodeArr[PolyArr[I].Indices[1]].Loc.X,
  +            NodeArr[PolyArr[I].Indices[1]].Loc.Y,
  +            NodeArr[PolyArr[I].Indices[2]].Loc.X,
  +            NodeArr[PolyArr[I].Indices[2]].Loc.Y, (Col OR (Cnt shl 24)) ); // (Col OR $50000000)
  +        end;
  +      end;
       end;
  -end;
  -
  +    //for I := 0 to fPolygons - 1 do
  +    //begin
  +    //  BestCnt := 0;
  +    //  for PL := 0 to gHands.Count - 1 do
  +    //  begin
  +    //    Cnt := PresenceAllGroups[PL,I];
  +    //    if (Cnt > BestCnt) then
  +    //    begin
  +    //      BestCnt := Cnt;
  +    //      if (WatchedPL = PL) then
  +    //        Col := $0000FF00 // Green
  +    //      else if (gHands[WatchedPL].Alliances[PL] = at_Ally) then
  +    //        Col := $00FF0000 // Blue
  +    //      else
  +    //        Col := $000000FF; // Red
  +    //    end;
  +    //  end;
  +    //  if (BestCnt > 0) then
  +    //  begin
  +    //    BestCnt := Min(BestCnt,$9F);
  +    //    //NavMesh polys coverage
  +    //    gRenderAux.TriangleOnTerrain(
  +    //      NodeArr[PolyArr[I].Indices[0]].Loc.X,
  +    //      NodeArr[PolyArr[I].Indices[0]].Loc.Y,
  +    //      NodeArr[PolyArr[I].Indices[1]].Loc.X,
  +    //      NodeArr[PolyArr[I].Indices[1]].Loc.Y,
  +    //      NodeArr[PolyArr[I].Indices[2]].Loc.X,
  +    //      NodeArr[PolyArr[I].Indices[2]].Loc.Y, (Col OR (BestCnt shl 24)) );
  +    //  end;
  +    //end;
  +  end;
  +end;
   
   end.
  
positive.code:       end;
    end;
  var
    S: TKMHouse;
    I, K, J: Integer;
  begin
    //Avoid areas where Gold/Iron mines should be
    for I := 3 to fMapY - 2 do
    for K := 2 to fMapX - 2 do
      if gTerrain.CanPlaceHouse(KMPoint(K,I), ht_IronMine) then
        CheckAndMarkMine(K,I, ht_IronMine)
      else if gTerrain.CanPlaceHouse(KMPoint(K,I), ht_GoldMine) then
        CheckAndMarkMine(K,I, ht_GoldMine);
  
    //Avoid Coal fields
    for I := 1 to fMapY - 1 do
    for K := 1 to fMapX - 1 do
     AvoidBuilding[I,K] := AvoidBuilding[I,K] or (Byte(gTerrain.TileIsCoal(K, I) > 1) * $FF);
  
    //Leave free space BELOW all players Stores
    for J := 0 to gHands.Count - 1 do
    begin
      S := gHands[J].FindHouse(ht_Store);
      if (S <> nil) then
      for I := Max(S.Entrance.Y + 1, 1) to Min(S.Entrance.Y + 2, fMapY - 1) do
      for K := Max(S.Entrance.X - 1, 1) to Min(S.Entrance.X + 1, fMapX - 1) do
        AvoidBuilding[I,K] := AvoidBuilding[I,K] or $FF;
    end;
  end;
  
  
  procedure TKMInfluences.InitInfluenceOwnable;
  var
    I, K: Integer;
  begin
    if not AI_GEN_INFLUENCE_MAPS then Exit;
  
    for I := 1 to fMapY - 1 do
    for K := 1 to fMapX - 1 do
      Ownable[I,K] := (tpOwn in gTerrain.Land[I,K].Passability);
  end;
  
  
  procedure TKMInfluences.UpdateDirectInfluence(aIndex: TKMHandIndex);
    procedure DoFill(X,Y: Word; V: Byte);
    begin
      if  (V > Influence[aIndex, Y, X])
      and (Ownable[Y,X]) then
      begin
        Influence[aIndex, Y, X] := V;
        if V - INFLUENCE_DECAY <= 0 then Exit;
  
        if Y-1 >= 1       then DoFill(X, Y-1, V - INFLUENCE_DECAY);
        if X-1 >= 1       then DoFill(X-1, Y, V - INFLUENCE_DECAY);
        if X+1 <= fMapX-1 then DoFill(X+1, Y, V - INFLUENCE_DECAY);
        if Y+1 <= fMapY-1 then DoFill(X, Y+1, V - INFLUENCE_DECAY);
  
        //We can get away with 4-tap fill, it looks fine already
        //Diagonals passages are uncommon and don't matter that much for influence
        {if V - INFLUENCE_DECAY_D <= 0 then Exit;
        DoFill(X-1, Y-1, V - INFLUENCE_DECAY_D);
        DoFill(X+1, Y-1, V - INFLUENCE_DECAY_D);
        DoFill(X-1, Y+1, V - INFLUENCE_DECAY_D);
        DoFill(X+1, Y+1, V - INFLUENCE_DECAY_D);}
      end;
    end;
  var
    I, K: Integer;
    P: TKMPoint;
    PlayerHouses: TKMHousesCollection;
  begin
    if not AI_GEN_INFLUENCE_MAPS then Exit;
    Assert(gTerrain <> nil);
  
    //Clear
    for I := 1 to fMapY - 1 do
    for K := 1 to fMapX - 1 do
      Influence[aIndex, I, K] := 0;
  
    //Sync tile ownership
    PlayerHouses := gHands[aIndex].Houses;
    for I := 0 to PlayerHouses.Count - 1 do
    if not PlayerHouses[I].IsDestroyed and (PlayerHouses[I].HouseType <> ht_WatchTower) then
    begin
      P := PlayerHouses[I].GetPosition;
      //Expand influence with faloff
      DoFill(P.X, P.Y, 255);
    end;
  end;
  
  
  procedure TKMInfluences.UpdateOwnershipInfluence(aIndex: TKMHandIndex);
  var
    I, K, H: Integer;
    T: Integer;
  begin
    if not AI_GEN_INFLUENCE_MAPS then Exit;
    Assert(gTerrain <> nil);
  
    //Fill Ownership map
    //Ownerhip = influence of player - influences of his enemies
    for I := 1 to fMapY - 1 do
    for K := 1 to fMapX - 1 do
    begin
      T := Influence[aIndex, I, K];
      if T <> 0 then
      begin
        for H := 0 to gHands.Count - 1 do
        if gHands[aIndex].Alliances[H] = at_Enemy then
          T := T - Influence[H, I, K] div INFLUENCE_ENEMY_DIV;
  
        Ownership[aIndex, I, K] := Max(T, 0);
      end
      else
        Ownership[aIndex, I, K] := 0;
    end;
  
    //Normalization is not working as intended,
    //it gives unfair advantage to one using it,
    //muting neighbours areas beyond reason
  end;
  
  
  procedure TKMInfluences.ExportInfluenceMaps;
  var
    I, J, K: Integer;
  begin
    for J := 0 to gHands.Count - 1 do
    with TBitmap.Create do
    begin
      Width := fMapX;
      Height:= fMapY;
      PixelFormat := pf32bit;
      for I := 0 to Height-1 do
        for K := 0 to Width-1 do
          Canvas.Pixels[K,I] := Influence[J, I, K];
      SaveToFile(ExeDir + 'Export\Influence map Player'+IntToStr(J) + '.bmp');
    end;
  
    for J := 0 to gHands.Count - 1 do
    with TBitmap.Create do
    begin
      Width := fMapX;
      Height:= fMapY;
      PixelFormat := pf32bit;
      for I := 0 to Height-1 do
        for K := 0 to Width-1 do
          Canvas.Pixels[K,I] := Influence[J, I, K];
      SaveToFile(ExeDir + 'Export\Influence map Player'+IntToStr(J) + '.bmp');
    end;
  end;
  
  
  procedure TKMInfluences.Save(SaveStream: TKMemoryStream);
  var
    PCount: Word;
    K: Integer;
  begin
    PCount := gHands.Count;
  
    SaveStream.WriteA('Influences');
  
    SaveStream.Write(PCount);
    SaveStream.Write(fMapX);
    SaveStream.Write(fMapY);
    SaveStream.Write(fUpdatePlayerId);
  
    SaveStream.Write(fInfluence[0], fMapX * fMapY * PCount * SizeOf(fInfluence[0]));
    SaveStream.Write(fOwnership[0], fMapX * fMapY * PCount * SizeOf(fOwnership[0]));
  
    for K := 0 to fMapY - 1 do
      SaveStream.Write(AvoidBuilding[K,0], fMapX * SizeOf(AvoidBuilding[0,0]));
  
    for K := 0 to fMapY - 1 do
      SaveStream.Write(Ownable[K,0], fMapX * SizeOf(Ownable[0,0]));
  end;
  
  
  procedure TKMInfluences.Load(LoadStream: TKMemoryStream);
  var
    PCount: Word;
    K: Integer;
  begin
    LoadStream.ReadAssert('Influences');
  
    LoadStream.Read(PCount);
    LoadStream.Read(fMapX);
    LoadStream.Read(fMapY);
    LoadStream.Read(fUpdatePlayerId);
  
    SetLength(fInfluence, PCount * fMapY * fMapX);
    SetLength(fOwnership, PCount * fMapY * fMapX);
    SetLength(AvoidBuilding, fMapY, fMapX);
    SetLength(Ownable, fMapY, fMapX);
  
    LoadStream.Read(fInfluence[0], fMapX * fMapY * PCount * SizeOf(fInfluence[0]));
    LoadStream.Read(fOwnership[0], fMapX * fMapY * PCount * SizeOf(fOwnership[0]));
  
    for K := 0 to fMapY - 1 do
      LoadStream.Read(AvoidBuilding[K,0], fMapX * SizeOf(AvoidBuilding[0,0]));
  
    for K := 0 to fMapY - 1 do
      LoadStream.Read(Ownable[K,0], fMapX * SizeOf(Ownable[0,0]));
  end;
  
  
  procedure TKMInfluences.UpdateState(aTick: Cardinal);
  begin
    //Update one player every 15 sec
    if aTick mod 150 = 15 then
    begin
      fUpdatePlayerId := (fUpdatePlayerId + 1) mod gHands.Count;
  
      UpdateDirectInfluence(fUpdatePlayerId);
      UpdateOwnershipInfluence(fUpdatePlayerId);
    end;
  end;
  
  
negative.code:   Classes, Graphics, SysUtils, Math,
    KM_RenderAux,
    KM_Terrain, KM_Houses, KM_HouseCollection,
    KM_Hand, KM_HandsCollection, KM_ResHouses,
    KM_AIFields;
  
  
  const
    GROUPS = 4;
    INIT_HOUSE_INFLUENCE = 255;
    MAX_INFLUENCE_DISTANCE = 150;
  
  
  { TKMInfluenceMaps }
  constructor TKMInfluences.Create(aNavMesh: TKMNavMesh);
  begin
    inherited Create();
  
    fNavMesh := aNavMesh;
    fUpdateCityIdx := 0;
    fUpdateArmyIdx := 0;
    fFloodFill := TKMInfluenceFloodFill.Create(False); // Check if True is better
    fInfluenceSearch := TNavMeshInfluenceSearch.Create(False);
  end;
  
  
  destructor TKMInfluences.Destroy();
  begin
    fFloodFill.Free;
    fInfluenceSearch.Free;
    inherited;
  end;
  
  
  procedure TKMInfluences.Save(SaveStream: TKMemoryStream);
  var
    PCount: Word;
    Y, Len: Integer;
  begin
    PCount := gHands.Count;
  
    SaveStream.WriteA('Influences');
    SaveStream.Write(PCount);
    SaveStream.Write(fMapX);
    SaveStream.Write(fMapY);
    SaveStream.Write(fPolygons);
    SaveStream.Write(fUpdateCityIdx);
    SaveStream.Write(fUpdateArmyIdx);
  
    SaveStream.WriteA('AvoidBuilding');
    for Y := 0 to fMapY - 1 do
      SaveStream.Write(AvoidBuilding[Y,0], fMapX * SizeOf(AvoidBuilding[0,0]));
  
    SaveStream.WriteA('Ownership');
    Len := Length(fOwnership);
    SaveStream.Write(Len);
    SaveStream.Write(fOwnership[0], SizeOf(fOwnership[0]) * Len);
  
    SaveStream.WriteA('ArmyPresence');
    Len := Length(fPresence);
    SaveStream.Write(Len);
    SaveStream.Write(fPresence[0], SizeOf(fPresence[0]) * Len);
  end;
  
  
  procedure TKMInfluences.Load(LoadStream: TKMemoryStream);
  var
    PCount: Word;
    Y, Len: Integer;
  begin
    LoadStream.ReadAssert('Influences');
    LoadStream.Read(PCount);
    LoadStream.Read(fMapX);
    LoadStream.Read(fMapY);
    LoadStream.Read(fPolygons);
    LoadStream.Read(fUpdateCityIdx);
    LoadStream.Read(fUpdateArmyIdx);
  
    LoadStream.ReadAssert('AvoidBuilding');
    SetLength(AvoidBuilding, fMapY, fMapX);
    for Y := 0 to fMapY - 1 do
      LoadStream.Read(AvoidBuilding[Y,0], fMapX * SizeOf(AvoidBuilding[0,0]));
  
    LoadStream.ReadAssert('Ownership');
    LoadStream.Read(Len);
    SetLength(fOwnership, Len);
    LoadStream.Read(fOwnership[0], SizeOf(fOwnership[0]) * Len);
  
    LoadStream.ReadAssert('ArmyPresence');
    LoadStream.Read(Len);
    SetLength(fPresence, Len);
    LoadStream.Read(fPresence[0], SizeOf(fPresence[0]) * Len);
  end;
  
  
  
  
  //Make the area around to be avoided by common houses
  procedure TKMInfluences.AddAvoidBuilding(aX,aY: Word; aRad: Single; aValue: Byte = 255);
  var
    X,Y: Integer;
  begin
    for Y := Max(aY - Ceil(aRad), 1) to Min(aY + Ceil(aRad), fMapY - 1) do
    for X := Max(aX - Ceil(aRad), 1) to Min(aX + Ceil(aRad), fMapX - 1) do
      if Sqr(aX-X) + Sqr(aY-Y) <= Sqr(aRad) then
        AvoidBuilding[Y,X] := Min(AvoidBuilding[Y,X] + aValue, 255);
  end;
  
  
  procedure TKMInfluences.RemAvoidBuilding(aArea: TKMRect);
  var
    X,Y: Integer;
  begin
    for Y := Max(aArea.Top , 1) to Min(aArea.Bottom, fMapY - 1) do
    for X := Max(aArea.Left, 1) to Min(aArea.Right , fMapX - 1) do
      AvoidBuilding[Y,X] := 0;
  end;
  
  
  //AI should avoid certain areas, keeping them for special houses
  procedure TKMInfluences.InitAvoidBuilding();
    procedure CheckAndMarkMine(aX,aY: Integer; aHT: THouseType);
    var
      X,Y,X2,Y2: Integer;
  