Basic concepts:

Point = a single pixel

Points = 2+ pixels

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

It's basically X and Y coordinates stored in a type. It's the same as:SCAR Code:Type

TPoint = Record

X, Y : Integer;

End;

Therefore a TPointArray is this:SCAR Code:Var

X, Y : Integer;

TP : TPoint;

Begin

TP.X := X;

TP.Y := Y;

End.

It's the same as:SCAR Code:Type

TPointArray = Array Of TPoint;

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:

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:function FindColorsTolerance(var Points : TPointArray; Color, Xs, Ys, Xe, Ye, Tolerance : Integer): Boolean;

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:procedure FindColorsSpiralTolerance(X, Y : Integer; var Points : TPointArray; Color, Xs, Ys, Xe, Ye, Tolerance : Integer);MSCX, MSCY = The middle of the main screenSCAR Code:Function FindRockPoints(RockColor : Integer): TPointArray;

Begin

FindColorsSpiralTolerance(MSCX, MSCY, Result, RockColor, MSX1, MSY1, MSX2, MSY2, 15);

End;

MSX1, MSY1, MSX2, MSY2 = Main screen coordinates

Now that you have the TPAs, how would you know what points did you get?

If you use it in a TPA, you would get its length example:SCAR Code:function GetArrayLength(x): Integer;

Note: Length does the same as GetArrayLength.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.

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:

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:function High(x): Integer;

But every time it loops, high(TPA) will be called and that would waste time: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.

If you use Length(TPA) - 1 (to get the correct highest index) it would cost you ~0.3 microseconds (approx.)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.

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 anArray ofTPointArray, 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:

You can have multiple points(like a TPA) but sorted in order, starting from ATPA[0] to ATPA[1].SCAR Code: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.

But, what we can do with them while finding colors/objects?

Here are the most important functions in color finding with "TPAs":

TPAtoATPA,TPAtoATPAEx,SplitTPAandSplitTPAEx.

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:

That's a common TPA object finding functions.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;

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://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);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.SCAR Code://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);

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:

How SCAR will react:SCAR Code:var

TPA : TPointArray;

begin

FindColorsPie(TPA, FindVarrockRoadColor, 0, 0, 15, 1, 40, mmx1, mmy1, mmx2, mmy2, mmcx, mmcy);

end.

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

What does it do? Debugs all the points stored in the tpa given.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;

DebugATPA (By Wizzup?):

Debugs all the points of the sorted tpas in different colors.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;

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