Alt+B rebuff on farm - run aside to end combat and kill agro mobs

Script checks buff time by specified ID and if rebuff is needed then: runs to the specified "safe" point -> kills all argo mobs -> waits for the end combat -> rebuff -> returns to farm.

uses SysUtils, Classes;

var
  SafePoint: array of integer = [147593, -112774, -2144];  // "safe" point - where to run for rebuff
  BuffID: integer = 1204;         // Buff ID to check for the need for rebuff
  RebuffTime: cardinal = 60000;   // the time until the end of the buff for rebuff (in ms)
  AltB: array of string = ['_bbshome', '_cbbsbuff;', '_cbbsblist:mage_scheme:index'];  // bypasses for buffs

procedure AltB_Rebuff_Thread();
var X, Y, Z: integer;
begin
  while delay(555) do begin
    if (BuffTime(BuffID) < RebuffTime) then begin
      Engine.Msg('[Rebuff]', 'It's time to rebuff, I'm leaving for a safe place', 0);
      // take the necessary actions, for example, slow down other threads or something else
      // if you want the bot to first finish off all the agro mobs that hang on it,
      // Before you run to a safe location, uncomment the code below.
      {if (HaveAgroMobs) then begin
        Engine.Msg('[Rebuff]', 'Fighting off mobs', 128);
        while (HaveAgroMobs) do delay(555);
        Engine.FaceControl(1, true);
      end; }
      X:= User.X;
      Y:= User.Y;
      Z:= User.Z;
      Engine.FaceControl(1, false);
      Engine.Msg('[Rebuff]', 'Remember my coordinates: ['+IntToStr(X)+', '+IntToStr(Y)+', '+IntToStr(Z)+']', 0);
      while (User.DistTo(SafePoint[0], SafePoint[1], SafePoint[2]) > 222) do           // if necessary, then
        if Engine.MoveTo(SafePoint[0], SafePoint[1], SafePoint[2]) then delay(555);    // run to a safe point
      Delay(1000);
      if (HaveAgroMobs) then begin                                                     // if agro mobs are hanging on us, then
        Engine.Msg('[Rebuff]', 'Fighting off mobs', 128);
        Engine.FaceControl(1, true);                                                   // turn on the interface
        while (HaveAgroMobs) do delay(555);                                            // wait while there are agro mobs
        Engine.FaceControl(1, false);                                                  // turn off the interface
        while (User.InCombat) do delay(555);                                           // waiting for the exit from the combat
      end;

      repeat BuffAltB();                                          // rebuff until
      until (BuffTime(BuffID) > RebuffTime);                      // the buff time is longer than required
      Engine.MoveTo(X, Y, Z);                                     // return to the coordinates that filled before the buff
      Engine.FaceControl(1, true);                                // turn on the interface back and continue the farm

    end;
  end;
end;

// https://adrenalinebot.com/ru/api/example/buff-time-check
function BuffTime(ID: integer): cardinal;
var i: integer;
begin
  result:= 0;
  for i:= 0 to User.Buffs.Count-1 do begin        // running through the list of our buffs
    if (User.Buffs.Items(i).id = ID) then begin   // if id matched then
      result:= User.Buffs.Items(i).EndTime;       // write to the result time before the end of the buff
      break;
    end;
  end;
end;

procedure BuffAltB();
var i: integer;
begin
  for i:= Low(AltB) to High(AltB) do
    if Engine.BypassToServer(AltB[i]) then delay(555);
end;

function HaveAgroMobs(): boolean;                 // the function checks if mobs hang on us
var i: integer;
begin
  result:= false;
  for i:= 0 to NpcList.Count-1 do begin
    if (IsAgr(NpcList(i))) then begin
      result:= true;
      exit;
    end;
  end;
end;

function IsAgr(Mob: TL2Npc): boolean;
begin
  result:= (Mob.AtkOID = User.OID) and (not Mob.Dead);
end;

begin
  Script.NewThread(@AltB_Rebuff_Thread);
  // there may be additional code...
  Delay(-1);
end.