# Thread: Detailed TPA and ATPA tutorial

1. ## Detailed TPA and ATPA tutorial

Basic concepts:
Point = a single pixel
Points = 2+ pixels

So whats a TPA? a TPointArray(array of TPoint). Whats a TPoint?:

SCAR Code:
Type  TPoint = Record    X, Y : Integer;  End;
It's basically X and Y coordinates stored in a type. It's the same as:
SCAR Code:
Var  X, Y : Integer;  TP : TPoint;Begin  TP.X := X;  TP.Y := Y;End.
Therefore a TPointArray is this:
SCAR Code:
Type  TPointArray = Array Of TPoint;
It's the same as:
SCAR Code:
Var  TP1, TP2, TP3 : TPoint;  TPA : TPointArray;Begin  SetLength(TPA, 3); // TPointArray's have an undefined length  TPA[0] := TP1;  TPA[1] := TP2;  TPA[2] := TP3;End.

When do you use TPA's? for example, FindColorTolerance saves the first point found on the screen, while FindColorsTolerance saves all the points found on the screen. So if you are searching for an object in Runescape, where there are similar objects(in colors), FindColorTolerance will give you only one point. If the point it gave you wasn't the one you where searching for, you can't do anything more. but while using FindColorsTolerance, you can try with every point till you find the correct one!

Like FindColorTolerance and FindColorSpiralTolerance, SCAR have functions to find them all:
SCAR Code:
function FindColorsTolerance(var Points : TPointArray; Color, Xs, Ys, Xe, Ye, Tolerance : Integer): Boolean;
Points has to be a var, so it can be filled with the ponts found. Color is the color to search for. Xs, Ys, Xe and Ye are the coordinates to search in and Tolerance is the tolerance used to find the colors. It will return true if any color was found.

SCAR Code:
procedure FindColorsSpiralTolerance(X, Y : Integer; var Points : TPointArray; Color, Xs, Ys, Xe, Ye, Tolerance : Integer);
Here we have two new parameters - X and Y. The difference between Spiral search and normal one is that spiral search starts from the center(X and Y) outwards, while normal search starts from Xs and Ys to Xe and Ye. So for example, if you are spiral searching in the main screen you would get the nearest points because you are starting from the center(MSCX and MSCY). Here is an example:
SCAR Code:
Function FindRockPoints(RockColor : Integer): TPointArray;Begin  FindColorsSpiralTolerance(MSCX, MSCY, Result, RockColor, MSX1, MSY1, MSX2, MSY2, 15);End;
MSCX, MSCY = The middle of the main screen
MSX1, MSY1, MSX2, MSY2 = Main screen coordinates

Now that you have the TPAs, how would you know what points did you get?
SCAR Code:
function GetArrayLength(x): Integer;
If you use it in a TPA, you would get its length example:
SCAR Code:
var  TPA : TPointArray;  L : Integer;Begin  SetLength(TPA, Random(5)); //Random(5) will return a random number betwenn 0-4  Writeln('Mhuahaha you don't know my length!');  L := GetArrayLength(TPA);//Can be Length(TPA) too  Writeln('Yes I do! it is ' + IntToStr(L));End.
Note: Length does the same as GetArrayLength.
SetLength(TPA, 5) for example, will set the length of TPA in this order:
TPA[0]
TPA[1]
TPA[2]
TPA[3]
TPA[4]
So if you want to search through every point, you have to use the function:
SCAR Code:
function High(x): Integer;
It returns the highest array index, in this case, 4. If you use Length(), it would return 5. Do you see the difference?
SCAR Code:
Var  TPA : TPointArray;  I : Integer;Begin  SetLength(TPA, 6);  TPA[0] := Point(Random(50), Random(100)); //Point() mixes two values(x and y) into a tpoint  TPA[1] := Point(Random(50), Random(100));   TPA[2] := Point(Random(50), Random(100));   TPA[3] := Point(Random(50), Random(100));   TPA[4] := Point(Random(50), Random(100));   TPA[5] := Point(Random(50), Random(100));   For I := 0 To High(TPA) Do    Writeln('TPA[' + IntToStr(I) + '].X = ' + IntToStr(TPA[I].X) + ', TPA[' + IntToStr(I) + '].Y := ' + IntToStr(TPA[I].Y));End.
But every time it loops, high(TPA) will be called and that would waste time:
SCAR Code:
Var  TPA : TPointArray;  I, H : Integer;Begin  SetLength(TPA, 6);  TPA[0] := Point(Random(50), Random(100)); //Point() mixes two values(x and y) into a tpoint  TPA[1] := Point(Random(50), Random(100));   TPA[2] := Point(Random(50), Random(100));   TPA[3] := Point(Random(50), Random(100));   TPA[4] := Point(Random(50), Random(100));   TPA[5] := Point(Random(50), Random(100));   H := High(TPA); //Here  For I := 0 To H Do    Writeln('TPA[' + IntToStr(I) + '].X = ' + IntToStr(TPA[I].X) + ', TPA[' + IntToStr(I) + '].Y := ' + IntToStr(TPA[I].Y));End.
If you use Length(TPA) - 1 (to get the correct highest index) it would cost you ~0.3 microseconds (approx.)

Here is another example:
SCAR Code:
Var  TPA : TPointArray;  I, H, Col : Integer;begin  FindColorsTolerance(TPA, 0, 0, 0, 100, 100, 15);  H := High(TPA);  For I := 0 To H Do  Begin    Col := GetColor(TPA[I].X, TPA[I].Y); //Gets the color of the current point    Writeln('TPA[' + IntToStr(I) + '] Color = ' + IntToStr(Col));  End;end.

End of TPA's. Now, we will start talking about ATPA's. What's an ATPA? It is an Array of TPointArray, multiples TPAs in an array. What are they used for? To sort TPAs in order, because a TPA is just an array tpoint, which in the case of color finding in runescape, might have different objects sorted in the same array but while using an ATPA you can have sorted separately. Example:
SCAR Code:
Var  TPA : TPointArray;  ATPA : T2DPointArray; //That's how we declare an ATPABegin  SetLength(TPA, 2);  SetLength(ATPA, 2);  TPA[0] := Point(Random(50), Random(50));  TPA[1] := Point(Random(50), Random(50));  ATPA[0] := TPA;  ATPA[1] := TPA;  Writeln('ATPA[0][0].X = ' + IntToStr(ATPA[0][0].X));  Writeln('ATPA[1][0].Y = ' + IntToStr(ATPA[0][0].Y));end.
You can have multiple points(like a TPA) but sorted in order, starting from ATPA[0] to ATPA[1].

But, what we can do with them while finding colors/objects?
Here are the most important functions in color finding with "TPAs":

TPAtoATPA, TPAtoATPAEx, SplitTPA and SplitTPAEx.

TPAtoATPA:
parameters: Dist : Integer. It makes many TPAs with the shape of a circle, that have points inside it. Look here:

The red boxes are the points you find using FindColorsTolerance, and as you see TPAtoATPA groups them in 3 different TPAs, ATPA[0], ATPA[1] and ATPA[2]. The dist parameter is the max distance between points, so if you use dist 5 with points where their distance is 6, it won't group them in the same TPA. Do you understand?
Imagine it in Runescape:

(Fishing spots)

TPAtoATPAEx
Does the same as TPAtoATPA except that it sorts with the shape of a rectangle. In certain things it's better to use TPAtoATPAEx than TPAtoATPA. W parameter is Width and H is height.

Example:

SplitTPA
The difference between this and TPAtoATPA, is that SplitTPA checks if one of the sorted tpas is in 'contact' with other tpa, or they are in a sortable range(according to Dist parameter) it groups them together. Example:

RS example:

These X and arrows indicate where SplitTPA groups two tpas, while TPAtoATPA leaves them apart. I use SplitTPA for example while finding trees because they have a dark and a light part, so I find colors from both sides and combine them.

SplitTPAEx
The same as SplitTPA except that it sorts with the shape of a rectangle. Parameters are W and H(see TPAtoATPAEx).

Well, these are the most common ATPA functions used in object finding. How a function would look:
SCAR Code:
function FindChicken(Var X, Y : Integer): Boolean;var  TPA : TPointArray;  ATPA : T2DPointArray;  I, H : Integer;Begin  FindColorsSpiralTolerance(MSCX, MSCY, TPA, ChickenColor, MSX1, MSY1, MSX2, MSY2, 15);  ATPA := TPAtoATPA(TPA, 25);  If Length(ATPA) = 0 Then //If no points were found    Exit;  H := High(ATPA);  For I := 0 To H Do  Begin    MiddleTPAEx(ATPA[I], X, Y); //Used to get the middle of the current sorted tpa    MMouse(X, Y, 3, 3);    Wait(50 + Random(50));    If IsUpText('hicken') Then    Begin      Writeln('Found chicken!');      GetMousePos(X, Y);      Result := True;      Exit;    End;  End;End;
That's a common TPA object finding functions.

Now, I'm explaining some tpa/atpa functions of the WizzyPlugin(where most of tpas functions are stored, big credits to him).

RearrangeAndShortenArray/RearrangeAndShortenArrayEx
They do the same as TPAtoATPA and TPAtoATPAEx, except they give the result in a TPointArray. But beware, it only gives the first point of every sorted tpa. Comparation:
SCAR Code:
//TPAtoATPAATPA := TPAtoATPA(TPA, X);H := High(TPA);For I := 0 To H DoBegin  MiddleTPAEx(ATPA[I], X, Y);  MMouse(X, Y, 3, 3);
SCAR Code:
//RearrangeAndShortenArrayTPA2 := RearrangeAndShortenArray(TPA, X);H := High(TPA2);For I := 0 To H DoBegin  //What it does:  //X := ATPA[I][0].X;  //Y := ATPA[I][0].Y;  //It gives the first point of the current sorted tpa  //while you use TPAtoATPA you get the middle, not the first point  MMouse(X, Y, 3, 3);
Sometimes you prefer to use when you don't care about the middle or the first pixel. But how do you know if you care? because if you move mouse to the first pixel of an object, remembering that MMouse uses randomness, you may move the mouse outside and the uptext check will fail. Parameters(normal): Dist(the same as TPAtoATPA) and a which is the tpa to use. Parameters(Ex): W and H(see tpatoatpa) and a which is the tpa to use.

RAaSTPA/RAaSTPAEx
It's the same as the functions above except it has a shorter name Well, not the same, it overwrites the tpa given to the result tpa, so in fact you don't another TPA variable.

CombineTPA
Combines 2 tpas into one. Example:
SCAR Code:
FinalTPA := CombineTPA(TPA1, TPA2);

SortTPAFrom/SortATPAFrom
Sorts the tpa/atpa starting from the give point. Why would you use it? example:
SCAR Code:
function FindMultiPoints(Colors : TIntegerArray): TPointArray;Var  I, H : Integer;  TPAex : TPointArray;Begin  H := High(Colors);  For I := 0 To H Do  Begin    FindColorsTolerance(TPAex, Colors[I], MSX1, MSY1, MSX2, MSY2, 15);    Result := CombineTPA(Result, TPAex);  End;  SortTPAfrom(Result, Point(MSCX, MSCY));End;

SortATPASize:
Sorts an atpa starting from the biggest or the smallest one, defined by the parameter const BigFirst : Boolean.
Useful in some cases, in others it doesn't matter.

GetTPABounds
Gets the boundaries of a tpa, example:

(SRL)FindColorsPie
Finds all the points in a circle arc(mostly used in the minimap). Parameters:
Points: a var to store points with(TPA)
Color: Color to find
Tol: Tolerance
StartD, EndD: Start and end degrees
MinR, MaxR: Min & Max radius to find in
x1, y1, x2, y2: ()
mx, my: Circle center.
Example:
SCAR Code:
var  TPA : TPointArray;begin  FindColorsPie(TPA, FindVarrockRoadColor, 0, 0, 15, 1, 40, mmx1, mmy1, mmx2, mmy2, mmcx, mmcy);end.
How SCAR will react:

That's it as for now, if you want me to explain any more function from WizzyPlugin, I'll be happy

TPA/ATPA useful functions:

DebugTPA (By Wizzup?):
SCAR Code:
Function DebugTPA(Points: TPointArray; BmpName: String): Boolean;Var   Width, Height, ClientBMP, I: Integer;   xs, ys, xe, ye: Integer;Begin  Try  Begin    xe := xs xor xs;    ye := ys xor ys;    xs := 1 shl 20;    ys := 1 shl 20;    For I := 0 To High(Points) Do    Begin      xs := Min(xs, Points[i].X);      ys := Min(ys, Points[i].Y);      xe := Max(xe, Points[i].X);      ye := Max(ye, Points[i].Y);    End;    Width := xe - xs;    Height := ye - ys;    DisplayDebugImgWindow(0, 0);    DisplayDebugImgWindow(Width, Height);    ClientBMP := BitmapFromString(Width, Height, '');    CopyClientToBitmap(ClientBMP, xs, ys, xe, ye);    For I := 0 To High(Points) Do      FastSetPixel(ClientBMP, Points[i].X - xs, Points[i].Y - ys, 255);    If BmpName <> '' Then      SaveBitmap(ClientBMP, ScriptPath + BmpName + '.bmp');    SafeDrawBitmap(ClientBMP, GetDebugCanvas, 0, 0);    DisplayDebugImgWindow(Width, Height);    FreeBitmap(ClientBMP);  End  Except    FreeBitmap(ClientBMP);  End;  Result := True;End;
What does it do? Debugs all the points stored in the tpa given.

DebugATPA (By Wizzup?):
SCAR Code:
Function DebugATPA(aPoints: Array Of TPointArray; BmpName: String): Boolean;Var   Width, Height, ClientBMP, I, L, C, Col: Integer;   xs, ys, xe, ye: Integer;   OuterPoints: TPointArray;Begin  For I := 0 To High(aPoints) Do    L := L + Length(aPoints[i]);  SetLength(OuterPoints, L + 1);  C := 0;  For I := 0 To High(aPoints) Do    For L := 0 To High(aPoints[i]) Do    Begin      C := C + 1;      OuterPoints[C] := aPoints[i][L];    End;  Try  Begin    xe := xs xor xs;    ye := ys xor ys;    xs := 1 shl 20;    ys := 1 shl 20;    For I := 0 To High(OuterPoints) Do    Begin      xs := Min(xs, OuterPoints[i].X);      ys := Min(ys, OuterPoints[i].Y);      xe := Max(xe, OuterPoints[i].X);      ye := Max(ye, OuterPoints[i].Y);    End;    Width := xe - xs;    Height := ye - ys;    DisplayDebugImgWindow(0, 0);    DisplayDebugImgWindow(Width, Height);    ClientBMP := BitmapFromString(Width, Height, '');    CopyClientToBitmap(ClientBMP, xs, ys, xe, ye)    For I := 0 To High(aPoints) Do    Begin      Col := Random(16777215);      For L := 0 To High(aPoints[i]) Do        FastSetPixel(ClientBMP, aPoints[i][L].X - xs, aPoints[i][L].Y - ys, Col);    End;    SafeDrawBitmap(ClientBMP, GetDebugCanvas, 0, 0);    DisplayDebugImgWindow(Width, Height);    If BmpName <> '' Then      SaveBitmap(ClientBMP, ScriptPath + BmpName + '.bmp');    FreeBitmap(ClientBMP);  End  Except    FreeBitmap(ClientBMP);  End;  Result := True;End;
Debugs all the points of the sorted tpas in different colors.

Tell me if I wrote , explained, showed, something wrong, or any other error that you think it deserves to be corrected.
That's my tutorial, hope you like it
Last edited by Cazax; 08-27-2010 at 12:01 AM.

2. nice tut i learned lot of thing in it.
but i have a question

function FindChicken(Var X, Y : Integer): Boolean;
var
TPA : TPointArray;
ATPA : T2DPointArray;
I, H : Integer;
Begin
FindColorsSpiralTolerance(MSCX, MSCY, TPA, ChickenColor, MSX1, MSY1, MSX2, MSY2, 15);
ATPA := TPAtoATPA(TPA, 25);
If Length(ATPA) = 0 Then //If no points were found
Exit;
H := High(ATPA);
For I := 0 To H Do
Begin
MiddleTPAEx(ATPA[i], X, Y); //Used to get the middle of the current sorted tpa
MMouse(X, Y, 3, 3);
Wait(50 + Random(50));
If IsUpText('hicken') Then
Begin
Writeln('Found chicken!');
GetMousePos(X, Y);
Result := True;
Exit;
End;
End;
End;

does the 25 means distance between points ?

3. Very Nice Cazax!!

4. Originally Posted by francishelie
nice tut i learned lot of thing in it.
but i have a question

SCAR Code:
function FindChicken(Var X, Y : Integer): Boolean;var  TPA : TPointArray;  ATPA : T2DPointArray;  I, H : Integer;Begin  FindColorsSpiralTolerance(MSCX, MSCY, TPA, ChickenColor, MSX1, MSY1, MSX2, MSY2, 15);  ATPA := [SIZE="5"]TPAtoATPA(TPA, [U]25[/U]);[/SIZE]  If Length(ATPA) = 0 Then //If no points were found    Exit;  H := High(ATPA);  For I := 0 To H Do  Begin    MiddleTPAEx(ATPA[i], X, Y); //Used to get the middle of the current sorted tpa    MMouse(X, Y, 3, 3);    Wait(50 + Random(50));    If IsUpText('hicken') Then    Begin      Writeln('Found chicken!');      GetMousePos(X, Y);      Result := True;      Exit;    End;  End;End;

does the 25 means the distance between point ??
Yes it is, read what I explained
Note: Distance is in pixels.

Updated.

5. SRL Junior Member
Join Date
Aug 2008
Location
!!LOL!!
Posts
247
Mentioned
0 Post(s)
Quoted
0 Post(s)
FINALLY i have understood atpa at last thank you a million!!!!!!!!

6. SRL Junior Member
Join Date
Aug 2007
Posts
259
Mentioned
0 Post(s)
Quoted
1 Post(s)
Hey, great guide, though I have a few questions:

What does the T in Tpoint stand for?

How exactly do you measure TpointArrays? Does SetLength(TPA, 3); mean all Tpoints 3 pixels from a given Tpoint?

In FindColorsSpiralTolerance(MSCX, MSCY, Result, RockColor, MSX1, MSY1, MSX2, MSY2, 15);
What does the "Result" stand for?

7. 1. I think the T is like an abbreviation of Type, because TPoints are actually types. Nothing important really.

2. A TPointArray holds multiple points(pixels, coordinate). So SetLength(TPA, 3); will carry 3 points.

3. Since it's a function, and the result is a TPA, whe can use the result as a variable.

8. Thanks, amazing! This is exactly what I needed!
But, in your MainScreen coords picture, you say that MSX2, MSY2 is in the bottom-right of the chat screen. But it ends higher then that, at the actual bottom-right corner of the MainScreen.

9. Didn't see that, I'm fixing it.

10. SRL Junior Member
Join Date
Aug 2008
Location
!!LOL!!
Posts
247
Mentioned
0 Post(s)
Quoted
0 Post(s)
this should be stickied

11. Cazax, once more ^^. This tut ROCKS!

I now fully understand and can use TPA's. They are great TBH.
First I just couldn't visualize what all these functions did, but now I totally do!

12. Erm... posting after 1 month on a great tut isn't gravediging, right?
Anyway, this deserves a little bumb, great tut, and there I thought I knew most things about TPAs and ATPAs... lol, it seems I'm learning something new every day I'm on this forum...
Well, now I'll incoperate some of it into my script, get 99 wc on my main, and then release it.

13. SRL Member
Join Date
Apr 2007
Location
The Netherlands
Posts
5,563
Mentioned
0 Post(s)
Quoted
0 Post(s)
It's still amazing and yes deserves a bump.

14. Awesome tut!
Great explanations and pictures
I didn't read it all yet, but still.

(also thanks for helping me in irc)
rep++

15. Excellent tutorial. I learned quite a bit about TPAs and their grouped counterparts that will most definitely assist in the making of my scripts.

Rep++;

Thank you ,
~Macro_FTW

16. now im fresh and understand what atpas and tpas r ^^ and the functions too

17. I really never have understood TPAs. This has helped me gain more of an understanding to them. I do have one question though: Why do most TPA procedure get the middle of a TPA, say, instead of the beginning or end TPoint of the TPA?

18. It's like a habit, you could use TPA[0] or TPA[High(TPA)], but with MMouse randomness you could miss the object you are searching. So if you have the middle you probably won't miss(unless it moves).
Last edited by Cazax; 08-27-2010 at 12:02 AM.

19. Re-uploaded pictures for new generations