PDA

View Full Version : Detailed TPA and ATPA tutorial



Cazax
02-24-2009, 08:07 PM
Basic concepts:
Point = a single pixel
Points = 2+ pixels

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

Type
TPoint = Record
X, Y : Integer;
End;
It's basically X and Y coordinates stored in a type. It's the same as:
Var
X, Y : Integer;
TP : TPoint;
Begin
TP.X := X;
TP.Y := Y;
End.
Therefore a TPointArray is this:
Type
TPointArray = Array Of TPoint;
It's the same as:
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:
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.

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: 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
http://i36.tinypic.com/30jipeg.jpg

Now that you have the TPAs, how would you know what points did you get?
function GetArrayLength(x): Integer;
If you use it in a TPA, you would get its length :) example:
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:
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?
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:
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:
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:
Var
TPA : TPointArray;
ATPA : T2DPointArray; //That's how we declare an ATPA
Begin
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:
http://i36.tinypic.com/f4heo5.jpg
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:
http://i33.tinypic.com/2ziu35k.jpg
(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:
http://i36.tinypic.com/11hvz9g.jpg

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:
http://i34.tinypic.com/rkofaa.jpg
http://i33.tinypic.com/2w70mc7.jpg

RS example:
http://i36.tinypic.com/11rq44p.jpg
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:
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:
//TPAtoATPA
ATPA := TPAtoATPA(TPA, X);
H := High(TPA);
For I := 0 To H Do
Begin
MiddleTPAEx(ATPA[I], X, Y);
MMouse(X, Y, 3, 3);
//RearrangeAndShortenArray
TPA2 := RearrangeAndShortenArray(TPA, X);
H := High(TPA2);
For I := 0 To H Do
Begin
//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 :p 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:
FinalTPA := CombineTPA(TPA1, TPA2);


SortTPAFrom/SortATPAFrom
Sorts the tpa/atpa starting from the give point. Why would you use it? example:
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:
http://i38.tinypic.com/10nrkmo.jpg

(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:
var
TPA : TPointArray;
begin
FindColorsPie(TPA, FindVarrockRoadColor, 0, 0, 15, 1, 40, mmx1, mmy1, mmx2, mmy2, mmcx, mmcy);
end.
How SCAR will react:
http://i37.tinypic.com/15h0ew2.jpg


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?):
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?):
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 :)

Naum
02-24-2009, 08:15 PM
;).

Amazing!

Phran6
02-24-2009, 08:21 PM
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 ?

NCDS
02-24-2009, 08:21 PM
Very Nice Cazax!!

Cazax
02-24-2009, 08:22 PM
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 the distance between point ??
Yes it is, read what I explained :)
Note: Distance is in pixels.

Updated.

hackncrack1
03-08-2009, 02:12 PM
FINALLY i have understood atpa at last thank you a million!!!!!!!!

MetalancA
03-08-2009, 09:16 PM
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?

Cazax
03-09-2009, 08:09 PM
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.

Floor66
03-09-2009, 08:26 PM
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.

Cazax
03-09-2009, 10:04 PM
Didn't see that, I'm fixing it.
EDIT: Reload the image

Smarter Child
03-09-2009, 10:31 PM
Genius, AMAZING, MASSIVE TUT>REP+.

hackncrack1
03-22-2009, 09:28 AM
this should be stickied

Floor66
03-22-2009, 01:51 PM
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!

Pure1993
04-20-2009, 11:01 PM
Erm... posting after 1 month on a great tut isn't gravediging, right? :D
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. ;)

ShowerThoughts
04-21-2009, 02:48 AM
It's still amazing and yes deserves a bump.

Ogre
05-21-2009, 11:43 AM
Awesome tut!
Great explanations and pictures
I didn't read it all yet, but still.

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

Macro_FTW
06-16-2009, 04:36 AM
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

Claymore
06-16-2009, 04:53 AM
now im fresh and understand what atpas and tpas r ^^ and the functions too

Esteban
06-24-2009, 04:53 AM
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?

Cazax
06-24-2009, 05:22 AM
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).

Cazax
08-27-2010, 12:02 AM
Re-uploaded pictures for new generations :)

Denis
04-29-2020, 06:32 AM
Hi! Re-upload again please!