PDA

View Full Version : Find objects with SRL & RSWalker



slacky
01-03-2018, 06:38 AM
What's needed for this totorial:
> Simba 1.2 RC6 - fixes (https://github.com/slackydev/Simba/releases/tag/Simba-1.2.0-rc6_fixes) (drop the .exe in Simba folder, and use it instead of Simba.exe)
> SRL for OSRS (https://github.com/SRL/SRL/)
> RSWalker (https://villavu.com/forum/showthread.php?t=111914) (download (https://github.com/slackydev/RSWalker/releases))
> SPSToolbox (https://github.com/TheTS/SPSToolbox/releases)


A fancy simple way to find objects using RSWalker and SRL:

It builds around RSWalker's GetTileMSEx, which will take a worldmap coordinate and convert it to a local tile on the mainscreen.

So first we can do with a simple datatype that stores the object, and the many locations it can be at:

type
TMSObject = record
WorldLoc: TPointArray; // loctions on the world map
Color: TCTS2Color; // must have color
MinCount: Int32; // size of TPA
SplitDist: Int32;
end;

That should be sufficient for most cases..

Then we need a function to utilize the above stuff, perhaps something like this:

function TMSObject.Find(DoSort: Boolean=True; Expand:Int32=0): TRectArray;
var
loc, me: TPoint;
rect: TRectangle;
locations, TPA: TPointArray;
ATPA: T2DPointArray;
begin
me := RSW.GetMyPos();
locations := Copy(Self.WorldLoc);
if DoSort then Locations.Sorted(me);

for loc in Locations do
begin
rect := RSW.GetTileMsEx(me, loc, 1).Expand(Expand);
if MainScreen.GetBounds.Contains(rect.Bounds) then
begin
if (srl.FindColors(TPA, Color, rect.Bounds) < Self.MinCount) then
Continue;

if (Self.SplitDist > 0) then
begin
TPA := rect.Filter(TPA);
ATPA := TPA.Cluster(Self.SplitDist);
SortATPAFromSize(ATPA, 0, False);
Result += ATPA[0].MinAreaRect;
end else
Result += rect;
end;
end;
end;

A bit complex I guess, but at least that reduces the chance of it failing. You might have spotted that it has two result scenarios depending on if you specify a split distance or not.. if you don't then the color count is all that is taken into account, and it returns the tile as returned by `GetTileMSEx`, that's fine for a lot of simple cases.
The latter one will split and return the rectangle covering the largest TPA within the rectangle returned by `GetTileMSEx`.

https://image.prntscr.com/image/np1V3QacTcWwtyooos-12w.png https://image.prntscr.com/image/6twYHMY2RkexpVUh009n7Q.png https://image.prntscr.com/image/17BS8wF9QlqH8VllLWZ9rg.png

Since neither RSWalker nor MM2MS is perfectly accurate the result may vary depending on your location, compass angle, and other factors that affect the minimap, and MM2MS is imperfect as a result of the camera not being perfectly focused on your character, and height differences between you and the object tile.
As a result of those, I've added a "Expand"-parameter, which will expand the area of the tile returned by `GetTileMSEx`. You might wanna play with the function I created, adjust it for your use if it's not suitable out of the box.


So, how do you get the world location of the objects? Well that's like making a path to walk with RSWalker, grab https://github.com/TheTS/SPSToolbox/releases and then just click the object locations.. might need to manually adjust the coordinate +/-2 px afterwards for optimal experience.

Putting it all together in a test script:

program new;
{$H-}
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}

type
TMSObject = record
WorldLoc: TPointArray; //loctions on the world map
Color: TCTS2Color; //must have color
MinCount: Int32; //size of TPA
SplitDist: Int32;
end;

var
RSW: TRSWalker;

function TMSObject.Find(DoSort: Boolean=True; Expand:Int32=0): TRectArray;
var
loc, me: TPoint;
rect: TRectangle;
locations, TPA: TPointArray;
ATPA: T2DPointArray;
begin
me := RSW.GetMyPos();
locations := Copy(Self.WorldLoc);
if DoSort then Locations.Sorted(me);

for loc in Locations do
begin
rect := RSW.GetTileMSEx(me, loc, 1).Expand(Expand);
if MainScreen.GetBounds.Contains(rect.Bounds) then
begin
if (srl.FindColors(TPA, Color, rect.Bounds) < Self.MinCount) then
Continue;

if (Self.SplitDist > 0) then
begin
TPA := rect.Filter(TPA);
ATPA := TPA.Cluster(Self.SplitDist);
ATPA.SortByMiddle(rect.Mean);
Result += ATPA[0].MinAreaRect;
end else
Result += rect.Expand(-Expand);
end;
end;
end;

procedure Test();
var
i: Int32;
obj: TMSObject;
rectangles: array of TRectangle;
begin
while True do
begin
// two booth locations, color of booth, min points, splitDist
obj := [[[143, 176], [147, 176]], CTS2(2380900,30), 200, 8];

rectangles := obj.Find(True, 3);
smart.Image.Clear();
for i:=0 to High(rectangles) do
smart.Image.DrawTPA(rectangles[i].ToTPA.Connect, $00FFFF);
end;
end;


begin
smart.EnableDrawing := True;
srl.Setup([]);

RSW.Init('images/varrock.png', -1);

test();

RSW.Free();
end.


This is my Varrock image used in the above test: https://i.imgur.com/xxQDMyo.png

PS: This concept is at the core of my Universal Miner (https://villavu.com/forum/showthread.php?t=117996), and is the sole reason I bothered making it.