Advertisement
WarPie90

RS07 - Walker

Jul 6th, 2014
439
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 13.47 KB | None | 0 0
  1. program new;
  2. {$I SimbaExt/SimbaExt.simba}
  3. {$I SimbaExt/Utils.simba}
  4. {$f-}
  5. (*
  6.  Copyright (2014) Jarl <slacky> Holta
  7.  Requires the SimbaExt version from: "08 July 14"  or later
  8.  Requires the [250x250] map pack from http://slackworld.net/downloads/
  9.  - Extract it in include folder, and name the extracted folder "OSRS_Map_250x250"
  10. *)
  11.  
  12. const
  13.   SEW_Path = 'C:\Simba\Includes\OSRS_Map_250x250\';
  14.   SEW_Extension = '.png';
  15.   SEW_Map_Size: TSize2D = [250,250];
  16.   SEW_Rows = 28;
  17.   SEW_Cols = 30;
  18.  
  19.   SEW_MMCenter: TPoint = [648, 83];
  20.   SEW_MMRad: Int8 = 75;
  21.   SEW_Outer: Int8 = 68;
  22.   SEW_Inner: Int8 = 42;
  23.  
  24. type
  25.   SEW_SafeProc = Procedure();
  26.  
  27. type
  28.   SEWalker = record
  29.     TopLeft: TPoint;
  30.     Map: TRafBitmap;
  31.     Custom: Boolean;
  32.     Initalized:Boolean;
  33.     ETimeOut: Int32;
  34.     DeepScan: Boolean;
  35.     SafeProc: SEW_SafeProc;
  36.     SkipDist: Single;
  37.     NoBlindWalk: Boolean;
  38.   end;
  39.  
  40.  
  41.  
  42. procedure SEWalker.Init(Area: TBox);
  43. begin
  44.   Self.Custom := False;
  45.   Self.TopLeft := Self.AssambleMaps( Self.GetArea(Area) );
  46.   Self.Initalized := True;
  47.   Self.ETimeOut := 10000;
  48.   Self.SkipDist := 4;
  49. end;
  50.  
  51.  
  52. procedure SEWalker.Init(Maps:TStringArray); overload;
  53. begin
  54.   Self.Custom := False;
  55.   Self.TopLeft := Self.AssambleMaps(Maps);
  56.   Self.Initalized := True;
  57.   Self.ETimeOut := 10000;
  58.   Self.SkipDist := 4;
  59. end;
  60.  
  61.  
  62. procedure SEWalker.InitCustom(MapPath:String);
  63. begin
  64.   Self.Custom := True;
  65.   Self.Map.Open(MapPath);
  66.   Self.TopLeft := Point(0,0);
  67.   Self.Initalized := True;
  68.   Self.ETimeOut := 10000;
  69.   Self.SkipDist := 4;
  70. end;
  71.  
  72.  
  73. (*
  74.   Must call once you are done walking to avoid Leak.
  75. *)
  76. procedure SEWalker.Free();
  77. begin
  78.   Self.Map.Free();
  79. end;
  80.  
  81.  
  82. (*
  83.  To avoid going in to an eternal loop for some reason,
  84.  say if your char pings out.. this function sets the number
  85.  of MS before the "walker" times out.
  86.  
  87.  > Default: 10000ms
  88. *)
  89. procedure SEWalker.SetTimeout(TimeMS:Int32);
  90. begin
  91.   Self.ETimeOut := TimeMS;
  92. end;
  93.  
  94. (*
  95.   For every step in the path we take this procedure will
  96.   be called.. So it can call some random-check procedure, or
  97.   just a wait procedure..
  98.  
  99.   > Default: nil
  100. *)
  101. procedure SEWalker.SetSafeProc(Proc:SEW_SafeProc);
  102. begin
  103.   Self.SafeProc := Proc;
  104. end;
  105.  
  106. (*
  107.   if True that means whenever the GetMyPos-function fails
  108.   it will just click the next corrdinate in "Path" and assume
  109.   averythings fine.
  110.  
  111.   > Default: True
  112. *)
  113. procedure SEWalker.SetBlindWalk(Disallow:Boolean=False);
  114. begin
  115.   Self.NoBlindWalk := Disallow;
  116. end;
  117.  
  118. (*
  119.   SetDeepScan to True means that you will search trough
  120.   the whole image. This is slow and almost never needed.
  121.  
  122.   Custom maps however always scans the whole custom map.
  123.  
  124.   > Default: False (True if custom-map)
  125. *)
  126. procedure SEWalker.SetDeepScan(Deep:Boolean=False);
  127. begin
  128.   if Self.Custom then
  129.     RaiseException(erException, 'SEWalker: Custom maps does not support this feature');
  130.   Self.DeepScan := Deep;
  131. end;
  132.  
  133.  
  134. (*
  135.   SetSkipClose sets how close to the resulting pos
  136.   you have to be before it click the next coordinate.
  137.  
  138.   > Default: 4 (px)
  139. *)
  140. procedure SEWalker.SetSkipClose(Dist:Single);
  141. begin
  142.   SkipDist := Dist;
  143. end;
  144.  
  145.  
  146.  
  147. {---| Implementation |---------------------------------------------------------}
  148. (*
  149.   Get the compass angle (Radians)
  150. *)
  151. function SEWalker.CompassAngle(): Single;
  152. var
  153.   A,B: TPoint; M:TPoint = [561,20];
  154.   i:Integer;
  155.   ATPA:T2DPointArray;
  156.   TPA:TPointArray;
  157.   Filter:TBox = [554,13,568,27];
  158. begin
  159.   FindColorsSpiralTolerance(M.x,M.y,TPA, 920735, 543,3,578,38, 1);
  160.   ATPA := TPA.Cluster(3,True);
  161.   SetLength(TPA, 0);
  162.   for i:=0 to High(ATPA) do
  163.     if TPA.Len() < 3 then begin
  164.       A := ATPA[i].Pop();
  165.       if not Filter.Contains(A) then TPA.Append(A);
  166.     end;
  167.   se.LongestPolyVector(TPA, A,B);
  168.   TPA.Remove(A);
  169.   TPA.Remove(B);
  170.   Result := Math.Modulo(ArcTan2(-(M.y-TPA[0].y),(M.x-TPA[0].x)),PI*2);
  171. end;
  172.  
  173.  
  174.  
  175. (*
  176.   Dirty search for minimap flag (it's all that's needed)
  177. *)
  178. function SEWalker.FFlag(): Boolean;
  179. var
  180.   TPA: TPointArray;
  181.   ATPA: T2DPointArray;
  182.   i: Integer;
  183. begin
  184.   Result := False;
  185.   if FindColorsTolerance(TPA, 255, SEW_MMCenter.x-SEW_Outer, SEW_MMCenter.y-SEW_Outer,
  186.                                    SEW_MMCenter.x+SEW_Outer, SEW_MMCenter.y+SEW_Outer, 1) then
  187.   begin
  188.     ATPA := SplitTPA(TPA,1);
  189.     for i := 0 to High(ATPA) do
  190.       if (Length(ATPA[i]) >= 15) AND (Length(ATPA[i]) <= 50) then
  191.         Result := True;
  192.   end;
  193. end;
  194.  
  195.  
  196. (*
  197.   Gathers the needed pieces from a the given TBox.
  198. *)
  199. function SEWalker.GetArea(Area:TBox): TStringArray;
  200. var
  201.   upper,lower:TPoint;
  202.   x,y:Int32;
  203. begin
  204.   Area.Expand(SEW_MMRad);
  205.  
  206.   Upper.X := Max(0,Area.x1) div SEW_Map_Size.W;
  207.   Upper.Y := Max(0,Area.y1) div SEW_Map_Size.H;
  208.   Lower.X := Max(0,Area.x2) div SEW_Map_Size.W;
  209.   Lower.Y := Max(0,Area.y2) div SEW_Map_Size.H;
  210.   for y:=Upper.y to Lower.y do
  211.     for x:=Upper.x to Lower.x do
  212.       Result.Append(ToStr(y)+'_'+ToStr(x));
  213. end;
  214.  
  215.  
  216. (*
  217.   Converts the given pieces in to one big map.
  218. *)
  219. function SEWalker.AssambleMaps(Maps:TStringArray): TPoint;
  220. var
  221.   lx,ly,sx,sy,i:Int32;
  222.   xy:TStringArray;
  223.   tpa:TPointArray;
  224.   tmp:TRafBitmap;
  225.   Pos:TPoint;
  226. begin
  227.   LX := $FFFFFF;
  228.   LY := $FFFFFF;
  229.   for i:=0 to High(Maps) do
  230.   begin
  231.     xy := Maps[i].Split('_');
  232.     TPA.Append( [StrToInt(xy[1]), StrToInt(xy[0])] );
  233.     LY := Min(TPA[i].y, LY);
  234.     LX := Min(TPA[i].x, LX);
  235.   end;
  236.   Result := Point(LX * SEW_Map_Size.W, LY * SEW_Map_Size.H);
  237.  
  238.   Map.Create(0,0);
  239.   for i:=0 to High(TPA) do
  240.   begin
  241.     SY := TPA[i].y;
  242.     SX := TPA[i].x;
  243.     tmp.Open(SEW_Path + Maps[i] + SEW_Extension);
  244.     Pos := Point((SX-LX) * SEW_Map_Size.W, (SY-LY) * SEW_Map_Size.H);
  245.     Map.Draw(tmp, Pos, True);
  246.   end;
  247.   tmp.Free();
  248. end;
  249.  
  250.  
  251. (*
  252.  Method is used to safely call the given safeproc.
  253. *)
  254. procedure SEWalker.CallSafeProc();
  255. begin
  256.   if Self.SafeProc <> nil then
  257.     try
  258.       Self.SafeProc();
  259.     except
  260.       RaiseException(erException, 'SEWalker: Failed while calling SafeProc');
  261.     end;
  262. end;
  263.  
  264.  
  265. (*
  266.  GetCorrelationInfo first extract the `n` highest peaks, then using those peaks
  267.  it then cluster them, and inspects each group for the max peak.
  268.  Returns the point where the peak is highest.
  269.  
  270.  //Note to self: Look once more.
  271. *)
  272. function SEWalker.GetCorrelationInfo(Mat:TFloatMatrix; n:Int32; out midpt:TPoint): Double;
  273. var
  274.   i,j:Int32;
  275.   ATPA:T2DPointArray;
  276.   TPA:TPointArray;
  277.   Sums:TExtArray;
  278. begin
  279.   TPA := Mat.ArgMax(n);
  280.   if (Length(TPA) = 0) then Exit();
  281.   ATPA := TPA.Cluster(1,False);
  282.   SetLength(Sums, Length(ATPA));
  283.   for i:=0 to High(ATPA) do
  284.     Sums[i] := Mat.Get(ATPA[i]).VarMax();
  285.   j := Sums.ArgMax();
  286.   Result := Sums[j];
  287.   midpt := ATPA[j][Mat.Get(ATPA[j]).ArgMax()];
  288. end;
  289.  
  290.  
  291. (*
  292.  Scans trough the whole global map for our current position.
  293. *)
  294. function SEWalker.GetMyPos(): TPoint;
  295. const
  296.   angles = [-10, 0, 10];
  297. var
  298.   i, size: Int32;
  299.   BMP,RotatedBMP:TRafBitmap;
  300.   Mid: TPoint;
  301.   Corr: TFloatMatrix;
  302.   values:TDoubleArray;
  303.   PTS: TPointArray;
  304. begin
  305.   BMP.FromClient(SEW_MMCenter.x - SEW_outer, SEW_MMCenter.y - SEW_outer,
  306.                  SEW_MMCenter.x + SEW_outer, SEW_MMCenter.y + SEW_outer);
  307.  
  308.   BMP.LazyRotate(-Self.CompassAngle()+PI/2, False);
  309.  
  310.   mid := Point(SEW_outer, SEW_outer);
  311.   Size := SEW_inner * 2 + 1;
  312.  
  313.   SetLength(PTS,Length(Angles));
  314.   for i:=0 to High(Angles) do
  315.   begin
  316.     RotatedBMP := BMP.Rotate(Radians(Angles[i]), False);
  317.     RotatedBMP.LazyCrop(mid.x - SEW_inner, mid.y - SEW_inner,
  318.                         mid.x + SEW_inner, mid.y + SEW_inner);
  319.  
  320.     Corr := se.MatchTemplate(Map, RotatedBMP, TM_CCOEFF_NORMED);
  321.     Values.append(GetCorrelationInfo(Corr, 50, PTS[i]));
  322.     RotatedBMP.Free();
  323.   end;
  324.   Mid := PTS[Values.ArgMax()];
  325.  
  326.   bmp.Free();
  327.   Mid.Offset(Point( SEW_inner+TopLeft.x, SEW_inner+TopLeft.y ));
  328.   Result := Mid;
  329. end;
  330.  
  331.  
  332. (*
  333.  Scans trough only a part of the global map for our current position.
  334.  The part which we scans trough is based on "AssumedPos", and the radius scanned
  335.  trough is the parameter "Radius".
  336. *)
  337. function SEWalker.GetMyPos(AssumedPos:TPoint; Radius:Int32=160): TPoint; overload;
  338. const
  339.   angles = [-10, 0, 10];
  340. var
  341.   i, size: Int32;
  342.   Part,BMP,RotatedBMP:TRafBitmap;
  343.   Mid,low,hei: TPoint;
  344.   Corr: TFloatMatrix;
  345.   values:TDoubleArray;
  346.   PTS: TPointArray;
  347. begin
  348.   low.x := Max(0, AssumedPos.x - Radius - TopLeft.x);
  349.   low.y := Max(0, AssumedPos.y - Radius - TopLeft.y);
  350.   hei.x := Min(Map.Width,  AssumedPos.x + Radius - TopLeft.x);
  351.   hei.y := Min(Map.Height, AssumedPos.y + Radius - TopLeft.y);
  352.   Part := Map.Crop(low.x, low.y, hei.x, hei.y);
  353.  
  354.   BMP.FromClient(SEW_MMCenter.x - SEW_outer, SEW_MMCenter.y - SEW_outer,
  355.                  SEW_MMCenter.x + SEW_outer, SEW_MMCenter.y + SEW_outer);
  356.  
  357.   BMP.LazyRotate(-Self.CompassAngle()+PI/2, False);
  358.   BMP.Debug();
  359.  
  360.   Mid := Point(SEW_outer, SEW_outer);
  361.   Size := SEW_inner * 2 + 1;
  362.  
  363.   SetLength(PTS,Length(Angles));
  364.   for i:=0 to High(Angles) do
  365.   begin
  366.     RotatedBMP := BMP.Rotate(Radians(angles[i]), False);
  367.     RotatedBMP.LazyCrop(mid.x - SEW_inner, mid.y - SEW_inner,
  368.                         mid.x + SEW_inner, mid.y + SEW_inner);
  369.  
  370.     Corr := se.MatchTemplate(Part, RotatedBMP, TM_CCOEFF_NORMED);
  371.     Values.Append(GetCorrelationInfo(Corr, 50, PTS[i]));
  372.     RotatedBMP.Free();
  373.   end;
  374.   Mid := PTS[Values.ArgMax()];
  375.  
  376.   BMP.Free();
  377.   Part.Free();
  378.  
  379.   Mid.Offset(Point( SEW_inner+TopLeft.x+low.x, SEW_inner+TopLeft.y+low.y ));
  380.   Result := Mid;
  381. end;
  382.  
  383.  
  384. (*
  385.  Converts the point to a point around center based around "Mid"
  386. *)
  387. function SEWalker.GetRelativePos(Mid,Off:TPoint): TPoint;
  388. begin
  389.   Result := Off;
  390.   Result.Offset(Point(-Mid.x, -Mid.y));
  391. end;
  392.  
  393.  
  394. (*
  395.  Gets the current pos using the selected method (global-, or "area"-search)
  396. *)
  397. function SEWalker.__GetPos(var Pos:TPoint; Goal:TPoint): Single;
  398. begin
  399.   case DeepScan of
  400.     True:  Pos := Self.GetMyPos();
  401.     False: Pos := Self.GetMyPos(Goal);
  402.   end;
  403.  
  404.   Result := Pos.DistanceTo(Goal);
  405. end;
  406.  
  407.  
  408. (*
  409.  Walks to the given point on the global map.
  410. *)
  411. procedure SEWalker.WalkTo(Goal:TPoint; Prev:TPoint=[-1,-1]);
  412. var
  413.   i:Int32;
  414.   Failed:Boolean;
  415.   Start,PT,Mark: TPoint;
  416.   Dist2,PrevDist: Single;
  417.   T:Double;
  418. begin
  419.   if not( Initalized ) then
  420.      RaiseException(erException, 'SEWalker: Not initalized');
  421.  
  422.   Dist2 := Self.__GetPos(Start,Goal);
  423.   for i:=0 to 5 do
  424.     if (Dist2 > SEW_MMRad) then begin
  425.       Dist2 := Self.__GetPos(Start,Goal);
  426.       Failed := True;
  427.       Wait(50);
  428.     end else begin
  429.       Failed := False;
  430.       Break;
  431.     end;
  432.  
  433.   if Failed then
  434.     if NoBlindWalk then
  435.       RaiseException(erException, 'SEWalker: Distance to `Goal` is exceeding boundaries: '+
  436.                                   '"'+ToStr(Start)+'", "'+ ToStr(Goal) +'"')
  437.     else begin
  438.       while Self.FFlag() do Wait(5);
  439.       if Prev.EQ([-1,-1]) then
  440.         RaiseException(erException, 'SEWalker: Distance to `Goal` is exceeding boundaries: '+
  441.                                     '"'+ToStr(Start)+'", "'+ ToStr(Goal) +'"');
  442.       Start := Prev;
  443.       Dist2 := Start.DistanceTo(Goal);
  444.     end;
  445.  
  446.   PT := Self.GetRelativePos(Start,Goal);
  447.   if PT.DistanceTo(Point(0,0)) > SEW_MMRad then
  448.     Exit();
  449.   PT := RotatePoint(PT,-Self.CompassAngle()+PI/2,0,0);
  450.   PT.Offset(SEW_MMCenter);
  451.  
  452.   Mouse.Click(PT, mbLeft);
  453.  
  454.   T := MarkTime();
  455.   while (Dist2 > SkipDist) and Self.FFlag() do
  456.   begin
  457.     case DeepScan of
  458.       True:  Dist2 := Self.GetMyPos().DistanceTo(Goal);
  459.       False: Dist2 := Self.GetMyPos(Goal).DistanceTo(Goal)
  460.     end;
  461.     if (T - MarkTime()) > Self.ETimeOut then
  462.       RaiseException(erException, 'SEWalker: Timed out while walking to '+
  463.                                   '"'+ToStr(Goal)+'", from "'+ToStr(Start)+'"');
  464.   end;
  465.  
  466.   for i:=1 to 3 do
  467.     if (Dist2 > SkipDist) then Wait(100);
  468. end;
  469.  
  470.  
  471. (*
  472.  Function is used to validate a path. It ensures that each point is reachable
  473.  from the previous point.
  474. *)
  475. function SEWalker.ValidatePath(Path:TPointArray): Boolean;
  476. var i:Int32;
  477. begin
  478.   for i:=1 to High(Path) do
  479.     if Path[i-1].DistanceTo(Path[i]) > SEW_Outer then
  480.     begin
  481.       WriteLn('SEWalker: "Path['+ToStr(i-1)+']" to "Path['+ToStr(i)+']" is greater then MaxDist: '+ToStr(SEW_Outer));
  482.       Exit(False);
  483.     end;
  484.   Result := True;
  485. end;
  486.  
  487.  
  488. (*
  489.  Walks a path..
  490. *)
  491. procedure SEWalker.Walk(Path:TPointArray);
  492. var
  493.   i,j,ii,halfdist,hi:Int32;
  494.   Pos:TPoint;
  495. begin
  496.   if not( Initalized ) then
  497.      RaiseException(erException, 'SEWalker: Not initalized');
  498.  
  499.   if not(Self.ValidatePath(Path)) then
  500.      RaiseException(erException, 'SEWalker: Invalid Path');
  501.  
  502.   HalfDist := (SEW_Inner div 2);
  503.   i := 0;
  504.   hi := High(Path);
  505.   while i <= hi do
  506.   begin
  507.     for j:=0 to 2 do
  508.     begin
  509.       Pos := Self.GetMyPos(Path[i]);
  510.       if (i < hi) then
  511.         if Pos.DistanceTo(Path[i+1]) < Pos.DistanceTo(Path[i]) then
  512.           Inc(i);
  513.  
  514.       if (Pos.DistanceTo(Path[i]) > HalfDist) or (j=0) then
  515.         Self.WalkTo(Path[i], Pos)
  516.       else
  517.         Break;
  518.     end;
  519.  
  520.     Self.CallSafeProc();
  521.     Inc(i);
  522.   end;
  523. end;
  524.  
  525.  
  526.  
  527. var
  528.   Walker:SEWalker;
  529.   Path:TPointArray;
  530. begin
  531.   //Path starts at varroc west bank (door)
  532.   Path := [Point(4559, 2959), Point(4600, 2959), Point(4635, 2963), Point(4655, 2955), Point(4678, 2939), Point(4720, 2957), Point(4755, 2962), Point(4791, 2963), Point(4834, 2960), Point(4814, 2953), Point(4807, 2925), Point(4782, 2904), Point(4749, 2904), Point(4718, 2929), Point(4705, 2961), Point(4687, 2981), Point(4660, 2975), Point(4628, 2966), Point(4600, 2959), Point(4559, 2959)];
  533.   Walker.Init(Path.Bounds());
  534.   Walker.SetSkipClose(10);
  535.   Walker.Walk(Path);
  536.   Walker.Free();
  537. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement