Advertisement
WarPie90

Crazy doors - Simba 1.5 [imperfect]

Jun 10th, 2023
1,582
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 9.63 KB | None | 0 0
  1. program new;
  2. {$DEFINE SRL_USE_REMOTEINPUT}
  3. {$I SRL/osr.simba}
  4.  
  5. type
  6.   TDoorMMInfo = record
  7.     Search: TQuad;
  8.     Shape: TQuad;
  9.     BaseAngle: Double;
  10.     mm1,mm2: TPoint;
  11.   end;
  12.   TDoorMMInfoArray = array of TDoorMMInfo;
  13.  
  14.   TRSDoor = record
  15.     Door: TQuad;
  16.     IsOpen: Boolean;
  17.   end;
  18.   TRSDoors = array of TRSDoor;
  19.  
  20.   TDoorFilter = record
  21.     EdgeSensitivity: Int32;
  22.     Grow: Int32;
  23.     Erode: Int32;
  24.     MinDensity: Double;
  25.   end;
  26.  
  27.  
  28. function DoorFilter(EdgeSensitivity: Int32; Grow: Int32; Erode: Int32; MinDensity: Double): TDoorFilter;
  29. begin
  30.   Result.EdgeSensitivity := EdgeSensitivity;
  31.   Result.Grow            := Grow;
  32.   Result.Erode           := Erode;
  33.   Result.MinDensity      := MinDensity;
  34. end;
  35.  
  36. function PolygonArea(const Poly:TPointArray): Double; override;
  37. begin
  38.   Result := Abs(inherited);
  39. end;
  40.  
  41. function GetPolyDensity(TPA: TPointArray; Poly: TPointArray): Double;
  42. begin
  43.   Result := Length(TPA) / PolygonArea(Poly);
  44. end;
  45.  
  46.  
  47. function ReduceToQuad(Poly: TPointArray): TPointArray;
  48. var
  49.   i: Int32;
  50.   base, area: Double;
  51.   best: record area: Double; i: Int32; end;
  52.   tmp: TPointArray;
  53. begin
  54.   while Length(Poly) > 4 do
  55.   begin
  56.     base := PolygonArea(Poly);
  57.  
  58.     best.area := 0;
  59.     best.i    := -1;
  60.  
  61.     for i:=0 to High(Poly) do
  62.     begin
  63.       tmp := Poly.Copy();
  64.       tmp.Pop(i);
  65.       area := PolygonArea(tmp);
  66.       if area > best.area then
  67.         best := [area,i];
  68.     end;
  69.  
  70.     Poly.Pop(best.i);
  71.   end;
  72.  
  73.   Result := Poly;
  74. end;
  75.  
  76.  
  77. procedure FurthestPoints(const TPA:TPointArray; out A,B:TPoint);
  78. var
  79.   i,j: Integer;
  80.   dist,tmp: Single;
  81. begin
  82.   for i:=0 to High(TPA) do
  83.     for j:=i+1 to High(TPA) do
  84.     begin
  85.       tmp := Hypot(TPA[i].x-TPA[j].x, TPA[i].y-TPA[j].y);
  86.       if tmp > dist then
  87.       begin
  88.         dist := tmp;
  89.         A := TPA[i];
  90.         B := TPA[j];
  91.       end;
  92.     end;
  93. end;
  94.  
  95. function DoorDirectionsAndArea(): TDoorMMInfoArray;
  96. var
  97.   dColor, wColor: TCTS1Color;
  98.   doors, w,d: TPointArray;
  99.   line: record a,b:TPoint; end;
  100.   theta,c: Single;
  101.   shape: TQuad;
  102.  
  103.   function Scale4Or8(start, other: TPoint): TPoint;
  104.   var rad, theta: Double;
  105.   begin
  106.     rad := start.DistanceTo(other);
  107.     theta := PI+ArcTan2(start.y-other.y, start.x-other.x);
  108.     if rad > 6 then
  109.     begin
  110.       Result.x := Round(start.x + 8 * Cos(theta));
  111.       Result.y := Round(start.y + 8 * Sin(theta));
  112.     end else begin
  113.       Result.x := Round(start.x + 4 * Cos(theta));
  114.       Result.y := Round(start.y + 4 * Sin(theta));
  115.     end;
  116.   end;
  117.  
  118. begin
  119.   dColor := CTS1($FF, 45);
  120.   wColor := CTS1($FFFFFF, 45);
  121.  
  122.   srl.FindColors(w, wColor, minimap.Bounds());
  123.   srl.FindColors(d, dColor, Minimap.Bounds());
  124.  
  125.   c := Minimap.GetCompassAngle(True);
  126.   d := d.PointsNearby(w, 0,8);
  127.   for doors in d.Cluster(3) do
  128.   begin
  129.     FurthestPoints(doors, line.a, line.b);
  130.     line.b := Scale4Or8(line.a, line.b);
  131.  
  132.     theta := ArcTan2(line.a.y-line.b.y, line.a.x-line.b.x);
  133.     theta := Degrees(theta);
  134.     theta := Modulo(theta-c, 180);
  135.  
  136.     // build a ms rectangle for later use for size comparison:
  137.     shape := [
  138.       Minimap.VecToMs([line.a.x, line.a.y, 8]),
  139.       Minimap.VecToMs([line.b.x, line.b.y, 8]),
  140.       Minimap.VecToMs([line.b.x, line.b.y, 0]),
  141.       Minimap.VecToMs([line.a.x, line.a.y, 0])
  142.     ];
  143.  
  144.     Result += [Minimap.PointToMsRect(TPointArray([line.a, line.b]).Mean()), shape, theta, line.a, line.b];
  145.   end;
  146. end;
  147.  
  148.  
  149. function FixOrderQuad(Q: TPointArray): TPointArray;
  150. var i,t: Int32;
  151. begin
  152.   for i:=1 to High(Q) do
  153.     if (Q[i].y < Q[t].y) or ((Q[i].y = Q[t].y) and (Q[i].x < Q[t].x)) then
  154.       t := i;
  155.  
  156.   Result += Q[t];
  157.   Result += Q[(t+1) mod 4];
  158.   Result += Q[(t+2) mod 4];
  159.   Result += Q[(t+3) mod 4];
  160. end;
  161.  
  162.  
  163. function QuadTop(Q: TPointArray; UpDirection: Double): TPointArray;
  164. var
  165.   p: TPoint;
  166.   d_0_3,d_0_1: Double;
  167. begin
  168.   d_0_1 := Abs(DeltaAngle(Degrees(PI + ArcTan2(Q[0].y-Q[3].y, Q[0].x-Q[3].x)), UpDirection, 360));
  169.   d_0_3 := Abs(DeltaAngle(Degrees(PI + ArcTan2(Q[0].y-Q[1].y, Q[0].x-Q[1].x)), UpDirection, 360));
  170.  
  171.   //Q[0] is highest, now I need second highest
  172.   if d_0_1 > d_0_3 then begin
  173.     P := Q[3];
  174.   end else begin
  175.     P := Q[1];
  176.   end;
  177.  
  178.   Result := [Q[0],P];
  179. end;
  180.  
  181. function GetUpAngle(mmpt: TPoint): Double;
  182. var
  183.   l1,l2: TPoint;
  184. begin
  185.   l1 := Minimap.VecToMs([mmpt.x, mmpt.y, 0]);
  186.   l2 := Minimap.VecToMs([mmpt.x, mmpt.y, 32]);
  187.  
  188.   Result := Degrees(ArcTan2(l1.y-l2.y, l1.x-l2.x));
  189. end;
  190.  
  191. function ExtractDoorsAndStates(ATPA: T2DPointArray; MinDensity: Double): TRSDoors;
  192. var
  193.   i,j, nearest: Int32;
  194.   poly, reduced: TPointArray;
  195.   up, best, dist, theta, roll, a1,a2: Single;
  196.   ms1,ms2: TPoint;
  197.   qp: TPointArray;
  198.   v1,v2: Vector3;
  199.   doors: TDoorMMInfoArray;
  200. begin
  201.   roll := Minimap.GetCompassAngle(True);
  202.   doors := DoorDirectionsAndArea();
  203.  
  204.   for i:=0 to High(ATPA) do
  205.   begin
  206.     if Length(ATPA[i]) < 100 then
  207.       continue;
  208.  
  209.     Poly := ATPA[i].ConvexHull();
  210.     if Length(Poly) < 4 then continue;
  211.  
  212.     reduced := FixOrderQuad(ReduceToQuad(Poly));
  213.  
  214.     if (GetPolyDensity(ATPA[i], Poly) > MinDensity) then
  215.     begin
  216.       // get corresponding door from minimap:
  217.       nearest := -1;
  218.       best := $FFFFFF;
  219.  
  220.       for j:=0 to High(doors) do
  221.       begin
  222.         dist := Distance(ATPA[i].Mean(), doors[j].Search.Mean());
  223.         if (dist < best) and (dist < MainScreen.NormalizeDistance(120)) then
  224.         begin
  225.           nearest := j;
  226.           best := dist;
  227.         end;
  228.       end;
  229.  
  230.       if best = $FFFFFF then
  231.         continue;
  232.  
  233.       up := GetUpAngle(TPointArray([doors[nearest].mm1, doors[nearest].mm2]).Mean());
  234.       qp := QuadTop(reduced, up);
  235.  
  236.       ms1 := Minimap.VecToMs([doors[nearest].mm1.x, doors[nearest].mm1.y, 8]);
  237.       ms2 := Minimap.VecToMs([doors[nearest].mm2.x, doors[nearest].mm2.y, 8]);
  238.  
  239.       v1 := MainScreen.PointToMM(qp[0], 8);
  240.       v2 := MainScreen.PointToMM(qp[1], 8);
  241.  
  242.       theta := Degrees(ArcTan2(v1.y-v2.y, v1.x-v2.x));
  243.       theta := Modulo(theta-roll, 180);
  244.  
  245.       if Abs(DeltaAngle(theta, doors[nearest].BaseAngle, 180)) < 40 then begin
  246.         Result += [[reduced[0], reduced[1], reduced[2], reduced[3]], False];
  247.       end else begin
  248.         Result += [[reduced[0], reduced[1], reduced[2], reduced[3]], True];
  249.       end;
  250.     end;
  251.   end;
  252. end;
  253.  
  254. function FindDoors(Color: TCTS2Color; Bounds: TBox; Filter: TDoorFilter): TRSDoors;
  255. var
  256.   client_raw: TMufasaBitmap;
  257.   Edge, TPA: TPointArray;
  258.   ATPA: T2DPointArray;
  259.   i: Int32;
  260. begin
  261.   srl.FindColors(TPA, Color, Bounds);
  262.   if Length(TPA) < 10 then
  263.     Exit;
  264.  
  265.   //TPA := TPA.Erode(1).Grow(1); // <--- reduce pixel noise?
  266.  
  267.   // if EdgeSensitivity is set to more than 0, then we use edges to process on
  268.   // this is needed wherever ground and doors have too similar color
  269.   if Filter.EdgeSensitivity > 0 then
  270.   begin
  271.     client_raw := TMufasaBitmap.CreateFromClient();
  272.     Edge := client_raw.PixelEdgesTPA(Filter.EdgeSensitivity);
  273.     client_raw.Free();
  274.     TPA := TPA.Intersection(Edge);
  275.   end;
  276.  
  277.   // apply grow and erode for noise filtering
  278.   TPA := TPA.Grow(Filter.Grow).Erode(Filter.Erode);
  279.   //TPA := TPA.ExcludePoints(Edge);
  280.  
  281.   // filter out interfaces
  282.   TPA := TPA.ExcludePoints(TPointArray.CreateFromBox(Chat.Bounds, True));
  283.   TPA := TPA.ExcludePoints(TPointArray.CreateFromBox(GameTabs.Bounds, True));
  284.   TPA := TPA.ExcludePoints(TPointArray.CreateFromBox(Minimap.Bounds, True));
  285.  
  286.  
  287.   ATPA := TPA.Cluster(1);
  288.   //RSClient.Image.DrawATPA(ATPA);
  289.   Result := ExtractDoorsAndStates(ATPA, Filter.MinDensity);
  290.  
  291.   for i:=0 to High(Result) do
  292.     Result[i].Door := Result[i].Door.Expand(Filter.Erode-Filter.Grow);
  293. end;
  294.  
  295. function FilterDoorsMM(Doors: TRSDoors; AcceptableTileDist: Double): TRSDoors;
  296. var
  297.   mmd: TDoorMMInfoArray;
  298.   idx, i, j: Int32;
  299.   best,dist: Double;
  300. begin
  301.   mmd := DoorDirectionsAndArea();
  302.   if Length(mmd) = 0 then Exit;
  303.  
  304.   AcceptableTileDist := mmd[0].Search.Top.DistanceTo(mmd[0].Search.Right) * AcceptableTileDist;
  305.   for i:=0 to High(mmd) do
  306.   begin
  307.     best := $FFFFFF;
  308.     for j:=0 to High(doors) do
  309.     begin
  310.       dist := mmd[i].Search.Mean().DistanceTo(doors[j].Door.Mean());
  311.       if dist < best then
  312.       begin
  313.         best := dist;
  314.         idx := j;
  315.       end;
  316.     end;
  317.     if best < AcceptableTileDist then
  318.       Result += Doors[idx];
  319.   end;
  320. end;
  321.  
  322. var
  323.   doors: TRSDoors;
  324.   i: Int32;
  325. begin
  326.   RSClient.Image.SetFontSize(12);
  327.   RSClient.Image.setFontAntialiasing(False);
  328.   RSClient.Image.Clear();
  329.   //TerminateScript;
  330.  
  331.   //Varrock simple door: CTS2(3561056, 19, 0.08, 0.34), MainScreen.Bounds(), DoorFilter(15, 4,6, 0.6)
  332.   //Varrock fancy door : CTS2(3302000, 18, 0.06, 0.89), MainScreen.Bounds(), DoorFilter(20, 5,7, 0.4)
  333.   //Lumby              : CTS2(1138041, 17, 0.08, 1.48), MainScreen.Bounds(), DoorFilter(0, 4,6, 0.6)
  334.   //A lumby gate!!     : CTS2(1138041, 17, 0.08, 1.48), MainScreen.Bounds(), DoorFilter(0, 6,8, 0.1)
  335.  
  336.   while True do
  337.   begin                 //Fally    = CTS2(5930899, 21, 0.04, 0.41)
  338.  
  339.  
  340.     doors := FindDoors(CTS2(3561056, 19, 0.08, 0.34), MainScreen.Bounds(), DoorFilter(15, 4,6, 0.6));
  341.     doors := FilterDoorsMM(doors, 2.5);
  342.  
  343.     RSClient.Image.Clear();
  344.     for i:=0 to High(doors) do
  345.     begin
  346.       if doors[i].IsOpen then begin
  347.         RSClient.Image.DrawQuad(doors[i].Door, $00FF00);
  348.         RSClient.Image.DrawText('Open', doors[i].Door.Mean()+Point(-20,0), $77FF77);
  349.         RSClient.Image.DrawText('Open', doors[i].Door.Mean()+Point(-19,0), $77FF77);
  350.       end else begin
  351.         RSClient.Image.DrawQuad(doors[i].Door, $FF);
  352.         RSClient.Image.DrawText('Closed', doors[i].Door.Mean()+Point(-20,0), $77FF77);
  353.         RSClient.Image.DrawText('Closed', doors[i].Door.Mean()+Point(-19,0), $77FF77);
  354.       end;
  355.     end;
  356.   end;
  357. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement