Hey everyone. If you already know what a TPoint is and what a TPA is, then you can skip to the second part of this tutorial.
I do not know how to effectively use any of the functions in the WizzyPlugin.
I do not know how to create custom TPointArrays.
I do not know how to effectively use any function that looks like:
SplitT2dTPAExAndSortATPAFromMiddleTPACombinedWithS ortATPABySize
Yet I can still find objects effectively.
I am not saying that it is bad to learn all that stuff like custom TPA's, because I am sure that in many instances (probably most instances) they are more effective than my methods (In fact, it is probably about time that I take the time to learn about it myself). But for the most part, you can get by in just about any script just fine without that stuff in my opinion.
TPoint Date Type
TPoint is just another type of variable. Lets start by declaring a TPoint variable like we would with any other type of variable:
TPoints are a data type that is basically 2 integer variables combined, called x and y. It was designed to hold the coordinates of a point, which we know by now are x and y. How can we access each individual integer? With a period ".":
SCAR Code:
T.x := 5;
T.y := 20;
MoveMouse(T.x,T.y);
Pretty self explanatory, right? Lets move onto TPointArrays
TPoint Arrays
This tutorial is in the advanced section, so I expect you to know what an array is. If you know what an array is, and you know what a TPoint is, than the concept of the TPA data type is very simple. Lets declare one:
Now to use it a bit:
SCAR Code:
var
TPA: TPointArray;
mx,my: Integer;
TPA[0].x := 12;
TPA[0].y := 75;
TPA[1].x := 186;
TPA[1].y := 375;
if(FindColor(x,y,2973685,TPA[0].x,TPA[0].y,TPA[1].x,TPA[1].y))then
MoveMouse(x,y);
Make sense? Just like TPoints except you can have multiple of them with one name. We used both the points (TPA[0] and TPA[1]) as a coordinate box to look for a color in. You can use each member like that just like any other integer. Moving on...
My methods of use for TPA's
So right now you should know what a TPoint is, what a TPointArray is, and how to declare them and use them on their own. Not much use for them without some functions. These are the only functions that we are going to need to use for all of our color finding:
Code:
FindColorsSpiralTolerance(x, y: Integer; var Points: TPointArray; color, xs, ys, xe, ye: Integer; Tolerance: Integer): Boolean;
GetArrayLength(var Arr): Integer;
High(x): int64;
You may be wondering how we can possibly do all of our color finding efficiently using only 3 functions, or you may have faith in me that we can do it. Either way, I'll explain all 3 of the functions here:
Code:
FindColorsSpiralTolerance
Notice that it is Colors, not Color. This makes it a completely different
function. This function is used to count all of the colors with tolerance in a
coordinates box (that you specify), and store them all in a TPointArray.
When using FindColorsSpiralTolerance, you send it 9 different parameters:
an x and y variable: You don't need to worry about what this is for because
we will not really be using it, but I believe that this is just the first point that
the function finds.
A TPointArray to store all of the found colors in.
The color that we want to search for.
The next 4 are the coordinates box to search for/count the colors in.
The last parameter is the tolerance for the color we are looking for.
Code:
GetArrayLength
This function you simply send an array to (we will be sending it a TPA), and
it returns the amount of members it uses. For example, if we stored values
in the first 5 members of a TPA (TPA[0].x and TPA[0].y through TPA[4].x
and TPA[4].y), GetArrayLength(TPA) would return 5.
Code:
High
This function returns the highest member in an array. Using the example
from GetArrayLength, High would return 4, because that is the last member
that has data stored in it.
Ok, now we can get to the fun part: Using all of this in your scripts. I am going to be using a few pieces from my clay softener as examples.
My FillBuckets function. We have to find the well on the main screen and click it to fill the buckets. There are many similar colors around this well though, so a simple FindObj will not work in this case. Here's the concept I used in my script (obviously not the whole thing):
SCAR Code:
function FillBuckets: Boolean;
var
TPA, TPA2: TPointArray;
i, Timer: Integer;
begin
FindColorsSpiralTolerance(x,y,TPA,3955306,MSX1,MSY1,338,MSY2,6);
repeat
FindColorsSpiralTolerance(x,y,TPA2,3955306,TPA[i].x-25,TPA[i].y-35,TPA[i].x+25,TPA[i].y+35,6);
if(GetArrayLength(TPA2) >= 188)then
begin
MMouse(TPA[i].x,TPA[i].y,4,4);
if(IsUpText('Well'))then
begin
Writeln('We found the well!');
GetMousePos(x,y);
Mouse(x,y,0,0,true);
Result := true;
Exit;
end;
end;
i := i + 10;
until(i >= High(TPA) - 11);
end;
Note: x and y are global variables.
First, I counted all of the colors (3955306) on the main screen with a tolerance (6) and stored them in TPA. Then I loop through each point of the array (skipping by 10's because I increment I by 10 each time). For each point, I do a second color count using TPA2, but only searching by a 50x50 box around it. If in that 50x50 box, there were 188 or more colors found, then it's probably the well (the biggest object there with these colors). So we move to the suspected well and check it out. If it is, we click and exit out of the function. If not we skip through TPA and do another search until we find it.
The reason I skip by 10's in this case and do not use a for loop to check every element is because if the mouse goes to the wrong spot, I don't want it to keep moving to elements around there. I know that there are going to be over 190 colors found in the well, so that gives me minimum 19 tries at finding the actual well anyways.
Hope that I explained that well enough. Lets look at how this can be used for map walking too. The bank I use in edgeville is very close to the well (one map click away). There is a dark red rug inside of the edgeville bank that looks like this:
and we are supposed to walk to that water symbol near the top left. What I did was counted all of the rug colors, and picked out the point on the rug that was furthest north. I then click specified coordinates to the left and a little up from that point, with a good amount of randomness, to get to the well. Once at the well, I will also use this same method to get to the bank.
I'm just going to show you a few more parts of the script with comments explaining the logic behind everything.
SCAR Code:
function GetTopRug: TPoint; //shortened
var
mx,my, i, Tol: Integer;
TPA, TPA2: TPointArray;
begin
MakeCompass('N');
for i := 3 to 22 do //for tolerance
begin
FindColorsSpiralTolerance(x,y,TPA,RugCol,MMX1+12,MMY1,MMX2,MMY2,i); //Count the red rug colors
if(GetArrayLength(TPA) > 90)then //If there are more than 90 colors, then we know that we used enough
begin //tolerance and we found the rug
Tol := i; //Save the required tolerance for later
break;
end;
end;
if(GetArrayLength(TPA) = 0)then //Never found the rug
begin
Writeln('Not finding rug color. Try setting it in the constants');
Exit;
end;
my := 1000;
for i := 0 to High(TPA) do //Step through the whole TPA
begin
if(TPA[i].y < my)then //if TPA[i].y is the new lowest number (closest to top of screen/top of rug)
begin
FindColorsSpiralTolerance(x,y,TPA2,RugCol,TPA[i].x-5,TPA[i].y,TPA[i].x+11,TPA[i].y+20,Tol);
if(GetArrayLength(TPA2) > 60)then //make sure that it is really the rug by counting around it ^
if(rs_OnMiniMap(TPA[i].x-32,TPA[i].y-4))then //Make sure that where the well is in reference to this point is on the MM
begin
mx := TPA[i].x; //This is the new top most point of the rug
my := TPA[i].y;
end;
end;
end;
result.x := mx; //we stepped through all the elements and this must be the top point
result.y := my;
end;
SCAR Code:
function WalkToWater: Boolean; //Shortened
var
T: TPoint;
begin
T := GetTopRug; //Get the point where the top of the rug is
if(not(rs_OnMiniMap(T.x-32,T.y-4))) then //Invalid point or didn't find rug
begin //fail safe. Main walking below
if(FindSymbolIn(T.x,T.y,'water',MMX1,MMY1,MMCX,MMCY-7))then
begin //Use the water symbol instead as a fail safe
Writeln('Did not use rug TPA. Trying water symbol');
Result := rs_OnMiniMap(T.x,T.y);
if(Result)then
begin
Mouse(T.x,T.y,5,5,true);
FFlag(2);
end else
begin
Writeln('Problem walking to water. Switching players...');
Logout;
end;
end;
Exit;
end;
Mouse(T.x-33,T.y-4,5,5,true); //If GetTopRug returned a valid point, then we move there
FFlag(2);
Result := true;
end;
SCAR Code:
//My custom bank opener for edgeville. Clicks on the banker, not the bank booth (shortened a lot)
function JADOpenBank: Boolean;
var
i, Timer, mx,my: Integer;
TPA, TPA2: TPointArray;
begin
if(not(LoggedIn)) or (BankScreen)then
Exit;
FindColorsSpiralTolerance(x,y,TPA,BankerCol,142,39,449,323,12); //BankerCol is a constant I have
result := false; //above. I have it there so the user can change if it doesn't work
for i := 0 to high(TPA) do //Step through all of the colors we just looked for (blue jacket on banker)
begin
FindColorsSpiralTolerance(x,y,TPA2,BankerCol,TPA[i].x-15,TPA[i].y-21,TPA[i].x+15,TPA[i].y+21,12);
if(GetArrayLength(TPA2) > 20) and (GetArrayLength(TPA2) < 100)then
begin //Same stuff as usual. Check the amount of colors around each point and if its
mx := TPA[i].X; //between 20 and 100, it is probably the banker
my := TPA[i].y;
result := true;
break;
end;
end;
if(not(Result))then
begin
Writeln('Could not find banker');
Exit;
end;
MMouse(mx,my,3,3);
end;
So there it is. I hope that you learned a few things after reading this and now have some more useful tools to help solve color finding problems. If you have any questions on anything that wasn't explained well enough here, please post and I will do my best to help you.
Cheers,
~JAD