[SCAR] TPAs For Dummies

Discussion in 'Code Snippets and Tutorials' started by Dusk412, Mar 6, 2009.

  1. Dusk412

    Dusk412 Level I

    Joined:
    Aug 2, 2008
    Messages:
    88
    Likes Received:
    9
    [​IMG]

    Note:

    This guide was taken from SRL-Forums but it is mine. If any mod wishes to verify that, feel free, just PM me so that I will go get on. I have already verified that account when I posted the DTM guide though. Also, thank you to whichever mod has to keep approving this guide as I have to edit it alot to fix the BBCode and unfortunately they must approve it each and every time.

    Table Of Contents:
    - Background Information
    - Basic Use Of TPAs
    - Advanced Use Of TPAs

    Background Information:

    What is a TPA, you ask?
    - Well, TPA stands for “TPointArray” Now that may sound like complex programmer language to you, but the truth is that TPAs are a fairly simple and powerful tool used frequently on SRL Forums. Before we can begin to explain exactly what and how to utilize this tool, we must first understand what an array is.

    Well then, what is an array?
    - An array is, in simple terms, a shorthand way of declaring a whole lot of variables of the same type. Some of the more frequently used types are integers, booleans, and strings. For the sake of understanding, here is an example.
    - Example: In a classroom, you are a student. In this class you have tons of grades. If you were to write a program to keep track of grades for you, you would need a variable for each and every grade you had. Say you had just 10 grades. In this program all we want to do is write each of the grades to the Debug box (the box in the corner of SCAR).

    Code (Text):
    1. program TPATutorial;
    2. {.include SRL/SRL.scar}
    3.  
    4. var
    5.   Grade1, Grade2, Grade3, Grade4, Grade5, Grade6, Grade7, Grade8, Grade9, Grade10 : Integer;
    6.  
    7. begin
    8.   Writeln(inttostr(Grade1));
    9.   Writeln(inttostr(Grade2));
    10.   Writeln(inttostr(Grade3));
    11.   Writeln(inttostr(Grade4));
    12.   Writeln(inttostr(Grade5));
    13.   Writeln(inttostr(Grade6));
    14.   Writeln(inttostr(Grade7));
    15.   Writeln(inttostr(Grade8));
    16.   Writeln(inttostr(Grade9));
    17.   Writeln(inttostr(Grade10));
    18. end.
    - As you can see this is a fairly long program for the simplest of tasks. We must declare each variable separately, and then call on each variable separately. Using arrays, we can shorten this to just a few lines.

    Code (Text):
    1. program TPATutorial;
    2. {.include SRL/SRL.scar}
    3.  
    4. var
    5.   Grade: array [0..9] of Integer;
    6.   i : Integer;
    7.  
    8. begin
    9.   for i := 0 to 9 do
    10.   begin
    11.     Writeln(inttostr(Grade[i]));
    12.   end;
    13. end.
    - In this much shorter example, we can declare all 10 grade variables at once. You could call on them individually by using Grade[0], Grade[1], … Grade[9], or we can use the much faster method of using a for statement that runs the integer I from 0 to 9, therefore calling on each grade in turn. If you wanted to do this for 100 or even 1000 grades, it would hardly lengthen at all, whereas the other function would gain hundreds more lines.

    - Now that we understand what an array is, you are probably asking yourself, how do we have an array of a TPoint? In fact, what on earth is a TPoint at all? Which brings me to my next point.

    What the heck is a TPoint?

    - I do not wish to go and totally cover basic geometry, so I will quickly summarize. On the Cartesian Plane (the graph with the x-axis and the y-axis), you can describe any one spot by using a combination of two numbers, the x and y coordinates, shown like this:

    Code (Text):
    1. (x, y)
    2. (0,0)
    3. (12, 3)
    - A combination of one x and one y coordinate describes exactly one spot, called a point. In SRL, we call points TPoints. Therefore a TPoint is really two values, an x and a y. You can store values to a TPoint like this:

    Code (Text):
    1. program TPATutorial;
    2. {.include SRL/SRL.scar}
    3.  
    4. var
    5.   MyPoint : TPoint;
    6.  
    7. begin
    8.   MyPoint:= inttopoint(5,7);
    9. end.
    - the function ‘inttopoint’ takes two integers, in this case x and y, and converts them to one TPoint. You can also store values and call on values of TPoints like this:

    Code (Text):
    1.  program TPATutorial;
    2. {.include SRL/SRL.scar}
    3.  
    4. var
    5.   MyPoint : TPoint;
    6.  
    7. begin
    8.   MyPoint.x := 5;
    9.   MyPoint.y := 7;
    10.   Writeln(inttostr(MyPoint.x));
    11. end.
    - Using the name of the TPoint, followed by a period, followed by either x or y, depending on which value you want. So now you understand arrays and TPoints, and you want to know why you could possible need to have a whole array of these silly points.

    Why do we need TPointArrays?

    - Say you have a square, each corner on said square has a coordinate. Now what you could do, as I explained with arrays, is make a variable TPoint for each and every corner. With a square this may seem simple, but what if you want an octagon, what about if you want to get every corner on the outline of a runescape object, such as a fish or a bucket. These objects have tens if not hundreds of points on them and it would take tons of memory and space to create a program to use them. But through the use of TPointArrays, you can store them all in one variable and utilize and manipulate them to your advantage.

    Basic Use Of TPAs:

    - The very first thing you must do, to get a TPA, is declare it. There are a few ways in which to go about this. The first would be to do it as if creating an array.

    Code (Text):
    1. MyTPA : array of TPoint;
    Code (Text):
    1. MyTPA : array [0..9] of TPoint;
    - But the developers of SCAR and SRL have gone beyond this and create a whole new type, just for TPAs called TPointArray (of course)! So the best, coolest, and newest way to do it would be like so:

    Code (Text):
    1. MyTPA : TPointArray;
    - But one thing you may have noticed that is missing, is the length of the array, that is, how many different TPoints we can store. If you do not know how long the TPA is going to need to be at the very beginning of the script, you may simply leave the length until later. If you know exactly how long it needs to be, you may declare that at the beginning. There are two procedures that do the exact same thing.

    Code (Text):
    1. procedure SetLength(var s; NewLength: Integer);
    Code (Text):
    1. procedure SetArrayLength(var Arr; Count: Integer);
    - Both functions take the TPointArray stored in either variable s or Arr (depending on the procedure) and change the length to either NewLength or Count (again, depending on which procedure). You use it like this:

    Code (Text):
    1. SetLength(MyTPA, 10);
    Code (Text):
    1. SetArrayLength(MyTPA, 10);
    - Both of these examples set the length TPA, MyTPA, to 10. Meaning there are 10 different values that can be stored, from MyTPA[0] to MyTPA[9];
    - Note: TPAs always start at 0, not 1! So if you want 10 values, the highest TPoint will be 9, if you want 100 values, the highest TPoint will be 99, etc.

    - The reason that you will not always need to declare a length at the beginning of a script is that many of the functions and procedures that are most common and most useful in SRL and SCAR are the ones that will find all the locations that meet a specific requirement, such as color, and will store however many values there are. That is why these next two functions where created.

    Code (Text):
    1. function Length(s): Integer;
    Code (Text):
    1. function GetArrayLength(var Arr): Integer;
    - These functions take the TPA stored under s or Arr and return the length of the TPA, or the number of values stored in it, as an integer;

    Code (Text):
    1. program TPATutorial;
    2. {.include SRL/SRL.scar}
    3.  
    4. var
    5.   TPALength : Integer;
    6.   MyTPA : TPointArray;
    7.  
    8. begin
    9.   TPALength := Length(MyTPA);
    10.   Writeln(inttostr(TPALength));
    11.   TPALength := GetArrayLength(MyTPA);
    12.   Writeln(inttostr(TPALength));
    13. end.
    - In this example I got the length of the TPA, MyTPA, and stored it in the variable TPALength, an integer. This is, as I stated earlier, useful when finding points and storing them all when you do not know how many different points you will get. You may then run through these points and check for something, like a specific uptext, for example. Some powerful, yet extremely simple, functions when manipulating TPAs are the following:

    Code (Text):
    1. function High(x): Int64;
    - By putting the TPA in for x, it will return the highest possible index for our TPA. The index is the number that goes in the brackets after the TPA name. MyTPA[2] has and index of 2. MyTPA has an index of i. So if we have a TPA of length 10 (this means our TPA goes from 0 to 9, remember), High would return 9.

    Code (Text):
    1. function Low(x): Int64;
    - Similarly, Low will return the lowest possible index for our TPA. So if we have a TPA of length 10 that goes from 0 to 9, it will return 0. This is not actually particularly useful for TPAs, it is generally only used on static arrays. I just thought I would mention it. (Credits to mixster for helping me figure out what the use of Low was for :D).

    Code (Text):
    1. program TPATutorial;
    2. {.include SRL/SRL.scar}
    3.  
    4. var
    5.   MyTPA : TPointArray;
    6.  
    7. begin
    8.   SetLength(MyTPA, 10);
    9.   Writeln('High = '+inttostr(High(MyTPA)));
    10.   Writeln('Low = '+inttostr(Low(MyTPA)));
    11. end.
    - There is an example of how the functions High and Low work.
     
    Billy likes this.
  2. Dusk412

    Dusk412 Level I

    Joined:
    Aug 2, 2008
    Messages:
    88
    Likes Received:
    9
    Advanced Use Of TPAs:

    - FindColorsTolerance
    - FindColorsSpiralTolerance
    - MiddleTPA

    FindColorsTolerance:

    - Now that you have all that basic knowledge under your belt, take a deep breath, stand up, stretch, and get ready to learn how you can really put this stuff to use. If at this point you do not know basic color finding, please go look at some other tutorials in the basic section. Glad to have covered that minor detail, moving on… The first function we will take a look at is FindColorsTolerance. This is not the same as FindColorTolerance. The difference is that it is Colors with an s on the end because we will be finding all locations of said color within a certain tolerance. To the extent of my knowledge, there is no FindColors function to compete with FindColor, mainly because you could always set the tolerance to 0.

    [SCAR]function FindColorsTolerance(var Points: TPointArray; Color, xs, ys, xe, ye, Tolerance: Integer): Boolean;[/SCAR]

    - Here is a little explanation:
    var Points: TPointArray – the TPA where the function will store all the points it finds within the color’s tolerance.
    Color: Integer – the color that the function will look for
    xs, ys, xe, ye: Integer – The coordinates of the box in which the function will look. (xs, ys) should be the upper left-hand corner and (xe, ye) should be the coordinates of the lower right-hand corner. Oftentimes people use built in coordinates such as MSx1, MSy1, MSx2, MSy2 (the main screen coordinates), MMx1, MMy2, MMx2, MMy2 (the mini map coordinates), MCx1, MCy2, MCx1, MCy2 (the main chat box coordinates), or MIx1, MIy1, MIx2, MIy2 (the main inventory coordinates).
    Tolerance: Integer - Value can be from 0-255. How close the set color must be to the one the script finds.
    FindColorsTolerance: Boolean – the function itself will return True if it finds any (one or more) occurences of the color or false if it does not find any occurences or has problems during its execution.

    [SCAR]program TPATutorial;
    {.include SRL/SRL.scar}

    var
    MyTPA : TPointArray;
    MyPoint : TPoint;
    x, y, i : Integer;

    begin
    FindColorsTolerance(MyTPA, 2961456, MSx1, MSy1, MSx2, MSy2, 10);
    if Length(MyTPA) = 0 then FindColorsTolerance(MyTPA, 8160390, MSX1, MSY1, MSX2, MSY2, 10);
    for i := 0 to High(MyTPA)do
    begin
    MyPoint := MyTPA
    MMouse (MyPoint.x, MyPoint.y, 3, 3);
    if (IsUpTextMultiCustom(['tair', 'case'])) then
    begin
    GetMousePos(x, y);
    Mouse(x, y, 0, 0, False);
    ChooseOption('limb');
    Wait(500+random(250));
    Exit;
    end;
    Wait(350+random(350));
    end;
    end.[/SCAR]

    - Okay this make pretty complicated at first, but I will break it down, and you should be able to do this yourself very soon. This is a severely modified and cut down section from a script of mine and the colors are used to find the stairs in Lumbridge Castle (in case you care). The first thing I do, of course, is name the program and then include SRL. Then I declare variables, I usually have my TPointArray, a TPoint, and an integer for use in my for-to-do statement. I also have the variables x and y that I use in all scripts for clicking coordinates. I gave them simple names so it is easy to understand in the script. Now things get interesting.

    [SCAR]FindColorsTolerance(MyTPA, 2961456, MSx1, MSy1, MSx2, MSy2, 10);[/SCAR]

    - This is where we are looking for the color 2961456 with a tolerance of 10. We are looking in the mainscreen (MSx1, MSy1, MSx2, MSy2). We are storing all the points we find in MyTPA.


    [SCAR]if Length(MyTPA) = 0 then FindColorsTolerance(MyTPA, 8160390, MSX1, MSY1, MSX2, MSY2, 10);[/SCAR]

    - Here I add a little failsafe that I have use ever time I use TPAs and I usually do more than once. This is if the length of MyTPA is 0 after the first color search (meaning it did not find that color) it will try again with a different color. You could also do this with and if statement around the first FindColorsTolerance and if it is false use the next color, but I prefer this method because the next procedure we will talk about is, as I just mentioned, a procedure and not a function. Therefore, it does not return a value and cannot be used in an if statement. I use this method to maintain the same style and to make it simpler. Again, it does the same thing as before but with a different color, this time 8160390.

    [SCAR]for i := 0 to High(MyTPA) do[/SCAR]

    - This line is perhaps the essence of using TPAs. What we do here is we run through every single point within our TPA (remember if our TPA has a length of 10, 0 would be the start, and 9 would be the end – which is returned by the function High). So we are able to look at any number of points simply with this easy line of code.

    [SCAR]MyPoint := MyTPA
    MMouse (MyPoint.x, MyPoint.y, 3, 3);[/SCAR]

    - Here we take whichever point in the TPA we happen to be on, and we set it to our TPoint. We then move our mouse to the TPoint. (Note: we could also do this with MyTPA.x and MyTPAP.y, but this is how I learned it and how I always do it :D).

    [SCAR]if (IsUpTextMultiCustom(['tair', 'case'])) then
    begin
    GetMousePos(x, y);
    Mouse(x, y, 0, 0, False);
    ChooseOption('limb');
    Wait(500+random(250));
    Exit;
    end;[/SCAR]

    - After we move our mouse to where we found the color, we check the uptext to see if it is what we wanted to find. In this case I am looking for the staircase in Lumbridge Castle. If I do find it, I click climb. I first use GetMousePos and then Mouse because you are moving with a bit of random to the point where the color is, but a real person doesn’t move with a tiny bit of random and then click that spot with a different tiny bit of random. GetMousePos allows me to move, check the uptext, and then right click in the exact same spot where my mouse is already. It is a method that keeps people from getting banned. Then I wait a little while and exit the loop so I don’t run through the other points in the TPA, after all, we already found what we wanted.

    [SCAR]Wait(350+random(350));[/SCAR]

    - This is outside of the if statement because we do not want the mouse to move, check the uptext, and then instantly move to the next point. If you do not have a wait then the mouse will go crazy and look like it is having a seizure across your screen because it is checking all the points in rapid succession. The wait allows the mouse to move at a speed and frequency that more closely simulates human movements.

    FindColorsSpiralTolerance:

    - FindColorsSpiralTolerance is like FindColorSpiralTolerance much the same way as the previous function. Again make sure to have the s on Colors. The difference between FindColorsSpiralTolerance and FindColorsTolerance is that while FindColorsTolerance begins searching from the upper left corner of the box you specify and goes to the bottom right, FindColorsSpiralTolernace starts the search from coordinates that you specify (Most people start the search from the center of the screen). It then proceeds to spiral outward in its search for the color. This allows the colors closest to the starting point to be earlier in your TPA, and therefore checked first when going through our for-to-do statement.

    - FindColorsSpiralTolerance is used almost 100% of the time over FindColorsTolerance because it keeps you from accidently clicking strange colors on the edge of your screen and it makes it easier to find objects closer to your character, which is generally the point.

    [SCAR]procedure FindColorsSpiralTolerance(x, y: Integer; var Points: TPointArray; color, xs, ys, xe, ye: Integer; Tolerance: Integer);[/SCAR]

    - Here is an explanation, I will copy the duplicate stuff from above so you do not have to scroll up and down so much:
    x, y: Integer – the coordinates for the starting point of the search. Oftentimes people use built in coordinates such as MSCx and MSCy (main screen center coordinates) or MMCx and MMCy (mini map center coordinates).
    var Points: TPointArray – the TPA where the function will store all the points it finds within the color’s tolerance.
    Color: Integer – the color that the function will look for
    xs, ys, xe, ye: Integer – The coordinates of the box in which the function will look. (xs, ys) should be the upper left-hand corner and (xe, ye) should be the coordinates of the lower right-hand corner. Oftentimes people use built in coordinates such as MSx1, MSy1, MSx2, MSy2 (the main screen coordinates), MMx1, MMy2, MMx2, MMy2 (the mini map coordinates), MCx1, MCy2, MCx1, MCy2 (the main chat box coordinates), or MIx1, MIy1, MIx2, MIy2 (the main inventory coordinates).
    Tolerance: Integer - Value can be from 0-255. How close the set color must be to the one the script finds.
    Note: This is a procedure and it isnot a function. This means that it will not return True if it finds the color. Hence, why I showed you that “if Length(MyTPA) = 0” trick.

    [SCAR]program TPATutorial;
    {.include SRL/SRL.scar}

    var
    MyTPA : TPointArray;
    MyPoint : TPoint;
    x, y, i : Integer;

    begin
    x := MSCx;
    y := MSCy;
    FindColorsSpiralTolerance(x, y, MyTPA, 2961456, MSx1, MSy1, MSx2, MSy2, 10);
    if Length(MyTPA) = 0 then FindColorsSpiralTolerance(x, y, MyTPA, 8160390, MSX1, MSY1, MSX2, MSY2, 10);
    for i := 0 to High(MyTPA) do
    begin
    MyPoint := MyTPA
    MMouse (MyPoint.x, MyPoint.y, 3, 3);
    if (IsUpTextMultiCustom(['tair', 'case'])) then
    begin
    GetMousePos(x, y);
    Mouse(x, y, 0, 0, False);
    ChooseOption('limb');
    Wait(500+random(250));
    Exit;
    end;
    Wait(350+random(350));
    end;
    end.[/SCAR]

    - I am going to attempt to keep this explanation marginally shorter by not re-explaining the parts that I went over before. Here is the new stuff:

    [SCAR]x := MSCx;
    y := MSCy;[/SCAR]

    - Okay, as I stated before, x and y are where we begin the search. These two lines set them equal to built in coordinates for the center of the mainscreen. So now our search shall begin at the exact center of the main screen.

    [SCAR]FindColorsSpiralTolerance(x, y, MyTPA, 2961456, MSx1, MSy1, MSx2, MSy2, 10);
    if Length(MyTPA) = 0 then FindColorsSpiralTolerance(x, y, MyTPA, 8160390, MSX1, MSY1, MSX2, MSY2, 10);[/SCAR]

    - Here I changed FindColorsTolerance to FindColorsSpiralTolerance and added the parameters x and y. That’s it.

    MiddleTPA:

    - The function MiddleTPA is used to find the center of all of your points. Do not get confused here. This function does not take the middle point of your TPA. If you have a TPA with index 0 to 2, it does not return the point at index 1. What this function does do, is it takes all the points in your TPA, and finds the center of them. For example, if you have a square and four TPoints in your TPA, one for each corner, MiddleTPA will find the center of the square.

    [SCAR] function MiddleTPA(tpa: TPointArray): TPoint; [/SCAR]

    - tpa is the TPointArray that you want the middle of and it will return it as a TPoint.

    [SCAR]program TPATutorial;
    {.include SRL/SRL.scar}

    var
    MyTPA : TPointArray;
    MyTPoint : TPoint;

    begin
    SetLength(MyTPA, 4);
    MyTPA[0] := inttopoint(0, 0);
    MyTPA[1] := inttopoint(0, 10);
    MyTPA[2] := inttopoint(10, 0);
    MyTPA[3] := inttopoint(10, 10);
    MyTPoint := MiddleTPA(MyTPA);
    Writeln(inttostr(MyTPoint.x));
    Writeln(inttostr(MyTPoint.y));
    end.[/SCAR]

    [SCAR]
    0 1

    x

    2 3
    [/SCAR]

    Okay here is my attempt at an example so that if you didn’t understand it before, you do now. We have a TPA of length 4 (index 0 to 3). I made a little picture with where each of these points goes on our square. The x is the point that MiddleTPA would give you and should have the coordinates (5, 5) from the example.