Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- program new;
- {$DEFINE SRL_USE_REMOTEINPUT}
- {$I SRL/osr.simba}
- type
- TDoorMMInfo = record
- Search: TQuad;
- Shape: TQuad;
- BaseAngle: Double;
- mm1,mm2: TPoint;
- end;
- TDoorMMInfoArray = array of TDoorMMInfo;
- TRSDoor = record
- Door: TQuad;
- IsOpen: Boolean;
- end;
- TRSDoors = array of TRSDoor;
- TDoorFilter = record
- EdgeSensitivity: Int32;
- Grow: Int32;
- Erode: Int32;
- MinDensity: Double;
- end;
- function DoorFilter(EdgeSensitivity: Int32; Grow: Int32; Erode: Int32; MinDensity: Double): TDoorFilter;
- begin
- Result.EdgeSensitivity := EdgeSensitivity;
- Result.Grow := Grow;
- Result.Erode := Erode;
- Result.MinDensity := MinDensity;
- end;
- function PolygonArea(const Poly:TPointArray): Double; override;
- begin
- Result := Abs(inherited);
- end;
- function GetPolyDensity(TPA: TPointArray; Poly: TPointArray): Double;
- begin
- Result := Length(TPA) / PolygonArea(Poly);
- end;
- function ReduceToQuad(Poly: TPointArray): TPointArray;
- var
- i: Int32;
- base, area: Double;
- best: record area: Double; i: Int32; end;
- tmp: TPointArray;
- begin
- while Length(Poly) > 4 do
- begin
- base := PolygonArea(Poly);
- best.area := 0;
- best.i := -1;
- for i:=0 to High(Poly) do
- begin
- tmp := Poly.Copy();
- tmp.Pop(i);
- area := PolygonArea(tmp);
- if area > best.area then
- best := [area,i];
- end;
- Poly.Pop(best.i);
- end;
- Result := Poly;
- end;
- procedure FurthestPoints(const TPA:TPointArray; out A,B:TPoint);
- var
- i,j: Integer;
- dist,tmp: Single;
- begin
- for i:=0 to High(TPA) do
- for j:=i+1 to High(TPA) do
- begin
- tmp := Hypot(TPA[i].x-TPA[j].x, TPA[i].y-TPA[j].y);
- if tmp > dist then
- begin
- dist := tmp;
- A := TPA[i];
- B := TPA[j];
- end;
- end;
- end;
- function DoorDirectionsAndArea(): TDoorMMInfoArray;
- var
- dColor, wColor: TCTS1Color;
- doors, w,d: TPointArray;
- line: record a,b:TPoint; end;
- theta,c: Single;
- shape: TQuad;
- function Scale4Or8(start, other: TPoint): TPoint;
- var rad, theta: Double;
- begin
- rad := start.DistanceTo(other);
- theta := PI+ArcTan2(start.y-other.y, start.x-other.x);
- if rad > 6 then
- begin
- Result.x := Round(start.x + 8 * Cos(theta));
- Result.y := Round(start.y + 8 * Sin(theta));
- end else begin
- Result.x := Round(start.x + 4 * Cos(theta));
- Result.y := Round(start.y + 4 * Sin(theta));
- end;
- end;
- begin
- dColor := CTS1($FF, 45);
- wColor := CTS1($FFFFFF, 45);
- srl.FindColors(w, wColor, minimap.Bounds());
- srl.FindColors(d, dColor, Minimap.Bounds());
- c := Minimap.GetCompassAngle(True);
- d := d.PointsNearby(w, 0,8);
- for doors in d.Cluster(3) do
- begin
- FurthestPoints(doors, line.a, line.b);
- line.b := Scale4Or8(line.a, line.b);
- theta := ArcTan2(line.a.y-line.b.y, line.a.x-line.b.x);
- theta := Degrees(theta);
- theta := Modulo(theta-c, 180);
- // build a ms rectangle for later use for size comparison:
- shape := [
- Minimap.VecToMs([line.a.x, line.a.y, 8]),
- Minimap.VecToMs([line.b.x, line.b.y, 8]),
- Minimap.VecToMs([line.b.x, line.b.y, 0]),
- Minimap.VecToMs([line.a.x, line.a.y, 0])
- ];
- Result += [Minimap.PointToMsRect(TPointArray([line.a, line.b]).Mean()), shape, theta, line.a, line.b];
- end;
- end;
- function FixOrderQuad(Q: TPointArray): TPointArray;
- var i,t: Int32;
- begin
- for i:=1 to High(Q) do
- if (Q[i].y < Q[t].y) or ((Q[i].y = Q[t].y) and (Q[i].x < Q[t].x)) then
- t := i;
- Result += Q[t];
- Result += Q[(t+1) mod 4];
- Result += Q[(t+2) mod 4];
- Result += Q[(t+3) mod 4];
- end;
- function QuadTop(Q: TPointArray; UpDirection: Double): TPointArray;
- var
- p: TPoint;
- d_0_3,d_0_1: Double;
- begin
- d_0_1 := Abs(DeltaAngle(Degrees(PI + ArcTan2(Q[0].y-Q[3].y, Q[0].x-Q[3].x)), UpDirection, 360));
- d_0_3 := Abs(DeltaAngle(Degrees(PI + ArcTan2(Q[0].y-Q[1].y, Q[0].x-Q[1].x)), UpDirection, 360));
- //Q[0] is highest, now I need second highest
- if d_0_1 > d_0_3 then begin
- P := Q[3];
- end else begin
- P := Q[1];
- end;
- Result := [Q[0],P];
- end;
- function GetUpAngle(mmpt: TPoint): Double;
- var
- l1,l2: TPoint;
- begin
- l1 := Minimap.VecToMs([mmpt.x, mmpt.y, 0]);
- l2 := Minimap.VecToMs([mmpt.x, mmpt.y, 32]);
- Result := Degrees(ArcTan2(l1.y-l2.y, l1.x-l2.x));
- end;
- function ExtractDoorsAndStates(ATPA: T2DPointArray; MinDensity: Double): TRSDoors;
- var
- i,j, nearest: Int32;
- poly, reduced: TPointArray;
- up, best, dist, theta, roll, a1,a2: Single;
- ms1,ms2: TPoint;
- qp: TPointArray;
- v1,v2: Vector3;
- doors: TDoorMMInfoArray;
- begin
- roll := Minimap.GetCompassAngle(True);
- doors := DoorDirectionsAndArea();
- for i:=0 to High(ATPA) do
- begin
- if Length(ATPA[i]) < 100 then
- continue;
- Poly := ATPA[i].ConvexHull();
- if Length(Poly) < 4 then continue;
- reduced := FixOrderQuad(ReduceToQuad(Poly));
- if (GetPolyDensity(ATPA[i], Poly) > MinDensity) then
- begin
- // get corresponding door from minimap:
- nearest := -1;
- best := $FFFFFF;
- for j:=0 to High(doors) do
- begin
- dist := Distance(ATPA[i].Mean(), doors[j].Search.Mean());
- if (dist < best) and (dist < MainScreen.NormalizeDistance(120)) then
- begin
- nearest := j;
- best := dist;
- end;
- end;
- if best = $FFFFFF then
- continue;
- up := GetUpAngle(TPointArray([doors[nearest].mm1, doors[nearest].mm2]).Mean());
- qp := QuadTop(reduced, up);
- ms1 := Minimap.VecToMs([doors[nearest].mm1.x, doors[nearest].mm1.y, 8]);
- ms2 := Minimap.VecToMs([doors[nearest].mm2.x, doors[nearest].mm2.y, 8]);
- v1 := MainScreen.PointToMM(qp[0], 8);
- v2 := MainScreen.PointToMM(qp[1], 8);
- theta := Degrees(ArcTan2(v1.y-v2.y, v1.x-v2.x));
- theta := Modulo(theta-roll, 180);
- if Abs(DeltaAngle(theta, doors[nearest].BaseAngle, 180)) < 40 then begin
- Result += [[reduced[0], reduced[1], reduced[2], reduced[3]], False];
- end else begin
- Result += [[reduced[0], reduced[1], reduced[2], reduced[3]], True];
- end;
- end;
- end;
- end;
- function FindDoors(Color: TCTS2Color; Bounds: TBox; Filter: TDoorFilter): TRSDoors;
- var
- client_raw: TMufasaBitmap;
- Edge, TPA: TPointArray;
- ATPA: T2DPointArray;
- i: Int32;
- begin
- srl.FindColors(TPA, Color, Bounds);
- if Length(TPA) < 10 then
- Exit;
- //TPA := TPA.Erode(1).Grow(1); // <--- reduce pixel noise?
- // if EdgeSensitivity is set to more than 0, then we use edges to process on
- // this is needed wherever ground and doors have too similar color
- if Filter.EdgeSensitivity > 0 then
- begin
- client_raw := TMufasaBitmap.CreateFromClient();
- Edge := client_raw.PixelEdgesTPA(Filter.EdgeSensitivity);
- client_raw.Free();
- TPA := TPA.Intersection(Edge);
- end;
- // apply grow and erode for noise filtering
- TPA := TPA.Grow(Filter.Grow).Erode(Filter.Erode);
- //TPA := TPA.ExcludePoints(Edge);
- // filter out interfaces
- TPA := TPA.ExcludePoints(TPointArray.CreateFromBox(Chat.Bounds, True));
- TPA := TPA.ExcludePoints(TPointArray.CreateFromBox(GameTabs.Bounds, True));
- TPA := TPA.ExcludePoints(TPointArray.CreateFromBox(Minimap.Bounds, True));
- ATPA := TPA.Cluster(1);
- //RSClient.Image.DrawATPA(ATPA);
- Result := ExtractDoorsAndStates(ATPA, Filter.MinDensity);
- for i:=0 to High(Result) do
- Result[i].Door := Result[i].Door.Expand(Filter.Erode-Filter.Grow);
- end;
- function FilterDoorsMM(Doors: TRSDoors; AcceptableTileDist: Double): TRSDoors;
- var
- mmd: TDoorMMInfoArray;
- idx, i, j: Int32;
- best,dist: Double;
- begin
- mmd := DoorDirectionsAndArea();
- if Length(mmd) = 0 then Exit;
- AcceptableTileDist := mmd[0].Search.Top.DistanceTo(mmd[0].Search.Right) * AcceptableTileDist;
- for i:=0 to High(mmd) do
- begin
- best := $FFFFFF;
- for j:=0 to High(doors) do
- begin
- dist := mmd[i].Search.Mean().DistanceTo(doors[j].Door.Mean());
- if dist < best then
- begin
- best := dist;
- idx := j;
- end;
- end;
- if best < AcceptableTileDist then
- Result += Doors[idx];
- end;
- end;
- var
- doors: TRSDoors;
- i: Int32;
- begin
- RSClient.Image.SetFontSize(12);
- RSClient.Image.setFontAntialiasing(False);
- RSClient.Image.Clear();
- //TerminateScript;
- //Varrock simple door: CTS2(3561056, 19, 0.08, 0.34), MainScreen.Bounds(), DoorFilter(15, 4,6, 0.6)
- //Varrock fancy door : CTS2(3302000, 18, 0.06, 0.89), MainScreen.Bounds(), DoorFilter(20, 5,7, 0.4)
- //Lumby : CTS2(1138041, 17, 0.08, 1.48), MainScreen.Bounds(), DoorFilter(0, 4,6, 0.6)
- //A lumby gate!! : CTS2(1138041, 17, 0.08, 1.48), MainScreen.Bounds(), DoorFilter(0, 6,8, 0.1)
- while True do
- begin //Fally = CTS2(5930899, 21, 0.04, 0.41)
- doors := FindDoors(CTS2(3561056, 19, 0.08, 0.34), MainScreen.Bounds(), DoorFilter(15, 4,6, 0.6));
- doors := FilterDoorsMM(doors, 2.5);
- RSClient.Image.Clear();
- for i:=0 to High(doors) do
- begin
- if doors[i].IsOpen then begin
- RSClient.Image.DrawQuad(doors[i].Door, $00FF00);
- RSClient.Image.DrawText('Open', doors[i].Door.Mean()+Point(-20,0), $77FF77);
- RSClient.Image.DrawText('Open', doors[i].Door.Mean()+Point(-19,0), $77FF77);
- end else begin
- RSClient.Image.DrawQuad(doors[i].Door, $FF);
- RSClient.Image.DrawText('Closed', doors[i].Door.Mean()+Point(-20,0), $77FF77);
- RSClient.Image.DrawText('Closed', doors[i].Door.Mean()+Point(-19,0), $77FF77);
- end;
- end;
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement