anchor.diff:      begin
         MaxIdx := WOOD_SHORTAGE_IDX;
         MinIdx := TRUNK_SHORTAGE_IDX;
  -      if (gHands[fOwner].Stats.GetHouseTotal(htWoodcutters) > 0) then
  +      if (fPlanner.PlannedHouses[htSawmill].Completed > 0) then
           MinIdx := WOOD_SHORTAGE_IDX;
       end
       else if fTrunkShortage then
  
positive.code:   BUILD_TOWER_DELAY = 17 * 60 * 10; // 17 minutes before end of peace
    MINIMAL_TOWER_DELAY = 50 * 60 * 10; // Towers will not be build before 50 minute
  var
    I, RequiredStones, RequiredWood, WoodReserves, Wood, Trunk: Integer;
    TrunkBalance: Single;
    HT: TKMHouseType;
    H: TKMHouse;
  begin
    fStoneShortage := False;
    fTrunkShortage := False;
    fWoodShortage := False;
    fGoldShortage := False;
    RequiredHouses := fPredictor.RequiredHouses;
    WareBalance := fPredictor.WareBalance;
  
    // Analyze basic force stats (max possible plans, construction ware, gold)
    MaxPlans := Ceil(aFreeWorkersCnt / GA_BUILDER_ChHTB_FreeWorkerCoef);
    // Use "rapid construction" in case that we have resources
    if   (fPredictor.WareBalance[wt_Stone].Exhaustion > 60) then // Some stone mines are too far so AI must slow down with expansion
      //AND (fPredictor.WareBalance[wt_Wood].Exhaustion > 60)
      //AND (fPredictor.WareBalance[wt_Gold].Exhaustion > 60) then
      MaxPlans := Max(MaxPlans, Ceil(gHands[fOwner].Stats.GetUnitQty(ut_Worker) / GA_BUILDER_ChHTB_AllWorkerCoef) - fPlanner.ConstructedHouses);
  
    // Quarries have minimal delay + stones use only workers (towers after peace time) -> exhaustion for wt_Stone is OK
    if (WareBalance[wt_Stone].Exhaustion < GA_BUILDER_STONE_SHORTAGE) then
      fStoneShortage := True;
  
    // Secure wood production: only process trunk -> wood => minimal delay, exhaustion is OK
    if (WareBalance[wt_Wood].Exhaustion < GA_BUILDER_WOOD_SHORTAGE) then
      fWoodShortage := True;
  
    // Make sure that gold will be produced ASAP -> minimal delay, exhaustion is OK
    if (WareBalance[wt_Gold].Exhaustion < GA_BUILDER_GOLD_SHORTAGE) then
      fGoldShortage := True;
  
    // Woodcutters have huge delay (8 min) + trunk is used only to produce wood -> decide shortage based on actual consumption and reserves
    Trunk := gHands[fOwner].Stats.GetWareBalance(wt_Trunk);
    Wood := gHands[fOwner].Stats.GetWareBalance(wt_Wood);
    WoodReserves := Trunk * 2 + Wood;
    TrunkBalance := WoodReserves / (2 * Max(0.1, WareBalance[wt_Trunk].ActualConsumption));
    if (TrunkBalance < GA_BUILDER_TRUNK_SHORTAGE) then
      fTrunkShortage := True;
  
    // Compute building materials
    RequiredStones := gHands[fOwner].BuildList.HousePlanList.GetPlansStoneDemands();
    RequiredWood := gHands[fOwner].BuildList.HousePlanList.GetPlansWoodDemands();
    for I := 0 to gHands[fOwner].Houses.Count - 1 do
    begin
      H := gHands[fOwner].Houses[I];
      if (H <> nil) AND not H.IsDestroyed AND not H.IsComplete then
      begin
        RequiredStones := RequiredStones + gRes.Houses[H.HouseType].StoneCost - H.GetBuildStoneDelivered;
        RequiredWood := RequiredWood + gRes.Houses[H.HouseType].WoodCost - H.GetBuildWoodDelivered;
      end;
    end;
    //fStoneShortage := fStoneShortage OR (gHands[fOwner].Stats.GetWareBalance(wt_Stone) < RequiredStones);
    //fTrunkShortage := fTrunkShortage OR (gHands[fOwner].Stats.GetWareBalance(wt_Wood) < RequiredWood);
    fTrunkShortage := fTrunkShortage OR (WoodReserves < RequiredWood);
    MaxPlace := Round((Wood // Available wood
                       + Min(Trunk * 2 , gHands[fOwner].Stats.GetHouseQty(htSawmill) * 4) // Trunk which can be turned into wood while the house is digged
                       - RequiredWood) / 3 // Consideration of required wood per a plan (approx 3)
                     );
    RequiredHouses[htWineyard] := RequiredHouses[htWineyard] * Byte(not(fTrunkShortage OR (MaxPlace < 3))); // Dont try to place wine we are out of wood
  
    // Find place for chop-only woodcutters when we start to be out of wood
    if ((GA_BUILDER_ChHTB_TrunkBalance - TrunkBalance) / GA_BUILDER_ChHTB_TrunkFactor - GetChopOnlyCnt() > 0) then
  
negative.code:     procedure UnlockPointOfNode(aPoint: TKMPoint; aCheckHousePlan: Boolean = False);
      procedure UnlockNode(var aNode: TBuildNode; aCheckHousePlan: Boolean = False);
  
      procedure CheckBasicMaterials(var aFreeWorkersCnt, aMaxPlans, aMaxPlace: Integer; var aTrunkBalance: Single; aTick: Cardinal);
      procedure CreateShortcuts();
    public
      constructor Create(aPlayer: TKMHandIndex; aPredictor: TKMCityPredictor);
  