Forum in READ ONLY mode! All questions and discussions on Discord official server, invite link: https://discord.gg/VxsGzJ7 
	Ходилка SomeBody.
- 
				RaTaMaHaTTa
 - Novice

 - Posts: 89
 - Joined: 16.06.2008 12:22
 - Location: <||TORCHKI||>
 - Contact:
 
Вот вам его ходилка для RC4.
Тестите, критикуйте )
Есть одно но! Теперь не используется CheckFlow. у разных шардов разные системные сообщения при сейве, поэтоу не считаю целесообразным её подключать. Если я не прав - исправляюсь )
Не забываем про настройку шарда Check Diagonal Move! Важный параметр. Про него можете прочесть в разделе FAQ / Несколько слов о поиске пути.
Для самых ленивых напишу.
move идёт до цели с учётом таймаута. Изначально рассчитывается прямое расстояние до цели. Соответственно считается что чар совершит такое кол-во шагов. На каждый шаг выделяется время. (Сейчас это 3 сек, реально нужно подстраивать под условия) . Итого чару даётся времени = (кол-во шагов)*(время одного шага). Конечно это очень приближённый подсчет необходимого таймаута, потому что ходилка реально "не знает" длины пути. Тем не менее ,если время вышло, а цель не достигнута, move прекращает работу с сообщением 'Move: Time moved out!'
Функция _move тупо зацикливает работу функции move. Вот и всё различие.
PS: Кстати, здесь реализован алгоритм обычной трассировки, а не надёжной, как написал Somebody.
			
			
									
									
						Тестите, критикуйте )
Есть одно но! Теперь не используется CheckFlow. у разных шардов разные системные сообщения при сейве, поэтоу не считаю целесообразным её подключать. Если я не прав - исправляюсь )
Не забываем про настройку шарда Check Diagonal Move! Важный параметр. Про него можете прочесть в разделе FAQ / Несколько слов о поиске пути.
Для самых ленивых напишу.
move идёт до цели с учётом таймаута. Изначально рассчитывается прямое расстояние до цели. Соответственно считается что чар совершит такое кол-во шагов. На каждый шаг выделяется время. (Сейчас это 3 сек, реально нужно подстраивать под условия) . Итого чару даётся времени = (кол-во шагов)*(время одного шага). Конечно это очень приближённый подсчет необходимого таймаута, потому что ходилка реально "не знает" длины пути. Тем не менее ,если время вышло, а цель не достигнута, move прекращает работу с сообщением 'Move: Time moved out!'
Функция _move тупо зацикливает работу функции move. Вот и всё различие.
Code: Select all
// написал Somebody. ICQ: 475728522 e-mail: [email protected]
// Реализация алгоритма "надёжной трассировки"
// http://pmg.org.ru/ai/stout.htm#robust_trace
const 
FMoveArrMax = 300; // ставь здесь больше, если твой чар ходит на дистанции больше 13 тайлов или вокруг чара очень много препятствий. Если препятствий на пути мало, то можно оставить как есть. 
var 
PrognosisX, PrognosisY, FMoveArrCount : integer; 
FMoveArr : array [1..FMoveArrMax] of array [1..2] of smallint; 
procedure LocalWaitConnection(WaitTime : Integer);
begin
if Connected then Exit;
while not Connected do Wait(1000);
{WaitTime - Waiting After Connected}
wait(WaitTime);
end;
Function Abs(A: integer): integer;
Begin
If A>=0 then result:=A 
Else result:=0-A;
End;
function SetDirection(x, y : integer) : integer; 
var
   MyX,MyY,DiffX,DiffY,GoDir: integer;
Begin
MyX:=GetX(self);
MyY:=GetY(self);
DiffX:=Abs(MyX-x);
DiffY:=Abs(MyY-y);
if (DiffX/(DiffY+0.1))>=2 then 
   begin
   if (MyX>X) then 
      GoDir:=6 
   else 
      GoDir:=2; 
   end  
else 
   
   if (DiffY/(DiffX+0.1))>=2 then 
      begin
      if (MyY>Y) then 
         GoDir:=0 
      else 
         GoDir:=4;
      end  
   else 
        
      if (MyX>X) and (MyY>Y) then  GoDir:=7
      else 
        if (MyX>X) and (MyY<Y) then  GoDir:=5 
        else 
           if (MyX<X) and (MyY>Y) then  GoDir:=1 
           else 
             if (MyX<X) and (MyY<Y) then  GoDir:=3; 
             
result:=GoDir;
end;
procedure CalcPrognosis(Dir : integer); 
begin 
   if (Dir = 1) or (Dir = 2) or (Dir = 3) then PrognosisX := GetX(self) + 1; 
   if (Dir = 5) or (Dir = 6) or (Dir = 7) then PrognosisX := GetX(self) - 1; 
   if (Dir = 0) or (Dir = 4) then PrognosisX := GetX(self); 
   if (Dir = 3) or (Dir = 4) or (Dir = 5) then PrognosisY := GetY(self) + 1; 
   if (Dir = 7) or (Dir = 0) or (Dir = 1) then PrognosisY := GetY(self) - 1; 
   if (Dir = 2) or (Dir = 6) then PrognosisY := GetY(self); 
end; 
function TryToMove(Direction : integer; RunFlag : boolean) : boolean; 
var 
  StepResult : byte;
begin 
   result:=false;
   wait(100);
   localWaitConnection(1000);     
   //While Not CheckLag(50) do Wait(500);   // checkLag не пашет!!! Визитера бить!!
 
   
   if IsWorldCellPassable(getX(self),getY(self),PrognosisX,PrognosisY,WorldNum,getZ(self)) then 
      begin
      if GetDirection(self) <> Direction then Step(Direction, RunFlag); 
      StepResult:=Step(Direction,RunFlag);
      If (StepResult=5) OR (StepResult=1) then wait(5000);
      If StepResult=7 then result:=true;
      end;
   
   
end; 
// available StepResult
// 0 - Unknown Error
// 1 - Mover: Resync is pending, ignoring.
// 2 - Mover: Step buffer overflow, Ignoring
// 3 - Mover: Client Canceled. Point not Passable.
// 4 - Mover: Move timeout.
// 5 - Mover: MoveReject
// 6 - Mover: Client Check OK, send move request
// 7 - Mover: Server Check OK, move request accepted
function WrongMove(x, y : integer) : boolean; 
var 
i : integer; 
begin 
   result := false; 
   if FMoveArrCount = 0 then exit; 
   for i := 1 to FMoveArrCount do 
      begin 
      if (x = FMoveArr[i][1]) and (y = FMoveArr[i][2]) then 
         begin 
         result := true; 
         exit; 
         end; 
      end; 
end; 
function Min(x,y: integer): integer;
begin
 if x>y then Result:=y else Result:=x;
end;
function HEst(x,y: integer): integer;
var dx,dy,Ddx : integer;
begin
  dx:= GetX(self)-x;
  dy:= GetY(self)-y;
  Ddx:= dx-dy;
  If dx<0 then dx:=0-dx;
  If dy<0 then dy:=0-dy;
  If Ddx<0 then Ddx:=0-Ddx;
  Result:= min(dx,dy)+Ddx;
end;
procedure SetWrongMove(x, y : integer); 
begin 
   if FMoveArrCount>298 then FMoveArrCount:=0;  // обнуление массива непроходимых тайлов
   FMoveArrCount := FMoveArrCount + 1; 
   FMoveArr[FMoveArrCount][1] := x; 
   FMoveArr[FMoveArrCount][2] := y; 
end; 
function RewindDir(Dir, c : integer) : integer; 
begin 
   result := Dir + c; 
   if result < 0 then result := result + 8; 
   if result > 7 then result := result - 8; 
end; 
function Move(x, y, tolerance : integer; RunFlag: boolean) : boolean; 
var 
Dir, Dist, lastX, lastY, t, i, timeout : integer; 
begin 
   FMoveArrCount := 0; 
   Dist := HEst(x, y); 
   timeout := Dist * 3000; // 3 секунды времени на шаг 
   t := timer; 
   while true do 
      begin 
      Dist := HEst(x, y); 
      if Dist <= tolerance then // пришёл 
         begin 
         result := true; 
         exit; 
      end; 
      if timer - t > timeout then // провал по таймауту 
      begin 
         AddToSystemJournal('Move: Time moved out!'); 
         result := false; 
         exit; 
      end; 
      Dir := SetDirection(x, y); 
      CalcPrognosis(Dir); 
      if WrongMove(PrognosisX, PrognosisY) then 
         begin 
         for i := 1 to 7 do 
            begin 
            Dir := RewindDir(Dir, 1); 
            CalcPrognosis(Dir); 
            if not WrongMove(PrognosisX, PrognosisY) then break; 
            end; 
      if i = 8 then 
         begin 
         AddToSystemJournal('Move: Cannot move'); 
         result := false; 
         exit; 
         end; 
      end; 
     // timeout := timeout + CheckFlow; 
      lastX := GetX(self); lastY := GetY(self); 
      if TryToMove(Dir, RunFlag) then SetWrongMove(lastX, lastY) // отсюда чар пришёл 
      else SetWrongMove(PrognosisX, PrognosisY); 
      end; 
end; 
procedure _move(x, y, tolerance : integer; RunFlag : boolean); 
begin 
while not Move(x, y, tolerance, RunFlag) do wait(100); 
end;
