SRL Archive - OSR Help

Color TPA


doom0791

2011-03-09 05:01:54

So I'm using FindColorsSpiralTolerance to get a TPA of colors, and in some spots the road is in the screen which puts over 20,000 points in the TPA.

Is there some way that I can exclude just the road section without taking too much time? Sorting through 20,000 points with SplitTPA takes 6-7 seconds and is just flat-out ridiculous.

*E: Yeah, I said I'd be offline for a few weeks, but one of the functions I've been working on has been bugging me all day and I finally found out why it wasn't working ;)

ReadySteadyGo

2011-03-09 05:07:49

I'm not sure if I read that correctly? Are you searching just the mini map? (MMX1, MMY1, MMX2, MMY2)

doom0791

2011-03-09 05:30:43

Sorry, it's late here and I wrote that in a hurry lol.

I'm looking on the main screen for the colors of tin ore. Unfortunately, the color of the road near the tin rocks is a very similar color (within tolerance) and therefore the road is included in the TPA, increasing the TPA size from 70-100 to 20,000. I'd like to exclude the very dense section of the TPA from the TPA (exclude the road from the TPA).

ReadySteadyGo

2011-03-09 05:35:15

Try using ATPA's (Array of TPA) then sort by size. This should allow you to exclude the larger areas of that colour (the road). Check the tutorial forums.

doom0791

2011-03-09 05:42:54

I'm using wizzyplugin to split a TPA into an ATPA, but the splitting process takes too long because of how many points the road adds to the array:

function FColorsSpiralTol(colors : TIntegerArray; var TPA : TPointArray; tol : Integer) : Boolean;
var
i : Integer;
Temp, TTPA : TPointArray;
begin
TPA := [];
for i := 0 to High(colors) do
begin
FindColorsSpiralTolerance(MSCX, MSCY, Temp, colors[i], MSX1, MSY1, MSX2, MSY2, tol);
TPA := CombineTPA(Temp, TTPA);
end;
if High(TPA) > 0 then
Result := True;
end;

function MineRocks(var MRock : TRSObject) : Boolean;
var
x, y, i, temp : Integer;
TPA : TPointArray;
PTS : T2DPointArray;
P : TPoint;
begin
if FColorsSpiralTol(RockColors, TPA, 7) then
begin
Debug('Found Rock Colors');
Pts := SplitTPA(TPA, 25);
SortATPAFrom(Pts, Point(MSCX, MSCY));
for i := High(Pts) downto 0 do
begin
P := MiddleTPA(Pts[i]);
MRock := GetInteractableAt(MsToClosestTile(P, RockT));
if Full(MRock) then
begin
MMouse(P.x, P.y, 3, 3);
GetMousePos(x, y);
Mouse(x, y, 0, 0, True);
if DidRedClick then
begin
MRock := GetInteractableAt(MSToClosestTile(Point(x, y), RockT));
Result := True;
Debug('Ore found at ATPA[' + IntToStr(i) + ']');
Exit;
end;
end else
Debug('Ore not at ATPA[' + IntToStr(i) + ']');
end;
end;
end;

ReadySteadyGo

2011-03-09 05:48:30

can you give me a screen shot of where you're searching, i'll try to figure a good way to do it.

Edit: If it's just speed that's the issue try SplitTPAEx, It finds TPA's in a Rectangle rather than a circle. Not sure how much it will speed this up. If not you need to find a way to exclude the Road prior to SplitTPA. I could do with a screenshot in order to help you.

Blumblebee

2011-03-09 13:04:12

you could, if you wish to speed up the process, have 2 TPA's, one for the Tin ore stream shit and the other for the basic rock color, then sort within a distance of 15 within the basic color, trimming down your array substantially. Although again like ReadySteadyGo has already pointed out, a screenshot would be very helpful to diagnose the problem.

NCDS

2011-03-09 14:01:02

Another, very simple alternative would be to just search near you (MSCx - 80, MSCy - 80, etc.) instead of the whole MS. That way it won't search near the road.

TomTuff

2011-03-09 20:44:05

Try using color tolerance speed 2 instead of 1, and set your hue and saturation modifiers.

doom0791

2011-03-10 01:01:59

Here's a screenshot:


Yes, speed is the issue, but I highly doubt that using SplitTPAEx would increase the speed by 6000 milliseconds.

TomTuff, Reading a tutorial on that now. Hopefully that works! Thanks!

NCDS

2011-03-10 01:20:10

Still use SplitTPA or TPAToATPA, but do a Max Length check on each tpa before 'using' it.

I can edit with an example in a couple mins.

Edit4Example:

begin
//Code..
//FindColor*();...
for i := 0 to High(atpa) do
begin
if not( InRange(Length(tpa), LowCountForRock, MaxCountForRock)) then
Continue;
//Rest of code..
end;
end;

doom0791

2011-03-10 01:28:12

From: NCDS
Still use SplitTPA or TPAToATPA, but do a Max Length check on each tpa before 'using' it.

I can edit with an example in a couple mins.


The problem is findcolors finds over 20,000 instances of the color. SplitTPA takes 6-7 seconds to sort through 20,000 points.

E: I know it's specifically splitTPA because I had this for testing purposes:

MarkTime(Mark);
SplitTPA(TPA, 25);
WriteLn(TimeFromMark(Mark));

NCDS

2011-03-10 01:34:33

From: doom0791
The problem is findcolors finds over 20,000 instances of the color. SplitTPA takes 6-7 seconds to sort through 20,000 points.


Check my edit, and also check my previous post in this thread.

To cut down on the Points found try doing what TomTuff said. CTS2 is more accurate and is simple to use. I can show you if you need me to?

Bonfield

2011-03-10 01:40:49

can you post your whole function please?

doom0791

2011-03-10 01:55:23

I'm reading tutorials on CTS2 and will try that.

Here's all the functions involved:



function Full(var MRock : TRSObject) : Boolean;
var
i : Integer;
begin
if not LoggedIn then
Exit;
Result := False;
MRock := GetInteractableAt(MRock.Tile);
for i := 0 to High(RockT) do
begin
if MRock.Tile = RockT[i] then
if MRock.ID = RockIDs[i] then
begin
//Debug('MRock is Full');
Result := True;
Exit;
end;
end;
Debug('MRock is Empty');
end;

function FColorsSpiralTol(colors : TIntegerArray; var TPA : TPointArray; tol : Integer) : Boolean;
var
i : Integer;
Temp, TPA : TPointArray;
begin
TPA := []; //initialize TPA as an empty TPA
for i := 0 to High(colors) do //for all in colors array
begin
FindColorsSpiralTolerance(MSCX, MSCY, Temp, colors[i], MSX1, MSY1, MSX2, MSY2, tol);
TPA := CombineTPA(Temp, TPA); // combine the TPA's
end;
if High(TPA) > 0 then
Result := True;
end;

function MineRocks(var MRock : TRSObject) : Boolean;
var
x, y, i, temp : Integer;
TPA : TPointArray;
PTS : T2DPointArray;
P : TPoint;
begin
if FColorsSpiralTol(RockColors, TPA, 7) then //get TPA
begin
Debug('Found Rock Colors'); //write in debug with timestamp
WriteLn(High(TPA));
MarkTime(temp);
Pts := SplitTPA(TPA, 25); //Split TPA into ATPA Pts
WriteLn('splittpa: ' + Inttostr(TimeFromMark(temp)));
SortATPAFrom(Pts, Point(MSCX, MSCY)); //Sort Pts from center
for i := High(Pts) downto 0 do //Closest point to furthest point
begin
P := MiddleTPA(Pts[i]); //Find midpoint of pts[i]
MRock := GetInteractableAt(MsToClosestTile(P, RockT)); //Get the object at pts[i]
if Full(MRock) then //check if the ID of the object at Pts[i] matches the rock ID at that point
begin
MMouse(P.x, P.y, 3, 3); //Move mouse to the point
GetMousePos(x, y);
Mouse(x, y, 0, 0, True); //Click where the mouse is. Of course, this can be reduced to 1 line, previously it was necessary to have it across 3 lines though.
if DidRedClick then
begin
MRock := GetInteractableAt(MSToClosestTile(Point(x, y), RockT)); //Reset MRock
Result := True; //set result to true
Debug('Ore found at ATPA[' + IntToStr(i) + ']'); //write in the debug
Exit;
end;
end else
Debug('Ore not at ATPA[' + IntToStr(i) + ']');
end;
end;
end;


E: NCDS, I don't want to search just near me because the script will move back and forth between different rocks based on different situations, so I don't want to limit the screen to just the left side or just near me. And as far as your edit goes, I have already done that before, but I've developed a better method of eliminating points which are not rocks. I just lose so much time when converting from tpa to atpa.

E2: Also, this is still in development so it's messy and not the best way to write the function. This will be cleaned up soon as I get the methods working properly.

Bonfield

2011-03-10 02:26:53

try something like this


function FColorsSpiralTol(colors : TIntegerArray; var TPA : TPointArray; tol : Integer) : Boolean;
var
i : Integer;
Temp, TPA : TPointArray;
begin
TPA := []; //initialize TPA as an empty TPA
for i := 0 to High(colors) do //for all in colors array
if not(InRange(Length(TPA), LowCountForRock, MaxCountForRock)) then //this or
if not(Length(TPA) < MaximumCountForRocks) then // this
begin
FindColorsSpiralTolerance(MSCX, MSCY, Temp, colors[i], MSX1, MSY1, MSX2, MSY2, tol);
TPA := CombineTPA(Temp, TPA); // combine the TPA's
end;
if High(TPA) > 0 then
Result := True;
end;

see where i added the length checks, does that make sense?

see if that lowers the total time taken

Feroc1ty

2011-03-10 02:34:27

If you're gonna use SMART why not utilize reflection? With reflection you can just use tiles.

Bonfield

2011-03-10 02:39:05

maybe a he wants to use colour and reflection as a backup or it could just be a challenge/learning experience to write it in colour

doom0791

2011-03-10 02:40:11

From: Bonfield


function FColorsSpiralTol(colors : TIntegerArray; var TPA : TPointArray; tol : Integer) : Boolean;
var
i : Integer;
Temp, TPA : TPointArray;
begin
TPA := []; //initialize TPA as an empty TPA
for i := 0 to High(colors) do //for all in colors array
if not(InRange(Length(TPA), LowCountForRock, MaxCountForRock)) then //this or
if not(Length(TPA) < MaximumCountForRocks) then // this
begin
FindColorsSpiralTolerance(MSCX, MSCY, Temp, colors[i], MSX1, MSY1, MSX2, MSY2, tol);
TPA := CombineTPA(Temp, TPA); // combine the TPA's
end;
if High(TPA) > 0 then
Result := True;
end;



If I'm understanding you're saying to stop finding colors and adding points to the TPA if the TPA is larger than a max length. Right now, I'm only using 2 rock colors though, so this wouldn't help much. Especially since the tin colors are a pain and vary much more than other ores.


From: Ferocity

If you're gonna use SMART why not utilize reflection? With reflection you can just use tiles.

I prefer using color for this. Reflection clicks about the center of the tile which I think looks very bot-like. Using color the click spot will vary a bit from time to time, because colors change over time, etc.

Right now I'm using color to find/click on the rocks and reflection for my timing because reflection is more efficient than I could ever be with color for timing rocks.

Frement

2011-03-10 02:40:52

From: Feroc1ty
If you're gonna use SMART why not utilize reflection? With reflection you can just use tiles.


Not everyone uses SMART for the reflection capability, for me its the minimization and virtual keyboard and mouse.

TomTuff

2011-03-10 02:57:37

Here's some help:

program MineIt;
{$i SRL\SRL.scar}
{$i SRL\SRL\Misc\Debug.scar}


function MineTin: Boolean;
var
CTS, x, y, i: Integer;
Hue, Sat: Extended;
TPA: TPointArray;
ATPA: T2DPointArray;
begin
if not(LoggedIn) then
Exit;
CTS := GetColorToleranceSpeed; //Storing start CTS to change back to later
SetColorToleranceSpeed(2); //Changing to CTS 2
GetColorspeed2Modifiers(Hue, Sat); //Storing start Hue/Sat mods to change back to later
SetColorspeed2Modifiers(0.19, 0.07); //Changing Hue/Sat mods
FindColorsTolerance(TPA, 7961216, MSX1, MSY1, MSX2, MSY2, 15); //Finding colors
SetColorspeed2Modifiers(Hue, Sat); //Changing back Hue/Sat mods
SetColorToleranceSpeed(CTS); //Changing back CTS
if (Length(TPA) < 1) then //Making sure we found some colors
Exit;
SortTPAFrom(TPA, Point(MSCX, MSCY)); //Sorting the TPA from center of the screen -- faster than FindColorsSpiralTolerance by a bit
ATPA := TPAtoATPA(TPA, 35); //Splitting into an ATPA, boxes of 35x35 pixels
DebugATPA(ATPA, '');
for i := 0 to High(ATPA) do //looping through ATPA
begin
MiddleTPAEx(ATPA[i], x, y); //Calculating center of ATPA
if PointInBox(Point(x, y), IntToBox(MSCX - 15, MSCY - 15, MSCX + 15, MSCY + 15)) then
Continue; //Checks if the point is within 15 pixels of player - if so, "Continue;" goes to the next TPA
MMouse(x - 3, y - 3, 6, 6); //Moving mouse to the point
if WaitUptextMulti(['Mine', 'ine R', 'ne Ro', 'e Roc', 'Rock', 'ocks'], 750 + Random(200)) then //checking for uptexts
begin
Wait(50 + Random(80)); //random wait for human-ness
ClickMouse2(True); //left clicking mouse (Via SRL proc)
Result := DidRedClick; //checking for red crosshairs that come up after clicking
end;
if Result then //exits the function so it doesn't click all over the place
Break;
end;
if Result then
Flag; //Waits to finish walking in case rock was > 1 tile away (Only if it clicked the rock!)
end;


begin
SetupSRL;
writeln(BoolToStr(MineTin));
end.

Heres the ATPA Debug:
read comments for how it works.

doom0791

2011-03-10 02:58:45

Okay I got it working much better now! CTS2 worked out Great:


function FColorsSpiralTol(colors : TIntegerArray; var TPA : TPointArray; tol : Integer) : Boolean;
var
i, CTS : Integer;
Temp : TPointArray;
begin
TPA := [];
CTS := GetColorToleranceSpeed;
SetColorToleranceSpeed(2);
for i := 0 to High(Colors) do
begin
SetColorSpeed2Modifiers(HMods[i], SMods[i]);
FindColorsSpiralTolerance(MSCX, MSCY, Temp, colors[i], MSX1, MSY1, MSX2, MSY2, tol);
TPA := CombineTPA(Temp, TPA);
end;
if High(TPA) > 0 then
Result := True;
SetColorToleranceSpeed(CTS);
end;

The TPA array went from a size of roughly 20,000 to 120, which is very usable! Only now I have to pick more colors to search for because it's not successfully finding all of the rocks :P


Thank you everyone for the great help! Now I know another great method to improve color scripts!

E: Oh, forgot to reset the hue/sat mods at the end.

TomTuff,
That's a great function! Thank you very much! Also, how did you get the ATPA debug?