Thread: [OSR][AeroLib][OSBuddy] Item Overlay Location Finder/Looter

1. [OSR][AeroLib][OSBuddy] Item Overlay Location Finder/Looter

Description:
OSBuddy, a popular client for OSRS, has a feature which will paint ground items onto the screen in the form of a text overlay. This function will search for any overlay text matching the specified text. If found it'll return the on-screen coordinates of the item (not the text) for easy looting.

Features:
• Finds and returns specified item location
• Will return the correct location of the item even if it's in a stack of items, no matter it's location in the stack:

(searching for any of these items texts would return the coordinates for the item pile below them).

Useful For:
• Adding item finding & looting to a non-reflection script.
• Those who don't want to use SMART
• Those who want to take advantage of reflection in the safest form possible.

Requirements:
• AeroLib
• OSBuddy
• OSBuddy Item Overlay feature set to 'on' AND go into the feature settings and change font to 'Runescape'

Limitations:
• Will not be able to match text that is overlayed with other text. For example when a large amount of items are spread across a small space the text will often overlap.
• Will not be able to correctly get the X coordinate if another item text is within a couple pixels to the right of your item on the same X plane.
• Will not be able to correctly get the Y coordinate if another item text is within a few pixels below your item on the Y plane. It will think your item is in a stack and return the non-existent stacks location (See below for fix. Params: Stack)

Code:
Simba Code:
function GetDropCoordX(Color: Integer; StartPoint: TPoint): TPoint;var  MPs: TPointArray;  MP: TPoint;  tCol: TColEx;  SB: TBox;  Found: Boolean;begin  SB := ToBox(StartPoint.x, StartPoint.y-1, StartPoint.x+6, StartPoint.y+7);  tCol.create(Color, 0);  Found := tCol.FindIn(SB, MP);  while Found do  begin    tCol.FindAllIn(SB, MPs);    SB.X1 := SB.X2;    SB.X2 := SB.X2+6;    Found := tCol.FindIn(SB, MP);  end;  SortTPAByX(MPs, False);  MP := Point(MPs[0].x, MPs[0].y);  MP.x := StartPoint.x+(5+((MP.x-StartPoint.x) shr 1));  Result := MP;end;function GetDropCoordY(Color: Integer; StartPoint: TPoint): TPoint;var  MPs: TPointArray;  MP: TPoint;  tCol: TColEx;  SB: TBox;  Found: Boolean;begin  SB := ToBox(StartPoint.x-4, StartPoint.y-1, StartPoint.x+4, StartPoint.y);  tCol.create(Color, 0);  Found := tCol.FindIn(SB, MP);  while Found do  begin    tCol.FindAllIn(SB, MPs);    SB.Y1 := SB.Y2;    SB.Y2 := SB.Y2+11;    Found := tCol.FindIn(SB, MP);  end;  SortTPAByY(MPs, False);  MP := Point(StartPoint.x, MPs[0].y+20);  Result := MP;end;function OSB_FindItem(var ItemPoint: TPoint; ItemText: String; Area: TBox; Stack: Boolean): Boolean;var  TextTPA, SearchTPA, Matches: TPointArray;  Height: Integer;  tCol: TColEx;begin  tCol.autoCreate([16777215,16448764,16316664]);  if not tCol.findAllIn(Area, SearchTPA) then    Exit(False);  TextTPA := loadTextTPA(ItemText, 'SmallChars07', Height);  Result := FindTextTPAinTPA(Height, TextTPA, SearchTPA, Matches);  if not Result then    Exit;  ItemPoint := GetDropCoordX(16777215, Matches[0]);  case Stack of    True : ItemPoint := GetDropCoordY(16777215, ItemPoint);    False: ItemPoint.y += 23;  end;end;

Params:
• ItemPoint: Function will fill this referenced variable with the TPoint of the item.
• ItemText: Text matching the item you want to find on screen. You do not need to provide the full item name for a match, but you will need to provide the start of it. For example to find a cabbage, "Cab" will work but "bage" will not. Be wary as any items with the same chars will match. CASE SENSITIVE
• Area: TBox of the area you want to look for the item in.
• Stack: Tells the function if it should look to see if the item is in a stack of items. Leave this to True to start with as it's most accurate and will match perfectly fine even if the item is by itself. Set to False if the item wasn't in the location specified when Stack = True.

Example usage:
Like most finder functions, this function only returns the TPoint it believes the item you specified is at. It's up to the scripter to make the correct fail safes with that information to ensure smooth looting.

A basic example with a fail safe covering the Stack paramater mentioned above:
Simba Code:
var  ItemLoc: TPoint;begin  InitAL;  if OSB_FindItem(ItemLoc, 'Cabbage', AREA_MS, True) then  begin    accurateMMouse(ItemLoc, 0,0);    if waitUptext('Cabbage',600) then      FastClick(Mouse_Left)    else      if OSB_FindItem(ItemLoc, 'Cabbage', AREA_MS, False) then      begin        accurateMMouse(ItemLoc, 0,0);        if waitUptext('Cabbage',600) then          FastClick(Mouse_Left);      end;  end;end.

I don't imagine this will be used by too many as I believe the number of people who match the 'useful for' section isn't that high, but it's here if anyone needs it. There's a few improvements I can make if some Simba-side issues can be resolved, if they can't I'll eventually get round to rewriting the heavy lifting function that makes the above code work.

2. Need help from those in the know

Today while writing this I've had a crash course in text and the multiple ways in which Simba handles it. There were a few versions of the code above using varying methods but this was the simplest, most reliable and most importantly low on the CPU usage (considering how often a function to check for loot will be called).

The function of choice was FindTextTPAinTPA. Now it appears this function is supposed to return a TPA of every matched point between SearchTPA and TotalTPA in the Matches param but it only matches the first index of the SearchTPA. Another very similar function FindTPAinTPA also has this same issue. The first point is enough to have the script work, but an entire match will improve accuracy to near 100% so long as the text is readable.

I've pulled the function from source and played around with it a bit but I'm getting the same issue. It seems to perform a very odd way of matching, inverting the TPA (not the same points in reversed order, instead every point except the ones in the original TPA) and looking for non-matches as a way of matching. Although weird (I'm sure there's a reason I'm not currently foreseeing that explains it) the code looks like it should do as the params suggest and return an entire TPA of matched points.

Any help with that is appreciated.

Also a small issue with FindTPAinTPA: The function preview in Simba states that both SearchTPA AND TotalTPA will be passed as const, but after having my local SearchTPA augmented after passing to the function I looked at the source and only TotalTPA is const, SearchTPA while not passed by ref is changed within the function and those changes carry over back to the script.

The following code highlights both issues mentioned:
Simba Code:
var  FirstTPA, SecondTPA, ThirdTPA: TPointArray;begin  FirstTPA := [ Point(10,10), Point(10,11), Point(10,12), Point(11,12), Point(12,12) ];  SecondTPA := [ Point(11,11), Point(11,12), Point(11,13), Point(12,13), Point(13,13)];  Writeln('First: ', FirstTPA);  Writeln('Secon: ', SecondTPA);  FindTPAinTPA(FirstTPA, SecondTPA, ThirdTPA);  Writeln('First: ', FirstTPA);  Writeln('Secon: ', SecondTPA);  Writeln('Third: ', ThirdTPA);end.

Code:
First: [{X = 10, Y = 10}, {X = 10, Y = 11}, {X = 10, Y = 12}, {X = 11, Y = 12}, {X = 12, Y = 12}]
Secon: [{X = 11, Y = 11}, {X = 11, Y = 12}, {X = 11, Y = 13}, {X = 12, Y = 13}, {X = 13, Y = 13}]
First: [{X = 0, Y = 0}, {X = 0, Y = 1}, {X = 0, Y = 2}, {X = 1, Y = 2}, {X = 2, Y = 2}]
Secon: [{X = 11, Y = 11}, {X = 11, Y = 12}, {X = 11, Y = 13}, {X = 12, Y = 13}, {X = 13, Y = 13}]
Third: [{X = 11, Y = 11}]
As you can see, FirstTPA has now been changed. ThirdTPA which should contain all points from SecondTPA as they all match with FirstTPA, only holds the first matched index.

I know double posting is frowned upon but I didn't want this clogging up the bottom of the OP and being skipped over.

3. Looks great Borland, very helpful indeed for those using OSSbuddy.

Now about your TPA issue: after running a few trials myself I came to the conclusion that within the function FindTPAinTPA the two TPAs you feed it will be rearranged in order to find matches. I'm surprised the function itself doesn't right away copy the two TPAs before it begins matching TPoints to be honest. However it doesn't, so to prevent this we simply feed a copy of the two TPAs to the function so our two original remain constant. Try this instead:
Simba Code:
var  FirstTPA, SecondTPA, ThirdTPA: TPointArray;begin  FirstTPA := [ Point(10,10), Point(10,11), Point(10,12), Point(11,12), Point(12,12) ];  SecondTPA := [ Point(11,11), Point(11,12), Point(11,13), Point(12,13), Point(13,13)];  FindTPAinTPA(copyTPA(FirstTPA), copyTPA(SecondTPA), ThirdTPA);  Writeln('First: ', FirstTPA);  Writeln('Secon: ', SecondTPA);  Writeln('Third: ', ThirdTPA);end.

On a side note, what helped me a lot with OCR-based routines through TPA-to-Text was studying how SRL read right-click menus to extract options/text. Take a look at the function getOptions in Menu.simba (AeroLib) to see how it's done. It may give you some pointers if you're still having issues somewhere else.

4. Great contribution mate.

Have considered using OSBuddy's features in my scripts but never got around to it.

Should make an include for OSbuddy.simba for Aerolib

5. Originally Posted by Dan the man
Great contribution mate.

Have considered using OSBuddy's features in my scripts but never got around to it.

Should make an include for OSbuddy.simba for Aerolib
It would likely make color-only agility a lot more feasible.

6. Originally Posted by Flight
Looks great Borland, very helpful indeed for those using OSSbuddy.

On a side note, what helped me a lot with OCR-based routines through TPA-to-Text was studying how SRL read right-click menus to extract options/text. Take a look at the function getOptions in Menu.simba (AeroLib) to see how it's done. It may give you some pointers if you're still having issues somewhere else.
Lol that's exactly where I looked I have a version of the function using the same brains as getOptions. It works a lot better when static but as soon as movement is involved (even NPCs and players moving while camera is still) large artifacting of characters occurred. It's perfect for getOptions as once the menu is open it's position is static and has the highest Index priority. BUT saying that, I was thinking about how to improve accuracy while at work today and one of the potential solutions is making use of Freeze to see if that can reduce the artifacts without doing regex or other hard coded replacing.

Originally Posted by Dan the man
Great contribution mate.

Have considered using OSBuddy's features in my scripts but never got around to it.

Should make an include for OSbuddy.simba for Aerolib
Originally Posted by acow
It would likely make color-only agility a lot more feasible.
Been thinking about doing agility like that. It was how I originally made my Salamander script but the paint overlay OSBuddy uses isn't always accurate and will sometimes be off the trap entirely, especially if the traps orientation is opposite others in the area. Switched to good old fashioned color techniques and I'm fairly proud of how accurate that script turned out. Also I believe the agility plugin is a pro feature? Not sure I'd want a requirement of my script to be locked behind a pay wall.

I haven't used/checked any other clients out there but I know a couple of them also have the agility overlay on them, from pictures I've seen here and there it looks as though they are painted to exact bounds.

I still hold hope that if there isn't one available, I'll be able to do an all-color agility script when it comes time for 99. Lord knows I aint doing that by hand lmao.

7. Originally Posted by Borland
Lord knows I aint doing that by hand lmao.
Heard that!

8. SRL Junior Member
Join Date
Feb 2017
Location
Sauce
Posts
30
Mentioned
0 Post(s)
Quoted
4 Post(s)
Agility is so terrible to train. Super repetitive with constant clicking.