anchor.diff:  
   // Calculate weapons demand from combat AI requirements
   function TKMCityManagement.WeaponsBalance(): TWarfareArr;
  -const
  -  ArmyDemands: array [TGroupType] of Integer = (  //TGroupType = (gt_Melee, gt_AntiHorse, gt_Ranged, gt_Mounted);
  -    100, 100, 500, 100
  -  );
  -  {
  -  AITroopTrainOrder: array [TGroupType, 1..3] of TUnitType = (
  -    (ut_Swordsman,    ut_AxeFighter, ut_Militia),
  -    (ut_Hallebardman, ut_Pikeman,    ut_None),
  -    (ut_Arbaletman,   ut_Bowman,     ut_None),
  -    (ut_Cavalry,      ut_HorseScout, ut_None)
  -  );
  -  UnitGroups: array [WARRIOR_MIN..WARRIOR_MAX] of TGroupType = (
  -    gt_Melee,gt_Melee,gt_Melee, //ut_Militia, ut_AxeFighter, ut_Swordsman
  -    gt_Ranged,gt_Ranged,        //ut_Bowman, ut_Arbaletman
  -    gt_AntiHorse,gt_AntiHorse,  //ut_Pikeman, ut_Hallebardman,
  -    gt_Mounted,gt_Mounted,      //ut_HorseScout, ut_Cavalry,
  -    gt_Melee,                   //ut_Barbarian
  -    //TPR Army
  -    gt_AntiHorse,        //ut_Peasant
  -    gt_Ranged,           //ut_Slingshot
  -    gt_Melee,            //ut_MetalBarbarian
  -    gt_Mounted           //ut_Horseman
  -  );
  -  TroopCost: array [ut_Militia..ut_Cavalry, 1..4] of TWareType = (
  -    (wt_Axe,          wt_None,        wt_None,  wt_None ), //Militia
  -    (wt_Shield,       wt_Armor,       wt_Axe,   wt_None ), //Axefighter
  -    (wt_MetalShield,  wt_MetalArmor,  wt_Sword, wt_None ), //Swordfighter
  -    (wt_Armor,        wt_Bow,         wt_None,  wt_None ), //Bowman
  -    (wt_MetalArmor,   wt_Arbalet,     wt_None,  wt_None ), //Crossbowman
  -    (wt_Armor,        wt_Pike,        wt_None,  wt_None ), //Lance Carrier
  -    (wt_MetalArmor,   wt_Hallebard,   wt_None,  wt_None ), //Pikeman
  -    (wt_Shield,       wt_Armor,       wt_Axe,   wt_Horse), //Scout
  -    (wt_MetalShield,  wt_MetalArmor,  wt_Sword, wt_Horse)  //Knight
  -  );
  -  WARRIOR_EQUIPABLE_MIN = ut_Militia;
  -  WARRIOR_EQUIPABLE_MAX = ut_Cavalry;
  -    ut_Militia,      ut_AxeFighter,   ut_Swordsman,     ut_Bowman,
  -    ut_Arbaletman,   ut_Pikeman,      ut_Hallebardman,  ut_HorseScout,
  -    ut_Cavalry,      ut_Barbarian,
  -  //}
  -var
  -  I: Integer;
  +var
  +  EnemyEval, AllyEval: TKMArmyEval;
  +  WarriorsDemands: array[WARRIOR_EQUIPABLE_MIN..WARRIOR_EQUIPABLE_MAX] of Integer;
  +
  +  procedure ComputeGroupDemands(aGT: TGroupType; aIronRatio: Single);
  +  const
  +    // It doesnt depends on future "optimalization" of parameters: against cav should be always good pikes etc. so this array doesnt have to be computed
  +    BEST_VERSUS_OPTION: array[TGroupType] of TGroupType = (gt_Melee, gt_Melee, gt_Ranged, gt_AntiHorse);
  +  var
  +    Wood, Iron: Boolean;
  +    I: Integer;
  +    EnemyAttack, EnemyDefence, MyAttack, MyDefence, AttackReq, DefenceReq: Single;
  +    UT: TUnitType;
  +    antiGT: TGroupType;
  +    UnitEval: TKMGroupEval;
  +  begin
  +    // Get best type of oponent and compute iron ratio
  +    antiGT := BEST_VERSUS_OPTION[aGT];
  +    Wood := False;
  +    Iron := False;
  +    for I := 1 to 3 do
  +    begin
  +      UT := AITroopTrainOrder[antiGT,I];
  +      if (UT <> ut_None) AND not gHands[fOwner].Locks.UnitBlocked[UT] then
  +        if (I = 1) then
  +          Iron := True
  +        else
  +          Wood := True;
  +    end;
  +    if Wood AND not Iron then
  +      aIronRatio := 0
  +    else if not Wood AND Iron then
  +      aIronRatio := 1
  +    else if not Wood AND not Iron then
  +      Exit;
  +
  +    // Compute strength of specific enemy group
  +    with EnemyEval[aGT] do
  +    begin
  +      EnemyAttack := Attack + AttackHorse * Byte(antiGT = gt_Mounted);
  +      EnemyDefence := ifthen( (antiGT = gt_Ranged), DefenceProjectiles, Defence) * HitPoints;
  +    end;
  +    // Decrease strength by owner's existing units
  +    with AllyEval[antiGT] do
  +    begin
  +      EnemyAttack := EnemyAttack - ifthen( (aGT = gt_Ranged), DefenceProjectiles, Defence) * HitPoints;
  +      EnemyDefence := EnemyDefence - Attack - AttackHorse * Byte(aGT = gt_Mounted);
  +    end;
  +    // Compute unit requirements
  +    for I := 1 to 3 do
  +    begin
  +      UT := AITroopTrainOrder[antiGT,I];
  +      // Skip unit type if case that it is blocked
  +      if (UT = ut_None) OR gHands[fOwner].Locks.UnitBlocked[UT] then
  +        continue;
  +      // Calculate required count of specific unit type
  +      UnitEval := gAIFields.Eye.ArmyEvaluation.UnitEvaluation[UT, True];
  +      with UnitEval do
  +      begin
  +        MyAttack := Attack + AttackHorse * Byte(aGT = gt_Mounted);
  +        MyDefence := ifthen( (aGT = gt_Ranged), DefenceProjectiles, Defence) * HitPoints;
  +      end;
  +      AttackReq := EnemyAttack / MyDefence;
  +      DefenceReq := EnemyDefence / MyAttack;
  +      WarriorsDemands[UT] := WarriorsDemands[UT] + Max(0, Round(  Max(AttackReq, DefenceReq) * ifthen( (I = 1), aIronRatio, 1-aIronRatio )  )   );
  +      if (I = 2) then // In case that ut_AxeFighter is not blocked skip militia
  +        break;
  +    end;
  +  end;
  +
  +  procedure CheckMinArmyReq();
  +  const
  +    DEFAULT_ARMY_REQUIREMENTS: array[WARRIOR_EQUIPABLE_MIN..WARRIOR_EQUIPABLE_MAX] of Word = (
  +      10, 10, 10, 30,//ut_Militia,      ut_AxeFighter,   ut_Swordsman,     ut_Bowman,
  +      30, 10, 10, 10,//ut_Arbaletman,   ut_Pikeman,      ut_Hallebardman,  ut_HorseScout,
  +      10//ut_Cavalry
  +    );
  +  var
  +    SoldierCnt: Integer;
  +    UT: TUnitType;
  +  begin
  +    SoldierCnt := 0;
  +    for UT := Low(WarriorsDemands) to High(WarriorsDemands) do
  +      SoldierCnt := SoldierCnt + WarriorsDemands[UT];
  +    if (SoldierCnt > 30) then
  +      Exit;
  +
  +    for UT := Low(WarriorsDemands) to High(WarriorsDemands) do
  +      if not gHands[fOwner].Locks.UnitBlocked[UT] then
  +        WarriorsDemands[UT] := WarriorsDemands[UT] + DEFAULT_ARMY_REQUIREMENTS[UT];
  +  end;
  +//AITroopTrainOrder: array [TGroupType, 1..3] of TUnitType = (
  +//  (ut_Swordsman,    ut_AxeFighter, ut_Militia),
  +//  (ut_Hallebardman, ut_Pikeman,    ut_None),
  +//  (ut_Arbaletman,   ut_Bowman,     ut_None),
  +//  (ut_Cavalry,      ut_HorseScout, ut_None)
  +//);
  +//UnitGroups: array [WARRIOR_MIN..WARRIOR_MAX] of TGroupType = (
  +//  gt_Melee,gt_Melee,gt_Melee, //ut_Militia, ut_AxeFighter, ut_Swordsman
  +//  gt_Ranged,gt_Ranged,        //ut_Bowman, ut_Arbaletman
  +//  gt_AntiHorse,gt_AntiHorse,  //ut_Pikeman, ut_Hallebardman,
  +//  gt_Mounted,gt_Mounted,      //ut_HorseScout, ut_Cavalry,
  +//  gt_Melee,                   //ut_Barbarian
  +//  //TPR Army
  +//  gt_AntiHorse,        //ut_Peasant
  +//  gt_Ranged,           //ut_Slingshot
  +//  gt_Melee,            //ut_MetalBarbarian
  +//  gt_Mounted           //ut_Horseman
  +//);
  +//TroopCost: array [ut_Militia..ut_Cavalry, 1..4] of TWareType = (
  +//  (wt_Axe,          wt_None,        wt_None,  wt_None ), //Militia
  +//  (wt_Shield,       wt_Armor,       wt_Axe,   wt_None ), //Axefighter
  +//  (wt_MetalShield,  wt_MetalArmor,  wt_Sword, wt_None ), //Swordfighter
  +//  (wt_Armor,        wt_Bow,         wt_None,  wt_None ), //Bowman
  +//  (wt_MetalArmor,   wt_Arbalet,     wt_None,  wt_None ), //Crossbowman
  +//  (wt_Armor,        wt_Pike,        wt_None,  wt_None ), //Lance Carrier
  +//  (wt_MetalArmor,   wt_Hallebard,   wt_None,  wt_None ), //Pikeman
  +//  (wt_Shield,       wt_Armor,       wt_Axe,   wt_Horse), //Scout
  +//  (wt_MetalShield,  wt_MetalArmor,  wt_Sword, wt_Horse)  //Knight
  +//);
  +//WARRIOR_EQUIPABLE_MIN = ut_Militia;
  +//WARRIOR_EQUIPABLE_MAX = ut_Cavalry;
  +//  ut_Militia,      ut_AxeFighter,   ut_Swordsman,     ut_Bowman,
  +//  ut_Arbaletman,   ut_Pikeman,      ut_Hallebardman,  ut_HorseScout,
  +//  ut_Cavalry,      ut_Barbarian,
  +
  +var
  +  I, SmithyCnt, WorkshopCnt, ArmorCnt: Integer;
     IronRatio: Single;
     WT: TWareType;
     GT: TGroupType;
     UT: TUnitType;
  -  WarriorsDemands: array[WARRIOR_EQUIPABLE_MIN..WARRIOR_EQUIPABLE_MAX] of Integer;
     Warfare: TWarfareArr;
   begin
  -  //gHands[fOwner].AI.General.DefencePositions.GetArmyDemand(Footmen, Pikemen, Horsemen, Archers);
  +  ArmorCnt := gHands[fOwner].Stats.GetHouseQty(ht_ArmorSmithy) + gHands[fOwner].Stats.GetHouseQty(ht_ArmorWorkshop);
  +  SmithyCnt := gHands[fOwner].Stats.GetHouseQty(ht_WeaponSmithy);
  +  WorkshopCnt := gHands[fOwner].Stats.GetHouseQty(ht_WeaponWorkshop);
  +  if (ArmorCnt + SmithyCnt + WorkshopCnt = 0) then // Save time when nothing can be produced
  +    Exit;
  +  IronRatio := 0.5;
  +  if (SmithyCnt + WorkshopCnt > 0) then // This will avoid to divide by zero
  +    IronRatio := SmithyCnt / ((SmithyCnt + WorkshopCnt)*1.0);
  +
  +  // Humans may spam archers -> AI will not produce long-range support because of balancing units in team
  +  // So it is better to calculate AllyEval just for Owner
  +  //AllyEval := gAIFields.Eye.ArmyEvaluation.GetAllianceStrength(aPlayer, at_Ally);
  +  AllyEval := gAIFields.Eye.ArmyEvaluation.Evaluation[fOwner];
  +  EnemyEval := gAIFields.Eye.ArmyEvaluation.AllianceEvaluation[fOwner, at_Enemy];
   
     // Compute requirements of warriors
     for UT := Low(WarriorsDemands) to High(WarriorsDemands) do
       WarriorsDemands[UT] := 0;
  -  for GT := Low(ArmyDemands) to High(ArmyDemands) do
  -  begin
  -    // Get distribution between iron / normal production (in case that iron / normal soldiers are blocked)
  -    IronRatio := (
  -                   + fSetup.EquipRateIron * Byte(not gHands[fOwner].Locks.UnitBlocked[ AITroopTrainOrder[GT,1] ])
  -                   + fSetup.EquipRateLeather * Byte(gHands[fOwner].Locks.UnitBlocked[ AITroopTrainOrder[GT,2] ] AND gHands[fOwner].Locks.UnitBlocked[ AITroopTrainOrder[GT,3] ])  // Check if is possible to block ut_None!!!!!!!!!!!!!!!!!!!!!
  -                 ) / (fSetup.EquipRateIron + fSetup.EquipRateLeather);
  -    for I := Low(AITroopTrainOrder[GT]) to High(AITroopTrainOrder[GT]) do
  -    begin
  -      UT := AITroopTrainOrder[GT,I];
  -      if (UT = ut_None)
  -        OR (ArmyDemands[ UnitGroups[UT] ] <= 0)
  -        OR gHands[fOwner].Locks.UnitBlocked[UT] then
  -      begin
  -        if (I = 2) then // Special case: ut_AxeFighter is blocked so distribute wood ratio of gt_Melee into ut_Militia
  -          IronRatio := IronRatio + 1;
  -      end
  -      else
  -      begin
  -        WarriorsDemands[UT] := Ceil(Abs(ArmyDemands[GT] * (IronRatio - Min(1,(I - 1)) ))); // for I = 1 -> IronRatio; for I = 2,3 -> inverse of IronRatio ...
  -        if (I = 1) then // Special case: ut_AxeFighter is NOT blocked so remove wood ratio to prevent produce weapons for ut_Militia
  -          IronRatio := 2;
  -      end;
  -    end;
  -  end;
  +  for GT := Low(TGroupType) to High(TGroupType) do
  +    ComputeGroupDemands(GT, IronRatio);
  +  // Make sure that
  +  CheckMinArmyReq();
   
     // Get weapons reserves
     for WT := Low(Warfare) to High(Warfare) do
  
positive.code: 
  procedure TKMCityManagement.Save(SaveStream: TKMemoryStream);
  begin
    SaveStream.Write(fOwner);
    // fSetup IS NOT SAVED!!!!
    fBuilder.Save(SaveStream);
    fPredictor.Save(SaveStream);
  end;
  
negative.code:   fBuilder.UpdateState(aTick, FreeWorkersCnt);
    //if ((FreeWorkersCnt > 0) OR (gHands[fOwner].Stats.GetHouseQty(ht_Metallurgists) > 0)) AND (aTick mod 12 = fOwner) then
    //if (aTick mod 12 = fOwner) AND (FreeWorkersCnt > 0) then
    if (aTick mod MAX_HANDS = fOwner) AND (FreeWorkersCnt > 0) then
    begin
      fPredictor.UpdateState(aTick);
      fBuilder.ChooseHousesToBuild(Max(1,Ceil(FreeWorkersCnt/WORKER_COEF)), fPredictor.RequiredHouses, fPredictor.WareBalance);
  