Back To Top
4. For the Intermediate:
In this section of the tutorial you will learn many different things about SCAR and making a working RuneScape scripts. You will learn this such as arrays, item finding, walking in RS, object finding, and many more! Since you already know all of the basics to SCAR, this part of the tutorial should be a lot easier to understand. Thank goodness, eh?
Basic Arrays:
Arrays are an extremely useful way of coding that makes your scripts work efficiently while keeping them looking neat and tidy. There are two types of arrays:
- Static - the length or the array cannot be changed throughout your script.
- Dynamic - the length of the array can be changed as many times as you wish.
Like any other variable, arrays must be declared globally or locally. Different types of arrays are declared differently.
Static:
Again, static arrays are static because the length remains constant throughout the whole script. Here is how a static array is declared:
SCAR Code:
var
Logs : Array[1..10] of Integer;//Notice how the array is of integers. Arrays can be of any variable you wish.
The "[1..10]" is called the "array range" or "array length". This means that there will be 10 parts in the array. Just like if I said Array[1..100] there would be 100 parts in the array. Simple, no?
Dynamic:
Dynamic arrays are dynamic because the length can be changed multiple times throughout your script with a simple little command. Dynamic arrays are declared like this:
SCAR Code:
var
Logs : Array of String;
Remember how I said the length can be changed with a simple command? Well, before you use a dynamic array, you need to set the length. You can set the length by using this simple command:
SCAR Code:
SetArrayLength(Logs, 10);//Notice the first parameter is the name of the array, and the second parameter is the length.
If you wanted to use the array again later in the script with a different length, all you would have to say is:
SCAR Code:
SetArrayLength(Logs, 15);
That's not too difficult, is it? So now you know what the two different types of arrays are and how to declare them. But, how do we use them?
Using Arrays:
Using arrays is a simple concept, and since you are an intermediate scripter now, you should be able to understand it no problem. Here is a simple breakdown of an array:
SCAR Code:
var
NameOfArray : Array[Start Integer..Finish Enteger] of Variable;//Variable can be anything you want. (i.e. integer, string, point.)
NameOfArray : Array of Variable;
begin
SetArrayLength(NameOfArray: Variant, Length: Integer);//For DYNAMIC arrays only! Variant simply means it can be any variable type.
NameOfArray[Start Integer] := Variant;//Variant is whatever you declared the array as. (i.e. if you said Array of Integer;, Variant would be an integer.)
NameOfArray[Finish Integer] := Variant;
end;
Not too difficult I hope. There is something you need to remember if you are working with dynamic arrays. The "Start Integer" ALWAYS starts at '0' and goes up. So if you set the array length to '1', the length would actually be 2 because it includes '0', understand?
If that breakdown seemed to be confusing, take a look at the following example, and you should understand arrays much better:
SCAR Code:
program Arrays;
procedure ArrayExample(TheArray: String);//Notice the parameter 'TheArray'.
var
Number : Array[0..4] of Integer;
Word : Array of String;
i : Integer;
begin
case Lowercase(TheArray) of//Depending on what you write for TheArray, it will do one of the 3 procedures. Remember learning that back in the beginner section?
'number': begin
Number[0] := 2645;//These numbers can be replaced with any number you wish.
Number[1] := 7482;
Number[2] := 1968;
Number[3] := 4357;
Number[4] := 5682;
for i := 0 to 2 do//Notice that it will only write the first 3 parts of the array.
begin
Wait(500);
Writeln('The number is ' + IntToStr(Number[i]) + '.');//Notice how it writes the number, depending on what you put for the parameter 'i'.
end;
end;
'word': begin
SetArrayLength(Word, 5);//Always be sure to set the array length with working with dynamic arrays.
Word[0] := 'Zero';//These words can be replaced with any word/sentence you wish.
Word[1] := 'One';
Word[2] := 'Two';
Word[3] := 'Three';
Word[4] := 'Four';
for i := 2 to 3 do
begin
Wait(500);
Writeln('The word is the number ' + Lowercase(Word[i]) + '.');
end;
end;
else
Writeln('TheArray is not in the case statement!');//You should always use an 'else' statement like this when working with cases.
end;
end;
begin
ClearDebug;
ArrayExample('Number');//Understand how to declare is properly, with the right number of parameters?
ArrayExample('Word');
Wait(500);
end.
You may have noticed I've added in different elements you learned in the beginner's section. I've done this so you will be introduced to different ways of using all the things you learned so far. I will be doing this for the rest of the tutorial, so be aware. If you successfully wrote the above script, when you hit run, the debug box should look something like this:
The number is 2645.
The number is 7482.
The number is 1968.
The word is the number two.
The word is the number three.
Successfully executed
There, you now know how to use arrays, excellent work!
Item Finding:
Now, this is the section where you will be learning a lot of different things at once, so take it slow, make sure you understand everything you're doing before moving on. From now until the end of the intermediate section, I will be using examples that actually work for RuneScape. Aren't you happy to hear that?
I can't stress this enough, before moving on, make sure your SRL is up to date, otherwise some of these example may not work.
|
|
Item finding can be used for many different things such as checking if your character is wielding a hatchet, or to count how many logs you have in you inventory. There are many different ways of finding items in RS, but I'm going to be teaching you about the two most common and most accurate ways of doing it. There are two options you have:
In the newer versions of SCAR, Bitmaps are faster than DTMs, but often people find it easier to work with DTMs. The choice is yours.
Bitmaps:
Bitmaps are just pictures that SCAR can store as strings, so they can be used for whatever is needed. In RS scripting, Bitmaps are most commonly used to find items in your inventory, or in your bank. For my example, I'm going to show you how to make a bitmap of a Willow log, and click it in your inventory.
Before we actually make the Bitmap, we have to setup our script to load it properly. We can do this by making a function that loads the bitmap:
SCAR Code:
var
Logs : Integer;//Each bitmap is used like an integer, but they are stored as strings. Therefore we declare it as an integer.
//Also, we declare it globally so we can use it in other functions later on.
function LoadBitmaps: Integer;//Notice the function returns an integer. This is because bitmaps are integers, understand?
begin
Logs: Result :=//Bitmap here. You will learn what goes here shortly, don't worry. ;)
end;
Pretty simple I'd say.
Now what I want you to do is load RS and log into your RuneScape account. Make sure you have a Willow log in your inventory, and take a screenshot of your RS screen. If you don't know how to take a screenshot, follow these steps:
- Find the "Print Screen" key on you keyboard. It is usually hiding in the upper right corner. One my keyboard it says "PrtSc".
- Once you have found the key, open the window you wish to take a screenshot of. In this case, it would be the RS window.
- Hit the key while the RS window is open, and there you go, you took a screenshot!
Once you have taken your screenshot, I want you to take the following steps to make your bitmap:
- Open SCAR.
- Go to Tools > Picture To String. A small window should come up called "Bitmap Loader".
- Hit "Paste", and the image of your RS screen will come up.
- Scroll to your inventory, so the Willow log is in view. Make the window larger if you have to.
- Click the "+" button (to the right of the "Mask Editor" button) 5 times to zoom in closer to the object. Make sure the Willow log is in view.
- Click and drag a small box (approx. 5 x 5 pixels) in the middle of the image of the Willow log.
- Name your bitmap in the space at the bottom of the window. You should now have a screen that looks something like this:
Click "Ok", and you should see something in your debug box that looks something like this (yours may be longer or shorter, depending on how big of box you made from the willow log):
SCAR Code:
LogBMP := BitmapFromString(5, 5, 'beNpzkIzwVyAShfjIQUggCvCQ' +
'9XGRtjUXc7KWACJ3B0l3AM9zEjg=');
Excellent! You successfully made your first bitmap! Now highlight and hit Ctrl + C to copy the bitmap from the debug box. Remember the function we made to load your bitmap? Well... paste your bitmap into that function. You should now have a function that looks like this:
SCAR Code:
function LoadBitmaps: Integer;
begin
LogBMP: Result := BitmapFromString(5, 5, 'beNpzkIzwVyAShfjIQUggCvCQ' +//Notice how I used the variable "Result".
'9XGRtjUXc7KWACJ3B0l3AM9zEjg=');
end;
Very simple. I would suggest using a function like that to load bitmaps, only of you have more than one bitmap, otherwise you can use the bitmap locally (like the the example to come).
There, you have learned how to make and load bitmaps. Easy. Now, loading the bitmap doesn't really do anything for anyone. So, we are going to make a script that will click the log in your inventory. Excited? Sorry, you will have to wait just a little longer. Darn, eh?
Before you can make the script, you need to know what function to use to find the bitmap, otherwise you will never find it. Here is a list of the finding bitmap functions we will be working with, straight from the SCAR Manual:
function FindBitmap(Bitmap: Integer; var x, y: Integer): Boolean;
Search for the bitmap in client window. If found coordinates are returned in x,y. bitmap contains handle to bitmap generated by
LoadBitmap.
function FindBitmapTolerance(Bitmap: Integer; var x, y: Integer; Tol: Integer): Boolean;
Works like
FindBitmap but with a tolerance parameter for finding any similar colored bitmap. Tolerance is used to find a colored bitmap in range of the bitmap you are looking for. The greater color range you want, the higher the tolerance parameter should be.
function FindBitmapIn(Bitmap: Integer; var x, y: Integer; x1, y1, x2, y2: Integer): Boolean;
Search for the bitmap in coordinates specified by x1, y1, x2, y2.
Bitmap contains handle to bitmap generated by
LoadBitmap.
function FindBitmapToleranceIn(Bitmap: Integer; var x, y: Integer; x1, y1, x2, y2: Integer; Tol: Integer): Boolean;
Works like
FindBitmapIn but with a tolerance parameter for finding any similar colored bitmap. Tolerance is used to find a colored bitmap in range of the bitmap you are looking for. The greater color range you want, the higher the tolerance parameter should be.
Each function finds a bitmap, but they all have different a element. I hope you can understand the difference between each of them without me having to explain them individually. I will, however, explain what is meant by Tol:
- Tol or Tolerance is an integer (as you can see from the above explanations), and the higher the integer the wider range of colors SCAR is going to look for. For example, if I set the tolerance to 5, SCAR will find much less colors than if I was to set the tolerance to 15.
Since FindBitmapToleranceIn is the fastest and most accurate, we will use it to find the logs. The reason it is fast is because it will look for the bitmap in a specified box, instead of the whole screen. The reason it is more accurate is because you can adjust the tolerance, understand? Good. The following example will open your inventory, attempt to find the Willow log, and click it:
SCAR Code:
program ClickWillowLogs;
{.include SRL/SRL.scar}//Remember to include this in ALL of your scripts if you want to use functions from SRL.
function ClickLogs: Boolean;
var
Logs, x, y : Integer;{Declared locally this time because we are only using it in this function. :)
We also need to declare 'x, y' so that the coordinates of the bitmap can be stored in them}
begin
Logs := BitmapFromString(5, 5, 'beNpzkIzwVyAShfjIQUggCvCQ' +
'9XGRtjUXc7KWACJ3B0l3AM9zEjg=');
GameTab(tab_Inv);//GameTab stands for all the different tabs in the RS interface. "(tab_Inv)" clicks on the inventory tab. A full list of the gametabs can be found in Gametab.scar in your SRL folder.
if FindBitmapToleranceIn(Logs, x, y, MIX1, MIY1, MIX2, MIY2, 15) then//Remember that MI = Main Inventory.
begin
Writeln('Found Willow log bitmap!');
MMouse(x, y, 4, 4);//Moves the mouse to the bitmap. Remember MMouse from earlier?
if IsUpText('illow') then//Checks the uptext of the object. Uptext is the text in the upper left corner of the RS main screen.
begin
Wait(200 + Random(100));//You should always have a random wait after checking an uptext because the uptext doesn't appear at the millisecond you mouse over the object.
Mouse(x, y, 0, 0, True);//No randomness is needed because the mouse is already on the object.
Result := True;//Make the result true after it has clicked the logs.
end else
Writeln('Couldn''t find the correct uptext of the logs.');
end else
Writeln('Couldn''t find the log bitmap');
FreeBitmap(Logs);//You MUST include this line. This frees the bitmap, otherwise it will say loaded and make your script much slower.
end;
begin
ClearDebug;
SetupSRL;//Don't forget this line in ANY of your RS scripts!
ActivateClient;//This is needed so the script switches to the RS window. If you have a DeclarePlayers procedure, it is not needed, as it is already built in.
Wait(1000 + Random(500));//This is just in case of possible lag, that SCAR has time to switch to the RS client.
if ClickLogs then//The condition will be true if it clicks the log. See the connection between that and the actual function?
Writeln('We have clicked the Willow logs!')
else
Writeln('We have not clicked the Willow logs.');
end.
Before you anxiously run the script to see if it works, I highly recommend you read through it carefully and make sure you understand everything. Also before you press run, I would suggest the following:
- Your character has to be logged in, otherwise it won't work.
- Have a GameTab other than the inventory open, so you get a better idea of what the GameTab function does.
- Close all unnecessary applications to prevent possible lag.
If you managed to write the above script without problems the script should switch to the RS client, open the inventory, and click on the Willow log, then stop, and your debug box should look something like this:
SRL Compiled in 15 msec
Found Willow log bitmap!
We have clicked the Willow logs!
Successfully executed
I can't stress this enough, make sure you ALWAYS free your bitmaps! Otherwise, it will slow your script/computer down tremendously!
|
|
Congratulations! You have successfully learned how to find and click items in RuneScape. Now that you understand how to use bitmaps, I suggest that you make a couple different bitmaps of different items to get a better feel of how to do them. Now, DTMs are used almost exactly the same as bitmaps. It's making them that is different.
DTMs:
DTM is an acronym for Deformable Template Model. Since SCAR has a built-in DTM editor, and every item in RS has a black outline, we can make DTMs very easily. Since in the Bitmap section of the tutorial, we learned how to click an item in the inventory, for this example, we will learn how to find a DTM of leather boots and withdraw a them from the bank. Sound good?
Like bitmaps, if you are going to use multiple DTMs, it is best to make a function that loads them:
SCAR Code:
var
Boots : Integer;
function LoadDTMs: Integer;
begin
Boots: Result :=//DTM here.
end;
Now I would like you to take another screenshot of your character with a pair of leather boots in the bank. Once you've taken the screenshot, I would like you to do the following:
- Open SCAR.
- Go to Tools > DTM Editor... A window should have popped up called "Deformable Template Model Editor".
- Go to Edit > Paste Image. The screenshot you just took should come up.
- Make the window bigger until you can see the Leather Boots.
Now you are ready to make your DTM. Follow these steps carefully to successfully make a DTM:
- Click on a part of the Leather Boots that is it's main color. In this case, the color would be brown. If you are not sure what color your mouse is on, look in the top left corner of the window for a zoomed in version of where your mouse is. This allows you to easily see which color you are on. After you click the color you want you should see a very small flashing dot where you clicked. This is going to be your main point.
- Now, click on 3-4 points on the black outline of the Leather Boots. Again, use the zoomed in image if you have to. The area around the Leather Boots should look something like this:
Also, look in the top right of the window, you should see a box, with sets of numbers in it, like this:
There are three numbers in each set. The first number is the x-coordinate of the color picked, the second number is the y-coordinate, and the third number is the color. The first set of numbers is your main point, and the remaining 3-4 sets are your sub points. The color you picked for each of your sub points should be exactly the same, 65536 (black). If they aren't, click on the set that has the different color and hit delete, and re-pick the point.
Once you have done this, you will see a whole list of things on the right side of the window. Do the following:
- Make sure the area size is 0. We will define this later.
- Set the tolerance to whatever you like, I usually use 15 for DTMs.
- Set the "Parent" to your main point. When it asks for the "Parent" it means the main color.
- It is up to you whether you save it or not. I recommend you do, in case you want to use it again later, then you don't have to remake it.
- Go to File > DTM To Text, and close the window. You should now see some code in the debug box that looks like this:
SCAR Code:
DTM := DTMFromString('78DA634C6362604865644006F6DA2A0CFC401' +
'A24FA1F0818F3806AF250D540646124904E06AA2925A02604A8A6' +
'80809A44A09A684C35FC486A00608A08C5');
Looks a lot like a bitmap doesn't it? I told you they weren't very different. Like you did with the bitmap, copy and paste your DTM into your LoadDTM function. Now you know how to make and load a DTM, although loading should have been review as it is done the same way for bitmaps.
Unlike for bitmaps, there is only one function from the SCAR Manual you need to know to find your DTM:
function FindDTM(DTM: Integer; var x, y: Integer; x1, y1, x2, y2: Integer): Integer;
Use DTM to find object on client window.
x1, y1, x2, y2 specifies box to search in,
x, y returns coordinates if found.
Now I'm going to take you through an example that will withdraw the Leather Boots from your bank, and equip them. A lot of it will be similar to the bitmaps example, but there will be a few new functions you'll learn:
SCAR Code:
program DTMsExample;
program DTMsExample;
{.include SRL/SRL.scar}//Remember to include this in ALL of your scripts if you want to use functions from SRL.
function EquipBoots: Boolean;
var
Boots, x, y : Integer;//Again, declared locally. Remember why?
begin
Boots := DTMFromString('78DA634C6362604865644006F6DA2A0CFC401' +
'A24FA1F0818F3806AF250D540646124904E06AA2925A02604A8A6' +
'80809A44A09A684C35FC486A00608A08C5');
if FindDTM(Boots, x, y, MSX1, MSY1, MSX2, MSY2) then//Remember MS = Main Screen.
begin
Writeln('Found Leather Boots!');
MMouse(x, y, 4, 4);
if IsUpText('eather') then
begin
Wait(80 + Random(100));//Without this wait, it most likely won't find the uptext.
Mouse(x, y, 0, 0, False);//Remeber that "False" means it will right click.
if ChooseOption('5') then//ChooseOption is a useful function that when you right click on something in RS, it will choose the specified string option if available.}
begin
CloseWindow;//This will close the bank screen window.
Wait(200 + Random(100));
if FindDTM(Boots, x, y, MIX1, MIY1, MIX2, MIY2) then//Notice that the same DTM can be used to find it in the inventory.
begin
Mouse(x, y, 4, 4, True);//This will click on the boots again, equipping them.
Writeln('We have clicked the Leather Boots, checking to see if they are equipped...');
Wait(1000 + Random(500));//It's always good to have random waits in random places in your script.
GameTab(tab_Equip);//Opens the equipment gametab to check if the boots got equipped.
Result := FindDTM(Boots, x, y, MIX1, MIY1, MIX2, MIY2);//See how the Result is a boolean? It will be true if it chooses the correct option.
if Result then//Checks if the Result is true.
Logout//If it finds the boots equipped, it will logout.
else
begin
Writeln('Couldn''t find boots DTM in equiptment interface, logging out.');
Logout;
end;//Notice that if no matter what goes wrong, IF something goes wrong, it will tell me what went wrong, and log out.
end else
begin
Writeln('Couldn''t find boots DTM in inventory, logging out.');
Logout;
end;
end else
begin
Writeln('Couldn''t choose the option to withdraw 5, logging out...');
Logout;
end;
end else
begin
Writeln('Couldn''t find the uptext, loggin out.');
Logout;
end;
end else
begin
Writeln('Couldn''t find the boots DTM, logging out.');
end;
FreeDTM(Boots);//Remember to ALWAYS free your DTMs!
end;
begin
ClearDebug;
SetupSRL;//Don't forget this line in ANY of your RS scripts!
ActivateClient;
Wait(1000 + Random(500));
if EquipBoots then
Writeln('Boots are equipped! Logging out.')
else
begin
Writeln('Couldn''t equip the boots, loggin out...');
Logout;
end;
end.
You may think that looks like a lot at once, but if you read it carefully, you should already know most of it. I was just showing you that you can use the same DTM more than once in the same procedure, and look for it in different spots on the screen. That procedure can be written EXACTLY the same, but with bitmaps. If you are up for the challenge, give it a try.
Now before you anxiously rush and run the script, make sure you fully understand the script. Also before you run it, you have to do the following:
- Make sure your character is logged in, has the bank screen open, and the Leather Boots visible in the bank.
- Drag the SCAR cross hairs and select the RS window.
If you fully understood and wrote the above script, when you hit run, it should withdraw 5 pairs of boots, exit the bank screen, equip one of those pairs of boots, logout, and the debug box should read:
SRL Compiled in 15 msec
Found Leather Boots!
We have clicked the Leather Boots, checking to see if they are equipped...
Boots are equipped! Logging out.
Successfully executed
I can't stress this enough, make sure you ALWAYS free your DTMs! Otherwise, it will slow your script/computer down tremendously!
|
|
Congratulations! You now know how to make and use DTMs. You also learned how to click items, and withdraw them from the bank. Now, before moving on, I suggest you try and write a script that withdraws... let's say a couple pieces of armor... and equip them. That may seem hard, but it can easily be done with the elements you have learned so far I know you can do it!
Object Finding:
Object finding is a must in almost every script, as it is most commonly used to find objects on the main screen such as trees or mining rocks. Without some form of decent object finding, you can't expect your script to work for more than 5 minutes. I'm going to be teaching you about two different methods of object finding:
- Using FindColor functions/procedures.
- Using FindObject functions/procedures.
Once you get into more advanced FindColor functions, they are faster and more accurate than FindObject functions, in my opinion.
FindColor:
Using FindColor is pretty straight forward - SCAR attempts to find a specified color. For this example example, we are going to find and click a normal tree, sound fun? We will be working with the following four functions. Here is the list, straight from the SRL Manual:
function FindColor(var x, y: Integer; color, xs, ys, xe, ye:Integer): Boolean;
Find color in box specified by
xs, ys, xe, ye starting from left to right. Returns True if color found, the coordinates of the color if found is put in
x,y.
function FindColorTolerance(var x, y: Integer; color, xs, ys, xe, ye: Integer; Tolerance: Integer): Boolean;
Works like the regular
FindColor function but with a tolerance parameter for finding any similar color.
Tolerance is used to find a color in range of the color you are looking for. The greater color range you want, the higher the tolerance parameter should be.
function FindColorSpiral(var x, y: Integer; color, xs, ys, xe, ye: Integer): Boolean;
Find color in box specified by
xs, ys, xe, ye but start from
x,y.
function FindColorSpiralTolerance(var x, y: Integer; color, xs, ys, xe, ye: Integer; Tolerance: Integer): Boolean;
Works like the regular
FindColorSpiral but with a tolerance parameter for finding any similar color.
Tolerance is used to find a color in range of the color you are looking for. The greater color range you want, the higher the tolerance parameter should be.
Again, each function has something that is a little different, and if you read them carefully, it should be self explanatory. We are going to be using FindColorSpiralTolerance because it includes all the elements from all four functions. Now, in the descriptions above, it tells you the difference between FindColor and FindColorSpiral, but I'm going to give you another definition.
- FindColorSpiral - In the definition above, it says... "but start from x, y". This means that SCAR will start searching for the color at the coordinates you specified for x and y. And the spiral means it will search in a spiral motion outward from x, y.
For example, if we wanted to search for a tree that is closest to our character, we would say something like this:
SCAR Code:
var
x, y : Integer;
begin
x := MSCX;
y := MSCY;
FindColorSpiral(x, y, Color, MSX1, MSY1, MSX2, MSY2);
//*Note that this:
FindColorSpiral(MSCX, MSCY, Color, MSX1, MSY1, MSX2, MSY2);
//would not work, because FindColorSpiral requires variables, and MSCX/Y are constants. Therefore, we need to declare them as variables (x := MSCX).
end;
There are two things you should know about the latter example:
- MSC stands for Main Screen Center. This means that SCAR will search outward from the middle of the RS main screen. In other words, it will search starting from where your character is, so it will find the tree closest to your character first.
- The parameter "Color" can be whatever color you picked using SCAR's color picker. If you don't know how to pick a color using SCAR, follow these steps:
- Open up SCAR, and make the window about half the size of your monitor, and drag it to one side of the screen.
- Do the same with your RS screen (or whichever screen you want to pick the color from), except move it to the opposite side of the screen that you moved SCAR too. You should have something that looks like this:
- Now, using the SCAR color picking icon:
Pick the color you want. Just click the icon, and then click on the color you want. After you click the color, is should pop up in your debug box:
Color Picked: 1787389 at (1254, 302)
- Now what you would do is copy and paste that color (1787389) into your FindColorProcedure, like so:
SCAR Code:
FindColorSpiral(x, y, 1787389, MSX1, MSY1, MSX2, MSY2);
Not so hard, is it?
Now that you know how to pick the color, and how to start searching from the middle of the main screen, we are going to make a function that returns true, IF it finds and clicks a normal tree. Like I said earlier, we are going to use FindColorSpiralTolerance:
SCAR Code:
program FindColorExample;
{.include SRL/SRL.scar}
function ClickTree: Boolean;
var
x, y : Integer;
begin
if not LoggedIn then Exit;//This is a simple failsafe that will prevent your script from running if your character is not logged in. It should be included in ALL your procedures/functions.
x := MSCX;
y := MSCY;
if FindColorSpiralTolerance(x, y, 4685428, MSX1, MSY1, MSX2, MSY2, 10) then//Notice how the result will return true if it finds the color.
//*Note that you should pick a color from the tree that ISN'T too close to the grass color.
begin
Writeln('Found tree!');
MMouse(x, y, 4, 4);
Wait(200 + Random(100));//Remember to wait before checking the uptext.
if IsUpText('ree') then//Remember to not include the capital letter of the tree name.
begin
Mouse(x, y, 0, 0, True);
Result := True;
end else
Writeln('Couldn''t find the uptext of the tree.');
end else
Writeln('Couldn''t find the color of the tree.');
end;
begin
ClearDebug;
SetupSRL;
ActivateClient;
Wait(1000 + Random(500));//Remember you should give it time to activate the RS client.
if ClickTree then
Writeln('Clicked tree!')
else
Writeln('Didn''t click tree. :(');
end.
I know I've said this 100 times throughout this tutorial, but before you eagerly press run, make sure you understand what is going on. You also have to make sure that:
- Your character is logged in, and has a normal tree within view.
- Have a hatchet in your inventory or wielded if you actually want to chop down the tree.
- You've dragged the crosshairs over the RS window.
If you wrote that script without problems, your debug box should read something like this:
SRL Compiled in 15 msec
Found tree!
Clicked tree!
Successfully executed
If you cannot get it to work, a common problem is that the color you have picked is simply not good, and you would have to repick the color. Congratulations, you have learned how to find objects in RS using FindColor functions. Before moving on, I would suggest you attempt to find some other objects, just to better understand the functions.
FindObject:
Using FindObject functions is a lot like FindColor functions, but you can be more specific on the properties of the object (i.e. uptext, color). However, the FindObject functions aren't part of SCAR, they are part of SRL, meaning the list is located in your core SRL folder. Open up Object.scar for a full list of FindObject functions (SCAR 3.21/Includes/SRL/SRL/core/Object.scar).
In this guide, I'm going to introduce you to two of the FindObject functions, simply because they are the most commonly used. Here are the two functions, straight from Object.scar:
SCAR Code:
{*******************************************************************************
function FindObj(var cx, cy: Integer; Text: string; Color, Tol: Integer): Boolean;
By: Starblaster100
Description: Finds Object
*******************************************************************************}
{*******************************************************************************
function FindObjCustom(var cx, cy: Integer; Text: TStringArray; Color: TIntegerArray; Tol: Integer): Boolean;
By: Starblaster100
Description: Finds Object with custom amount of colors and custom amount of Uptext
Example: FindObjCustom(x, y, ['att', 'ack'], [123456, 345678], 5);
*******************************************************************************}
If you can't see the difference, it is that FindObjectCustom can have more than one color, or more than one uptext, making it more accurate, while FindObj can only have one color, and one uptext choice. Given what I have used for previous examples, can you guess what I'm going to use for this one? But before we do that, I am going to explain the structure of FindObjCustom:
SCAR Code:
FindObjCustom(x, y, ['att', 'ack'], [123456, 345678], 5);
- Firstly, the x and y parameters will store the coordinates of where the object is found.
- The ['att', 'ack'] is the uptext of the object. Notice how there is more than one? That makes it more likely to find the object. The reason there are "[]" around it is because it is a TStringArray (more about adavnced arrays in the advanced section), but you don't have to worry about what that is right now, you just have to know to put square brackets around the uptexts.
- The [123456, 345678] part is the colors. Like uptext, you can have multiple colors, making it more accurate. And like the uptext there are square brackets because the colors are a TIntegerArray (again, more on that later). And again, you just have to know to put square brackets around the colors.
- The 5 should be pretty obvious, the tolerance of the colors.
The main thing I wanted to tell you about that example is the square brackets bit, because if you forget to include them, you will get an "Invalid number of parameters" error.
In this example, just to do something different we are going to find and click a copper rock.
SCAR Code:
program FindObjExample;
{.include SRL/SRL.scar}
function MineCopper: Boolean;
var
x, y : Integer;
begin
if not LoggedIn then Exit;
if FindObjCustom(x, y, ['ine', 'ocks'], [4879522, 4220300], 5) then//Notice how I used "[]".
begin
Writeln('Found copper rock!');
Mouse(x, y, 0, 0, True);//MMouse and uptext check isn't needed becaue it's already built into FindObjCustom, understand?
Result := True;//Returns true of the copper ore was clicked.
end else
Writeln('Couldn''t find the copper rock.');
end;
//Notice that we didn't use MSCX or MSCY. This is because FindObjCustom automatically starts searching from the center. :)
begin
ClearDebug;
SetupSRL;
ActivateClient;
if MineCopper then
Writeln('Mined copper ore!')
else
Writeln('Didn''t mine copper ore.');
end.
By now, I shouldn't have to tell you to make sure you understand everything before automatically hitting play, should I? If there is something you don't understand, look back on that part in the tutorial to try and understand it better. Before you press play, make sure you have:
- Logged in to your account.
- Have a copper rock in view.
- Have a pickaxe in equipped or in your inventory (optional).
- Drag the corsshairs over the RS window.
A successful run of that script will result with the following in your debug box:
SRL Compiled in 0 msec
Found copper rock!
Mined copper ore!
Successfully executed
Like I've said countless other times throughout this tutorial, try finding another object to get a better feel of the functions. Congratulations! You now know two different ways of finding and clicking objects.
Walking:
During this part of the tutorial we are going to learn how to walk on the minimap using various methods. Map walking can be incorporated into almost any script, whether it is a PowerChopper or a script that banks Willows in Draynor. The three types of walking methods you will be learning are starting from the most accurate first:
- DDTM
- Raidal Walking
- Symbol Finding
Each method works just fine, but some aren't as reliable. For example, DDTMs are more reliable than Raidal Walking and Symbol Finding, but Radial Walking is more reliable than Symbol Finding, understand? (if that makes any sense at all).
DDTMs:
DDTM stands for Dynamic Deformable Template Model, and it used almost exactly like normal DTMs. It is dynamic because the information (i.e. color, tolerance, size) can all be changed throughout your script to make it fit your needs.
Making Your DDTM:
For this example, we will be walking out of Varrock west bank, and we will be using the DDTM Editor by Nielsie95, which is in your Scripting Tools folder. First thing, open the DDTM Editor. Now, I'm not going to explain the different elements of the DDTM Editor just yet, because they should be self-explanatory as most of them are the same as in the DTM Editor. Once the DDTM Editor is open, I want you to do the following:
- Take a screenshot of your RS character standing anywhere in the Varrock west bank, make sure the road is visible.
- Open the DDTM editor and go to Image > Paste, and you should see your RS screen there.
- Scroll to where you can see the minimap.
- Pick your main point somewhere on the Varrock road (just like in making a normal DTM).
- Pick 3-4 subpoints around your main point, and you should end up with something looking like this:
- Now, remember in the DTM Editor where it had the coordinates of the color you picked + the color itself (in the top right corner)? Well, in the DDTM editor it is the exact same, EXCEPT, all the colors should be the same.
- One the right, there is a spot to set the "Area Size". Set it to 1. If it is 0, it has no area to search in. This part may be obvious, but the larger the area size, the better chance SCAR has of finding the DDTM, but it also increases the chance of lag, to be aware.
- Once you have done this, go to file > DDTM to Text. A window should come up, with a function in it that looks like this:
SCAR Code:
function SetDDTM: Integer;
var
dtmMainPoint: TDTMPointDef;
dtmSubPoints: Array [0..4] of TDTMPointDef;
TempTDTM: TDTM;
begin
dtmMainPoint.x := 926;
dtmMainPoint.y := 400;
dtmMainPoint.AreaSize := 1;
dtmMainPoint.AreaShape := 0;
dtmMainPoint.Color := 8357514;
dtmMainPoint.Tolerance := 0;
dtmSubPoints[0].x := 926;
dtmSubPoints[0].y := 400;
dtmSubPoints[0].AreaSize := 1;
dtmSubPoints[0].AreaShape := 0;
dtmSubPoints[0].Color := 8357514;
dtmSubPoints[0].Tolerance := 0;
dtmSubPoints[1].x := 932;
dtmSubPoints[1].y := 394;
dtmSubPoints[1].AreaSize := 1;
dtmSubPoints[1].AreaShape := 0;
dtmSubPoints[1].Color := 8357514;
dtmSubPoints[1].Tolerance := 0;
dtmSubPoints[2].x := 939;
dtmSubPoints[2].y := 399;
dtmSubPoints[2].AreaSize := 1;
dtmSubPoints[2].AreaShape := 0;
dtmSubPoints[2].Color := 8357514;
dtmSubPoints[2].Tolerance := 0;
dtmSubPoints[3].x := 916;
dtmSubPoints[3].y := 398;
dtmSubPoints[3].AreaSize := 1;
dtmSubPoints[3].AreaShape := 0;
dtmSubPoints[3].Color := 8357514;
dtmSubPoints[3].Tolerance := 0;
dtmSubPoints[4].x := 911;
dtmSubPoints[4].y := 407;
dtmSubPoints[4].AreaSize := 1;
dtmSubPoints[4].AreaShape := 0;
dtmSubPoints[4].Color := 8357514;
dtmSubPoints[4].Tolerance := 0;
TempTDTM.MainPoint := dtmMainPoint;
TempTDTM.SubPoints := dtmSubPoints;
Result := AddDTM(TempTDTM);
end;
There, you have successfully made your first DDTM. There are most likely some parts of the latter example that you don't understand, that's why I'm going to explain the different parts the best I can.
First off, this little part here:
SCAR Code:
dtmSubPoints[0].x := 926;
dtmSubPoints[0].y := 400;
Is the subpoint's x and y coordinates, pretty straight forward I'd say. You should also know that when the DDTM is found, it's coordinates are stored in a small area around the mainmpoint's x/y coordinates, and that is where SCAR will click.
Next, this part:
SCAR Code:
dtmSubPoints[0].AreaSize := 1;
dtmSubPoints[0].AreaShape := 0;
The AreaSize is also pretty straight forward, the larger the size, the larger area SCAR will search for the DDTM. The AreaShape is just the shape of the area to look in. The different options are available in the DDTM Editor. "1" is most commonly used as it is a rectangle.
Finally this small part:
SCAR Code:
dtmSubPoints[4].Color := 8357514;
dtmSubPoints[4].Tolerance := 0;
Is pretty straight forward, the color of the subpoint, and the tolerance of the color.
Using Your DDTM:
Now, in the above example, you may notice that all the colors are the same, and all the tolerances are 0. Since they are they same, the DDTM is just like a normal, static, DTM. So, in order to make a DDTM dynamic, we have to adjust the color and the color's tolerance. To do so, I want you to follow these steps:
- The first step in making your DDTM dynamic is to use what is called Autocoloring. This allows us to find the color we want each time the DDTM is called, thus making it dynamic. If you open Autocolor.scar in the core folder (SCAR 3.21/Includes/SRL/SRL/core/Autocolor.scar), you will see a while list of autocolor functions available for you to use.
If there is a color that you want, but it is not in Autocolor.scar, there is always the option to make your own, but that won't be introduced until the Advanced section of the tutorial.
What I want you to do is make a local variable in your SetDDTM function, and assign FindVarrockRoadColor to it like so:
SCAR Code:
function SetDDTM: Integer;
var
dtmMainPoint: TDTMPointDef;
dtmSubPoints: Array [0..4] of TDTMPointDef;
TempTDTM: TDTM;
RoadColor : Integer;//Like this.
begin
RoadColor := FindVarrockRoadColor;//Notice how we used FindVarrockRoadColor because that's exactly what we are trying to do, walk to the Varrock road.
//The rest of the DDTM code here.
- Next what you want to do is replace the color of the MainPoint, and all the SubPoints with RoadColor, like this:
SCAR Code:
dtmMainPoint.Color := RoadColor;
There, you now have made your DDTM dynamic!
- Although your DDTM is now dynamic, that is not all you should do. Remember how we set the Tolerance to 0? Well, chances are that's not going to work so well. Therefore, we are also going to make the Tolerance dynamic.
In order to do this, we need to make a global variable called DDTMTolerance, like so:
SCAR Code:
program DDTMExample;
{.include SRL/SRL.scar}
var
DDTMTolerance : Integer;
//The rest of your script here.
The reason we make it global, instead of local is because we are going to be using it in our SetDDTM function, and assigning it to an integer in our walking function.
- Once you have made your variable, I want you to replace the tolerance in your MainPoint and all your SubPoints with DDTMTolerance, just like this:
SCAR Code:
dtmMainPoint.Tolerance := DDTMTolerance;
There, you have now made both your DDTM's color and tolerance dynamic, and you should have a script that looks something like this:
SCAR Code:
program DDTMExample;
{.include SRL/SRL.scar}
var
DDTMTolerance : Integer;
function SetDDTM: Integer;
var
dtmMainPoint: TDTMPointDef;
dtmSubPoints: Array [0..4] of TDTMPointDef;
TempTDTM: TDTM;
RoadColor : Integer;
begin
RoadColor := FindVarrockRoadColor;
dtmMainPoint.x := 926;
dtmMainPoint.y := 400;
dtmMainPoint.AreaSize := 1;
dtmMainPoint.AreaShape := 0;
dtmMainPoint.Color := RoadColor;
dtmMainPoint.Tolerance := DDTMTolerance;
dtmSubPoints[0].x := 926;
dtmSubPoints[0].y := 400;
dtmSubPoints[0].AreaSize := 1;
dtmSubPoints[0].AreaShape := 0;
dtmSubPoints[0].Color := RoadColor;
dtmSubPoints[0].Tolerance := DDTMTolerance;
dtmSubPoints[1].x := 932;
dtmSubPoints[1].y := 394;
dtmSubPoints[1].AreaSize := 1;
dtmSubPoints[1].AreaShape := 0;
dtmSubPoints[1].Color := RoadColor;
dtmSubPoints[1].Tolerance := DDTMTolerance;
dtmSubPoints[2].x := 939;
dtmSubPoints[2].y := 399;
dtmSubPoints[2].AreaSize := 1;
dtmSubPoints[2].AreaShape := 0;
dtmSubPoints[2].Color := RoadColor;
dtmSubPoints[2].Tolerance := DDTMTolerance;
dtmSubPoints[3].x := 916;
dtmSubPoints[3].y := 398;
dtmSubPoints[3].AreaSize := 1;
dtmSubPoints[3].AreaShape := 0;
dtmSubPoints[3].Color := RoadColor;
dtmSubPoints[3].Tolerance := DDTMTolerance;
dtmSubPoints[4].x := 911;
dtmSubPoints[4].y := 407;
dtmSubPoints[4].AreaSize := 1;
dtmSubPoints[4].AreaShape := 0;
dtmSubPoints[4].Color := RoadColor;
dtmSubPoints[4].Tolerance := DDTMTolerance;
TempTDTM.MainPoint := dtmMainPoint;
TempTDTM.SubPoints := dtmSubPoints;
Result := AddDTM(TempTDTM);
end;
- But now we need to make a function that will find and click your DDTM. Now, the following example has a few new strategies and functions that may be hard to follow, but I'm sure you're up for the challenge:
SCAR Code:
program DDTMExample;
{.include SRL/SRL.scar}
var
DDTMTolerance : Integer;
function SetDDTM: Integer;
var
dtmMainPoint: TDTMPointDef;
dtmSubPoints: Array [0..4] of TDTMPointDef;
TempTDTM: TDTM;
RoadColor : Integer;
begin
RoadColor := FindVarrockRoadColor;
dtmMainPoint.x := 926;
dtmMainPoint.y := 400;
dtmMainPoint.AreaSize := 1;
dtmMainPoint.AreaShape := 0;
dtmMainPoint.Color := RoadColor;
dtmMainPoint.Tolerance := DDTMTolerance;
dtmSubPoints[0].x := 926;
dtmSubPoints[0].y := 400;
dtmSubPoints[0].AreaSize := 1;
dtmSubPoints[0].AreaShape := 0;
dtmSubPoints[0].Color := RoadColor;
dtmSubPoints[0].Tolerance := DDTMTolerance;
dtmSubPoints[1].x := 932;
dtmSubPoints[1].y := 394;
dtmSubPoints[1].AreaSize := 1;
dtmSubPoints[1].AreaShape := 0;
dtmSubPoints[1].Color := RoadColor;
dtmSubPoints[1].Tolerance := DDTMTolerance;
dtmSubPoints[2].x := 939;
dtmSubPoints[2].y := 399;
dtmSubPoints[2].AreaSize := 1;
dtmSubPoints[2].AreaShape := 0;
dtmSubPoints[2].Color := RoadColor;
dtmSubPoints[2].Tolerance := DDTMTolerance;
dtmSubPoints[3].x := 916;
dtmSubPoints[3].y := 398;
dtmSubPoints[3].AreaSize := 1;
dtmSubPoints[3].AreaShape := 0;
dtmSubPoints[3].Color := RoadColor;
dtmSubPoints[3].Tolerance := DDTMTolerance;
dtmSubPoints[4].x := 911;
dtmSubPoints[4].y := 407;
dtmSubPoints[4].AreaSize := 1;
dtmSubPoints[4].AreaShape := 0;
dtmSubPoints[4].Color := RoadColor;
dtmSubPoints[4].Tolerance := DDTMTolerance;
TempTDTM.MainPoint := dtmMainPoint;
TempTDTM.SubPoints := dtmSubPoints;
Result := AddDTM(TempTDTM);
end;
function WalkOutOfBank: Boolean;
var
TheDDTM, x, y : Integer;//The reason "TheDDTM" is declared as an integer is because the function SetDDTM returns an integer.
begin
if not LoggedIn then Exit;//Remember to put this at the beginning of all your functions/procedures.
SetRun(True);//This will turn your run, simple as that.
DDTMTolerance := 5;//Notice how we set the INITIAL DDTMTolerance to 5.
TheDDTM := SetDDTM;//Notice how we declare the variable "TheDDTM" as the SetDDTM function.
repeat//This is going to repeatly try and find the DDTM if it is not found the first time.
if not DTMRotated(TheDDTM, x, y, MMX1, MMY1, MMX2, MMY2) then//Notice how we use DTMRotated this time. This is because the MiniMap may not be on the same angle of which you made you DDTM. This allows it to find the DDTM, now matter which angle the MM is at.
begin//Notice in the above line (69) we used "if not...". Simply means if it doesn't find the DDTM it will do what's in this begin..end nest.
Writeln('Didn''t find DDTM, increasing tolerance...');
IncEx(DDTMTolerance, 5);//IncEx works like Inc, except it will increase by a set integer, rather than increase by only one. In this case, we increase the tolerance by 5 each time the DDTM is not found.
FreeDTM(TheDDTM);//ALWAYS remember to free the DDTM! We free it here because it will reload each time the loop repeats, so therefore, we need to free it each time the loop repeats.
TheDDTM := SetDDTM;//We set it here because it will reset everytime the loop repeats.
end else//This is to tell it what to do if it finds the DDTM.
begin
Writeln('Found Varrock road!');
Mouse(x, y, 4, 4, True);
Result := True;//Set the result to true because SCAR clicked the DDTM.
Break;//Make sure it breaks out of the loop if the DDTM is found, otherwise it will click the DDTM every time it is found until the tolerance is 50.
end;
until((DDTMTolerance >= 50) or not LoggedIn);//Notice how it will repeatedly try to find the DDTM until the tolerance is greater or equal to 50, or your account has logged out, or it the DDTM has been found.
DDTMTolerance := 5;//We do this to reset the DDTM's tolerance, incase we decide to use it again later in the script.
FreeDTM(TheDDTM);//This frees the DDTM if it is found. ALWAYS remember to free the DDTM!
end;
begin
ClearDebug;
SetupSRL;
ActivateClient;
if WalkOutOfBank then//Remember to include your function in you main loop. =P
Writeln('Walking out of the bank.')
else
Writeln('Couldn''t walk out of the bank.');
end.
Again, make sure you read all my comments, and understand everything in the script before you try testing. You should also know that in a particular walking procedure such as this, it would be a perfect time to call FindNormalRandoms.
However, remember how I said you will get an "Out of Range..." error if you didn't include a DeclarePlayers procedure. Well, that is exactly why I didn't include FindNormalRandoms, because there is no DeclarePlayers procedure, understand? Once you understand everything, and you think you've made the script properly, make sure you do the following before hitting run:
- Log in your player.
- Have your player stand in the Varrcok west bank. Be sure your DDTM is visible on the map.
- Click and drag the SCAR crosshairs over the RS window.
- If you ran the script successfully, your debug box should read something like this:
SRL Compiled in 16 msec
Found Varrock road!
Walking out of the bank.
Successfully executed
Congratulations! You have now learned how to make, load, and click your DDTMs! You've learned the most accurate way of walking in RuneScape using color methods.
Declaring Multiple DDTMs:
Since you know how to make and use a single DDTM, I thought I would teach you now to load multiple DDTMs in the same function, and have the option to load only one at a time. This section of the tutorial is not difficult at all, you should have no problems following along.
What we are going to do is use a case statement to load two DDTMs, and using a parameter to determine which of the two we want to find. The example I am going to use will load the DDTM associated with the parameter "WalkNumber", and will allow us to walk from the Varrock west bank towards Barbarian Village.
To make your second DDTM, do it just like we did in the "Making Your DDTM" part of the tutorial. Your DDTM should look something like this:
Notice how I'm standing in the area where we would walk to the first DDTM. Doing this will allow us to see the second DDTM after walking to the first. The following example has both the DDTMs in the same function, and are both used in the walking towards Barbarian Village:
SCAR Code:
program DDTMExample;
{.include SRL/SRL.scar}
var
DDTMTolerance : Integer;
function SetDDTM(WalkNumber: Integer): Integer;//Notice the parameter "WalkNumber".
var
dtmMainPoint: TDTMPointDef;
dtmSubPoints: Array of TDTMPointDef;//Notice how I took out the [0..4], this is so we can set the length of each DDTM differently.
TempTDTM: TDTM;
RoadColor : Integer;
begin
RoadColor := FindVarrockRoadColor;
case WalkNumber of//Notice the case statement dependant on what the parameter "WalkNumber" is assined to.
0: begin//Notice that if i = 0, it will load the first DDTM.
SetArrayLength(dtmSubPoints, 5);//Don't forget to set the array length, otherwise you will get an "Out of Range..." error!
dtmMainPoint.x := 926;
dtmMainPoint.y := 400;
dtmMainPoint.AreaSize := 1;
dtmMainPoint.AreaShape := 0;
dtmMainPoint.Color := RoadColor;
dtmMainPoint.Tolerance := DDTMTolerance;
dtmSubPoints[0].x := 926;
dtmSubPoints[0].y := 400;
dtmSubPoints[0].AreaSize := 1;
dtmSubPoints[0].AreaShape := 0;
dtmSubPoints[0].Color := RoadColor;
dtmSubPoints[0].Tolerance := DDTMTolerance;
dtmSubPoints[1].x := 932;
dtmSubPoints[1].y := 394;
dtmSubPoints[1].AreaSize := 1;
dtmSubPoints[1].AreaShape := 0;
dtmSubPoints[1].Color := RoadColor;
dtmSubPoints[1].Tolerance := DDTMTolerance;
dtmSubPoints[2].x := 939;
dtmSubPoints[2].y := 399;
dtmSubPoints[2].AreaSize := 1;
dtmSubPoints[2].AreaShape := 0;
dtmSubPoints[2].Color := RoadColor;
dtmSubPoints[2].Tolerance := DDTMTolerance;
dtmSubPoints[3].x := 916;
dtmSubPoints[3].y := 398;
dtmSubPoints[3].AreaSize := 1;
dtmSubPoints[3].AreaShape := 0;
dtmSubPoints[3].Color := RoadColor;
dtmSubPoints[3].Tolerance := DDTMTolerance;
dtmSubPoints[4].x := 911;
dtmSubPoints[4].y := 407;
dtmSubPoints[4].AreaSize := 1;
dtmSubPoints[4].AreaShape := 0;
dtmSubPoints[4].Color := RoadColor;
dtmSubPoints[4].Tolerance := DDTMTolerance;
end;
1: begin//Notice that if i = 1, it will load the second DDTM.
SetArrayLength(dtmSubPoints, 5);
dtmMainPoint.x := 913;
dtmMainPoint.y := 388;
dtmMainPoint.AreaSize := 1;//Remember to make the AreSize = 1.
dtmMainPoint.AreaShape := 0;
dtmMainPoint.Color := RoadColor;//Remember to replace the color with the autocoloring function.
dtmMainPoint.Tolerance := DDTMTolerance;//Remember to replace the tolerance with DDTMTolerance variable.
dtmSubPoints[0].x := 913;
dtmSubPoints[0].y := 388;
dtmSubPoints[0].AreaSize := 1;
dtmSubPoints[0].AreaShape := 0;
dtmSubPoints[0].Color := RoadColor;
dtmSubPoints[0].Tolerance := DDTMTolerance;
dtmSubPoints[1].x := 918;
dtmSubPoints[1].y := 379;
dtmSubPoints[1].AreaSize := 1;
dtmSubPoints[1].AreaShape := 0;
dtmSubPoints[1].Color := RoadColor;
dtmSubPoints[1].Tolerance := DDTMTolerance;
dtmSubPoints[2].x := 925;
dtmSubPoints[2].y := 378;
dtmSubPoints[2].AreaSize := 1;
dtmSubPoints[2].AreaShape := 0;
dtmSubPoints[2].Color := RoadColor;
dtmSubPoints[2].Tolerance := DDTMTolerance;
dtmSubPoints[3].x := 908;
dtmSubPoints[3].y := 392;
dtmSubPoints[3].AreaSize := 1;
dtmSubPoints[3].AreaShape := 0;
dtmSubPoints[3].Color := RoadColor;
dtmSubPoints[3].Tolerance := DDTMTolerance;
dtmSubPoints[4].x := 906;
dtmSubPoints[4].y := 399;
dtmSubPoints[4].AreaSize := 1;
dtmSubPoints[4].AreaShape := 0;
dtmSubPoints[4].Color := RoadColor;
dtmSubPoints[4].Tolerance := DDTMTolerance;
end;
end;
TempTDTM.MainPoint := dtmMainPoint;//Notice how these three lines are outside the case.
TempTDTM.SubPoints := dtmSubPoints;//This is because they are exactly the same in both DDTMs.
Result := AddDTM(TempTDTM);
end;
function WalkToBarbVillage(WalkNumber: Integer): Boolean;//We use the WalkNumber parameter again so we can call the procedure to walk to whichever DDTM we wish without having to write the same code over and over again.
var
TheDDTM, x, y : Integer;
begin
if not LoggedIn then Exit;
SetRun(True);
DDTMTolerance := 5;
TheDDTM := SetDDTM(WalkNumber);//Notice how to function is dependant on what you assign WalkNumber to.
repeat
if not DTMRotated(TheDDTM, x, y, MMX1, MMCY, MMCX, MMY2) then//Notice how I have MMCY and MMCX - I will explain that below.
begin
Writeln('Didn''t find DDTM number ' + IntToStr(WalkNumber) + ', increasing tolerance...');//Notice how I added a small part that tells us which DDTM it found. This way, if there is an error, we can tell which DDTM is having the problems.
IncEx(DDTMTolerance, 5);
FreeDTM(TheDDTM);
TheDDTM := SetDDTM(WalkNumber);
end else
begin
Writeln('Found DDTM number ' + IntToStr(WalkNumber) + '!');
Mouse(x, y, 4, 4, True);
Result := True;
FFlag(3);//This is new. This will wait until your player is within 3 tiles on the MM. There is a whole list of Flag functions in Flag.scar.
Break;
end;
until((DDTMTolerance >= 50) or not LoggedIn);
DDTMTolerance := 5;
FreeDTM(TheDDTM);
end;
begin
ClearDebug;
SetupSRL;
ActivateClient;
if WalkToBarbVillage(0) then//Noticed how we called upon the first DDTM.
begin
Writeln('Walking out of the bank, first DDTM.');
if WalkToBarbVillage(1) then//Notice how it will only try to find the second DDTM, IF it finds the first. This is an excellent way of looking less "Bot-like".
Writeln('Walking to second DDTM.')
else
Writeln('Couldn''t walk to second DDTM');
end else
Writeln('Couldn''t walk out of the bank.');
end.
At this time I would normally say, "Make sure you understand everything in that script before hitting run", but this time, I have to explain what MMCX/MMCY are, and why I used them. So, breaking them down:
- MMCX stands for MiniMap Center. The "X" refers to whether it is the x/y corrdinate.
- MMCY stands for MiniMap Center Y. "Y" is just like "X", it refers to the y coordinate.
Now, that's all good and great, but why did I use them? Well, I used them to make the area to look for the DDTM smaller, which will make it more accurate and faster.
But, why did I have it in the order I did (MMX1, MMCY, MMCX, MMY2)? Well, think of it like a box - MMX1 = X1, MMCY = Y1, MMCX = X2, and MMY2 = Y2. I have made this diagram to help you understand:
The first diagram represents the box that SCAR will look in for the DDTM if you use the parameters (MMX1, MMY1, MMX2, MMY2). I also marked the center, so you understand what I mean by MMCX/MMCY.
The second diagram represents the box SCAR will look for the DDTM for the parameters I used to the last example, understand? I hope so, that may have been a little jumbled.
Not only does using those parameters make you script faster, but it also makes it a lot less likely that SCAR will find the DDTM on another part of the map, that isn't where you want to walk. For example, with the second DDTM in the last example, Juliette's house a little north-west of our DDTM The color of the house floor is very close to that of the Varrock road color. So, to avoid clicking inside the house by accident, all you have to do is narrow down the box that SCAR looks in.
If you have successfully made, and understand the above example, your character should have turned run on, and then walked to an area just south of Juliette's house. Before hitting run make sure you drag the cosshairs over the RS screen. If you did it correctly, your debug box should read something like this:
SRL Compiled in 16 msec
Found DDTM number 0!
Walking out of the bank, first DDTM.
Found DDTM number 1!
Walking to second DDTM.
Successfully executed
Congratulations, after much explanation, you know everything you need to know about DDTMs! If you don't understand a part of the tutorial, try rereading that part, or you can take a look at this nice DDTM tutorial -> Correctly Creating/Using a DDTM
Radial Walking:
Radial Walking should always be used as a failsafe for DDTMs. It is slightly less accurate than a DDTM, and they take up only one line as appose to 50, so it can be used very easily as a failsafe. Basically how radial walking works, it SCAR will search for a color based on what you use for your parameters. Here is the radial walking function:
SCAR Code:
function RadialWalk(TheColor: Integer; StartRadial, EndRadial: Integer; Radius: Integer; Xmod, Ymod: Integer): Boolean;
Now you probably have no idea what what most of those parameters are, so I'll explain them to the best of my ability.
- TheColor - Pretty straight forward - the color you are looking for on the MM.
- StartRadial/EndRadial - This is basically the start and end angles to search for the color. In RS, the angles are as follows (credit 100% to Zeph for the diagram):
- Radius - This is how far out from the center of the MiniMap, in pixels, you want SCAR to search. Here's a quote from Zeph, with a nice little analogy:
Originally Posted by
ZephyrsFury
Imagine a piece of pizza, the tip of the piece is the MiniMap center and the crust is the radius.
- XMod/YMod - These parameters are used if SCAR clicks the MM, and the flag doesn't appear. For example, maybe it clicks somewhere that you can't walk, and the flag doesn't appear on the MiniMap. If this happens, the values you use for XMod/YMod represent the amount of pixels away from the first point SCAR will try to click next.
The values for XMod/YMod can be both positive and negative. A positive XMod will click to the right, negative to the left. A positive YMod will click down, a negative up. Yes, you read that right, because how RS is set up, for the Y values, positive is down and negative is up. If you don't understand, I'm sure you will after you see an example.
For this example, we will be walking from the Draynor bank, to the Willow trees. Exciting, no? Now, to obtain the best StartRadial, EndRadial, and Radius values, we will use a nifty little tool called Radial Walking Aid (RRA), developed by Yakman.
This tool can be found in your "Scripting Tools" folder in SRL. Just open the script, and press run. You will be greeted with a window called "Radial Walking Aid - Yakman" When you've managed to do this, follow these steps:
- Log your character into RS, and make sure they are standing in Draynor Bank.
- Open RRA and click Find RS, followed by Capture From Client. You should now see your RS MiniMap in the RRA window.
- Now, fill in the Start Radial, End Radial, and Radius according to where you want to search. I used 190, 230, and 60.
- Once you have chosen your values, hit Show Path. You should see the RRA draw some red lines. This will be your searching area. It should look something like this:
Adjust the parameters until you have found the the searching area you like the best. I should also mention what we will be doing about the parameter "TheColor". Well, like we used in DDTMs, we will be using AutoColoring functions. Because the RS water color is easily visible from any point in the Draynor bank. Therefore, we will be using FindWaterColor.
- Now, at this point, you can hit Print Procedure if you would like. However, neither of the two functions that get printed are ones we will be using. Otherwise, just fill in the parameters that you've chosen.
- As for XMod/YMod, it is best to use 2 and 1 because you don't want it to click too far away from your point. Also, we use positive numbers because we don't want to click the water, am I right?
So, with all the parameters filled out, you should have a function that looks something like this:
SCAR Code:
RadialWalk(FindWaterColor, 190, 230, 60, 2, 1)
Well, now that we have the function, it's not doing anything. We have to make a function that will walk from the bank to the Willows. A function such as this should do the job:
SCAR Code:
program RadialWalkExample;
{.include SRL/SRL.scar}
function WalkToWillows: Boolean;
begin
if not LoggedIn then Exit;//Get into the habbit of writing this in all your procedures early.
SetRun(True);
Result := RadialWalk(FindWaterColor, 190, 230, 60, 2, 1);//Notice how the Result is true if it walks to the Willows.
if Result then
begin
Writeln('We are walking to the Willow trees, Radial walk method.');
Wait(80 + Random(100));
FFlag(3);
end else
Writeln('Radial walking method failed.');
end;
//You may notice that there is no point in the function that clicks the mouse. This is because it is already incorperated into RadialWalk. So, there is no need to click twice.
begin
ClearDebug;
SetupSRL;
ActivateClient;
if not WalkToWillows then//Decided to do something differet this time.
TerminateScript;//This means that if it doesn't walk to the Willows, the script will execute.
end.
Once again, make sure you understand everything before you test it out. Before testing, make sure you have done the following:
- Have your character logged in, sitting in the Draynor bank.
- Dragged the crosshairs over the RS window.
If you wrote this script correctly, it should turn the run on if it isn't already, and walk to the Willow trees, and you debug box should say something like this:
SRL Compiled in 0 msec
We are walking to the Willow trees, Radial walk method.
Successfully executed
Congratulations, you now know two different methods of walking in RuneScape using SCAR. Remember, if there is some part of this guide that you don't understand, be sure to look back at that specific part and reread for a better understanding.
Symbol Finding:
Symbol finding is probably the easiest way of walking in RuneScape, but it's also the most unreliable of the three walking methods I'm showing you. This is because there are several things that can happen that will make SCAR not find the symbol:
- The symbol is not in view of the MiniMap.
- The symbol is only in partial view of the MiniMap.
- There is a person (white dot) or NPC (yellow dot) on top of the symbol.
- The symbol moves ALOT, so it may not be where you need it to be.
As you can see, there are many reasons why you shouldn't use Symbol Finding as your first walking procedure. It is best to use as a fail safe for Radial Walking.
However, some of these problems can sometimes be avoided with a small little command called SymbolAccuracy. For example:
This will make FindSymbol return true even if only 50% of the symbol is found (1.0 = 100%, 0.4 = 40%, etc.). If you don't understand, you will in the next example.
What you should do is use a DDTM for your first walking procedure, then Radial Walking for a failsafe, and then Symbol Finding as a third failsafe. If you use this method for all your walking procedures, chances are that it will never fail, and your script has the chance of running for hours without failing.
Symbol Finding procedures are extremely easy to use, especially after you know how to do DDTMs and Radial Walking. Here is the function, straight out of Symbol.scar:
SCAR Code:
function FindSymbol(var rx, ry: Integer; Name: string): Boolean;
There are also several other Symbol Finding function in Symbol.scar for you to choose from, including some with customizable area to look in (remember the DDTM example).
You should already know what the x, y do. They store the coordinates of the symbol when it's found. The Name is the symbol name, and can be any of the following (also from Symbol.scar):
SCAR Code:
{*******************************************************************************
Valid Arguments are:
- agility - furnace - rare trees, tree
- altar - gem stall - rest, resting spot
- anvil - guide - sandpit
- apothecary - hair dresser - saw mill
- archery shop - herbalist - scimitar shop
- arrow - house - shield
- axe shop - hunter store - shop, store
- bar - hunter training - short cut
- bank - jewelery - silk stall
- candle shop - kebab shop - silver stall
- churn - mace shop - slayer master
- clothes shop - magic shop - spice stall
- cookery shop - makeover mage - spinning wheel, spin
- cookery, cook - mill - staff shop
- crafing shop - minigame - summoning store
- dungeon - mining shop - sword shop
- farming shop - pet shop - tanner
- farming spot - platebody shop - training dummy
- fishing shop, fish store - plateskirt shop - underground
- fishing spot, fish - portal (to player owned houses) - water source, water
- food shop - pottery, pot - weave
- fur trader - quest - windmill
*******************************************************************************}
For my symbol finding example, we are going to find the fishing symbol south of the Draynor bank, and click it. The following example should be pretty easy for you to understand, as it is very simple:
SCAR Code:
program FindSymbolExample;
{.include SRL/SRL.scar}
function WalkToWillows: Boolean;
var
x, y : Integer;
begin
if not LoggedIn then Exit;
SetRun(True);
SymbolAccuracy := 0.5;//Notice how I set the accuracy to 50%, so it will still work if it only finds half of the symbol.
Result := FindSymbol(x, y, 'fish');
if Result then
begin
Writeln('Found fishing symbol!');
Mouse(x, y, 4, 4, True);//Click the fishing symbol.
end else
begin
Writeln('Couldn''t find the fishing symbol');
Logout;//Logout and execute script if it can't find the symbol.
TerminateScript;
end;
SymbolAccuracy := 0.8;//Make sure you set the SymbolAccuracy back to the defaut accuracy, 0.8 or 80%.
end;
begin
ClearDebug;
SetupSRL;
ActivateClient;
if WalkToWillows then
Writeln('Walking to Willows!')
else
Writeln('Not walking to Willows.');
end.
Now, I'm sure you wont have any trouble understanding that example, but before you hit run, make sure the fishing symbol is in view in the MiniMap and don't forget to drag your crosshairs over the RS window. If you made a successful script, your debug box should read something like this:
SRL Compiled in 16 msec
Found fishing symbol!
Walking to Willows!
Successfully executed
There, you now know how to use the three best methods of walking. For a more in depth walking tutorial you can visit this thread -> Map Walking - The Basics to the Advanced
Using All Three Methods:
This section is going to be very small as I am just going to show you an example of a walking function that includes all three methods of walking, each as a failsafe of the other. Note that the following script will NOT work if you press run as the DDTM isn't loaded in the script.
I am showing you this because I want you to have an idea of what the function looks like with all three methods incorporated into it. This example is from my Draynor Chop N' Bank script:
SCAR Code:
procedure W_WalkToWillows;
var
x, y : Integer;
begin
if not LoggedIn then Exit;
SetRun(True);
MakeCompass('n');//This just makes the RS compass point to which ever direction you wish ('n', 'e', 's', 'w').
if DTMRotated(W_WalkDDTMs(1), x, y, MMX1, MMY1, MMX2, MMY2) then
begin
S_FindRandoms;
Wait(80 + Random(100));
Writeln('Walking to Willows, DDTM method.');
Mouse(x + 35, y + 5, 4, 4, True);
FFlag(0);
end else//Notice the end else, so it will do RadialWalk if it doesn't find the DDTM.
if RadialWalk(FindWaterColor, 190, 230, 60, 2, 1) then
begin
S_FindRandoms;
Writeln('DDTM method failed, using radial walking.');
Wait(80 + Random(100));
Writeln('Arrived at Willows.');
FFlag(0);
end else//Again, notice that it will do FindSymbol if RadialWalk fails.
if FindSymbol(x, y, 'fish') then
begin
S_FindRandoms;
Writeln('Radial walking failed, using sumbol finding.');
Wait(80 + Random(100));
Writeln('Arrived at Willows.');
Mouse(x, y + 10 + Random(15), 4, 4, True);
FFlag(0);
end else
begin
Writeln('Couldn''t walk to Willows, logging out.');
S_EndScript;//This is just a procedure I have elseware in my script
end;
FreeDTM(W_WalkDDTMs(1));
end;
Now, after seeing that procedure, do you understand what I mean by using Radial Walking and Symbol Finding as a failsafe? Good.
Multiplayer:
Multiplayer is a very useful aspect that should be incorporated into every script. Multiplayer allows you to switch between RS characters when the previous one is finished, or is taking a break. In this section of the tutorial, you are going to learn how to add multiplayer to your script.
The first thing you should know about adding multiplayer is the very useful command, NextPlayer. This command is used to switch between players, and can be used in two different ways:
- NextPlayer(True) - This will switch players, but leave the current player true, so it can come back to it later.
- NextPlayer(False) - This will switch players and set the current player to not active. You would want to do this if the current player cut enough logs for example, or got lost.
You should always only have to use the NextPlayer command in your main loop. Look at this main loop for example:
SCAR Code:
begin
repeat
repeat
ChopLogs;
BankLogs;
until((NumOfLogs >= 1000) or not LoggedIn);
NextPlayer(True);
until(AllPlayersInactive);//This will end the script when all the players are inactive.
end.
That example will chop and bank logs using the current player until it has cut more than 1000 logs, or if it is not logged in.
However, sometimes the script will mess up during a procedure such as walking, or banking the logs, and you don't want the script to continue thinking that player is active when it got lost somewhere. So, what you have to do is change all your procedures, and use something like this:
SCAR Code:
function BankLogs: Boolean;
begin
if BankLogs then
//Do this...
else//Notice how if it can't bank the logs, it will set the player to inactive, and logout.
begin
Players[CurrentPlayer].Active := False;//Set the current player to inactive because it got lost in the script.
Logout;//Logout the player!
Exit;//Be sure to exit the procedure! Otherwise it will continue and not do anything, wasting time.
end;
end;
Do you understand what is needed for multiplayer when a procedure messes up? Good. Now, if something such as this should occur, the script will try to move on with other procedures. This is where adding "if not LoggedIn then Exit" to the beginning to every procedure/function becomes really useful.
Since the character logged out because it messed up somehwere, it will just exit out of every other procedure/function in the main loop until it gets to the spot where it switches players.
Now, when it switches players, it will switch just fine, but it will keep the current player active because you used NextPlayer(True). To avoid this small bug, you should change that line to:
SCAR Code:
NexPlayer(Players[CurrentPlayer].Active);
Using that small change, it will switch to the next player in DeclarePlayers that is set to active. When it is all said and done, you should have the ending of each procedure/function looking something like this:
SCAR Code:
function DoSomething: Boolean;
begin
if Condition then
//Do this...
else
begin
Players[CurrentPlayer].Active := False;
Logout;
Exit;
end;
end;
And, your main loop should look something like this:
SCAR Code:
begin
repeat
repeat
ChopLogs;
BankLogs;
until((NumOfLogs >= 1000) or not LoggedIn);
NextPlayer(Players[CurrentPlayer].Active);
until(AllPlayersInactive);
end.
Hopefully that wasn't too difficult to understand. For are more in depth tutorial on multiplayer, check out this nice guide -> Adding Multiplayer
Congratulations! You can now call yourself an intermediate scripter! Well done! Again, look over a section of the tutorial that you don't understand before you move on to the advanced section. Before moving on, you should know that some of the content in the Advanced section is much more complicated than what you have done so far, but I know you're up for the challenge.