anchor.diff:  begin
     inherited Create;
     fOwner := aPlayer;
  -  fPathfinding := TNavMeshPathFinding.Create();
  +  fTargetHouse := nil;
  +  fTargetUnit := nil;
  +
     for GT := Low(TGroupType) to High(TGroupType) do
       fSquads[GT] := TKMList.Create();
   end;
   
   
  -destructor TAICompany.Destroy;
  +destructor TAICompany.Destroy();
   var
     GT: TGroupType;
   begin
  -  fPathfinding.Free;
  +  gHands.CleanUpUnitPointer(fTargetUnit);
  +  gHands.CleanUpHousePointer(fTargetHouse);
     for GT := Low(TGroupType) to High(TGroupType) do
       fSquads[GT].Free;
     inherited;
   end;
   
   
  +constructor TAICompany.Load(LoadStream: TKMemoryStream);
  +var
  +  I,Cnt: Integer;
  +  GT: TGroupType;
  +begin
  +  inherited Create;
  +  LoadStream.ReadAssert('Company');
  +  LoadStream.Read(fOwner);
  +  LoadStream.Read(fPosition);
  +  LoadStream.Read(fTargetUnit, 4);
  +  LoadStream.Read(fTargetHouse, 4);
  +
  +  for GT := Low(TGroupType) to High(TGroupType) do
  +  begin
  +    fSquads[GT] := TKMList.Create();
  +    LoadStream.Read(Cnt);
  +    for I := 0 to Cnt - 1 do
  +      fSquads[GT].Add( TAISquad.Load(LoadStream) );
  +  end;
  +end;
  +
  +
   procedure TAICompany.Save(SaveStream: TKMemoryStream);
  -begin
  -  //SaveStream.Write(fOwner);
  -end;
  -
  -
  -procedure TAICompany.Load(LoadStream: TKMemoryStream);
  -begin
  -  //LoadStream.Read(fOwner);
  +var
  +  I,Cnt: Integer;
  +  GT: TGroupType;
  +  Squad: TAISquad;
  +begin
  +  SaveStream.WriteA('Company');
  +  SaveStream.Write(fOwner);
  +  SaveStream.Write(fPosition);
  +  if (fTargetUnit <> nil) then
  +    SaveStream.Write(fTargetUnit.UID) //Store ID
  +  else
  +    SaveStream.Write(Integer(0));
  +  if (fTargetHouse <> nil) then
  +    SaveStream.Write(fTargetHouse.UID) //Store ID
  +  else
  +    SaveStream.Write(Integer(0));
  +
  +  for GT := Low(TGroupType) to High(TGroupType) do
  +  begin
  +    Cnt := fSquads[GT].Count;
  +    SaveStream.Write(Cnt);
  +    for I := 0 to Cnt - 1 do
  +    begin
  +      Squad := fSquads[GT].Items[I];
  +      Squad.Save(SaveStream);
  +    end;
  +  end;
  +end;
  +
  +
  +procedure TAICompany.SyncLoad();
  +var
  +  I: Integer;
  +  GT: TGroupType;
  +  Squad: TAISquad;
  +begin
  +  fTargetUnit := gHands.GetUnitByUID( Cardinal(fTargetUnit) );
  +  fTargetHouse := gHands.GetHouseByUID( Cardinal(fTargetHouse) );
  +  for GT := Low(TGroupType) to High(TGroupType) do
  +    for I := 0 to fSquads[GT].Count - 1 do
  +    begin
  +      Squad := fSquads[GT].Items[I];
  +      Squad.SyncLoad();
  +    end;
  +end;
  +
  +
  +function TAICompany.SetTarget(aHouse: TKMHouse; aUnit: TKMUnit = nil): Boolean;
  +begin
  +  Result := False;
  +  if (aHouse = nil) AND (aUnit <> nil) then
  +  begin
  +    gHands.CleanUpUnitPointer(fTargetUnit);
  +    fTargetUnit := aUnit.GetUnitPointer;
  +    Result := True;
  +  end
  +  else if (aHouse <> nil) AND (aUnit = nil) then
  +  begin
  +    gHands.CleanUpHousePointer(fTargetHouse);
  +    fTargetHouse := aHouse.GetHousePointer;
  +    Result := True;
  +  end;
  +end;
  +
  +
  +function TAICompany.GetPointerPosition(aHouse: TKMHouse; aUnit: TKMUnit): TKMPoint;
  +begin
  +  Result := KMPOINT_ZERO;
  +  if (aHouse <> nil) AND not aHouse.IsDestroyed then
  +    Result := aHouse.GetPosition
  +  else if (aUnit <> nil) AND not aUnit.IsDead then
  +    Result := aUnit.GetPosition;
  +end;
  +
  +function TAICompany.GetTargetPosition(): TKMPoint;
  +begin
  +  Result := GetPointerPosition(fTargetHouse, fTargetUnit);
   end;
   
   
   procedure TAICompany.UpdateState(aTick: Cardinal);
  -begin
  -
  +  function CheckPrimaryTarget(): Boolean;
  +  begin
  +    Result := False;
  +    if (fTargetHouse <> nil) then
  +      if fTargetHouse.IsDestroyed then
  +        gHands.CleanUpHousePointer(fTargetHouse)
  +      else
  +        Result := True;
  +    if (fTargetUnit <> nil) then
  +      if fTargetUnit.IsDead then
  +        gHands.CleanUpUnitPointer(fTargetUnit)
  +      else
  +        Result := True;
  +  end;
  +var
  +  SquadsAreReady: Boolean;
  +  I: Integer;
  +  ActualPosition: TKMPoint;
  +  GT: TGroupType;
  +  HA: TKMHouseArray;
  +  UGA: TKMUnitGroupArray;
  +  ClosestHouse: TKMHouse;
  +  ClosestUnit: TKMUnit;
  +  Squad: TAISquad;
  +begin
  +  // Check Squads
  +  SquadsAreReady := True;
  +  for GT := Low(TGroupType) to High(TGroupType) do
  +    for I := fSquads[GT].Count - 1 downto 0 do
  +    begin
  +      Squad := fSquads[GT].Items[I];
  +      if (Squad = nil) OR (Squad.Group = nil) OR Squad.Group.IsDead then
  +        fSquads[GT].Delete(I)
  +      else
  +        SquadsAreReady := SquadsAreReady AND Squad.IsReady;
  +    end;
  +
  +  if (SquadCnt = 0) then
  +    Exit;
  +
  +  // Check target
  +  ActualPosition := Position;
  +  ClosestHouse := nil;
  +  ClosestUnit := nil;
  +  //ClosestHouse := gHands.GetClosestHouse(ActualPosition, fOwner, at_Enemy);
  +  //ClosestUnit := gHands.GetClosestUnit(ActualPosition, fOwner, at_Enemy);
  +  HA := gHands.GetHousesInRadius(ActualPosition, SQR_COMPANY_ATTACK_RAD, fOwner, at_Enemy, TARGET_HOUSES, True);
  +  UGA := gHands.GetGroupsInRadius(ActualPosition, SQR_COMPANY_ATTACK_RAD, fOwner, at_Enemy);
  +  if not CheckPrimaryTarget() then
  +  begin
  +    if (Length(UGA) > 0) then
  +      ClosestUnit := UGA[0].GetAliveMember;
  +    if (Length(HA) > 0) then
  +      ClosestHouse := HA[0];
  +    if not SetTarget(ClosestHouse, ClosestUnit) then
  +      Exit;
  +  end;
  +
  +  // Give new orders
  +  if (Length(UGA) > 0) then
  +    OrderToAttack(ActualPosition, UGA, HA, False)
  +  else if (Length(HA) > 0) then
  +    OrderToAttack(ActualPosition, UGA, HA, True)
  +  else if SquadsAreReady then
  +    OrderMove(ActualPosition);
  +
  +  // Update state of Squads
  +  for GT := Low(TGroupType) to High(TGroupType) do
  +    for I := fSquads[GT].Count - 1 downto 0 do
  +    begin
  +      Squad := fSquads[GT].Items[I];
  +      Squad.UpdateState(aTick);
  +    end;
  +end;
  +
  +
  +procedure TAICompany.OrderToAttack(aActualPosition: TKMPoint; UGA: TKMUnitGroupArray; HA: TKMHouseArray; aTargetHouse: Boolean);
  +  //function HouseTypeCnt(aHT: THouseType): Word;
  +  //var
  +  //  I: Integer;
  +  //begin
  +  //  Result := 0;
  +  //  for I := Low(HA) to High(HA) do
  +  //    if (HA[I].HouseType = aHT) then
  +  //      Result := Result + 1;
  +  //end;
  +  //function TargetHouses();
  +  //const
  +  //  IGNORE_TOWER_CNT = 3;
  +  //  ANTI_TOWER_TYPE = gt_Ranged;
  +  //var
  +  //  I: Integer;
  +  //  BestDistSqr, DistSqr: Single;
  +  //  BestSquad,Squad: TAISquad;
  +  //  GT: TGroupType;
  +  //  aGroups: set of TGroupType;
  +  //begin
  +  //  for I := Low(HA) to High(HA) do
  +  //  begin
  +  //    if (HA[I].HouseType = aHT) then
  +  //      aGroups := [ANTI_TOWER_TYPE];
  +  //    for GT in aGroups do
  +  //    begin
  +  //      BestDistSqr := 1000000;
  +  //      for I := 0 to fSquads[GT].Count - 1 do
  +  //      begin
  +  //        Squad := fSquads[GT].Items[I];
  +  //        DistSqr := Squad.TargetUnit := ;
  +  //        Idx := Idx + 1;
  +  //      end;
  +  //    end;
  +  //  end;
  +  //end;
  +var
  +  TowersCnt, BarrackCnt: Word;
  +  I, Idx: Integer;
  +  GT: TGroupType;
  +  Squad: TAISquad;
  +begin
  +  // Attack houses in radius
  +  if aTargetHouse then
  +  begin
  +    //if (HouseTypeCnt(ht_Barracks) > 0) then
  +    //  TargetHouses([gt_Melee, gt_]);
  +    //
  +    //TowersCnt := HouseTypeCnt(ht_WatchTower);
  +    //// Ignore towers in case that
  +    //if (TowersCnt <= IGNORE_TOWER_CNT) OR (fSquads[ANTI_TOWER_TYPE].Count = 0) then
  +    //  OrderMove(ActualPosition);
  +    for GT := Low(TGroupType) to High(TGroupType) do
  +      for I := 0 to fSquads[GT].Count - 1 do
  +      begin
  +        Squad := fSquads[GT].Items[I];
  +        Squad.TargetHouse := HA[ KaMRandom(Length(HA)) ];
  +      end;
  +  end
  +  else
  +  begin
  +    Idx := 0;
  +    for GT := Low(TGroupType) to High(TGroupType) do
  +      for I := 0 to fSquads[GT].Count - 1 do
  +      begin
  +        Squad := fSquads[GT].Items[I];
  +        Squad.TargetUnit := UGA[Idx].GetAliveMember;
  +        Idx := Idx + 1;
  +        if (Idx = Length(UGA)) then
  +          Idx := 0;
  +      end;
  +  end;
  +end;
  +
  +
  +procedure TAICompany.OrderMove(aActualPosition: TKMPoint);
  +const
  +  MINIMAL_MOVEMENT = 5;
  +var
  +  InitPolygon: Word;
  +  I, Idx, Cnt: Integer;
  +  TargetPoint: TKMPoint;
  +  Dir: TKMDirection;
  +  GT: TGroupType;
  +  PolygonPath: TKMWordArray;
  +  PointPath, PointPath2: TKMPointArray;
  +  InitPolygons: TKMWordArray;
  +  Squad: TAISquad;
  +begin
  +  TargetPoint := TargetPosition;
  +  if gAIFields.Eye.Pathfinding.Route_Make(aActualPosition, TargetPoint, PolygonPath, PointPath) then
  +  begin
  +    // Get center point on the path
  +    I := Length(PointPath)-1;
  +    while (I >= 0) AND (KMDistanceAbs(aActualPosition, PointPath[I]) < MINIMAL_MOVEMENT) do
  +      I := I - 1;
  +    InitPolygon := gAIFields.NavMesh.FindClosestPolygon(aActualPosition);
  +    repeat
  +      fPosition := PointPath[ Max(0, I) ];
  +      I := I - 1;
  +    until (InitPolygon <> gAIFields.NavMesh.FindClosestPolygon(fPosition)) OR (I < 0);
  +
  +    fDEBUGPointPath := PointPath;
  +
  +    Cnt := SquadCnt();
  +    I := I + 1;
  +    SetLength(InitPolygons, Min(Length(PointPath) - I, Max(1, Cnt div 4)) );
  +    Idx := 0;
  +    while (I < Length(PointPath)) AND (Idx < Length(InitPolygons)) do
  +    begin
  +      InitPolygons[Idx] := gAIFields.NavMesh.FindClosestPolygon(PointPath[I]);
  +      Idx := Idx + 1;
  +      I := I + 2;
  +    end;
  +
  +    gAIFields.Eye.Positioning.FindPositions(Cnt, InitPolygons, PointPath2);
  +    Idx := 0;
  +    Dir := KMGetDirection( aActualPosition, fPosition );
  +    for GT := Low(TGroupType) to High(TGroupType) do
  +      for I := 0 to fSquads[GT].Count - 1 do
  +      begin
  +        if (Idx >= Length(PointPath2)) then
  +          break;
  +        Squad := fSquads[GT].Items[I];
  +        Squad.FinalPosition := KMPointDir(PointPath2[Idx], Dir);
  +        Idx := Idx + 1;
  +      end;
  +  end;
  +end;
  +
  +
  +function TAICompany.SquadCnt(aTypes: TGroupTypeSet = [Low(TGroupType)..High(TGroupType)]): Word;
  +var
  +  GT: TGroupType;
  +begin
  +  Result := 0;
  +  for GT in aTypes do
  +    Result := Result + fSquads[GT].Count;
   end;
   
   
  
positive.code:     for I := 0 to fSquads[G].Count-1 do
      begin
        Squad := fSquads[G][I];
        Output.X := Output.X + Squad.Group.Position.X;
        Output.Y := Output.Y + Squad.Group.Position.Y;
        Count := Count + 1;
      end;
  
    if Count > 0 then
    begin
      Output.X := Round( Output.X / Count );
      Output.Y := Round( Output.Y / Count );
  
negative.code:   inherited Create;
    fCompanies := TKMList.Create();
    fOwner := aPlayer;
  end;
  
  
  destructor TKMArmyAttack.Destroy;
  begin
    fCompanies.Free;
    inherited;
  end;
  
  
  procedure TKMArmyAttack.Save(SaveStream: TKMemoryStream);
  var
    I: Integer;
  begin
    SaveStream.WriteA('ArmyAttack');
    SaveStream.Write(fOwner);
    SaveStream.Write( Integer(Count) );
  
    for I := 0 to Count - 1 do
      Company[I].Save(SaveStream);
  end;
  
  
  procedure TKMArmyAttack.Load(LoadStream: TKMemoryStream);
  var
    I, NewCount: Integer;
  begin
    LoadStream.ReadAssert('ArmyAttack');
    LoadStream.Read(fOwner);
    LoadStream.Read(NewCount);
  
    for I := 0 to NewCount - 1 do
      fCompanies.Add( TAICompany.Load(LoadStream) );
  end;
  
  
  procedure TKMArmyAttack.SyncLoad();
  var
    I: Integer;
  begin
    for I := 0 to Count - 1 do
      Company[I].SyncLoad();
  end;
  
  
  procedure TKMArmyAttack.AfterMissionInit();
  begin
  
  end;
  
  
  procedure TKMArmyAttack.UpdateState(aTick: Cardinal);
  var
    I: Integer;
    Company: TAICompany;
  begin
    for I := Count - 1 downto 0 do
    begin
      Company := fCompanies.Items[I];
      Company.UpdateState(aTick);
      if (Company.SquadCnt = 0) OR KMSamePoint(Company.TargetPosition, KMPOINT_ZERO)then
        fCompanies.Remove( Company );
    end;
  end;
  
  