anchor.diff:  //* or -1 if no such group was found.
   //* Result: Group ID
   function TKMScriptStates.ClosestGroupEx(aPlayer, X, Y: Integer; aGroupType: TKMGroupType): Integer;
  -begin
  -  try
  -    Result := _ClosestGroup(aPlayer, X, Y, aGroupType, 'States.ClosestGroupEx');
  -  except
  -    gScriptEvents.ExceptionOutsideScript := True; //Don't blame script for this exception
  -    raise;
  -  end;
  -end;
  -
  -
  -function TKMScriptStates._ClosestGroupMultipleTypes(aPlayer, X, Y: Integer; aGroupTypes: TKMGroupTypeSet; aMethodName: string): Integer;
  +var
  +  succeed: Boolean;
  +begin
  +  try
  +    Result := _ClosestGroup(aPlayer, X, Y, aGroupType, succeed);
  +    if not succeed then
  +      LogParamWarn('States.ClosestGroupEx', [aPlayer, X, Y, GetEnumName(TypeInfo(TKMGroupType), Integer(aGroupType))]);
  +  except
  +    gScriptEvents.ExceptionOutsideScript := True; //Don't blame script for this exception
  +    raise;
  +  end;
  +end;
  +
  +
  +function TKMScriptStates._ClosestGroupMultipleTypes(aPlayer, X, Y: Integer; aGroupTypes: TKMGroupTypeSet; out aSucceed: Boolean): Integer;
   var
     G: TKMUnitGroup;
   begin
     Result := -1;
  -  try
  -    if InRange(aPlayer, 0, gHands.Count - 1) and (gHands[aPlayer].Enabled)
  -      and gTerrain.TileInMapCoords(X, Y) then
  -    begin
  -      aGroupTypes := aGroupTypes * GROUP_TYPES_VALID;
  -
  -      G := gHands[aPlayer].UnitGroups.GetClosestGroup(KMPoint(X,Y), aGroupTypes);
  -      if G <> nil then
  -      begin
  -        Result := G.UID;
  -        fIDCache.CacheGroup(G, G.UID);
  -      end;
  -    end
  -    else
  -      LogIntParamWarn(aMethodName, [aPlayer, X, Y]);
  -  except
  -    gScriptEvents.ExceptionOutsideScript := True; //Don't blame script for this exception
  -    raise;
  +  aSucceed := False;
  +  if InRange(aPlayer, 0, gHands.Count - 1) and (gHands[aPlayer].Enabled)
  +    and gTerrain.TileInMapCoords(X, Y) then
  +  begin
  +    aGroupTypes := aGroupTypes * GROUP_TYPES_VALID;
  +    G := gHands[aPlayer].UnitGroups.GetClosestGroup(KMPoint(X,Y), aGroupTypes);
  +    if G <> nil then
  +    begin
  +      Result := G.UID;
  +      fIDCache.CacheGroup(G, G.UID);
  +    end;
  +    aSucceed := True;
     end;
   end;
   
  
positive.code: function TKMScriptStates.ClosestHouse(aPlayer, X, Y, aHouseType: Integer): Integer;
  var
    HT: TKMHouseType;
  begin
    HT := htNone;
  
    if aHouseType = -1 then
      HT := htAny
    else
    if HouseTypeValid(aHouseType) then
      HT := HOUSE_ID_TO_TYPE[aHouseType];
  
    Result := _ClosestHouse(aPlayer, X, Y, HT, 'States.ClosestHouse')
  end;
  
  
  
negative.code: //* If the house type is htAny any house type will be accepted
  //* Result: House ID
  function TKMScriptStates.ClosestHouseEx(aPlayer, X, Y: Integer; aHouseType: TKMHouseType): Integer;
  var
    succeed: Boolean;
  begin
    try
      Result := _ClosestHouse(aPlayer, X, Y, aHouseType, succeed);
      if not succeed then
        LogParamWarn('States.ClosestHouseEx', [aPlayer, X, Y, GetEnumName(TypeInfo(TKMHouseType), Integer(aHouseType))]);
    except
      gScriptEvents.ExceptionOutsideScript := True; //Don't blame script for this exception
      raise;
    end;
  end;
  
  
  function TKMScriptStates._ClosestHouseMultipleTypes(aPlayer, X, Y: Integer; aHouseTypes: TKMHouseTypeSet; out aSucceed: Boolean): Integer;
  var
    H: TKMHouse;
  begin
    Result := -1;
    aSucceed := False;
    if InRange(aPlayer, 0, gHands.Count - 1) and (gHands[aPlayer].Enabled)
      and gTerrain.TileInMapCoords(X, Y) then
    begin
      aHouseTypes := aHouseTypes * HOUSES_VALID;
      H := gHands[aPlayer].Houses.FindHouse(aHouseTypes, X, Y);
      if H <> nil then
      begin
        Result := H.UID;
        fIDCache.CacheHouse(H, H.UID);
      end;
      aSucceed := True;
    end;
  end;
  
  