Thread: All-In-One RS3 and SRL6 Scripting Tutorial!

1. All-In-One RS3 and SRL6 Scripting Tutorial!

Version: 1.10
Updated: Feb 2015 (exitSquelOfFortune() -> exitTreasure())

Introduction

The SRL forums have always been about teaching and learning, and many tutorials from past and present members exist on these forums. The problem is, the majority of them are outdated due to RuneScape updates, and the knowledge contained within them is not directly compatible with the current SRL6 include. I believe this is holding the community back, and stopping the next generation of scripters coming through. The main purposes of this tutorial are to (1) introduce basic programming concepts, (2) explain the SRL6 include, and (3) demonstrate how to write a script for RuneScape using the SRL6 include. I hope this will help many future, past and present SRL members get started and enjoy scripting for RS3!

This tutorial covers many things from basic to more advanced techniques, and I’ve only included what I feel is relevant to give you a good understanding of pascal programming, and how to use the SRL6 include to write scripts for RuneScape.

If you know absolutely nothing about programming, I recommend reading Coh3n’s beginner tutorial for an excellent introduction to the scripting world (I actually learnt to script from his tutorial). Even though his tutorial isn't currently updated for SRL6, the fundamental programming concepts remain unchanged. Although I do cover these principles in the first three sections below, I cover them somewhat briefly. If you struggle with the ideas I have written, I recommend you read Cohen’s tutorial first.

Please note: This tutorial is a work in progress and I will keep refining it and adding new thing over the coming months. And remember: other SRL members are always willing to help you with your code - all you have to do is ask.

Contents

• Section 1: The skeleton of a Simba script – procedures, functions and the main loop.
• Section 2: A brief overview of variables, arrays, and constants.
• Section 3: A brief overview of conditional statements, operators, and loops.
• Section 4: How to turn a script idea into a working script.
• Section 5: Understanding the SRL6 include.
• Section 6: A step-by-step example of writing a script, including the following sub-tutorials:
• Creating SPS maps and using them to walk anywhere
• Creating a DTM and then finding it
• Using Auto Color Aid (ACA) to pick colors
• Understanding TPoints, TPAs and ATPAs – setting your color script apart from the rest
• Appendix A: A full list of SRL6 Procedures and Functions (Attached here as a PDF)

Note: Everything in this tutorial is just what I have learnt by being part of the SRL community. I don't study any type of computer science, so if you come across anything which is wrong please tell me and I will fix it.

Section 1: The skeleton of a Simba script – procedures, functions and the main loop.

A Simba script, when broken down into its simplest form, is made up of individual procedures and functions, with a main loop at the bottom. Procedures and functions are blocks of code, which always start with a begin and finish with an end. The code in between the begin and end varies depending on what you want the procedure (or function) to achieve. The main loop is the last begin and end in the script, which is situated at the bottom. You can see in the following example we have a simple program which has 2 procedures and a main loop at the bottom:

(Note: In this section, the code within each procedure and function is not filled in, just to keep things simple).

Simba Code:
program exampleScript;procedure chopTree();begin // Here would be some code to chop the treeend;procedure dropLogs();begin // Here would be some code to drop the logsend;begin  // main loop  chopTree();  dropLogs();end.

The main loop at the bottom of the script can be thought of as the ‘brain’ of the script – it controls what procedures and functions run in what order. In the main loop, you list the names of the procedures in the order you want them to run. You can see in the above example the chopTree procedure runs first, followed by the dropLogs procedure (I would write something like this if I was making a power chopper). I should also point out that the main loop’s end is always distinguishable as it ends with a period [.] not a semicolon [;] like all other ends in your script. This is how Simba knows it’s your main loop.

Let me give you another example, this also has two procedures, writeHello and writeGoodbye. Both procedures use a writeLn statement, which just prints text to the debug box. Copy and paste this into Simba and press run:

Simba Code:
program example;procedure writeHello();begin  writeLn('Hello, welcome to the tutorial!');end;procedure writeGoodbye();begin  writeLn('Goodbye, see you soon!');end;begin  writeHello();  writeGoodbye();end.

And this should be the output in the debug box:

Code:
Compiled successfully in 141 ms.
Hello, welcome to the tutorial!
Goodbye, see you soon!
Successfully executed.
In the main loop, try putting writeHello below writeGoodbye and press run. You will notice it ran the procedures in the new order:

Code:
Compiled successfully in 141 ms.
Goodbye, see you soon!
Hello, welcome to the tutorial!
Successfully executed.
Now try 'commenting out' one procedure in the main loop with two forward slashes and press run:

Simba Code:
program example;procedure writeHello();begin  writeLn('Hello, welcome to the tutorial!');end;procedure writeGoodbye();begin  writeLn('Goodbye, see you soon!');end;begin  //writeGoodbye();  writeHello();end.

Code:
Compiled successfully in 140 ms.
Hello, welcome to the tutorial!
Successfully executed.
Notice how the procedure we commented out didn't run? Comments are invisible to the interpreter, and are useful for writing notes in your code, such as instructions for other users, and for debugging (if you want to test 1 procedure at a time, for example). Even though we still had the full writeGoodbye procedure in our script, it didn't run because Simba only executes what you tell it to run in the main loop. Quite straightforward isn't it?

The difference between procedures and functions

I will explain the difference between a procedure and a function shortly, but first I want to briefly introduce you to variables. I cover variables in more detail in the following section, but I introduce them here as it will make understanding the difference between procedures and functions much easier. In programming, a variable is something that stores or holds information. There are different types of variables used in Simba, and they differ depending on the type of information they hold. For example, here are the 3 most commonly used variable types:

integer
An integer variable stores whole numbers, positive or negative.
Examples are: 1, 100, -23, 6549.

string
A string variable stores letters and words. Strings are normally presented between single quotes and are colored blue in Simba.
Examples are: ‘Hello’, ‘This is a tutorial’, 'cfr456674fsd'.

boolean
A boolean variable stores a result which can only be either true or false.
Examples: true, false.

Now that you understand a variable holds information, and that different types of variables hold different types of information, let's move onto functions. The difference between procedures and functions is that a procedure just runs the code between its begin and end, but a function runs its code AND returns a result. The result can be any variable such as an integer (e.g. a number), a string (e.g. a word), or even a boolean (e.g. either true or false). You can tell which type of result a function returns by looking at the word after the function name. Here is an example of a procedure (which doesn't return a result) and some functions which I just made up to demonstrate:

This is a procedure which is called “walkToBank”. It doesn't return a result.

Simba Code:
procedure walkToBank();begin    // Here would be some code which makes the player walk to the bank.end;

This is a function which is called “getAttackLevel”. You can see after the function name, there is a second parameter - the type of result it returns. This function returns an integer as the result (because attack level would be a number).

Simba Code:
function getAttackLevel(): integer;begin    // Here would be some code which gets the attack level AND makes that number the resultend;

This is a function which is called “getPlayerName” You can see this function returns a string as the result (because the player’s name would be a word).

Simba Code:
function getPlayerName(): string;begin    // Here would be some code which reads the player’s name AND makes that word the resultend;

Lastly, this is a function which is called “isBankOpen”. You can see this function returns a boolean as the result (because the bank can either be open (true) or not open (false)).

Simba Code:
function isBankOpen(): boolean;begin    // Here would be some code determines if the bank is open. If it is, the functions results true, if not, it results false.end;

So just to recap, procedures just run the code they contain, but functions run the code AND return a result, which can be any type of variable. The result of functions are often used inside other prodecures or functions. Sound confusing? Look at this example:

Simba Code:
program exampleScript;function myName(): string;begin  result := 'The Mayor';end;begin    writeLn('My name is: ' + myName())end.

You can see the myName function results in a string, and I make the result 'The Mayor'. In the main loop I then use the result of the myName function inside the writeLn statement. If I run this I get:

Code:
My name is: The Mayor
Take my original example of the power chopper. I have added in a function which returns the players wood cutting level as an integer. I then use the result of this function inside the chopTree procedure to determine which type of tree I should cut:

Simba Code:
program exampleScript;function woodCuttingLevel(): integer;begin  // code to get the player's wood cutting levelend;procedure chopTree();begin  if woodCuttingLevel() > 30 then    chopWillows()  else    chopOaks();end;procedure dropLogs();begin // code to drop logsend;begin  chopTree();  dropLogs();end.

You can see if my woodcutting level is greater than 30 then I will chop willows, else I will chop oaks. Don't worry if you don't understand the if ... then ... else part - it's just a conditional statement which I cover in section 3.

Section 1 recap:
• All Simba scripts are made up of various procedures and functions.
• The main loop controls what procedures and functions run in what order.
• Procedures just run their code, but functions also return a result, which is normally used inside other procedures or functions.

Now we’ve got that covered, let’s take a closer look at the other variable types.

Section 2: A brief overview of variables, arrays, and constants.

Variables are used in just about every procedure and function within a script. The information that your script sees, reads, collects, or calculates is all stored in variables. As I mentioned in the previous section, there are different types, and they vary depending on the type of information they store. I've already outlined three types (integers, strings, and booleans) and I will cover the rest below. However, before I do that, you need to know that all variables can either be local variables or global variables.

The difference between local and global variables

Local variables are declared inside a procedure or function, before the begin. These can only be used by the procedure/function which they are declared in. Here is an example of a local variable which I called randomNumber:

Simba Code:
program example;procedure random();var  randomNumber: integer;begin  randomNumber := random(10);  writeLn(intToStr(randomNumber));end;procedure writeNumber();begin          // I would get an error here because this procedure doesn't know what "randomNumber" is  writeLn(intToStr(randomNumber));end;begin  random();  writeNumber();end.

You can see I declared the randomNumber variable before the begin, and then I use that variable within the procedure. Using the 'assignment operator' ( := ) I assign the randomNumber variable a random number out of 10 (between 0 and 9). Now the randomNumber variable is storing information, specifically an integer, which has the value of something between 0 and 9 (inclusive). As the writeLn statement can only print strings, and the randomNumber variable is an integer, we need to convert it - the intToStr simply converts the integer to a string. Because I declared it locally, the other procedure can't use it. Local variables also get 'reset' each time you run a procedure or function (you'll learn this as you go).

Global variables are declared outside a procedure or function (normally at the top of the script, and start with a capital letter). These can be used by any procedure or function in the entire script. Anytime you want to use the same variable in multiple procedures or functions, it must be declared globally. In the following example I have declared the ProfitMade variable globally:

Simba Code:
program exampleScript;var  ProfitMade: integer;procedure calculateProfit();begin  ProfitMade := 100 * 10;end;procedure progressReport();begin  writeLn('The Mayor''s Profit Maker Script');  writeLn('Our profit gained is: ' + intToStr(ProfitMade));end;begin  calculateProfit();  progressReport();end.

You can see I used the profitMade variable in 2 procedures. If I declared it within the calculateProfit procedure only, the progressReport procedure wouldn't have been able to use it, resulting in an error. Now that you understand the difference between local and global variables, I'll quickly go over the other variable types which you will come across fairly regularly.

Variable Types

Extended

An extended variable is similar to an integer because it is a number, but the difference is it can have decimal places. These are regularly used in color settings (see the ACA tutorial in section 6).
Examples: 1.20, 4.5678, 0.002.

TPoint

A TPoint is a single point (i.e. a single pixel) on your screen. In the image on the left below is the backpack tab icon. In the subsequent pictures I zoom in a little bit more until you can see individual pixels. In the right hand picture, I have highlighted one pixel red - this is an example of a single TPoint.

A TPoint is made up of 2 integers - the x and y coordinates. If you are unfamiliar with coordinates, look at this example of the RuneScape screen. The x axis goes from left to right. The y axis goes from top to bottom. Both axes start in the top left corner:

Basically, every single individual pixel on the screen is a TPoint, which has its own x and y coordinates. TPoints are used very regularly - such as when you move your mouse to any coordinates on the screen.

TBox

A TBox is a box. A Tbox is made up of 2 TPoints (or 4 integers) on the top left (x1, y1) and bottom right (x2, y2) corners. TBoxes come in handy when dealing with things like bank slots, buttons, and backpack slots. You can look for certain colors within a box, or move the mouse to a random place inside the box, for example.

Arrays

Arrays are a little bit more advanced, and the beginner may have trouble understanding them at first. Nonetheless, I'll explain them as simply as I can as arrays are used quite often in RuneScape scripting. You can think of all of the above variables as 'single' but in many cases you deal with multiple variables of the same type at once. An array is a data structure which contains a group of variables of the same type (e.g., a group of integers, or a group of TPoints). Arrays are presented inside square brackets, with each index in the array (i.e. each variable) separated by a comma.

TIntergerArray

This is an array of integers. Here is an example of declaring and assigning a TIntegerArray to a variable:

Simba Code:
procedure exampleIntArray();var  myArray: TIntegerArray;begin  myArray := [0, 1, 2, 3, 37];end;

TStringArray

This is an array of strings. Here is an example of declaring and assigning a TStringArray to a variable:

Simba Code:
procedure exampleStrArray();var  myArray: TStringArray;begin  myArray := ['Hi', 'Hello', 'Tutorial Cup Pl0x'];end;

TExtendedArray

This is an array of extended type variables. Here is an example of declaring and assigning a TExtendedArray to a variable:

Simba Code:
procedure exampleExtArray();var  myArray: TExtendedArray;begin  myArray := [0.02, 1.45, 13.5432, 0.1];end;
Arrays of TPoints and TBoxes are declared in the same way as above, but are better demonstrated through a picture.

TBoxArray

Here is a TBoxArray that consists of 28 backpack slot boxes:

TPointArray

TPoint Arrays (commonly known as TPAs) are used very often in Simba. Remember the single TPoint I highlighted red on the backpack tab icon above? The following is an array of approx. 13 TPoints which match the gold color on the backpack buckle:

Array of Arrays

You think we could store a lot of information in an array? Well we also have Array of Arrays (sometimes referred to as 2-dimensional arrays). It is possible to have 2-dimensional arrays for all of the previous variables, but there is only 1 you really need to know in the world of scripting.

Array of TPointArray (or T2DTpointArray)

Array of TPointArrays, or more commonly referred to as ATPAs are a group of TPAs. Using ATPAs correctly can improve the reliability, accuracy and speed of your color finding by a tremendous amount. However, using them is a bit more advanced, but I have a sub-tutorial on using TPAs and ATPAs in section 6 below. I think the picture below demonstrates nicely what an ATPA is. There are also more visual examples in the sub-tutorial.

Constants

Constants are similar to variables in that they hold information, but the difference is they cannot change their value at anytime when the script is running. These are usually declared at the top of the script, and written in capital letters. Like variables, constants can also be declared as different types:

Simba Code:
program exampleScript;const  MY_NAME = 'The Mayor';  // note the string  HP_LEVEL = 99;          // note the integer  TREE_TO_CUT = 'Willow';  HUE_MOD = 0.65;         // note the extendedbegin  // Main loopend.

Notice how I didn't use the assignment operator ( := ) but just equals ( = ), as this is how you declare constants. Here is another example of when I use constants, notice the LOGS_TO_CHOP constant and the global variable LogsChopped are integers.

Simba Code:
program exampleScript;const  LOGS_TO_CHOP = 1000;var  LogsChopped: integer; procedure chopTree();begin // code to chop tree // each time we chop a log I will increase the LogsChopped variable by 1end;procedure dropLogs();begin // code to drop logsend;begin   repeat    chopTree();    dropLogs();  until LogsChopped = LOGS_TO_CHOP;end.

You see in the main loop, it repeats the chopTree and dropLogs procedures until the amount stored in the LogsChopped variable is equal to the LOGS_TO_CHOP constant. The LogsChopped variable increases each time we chop a log, but the LOGS_TO_CHOP constant remains the same. This is also an example of a loop, which I will cover in the next section.

Section 3: A brief overview of conditional statements, operators, and loops.

Now that you understand some of the basics, let’s look at how the code within procedures, functions and the main loop work. Before we move on to writing an actual script in the latter sections, you should have a basic understanding of conditional statements, logical operators and loops. If you want your script to be reliable and run for a long time, conditional statements and loops are an absolute must. By writing conditional statements, you are basically showing your script how to ‘think’ when it comes across a particular situation (e.g. if the bank isn't open, then open it!). By writing loops, you are telling your script to repeat a portion of code a certain number of times, or until a condition is met (e.g, keep chopping trees until the backpack is full!). Like begin and end, all of these statements are displayed as bold characters in Simba.

Conditional statements

Conditional statements run a piece of code depending on whether one or more conditions are met.

if … then … else

This is the simplest conditional statement, and is found in almost all programming languages. This will be the one you use most often in your scripts. An if statement runs a piece of code if a condition is met. It works like so:

if this happens then do this
if inventory is full then walk to the bank

You can also have an additional parameter, else, which works like so:

if this happens then do this else if it didn’t happen do this instead
if inventory is full then walk to the bank else keep chopping trees

To give you a practical example, let’s look at a power-chopper. You can see that "backPackIsFull" is a boolean function that results true if the backpack is full. Knowing that, the main logic of the script would work like this:

Simba Code:
program exampleScript;function backpackIsFull(): boolean;begin  // Code here which checks if the backpack is full, and results true if it is.end; procedure chopTree();begin // code to chop treeend;procedure dropLogs();begin // code to drop logsend;begin  if backpackIsFull() then    dropLogs()  // notice no semicolon here, because the statement isn't finished yet  else    chopTree();end.

You can see in the main loop, if the boolean function backpackIsFull results true (and thus the if statement condition is met) then the script will drop the logs, else if it returns false (i.e. the backpack isn't full), it will chop the tree instead. Simple eh?

Now for a simple but important tip. If you have more than one statement following a ‘then’ you will need to add a begin and end. For example, this is incorrect:

Simba Code:
if backpackIsFull() then   walkToBank();   findBanker();   depositLogs();

And this is correct:

Simba Code:
if backpackIsFull() thenbegin   walkToBank();   findBanker();   depositLogs();end;

In the second example, you can see if the backpack is full, it will begin to read a new ‘block’ of code, which contains 3 procedures, walkToBank, findBanker, and depositLogs. In the first example, since there isn't a begin and end, Simba will think only the walkToBank is part of the if … then statement, and it will see the findBanker and depositLogs as separate, sort of like this:

Simba Code:
if backpackIsFull() then   walkToBank();findBanker();depositLogs();

This means the findBanker and depositLogs procedures will ALWAYS run, even if the inventory isn't full! Remember - more than 1 statement after a then, you need a begin and end!

Case

Case statements are another type of conditional statement that are useful if you have a lot of else ... if statements together. For example, lets say the user inputted the type of rock they wanted to mine at the top of the script. Depending on the rock type they selected, we want to tell the script to mine the correct type of rock. This could be done using if..then..else statements like:

Simba Code:
if rockType = 'copper' then  mineCopperRocks()else if rockType = 'tin' then  mineTinRocks()else if rockType = 'iron' then  mineIronRocks();

A better method is to use a case statement, especially if you have more than 2 or 3 options. A case statement is written like so:

Simba Code:
case rockType of  'copper': mineCopperRocks();  'tin': mineTinRocks();  'iron': mineIronRocks();end;

That is much cleaner isn't it?

Arithmetic and relational operators

Operators (like the assignment operator := ) are symbols that tell the compiler to perform specific tasks. Below I have outlined the arithmetic and relational operators frequently used in Simba.

Arithmetic Operators

Arithmetic operators take two variables and perform a calculation. You should know these already:

 + Add - Subtract / Divide * Multiply MOD Returns the remainder (known as the modulus operator)

Relational Operators

Relational operators test the relation between two variables. You are probably familiar with these also:

 = Equal to <> Not equal to > Greater than < Less than >= Greater than or equal to <= Less than or equal to

Simba Code:
procedure maths();begin  if (2 * 5) > (10 - 4) then    writeLn('Condition 1 is greater than condition 2');end;

Logical operators

Logical operators (sometimes referred to as boolean operators) are relatively easy to understand, and are typically used with conditional statements to add another level to their conditional logic.

and

Both conditions have to be true for the code to run:

if this happens and this happens as well then do this

Simba Code:
if isLoggedIn() and tabBackpack.isFull() then    dropLogs();

or

Only one condition has to be true for the code to run:

if either this happens or this happens then do this

Simba Code:
if (attackLevel < 21) or (defenceLevel < 21) then    writeLn('Your cannot wield and wear Mithril equipment at the same time');

not

The condition must not be met (i.e. false) for the code to run:

if not this happens then do this (This is the same as: If this = false then do this)

Simba Code:
If not isLoggedIn() then        players.[current player].login();

There are a couple of others, such as xor, nor, nand, and xnor but they aren't used that often so we won’t get into those (Although I might add them later if anyone is keen).

Loops

There are three types of loops that are used in Simba. They each basically do the same thing but are written in different ways. There are instances where one type of loop is preferable to another, such as using for ... to ... do loops to loop through arrays.

repeat ... until

The repeat ... until loop is the easiest to understand, and will probably be the one you use the most when you start scripting. Basically, all the code between the repeat and until is repeated over and over again, until the ‘until condition’ is met. For example:

Simba Code:
repeat  findBanker();until bankScreen.isOpen();

This loop will keep on trying to find the banker until the bank screen is open. However, this is an example of an infinite loop – a loop which you can get stuck inside. What happens if we couldn't find the bank because our player got logged out for some reason? We would keep searching for the banker and never find it! I could easily tell it to break out of the loop using a conditional statement and logical operator which you learned above:

Simba Code:
repeat  if not isLoggedin() then     break;  findBanker();until bankScreen.isOpen();

If the player isn’t logged in, it will break out of the loop - even if the ‘until condition’ isn’t met. The other way to break out of loops is by using the exit command. The difference between exit and break is that break only breaks out of the loop, and then continues with the rest of the procedure or function, whereas exit breaks out of the loop and exits the whole procedure. Take the following example:

Simba Code:
program example;var  a: integer = 10;procedure one();begin  repeat    if a > 5 then      break;  until(false);  writeLn('I''m The Mayor');end;procedure two();begin  repeat   if a > 5 then     exit;  until(false);  writeLn('SRL is not cool');end;begin  one();  two();end.

You will notice both procedures are exactly the same, except the first one uses break, and the second one uses exit. Because variable a = 10, and is thus greater than 5, both procedures will be able to break out of their repeat ... until loops. The difference is procedure one will continue with the rest of the prodecure and write "I'm The Mayor", but procedure two will exit out of the whole thing, and not write "SRL is not cool" (because why would we write that, SRL is cool!). Try it out and see if you don't understand.

The other two types of loops are a little bit harder for the novice to understand, and you can get away with not using them most of the time. I'll explain them briefly below:

while … do

while this condition remains true do this

Simba Code:
program example;procedure exampleWhileLoop();var  a: integer;begin  a := 0;    while a < 10 do  begin    writeLn(intToStr(a));    a := a + 1;  end;end;begin  exampleWhileLoop();end.

You can see I have variable a, an integer, which I make equal to 0. Then, while a is less than 10 the loop will keep repeating. You can see I increase the value of a by 1 each time it loops, and write the value of a to the debug box. The output is this:

Code:
Compiled successfully in 265 ms.
0
1
2
3
4
5
6
7
8
9
Successfully executed.

for ... to ... do

For ... to ... do loops are a little bit different, because you can tell it how many times you want it to loop. It is basically:

for thisnumber to thisnumber do

In the following example I perform the exact same thing as I did in the while ... do loop above - the output will be the same. Note that I don't actually need the begin and end here, because there is only one statement after the 'do'. I just left it in because I think it is easier to understand.

Simba Code:
procedure exampleForLoop();var  a: integer;begin  for a := 0 to 9 do  begin    writeLn(intToStr(a));  end;end;

For loops are normally used to loop through an array, and I provide an example of this in the TPA/ATPA sub-tutorial in section 6.

Indentation standards

Even though the indentation of your code doesn't affect how the script runs, correct indenting standards make your code easier to read and understand. Simply, you should indent your code (i.e. press the tab button) at the following places:
• After a begin
• After a repeat
• After a 'then' if one statement follows

Simba Code:
begin  writeln('One indent between a corresponding begin and end');end;

Simba Code:
begin  repeat    writeln('2 levels of indentation');  until(false);end;

Simba Code:
begin  writeLn('Indent after a begin');  repeat    if attackLevel = 99 then      writeLn('Indent if only one statement follows a then');    if strengthLevel = 99 then    begin      writeLn('More than one statement after a then - we need a begin and end');      writeLn('My name is The Mayor');    end;    chopTree;    findBanker;  until(false);  writeLn('Indent after a begin');end

Now that we’ve got that covered, let’s look at how all of these concepts fit together in an actual script. Instead of just pasting a script here and explaining it, I have a better idea. We’re going to plan and construct a script from scratch, starting with a script idea.

Section 4: How to turn a script idea into a script

It can be quite daunting when you think about how you’re going to turn your script idea into a working script. It is much easier if you take your script idea, and break it down into smaller sections. From these smaller sections you can plan the individual procedures and/or functions that will make up the script, and how they will flow.

My script idea is this:
I want to design a Remmington clay miner. The player will get to the mine by teleporting to the clan camp using the clan vexillum, and then run south to the mine. Once the player has a full load of clay, he will then teleport to Port Sarim using the lodestone network. He will then run north along the wharf to the deposit box (by the monks of Entranta), and deposit the clay. These steps will then repeat over and over again.
This might seem a little complicated but I think you will learn a lot more from this script, compared to a simple woodcutter and dropper! Once you have your idea, the next step is to break it down into logical parts, or stages, because it makes things much easier to comprehend and to write. In some cases each of these stages can be a separate procedure (although the more complex the script gets - the more procedures and functions you may need to add in). For my idea above, I have broken it down into the following parts:

1. Teleport to the clan camp with Clan Vexillum
2. Run south to the clay rocks at Remington mine
3. Mine a full inventory of clay.
4. Lodestone teleport to Port Sarim and run north to the deposit box.
5. Find and open the Deposit Box.
6. Deposit the clay and close the deposit box screen.

If my script repeats steps 1 through 6 over and over again, I've got a working mining script! Next, we can start by giving each of the steps we planned a procedure name:

Simba Code:
procedure teleToClanCamp();begin    //code hereend;procedure runToMine();begin    //code hereend;procedure mineRocks();begin    //code hereend;procedure teleToPortSarim();begin    //code hereend;procedure findDepositBox();begin    //code hereend;procedure depositClay();begin    //code hereend;

Now that we’ve got these steps sorted, let’s turn this into a script! I know it can be hard when you open up Simba and see a blank canvas:

I find it easier to start with a template which already contains the basic code to setup SRL, SPS, and SMART, as well as the declare players procedure. I have put my template below and written comments to explain what everything means:

Simba Code:
program scriptTemplate;{$DEFINE SMART} // Always have this to load smart{$I SRL-6/SRL.simba}         // To load the SRL include files{$I SPS/lib/SPS-RS3.Simba} // To load the SPS include filesprocedure declarePlayers();begin setLength(players, 1); with players[0] do begin loginName := 'username'; password := 'password'; isActive := true; isMember := true; end currentPlayer := 0;end;// main loopbegin clearDebug(); // Clear the debug box smartEnableDrawing := true; // So we can draw on SMART setupSRL(); // Load the SRL include files declarePlayers(); // Set up your username/pass if not isLoggedIn() then // If player isn't logged in then begin players[currentPlayer].login(); // Log them in exitTreasure(); // Exit treasure hunter minimap.setAngle(MM_DIRECTION_NORTH); // Make compass north and angle high mainScreen.setAngle(MS_ANGLE_HIGH); end;end. If you like, what you can do is in Simba, click File -> Save as default, so each time you open up Simba you get this template instead of a blank canvas. Lets paste the procedures we made above into the template, and call them in the main loop in the order we want them to run. Like so: Simba Code: program scriptTemplate;{$DEFINE SMART}{$I SRL-6/SRL.simba}{$I SPS/lib/SPS-RS3.Simba}procedure declarePlayers();begin  setLength(players, 1);  with players[0] do  begin    loginName := 'username';    password := 'password';    isActive := true;    isMember := true;  end  currentPlayer := 0;end;procedure teleToClanCamp();begin    //code hereend;procedure runToMine();begin    //code hereend;procedure mineRocks();begin    //code hereend;procedure teleToPortSarim();begin    //code hereend;procedure findDepositBox();begin    //code hereend;procedure depositClay();begin    //code hereend;{Main Loop}begin  clearDebug();  smartEnableDrawing := true;  setupSRL();  declarePlayers();  if not isLoggedIn() then  begin    players[currentPlayer].login();    exitTreasure();    mainScreen.setAngle(MS_ANGLE_HIGH);    minimap.setAngle(MM_DIRECTION_NORTH);  end;  teleToClanCamp();  runToMine();  mineRocks();  teleToPortSarim();  findDepositBox();  depositClay();end.

Now we have got the ‘bare bones’ of our script laid out. Just by looking at this you can see how the script will work. All we have left to do now it fill in the 6 procedures with their respective code.

You’re probably thinking it’s going to be really hard to fill in the 6 procedures. There are so many objects we have to find, so many buttons we have to click, and so much code you haven't learnt yet. This is where the SRL6 include comes into play. This is a good opportunity to spend some time understanding how the SRL6 include works, and then we can return to writing our script afterwards. If you understand how the SRL6 include works, it will make scripting 100 times easier!

This is because inside each procedure and function you write, there is basically a combination of:
• Conditional statements
• Loops
• Operators
• SRL6 functions

You've learnt the first three already, all you need to know now is how SRL6 works.

Section 5: Understanding the SRL6 include

The "SRL Include" is essentially a library of individual Simba scripts, each dedicated to a particular area or theme. SRL actually used to stand for “Scar Resource Library” when we used to use Scar, the predecessor to Simba. Each of the scripts in this library contains many procedures and functions related to their respective areas. For example, the file bankscreen.simba contains procedures and functions related to withdrawing and depositing items from the bankscreen. The file backpack.simba contains procedures and functions for determining what slots items are in, clicking items, and counting items in the backpack. All of the include files are located in C:\Simba\Includes\srl-6\lib\

The layout of the include

Below is the layout of the individual simba files within the include library:

Folder: Core
• Client
• Debug
• Globals
• Mouse
• Players
• Text

Folder: Interfaces
• Sub-folder: Gametabs
• Backpack
• Gametab
• Stats
• Sub-folder: Lobby
• Lobby
• Worlds
• Actionbar
• Bankscreen
• Chatbox
• Chooseoptions
• Conversationbox
• Depositbox
• Interfaces
• Lodestone
• Mainscreen
• Minimap
• Options
• Pinscreen
• Production
• ProgressScreen
• ToolScreen

Folder: Misc
• Antiban
• Items
• Smart
• SRLplayerform
• srlstats

Folder: Tesseract
• tesseract

Folder: Utilities
• Sub-folder: types
• extendedArrays
• intergerArrays
• stringArrays
• tBox
• tPoint
• tPointArrays
• types
• color
• drawing
• math
• pixelshift
• time
• wrappers

As I said before, there are hundreds of procedures and functions inside these individual files. If you want to create amazing scripts for RuneScape, then you need to learn how to use these procedures and functions in your own script.

How the SRL6 include works

By calling {$I SRL-6/SRL.simba} at the top of our script (like we did in the template above) we are 'including' external files into our script. This is basically giving Simba access to all of those files in the include library. This enables us to use any of the procedures and functions contained within those files, in our own script! I guess you don't really need to know this, but the {$I SRL-6/SRL.simba} is actually including one file, the SRL.simba file. If you open the SRL.simba file, you will notice it then includes all of the other files inside the include. When you setupSRL() at the start of your main loop, you are telling SRL.simba to include all of those other files. In the following picture, you can see how it would include the files in the interfaces folder:

Let me give you an example. Lets say I wanted check if the player was logged in. You are probably thinking I have to write heaps of code to somehow check if we were logged in - luckily I don’t - all I have to write is 1 word: isLoggedIn.

Simba Code:
program includeExample;{$I SRL-6/SRL.simba}procedure areWeLoggedIn();begin if isLoggedIn() then writeLn('Yay we are logged in');end;begin setupSRL(); areWeLoggedIn();end. You've probably guess how this works - we didn't have a boolean function in our script called isLoggedIn(), but there is one inside the include. If you go to C:\Simba\Includes\srl-6\lib\core\ and open players.simba, you will see the full isLoggedIn function: Simba Code: (*isLoggedIn()~~~~~~~~~~~~.. code-block:: pascal function isLoggedIn(): boolean;Returns true if a player is logged in, uses the center of the compass work outthe result... note:: - by Olly & Coh3n - Last updated: 11 August 2013 by Coh3nExample:.. code-block:: pascal if (isLoggedIn()) then writeln('We are logged in!');*)function isLoggedIn(): boolean;const CENTER_COMPASS_COLOR = 8508157;begin result := (getColor(minimap.button[MM_BUTTON_COMPASS].center) = CENTER_COMPASS_COLOR); if (result) and (not __areDynamicInterfacesSet) then __setDynamicInterfaces();end; You will notice in the function above, there are some comments which explain what the function does, who wrote it, when it was updated, and an example of how to use it in your script. In a way, it's like you have all of the SRL procedures and functions written in your own script, but they are invisible (if you know what I mean). By using SRL functions and procedures in your script, it can save you a lot of time, and a lot of effort. This is what I meant by making scripting 100 times easier. If you are learning how to script, then it's a good idea to read through the include files and get familiar with what they contain. I have provided a full list of procedures and functions in each of the include files in appendix A, which is attached as a PDF at the beginning of this thread. If you like, you can print this out and keep it for quick reference when writing a script. New procedures and functions are being added to the include all the time. If you think of something useful that isn't already in the include, you can submit suggestions here, or of you come across any bugs you can also submit them too, and they will be fixed by the developers. The SPS-RS3 Include Similarly, by calling {$I SPS/lib/SPS-RS3.Simba} at the top of your script, you are enabling Simba to use the SPS (SRL Positioning System) functions for walking. This is the layout of the SPS include, which is located in C:\Simba\Includes\SPS

Folder SPS

• Sub-folder: img
• Sub-folder: runescape_other
• SPS maps are stored here

Sub-folder: runescape_surface
• SPS maps are stored here

Sub-folder: lib
• sps-rs3

The runescape_other and runescape_surface folders is where you store your SPS maps. The sps-rs3.simba file contains all the functions related to walking. I have a SPS sub-tutorial in section 6, so don't worry too much about it now.

The SRL procedures and functions you will use most

Although I have a full list of procedures and functions below in appendix A, you probably won't use the majority of these to start. To make things easy, I have compiled a short list of functions which, in my opinion, are the most important for writing a basic script:

Actually, please refer to my Simplistic Beginners Guide To RS3 Scripting.

Using the inbuilt debugging functions in SRL6

The process known as “debugging” basically means removing all the “bugs” or errors from your script. Sometimes it can be extremely hard to locate an error in your code, which is why we write comments throughout our script to get feedback from the compiler. This makes it easier to pinpoint, and subsequently fix the error. If you are new to scripting you can probably skip this part and move on to section 6.

SRL6 comes with new built-in debug functionality, and it’s encouraged to use this over custom “writeLn” debug processes. All debugging is done through the print() procedure, which is found in debug.simba. The exact parameters of this procedure are:

Simba Code:
procedure print(txt: string; debugType: TDebug = TDebug.DEBUG);

There are 9 different debugTypes, each of which has a specific purpose:

• TDebug.DEBUG
• TDebug.FOOTER
• TDebug.SUB
• TDebug.HINT
• TDebug.WARNING
• TDebug.ERROR
• TDebug.LOG
• TDebug.FATAL

You can see from the print procedure parameters above that TDebug.DEBUG is the default debugType, so if you leave the second parameter blank, it will default to this. This is your generic debugType which you will use most often. It is written like so:

Simba Code:
if thisHappens then  print('This is a debug message');

The next 2 debugTypes (HEADER and FOOTER) are both used within the same function or procedure. These are normally only used in large procedures or functions to make the debug output neat and easily readable. Between the HEADER and FOOTER you can use the default DEBUG message above. The messages between the HEADER and the FOOTER are automatically indented, like so:

--DEBUG
--DEBUG
FOOTER

The HEADER doesn't have to contain a debug message, as it’s just used to initialize the header, which should be the name of the function (or procedure) you are debugging (see example below). If you use a HEADER, you must always close with a FOOTER. In the footer you can either just write the function name (like in the header), or write the result of the function:

Simba Code:
print('bankscreen.openBankBooth()', TDebug.HEADER); print('Searching for bank booth');print('The mouse-over text matched');print('bankscreen.openBankBooth()result = ' + toStr(result), TDebug.FOOTER);

Code:
-- bankscreen.openBankBooth()
---- Searching for bank booth
---- The mouse-over text matched
-- bankscreen.openBankBooth()result = False
I will finish this section later

Now that we know how the SRL6 include works, let’s get back to writing our clay mining script!

Section 6: A step-by-step example of writing a script

Now that you understand how we can make use of the procedures and functions within the SRL6 include, let’s continue filling in the 6 procedures in our clay mining script. Each procedure will be split into its own section and explained individually. I start with the easier procedures first and then move onto the procedures which require more advanced techniques. At the start of each section I will describe the aim of the procedure, and list the SRL6 functions that will be used. Some procedures require special skills and additional knowledge before they can be completed (i.e. those that use SPS or DTMs). If this is the case, I introduce the new concept in a short sub-tutorial before beginning on the actual procedure. I think by doing it this way it will be easier for you understand, and you won’t have to jump between different tutorials for each new scripting concept.

Section 6 is laid out as follows:

• 6.1 The depositClay procedure
• Sub-tutorial 1- Creating SPS maps and using them to walk anywhere
• 6.2 The runToMine procedure
• 6.3 The teleToPortSarim procedure
• Sub-Tutorial 2 - Creating a DTM and then finding it
• 6.4 The teleToClanCamp procedure
• Sub-Tutorial 3 - Using Auto Color Aid (ACA) to pick colors
• 6.5 The findDepositBox procedure
• Sub-Tutorial 4 - Understanding TPoints, TPAs and ATPAs
• 6.6 The mineRocks procedure
• 6.7 Bonus procedure: progressReport
• 6.8 Cleanup and final script

6.1 The depositClay procedure

As this is the first procedure, I’m going to explain how I write this in detail. This is so you will understand what I’m doing in the subsequent procedures. We will draw on the knowledge you've learned above, that being conditional statements, operators, loops, and making use of the SRL6 include. I will also teach you about 'failsafes', and avoiding infinite loops.

Aim of the procedure:
If the deposit box screen is open, it will click on the quick deposit button to deposit all of the items in our backpack. Once the backpack is empty, it will then close the deposit box screen.

The following SRL6 functions will be used in this procedure:
Simba Code:
function isLoggedIn(): boolean;function depositBox.isOpen(waitTime: integer = 0): boolean;function depositBox.quickDeposit(depositType: integer): boolean;function depositBox.close(): boolean;function depositBox.count(): integer;function depositBox.isEmpty(): integer;procedure TTimeMarker.start();function TTimeMarker.getTime(): LongWord;

You will notice above this procedure uses a number of functions from the depositbox.simba file in the include. I've started writing the procedure below:

Simba Code:
procedure depositClay();begin  if not isLoggedIn() then    exit;  if depositBox.isOpen() then    depositBox.quickDeposit(QUICK_DEPOSITBOX_INVENTORY);      depositBox.close();end;

You can see the procedure works like this: It starts off with a simple ‘failsafe’. If the player isn't logged in, then it will exit out of the whole procedure. We don’t want it to try and deposit items when we aren't even logged in! You should start all of your procedures with this simple check. If we are logged in, then it will continue with the rest of the procedure. If the deposit box is open, then it clicks the quick deposit button, and then closes the deposit box screen. If I wanted to, I could also deposit certain slots (which is necessary if I had something like a pickaxe in my backpack) I could write depositBox.deposit([2..28]) to deposit slots 2 to 28. The same goes for the bank screen too, bankScreen.deposit([2..28]).

However, this has some flaws, what if we have nothing in our inventory? It will still click the deposit button, which is a bit bot-like. Let's edit it:

Simba Code:
procedure depositClay();begin  if not isLoggedIn() then    exit;  if depositBox.isOpen() then    if (depositBox.count > 0) then      depositBox.quickDeposit(QUICK_DEPOSITBOX_INVENTORY);  depositBox.close();end;

Now you can see it will only click the deposit button if there is greater than 0 items in our backpack. Even though this procedure looks good, there are some flaws. What if we lag when we click the deposit button and it doesn't end up depositing? We will run back to the mine with a full inventory! Let’s make it repeat the deposit part until the inventory count is 0.

Simba Code:
procedure depositClay();begin  if not isLoggedIn() then    exit;  if depositBox.isOpen() then  repeat    if (depositBox.count > 0) then    begin      depositBox.quickDeposit(QUICK_DEPOSITBOX_INVENTORY);      wait(randomRange(1000, 2000));    end;  until(depositBox.isEmpty());  depositBox.close();end;

The first thing you’ll see is it repeats that block of code until the deposit box is empty. You’ll also notice, I've added a wait after it clicks the deposit button – this it to give it time for the items to be deposited. If I didn't make it wait, it would keep looping very fast and end up spam clicking the deposit button until the inventory was empty. In this case, it waits for a random time between 1 and 2 seconds. You should always use random waits, because static waits (e.g. wait(1000) ) are easily detectable. However, what happens if we lag out or we have an item that can’t be deposited? We will be stuck in the repeat…until loop FOREVER, because the deposit box will never be empty! Jagex will see you stuck on the deposit box screen and will probably ban you! Let’s add in some failsafes:

Simba Code:
procedure depositClay();var  bankTimer: TTimeMarker;begin  if not isLoggedIn() then    exit;  if depositBox.isOpen() then  begin    bankTimer.start();    repeat      if (depositBox.count > 0) then      begin        depositBox.quickDeposit(QUICK_DEPOSITBOX_INVENTORY);        wait(gaussRangeInt(500, 750));      end;    until(depositBox.isEmpty()) or (not isLoggedIn()) or (bankTimer.getTime() > 10000);  end;  depositBox.close();end;

Now you can see I have added a new local variable to the procedure which I have called bankTimer (you can name variables whatever you want). I have declared this as a TTimeMarker. I know you haven't been introduced to TTimeMarkers before, but they are simply variables that hold time - think of them as stopwatches! You can see I start the timer BEFORE the repeat…until loop. Never do this inside the loop because it will keep starting the timer each time it loops! You can also see I've added 2 more conditions to the until clause. I break out of the loop if I am not logged in, or if the bankTimer has been running for more than 10 seconds. Cool aye?

Let’s just check that the script compiles before moving on. Click Script -> Compile (or Ctrl + F9). I do this after each step because if I get a compiling error, I know it’s in the code I just wrote! I normally test each procedure I've written before writing the next one. Start with the deposit box screen open and with items in your inventory. Press play – did it deposit and close the deposit box? Mine works! If your's didn't then you must have done something wrong. Now try it with an empty inventory – did it just close the screen without clicking the deposit button? Cool! Now we have an awesome deposit procedure, let’s move on.

Extra note: You can see in the list of functions the depositBox.isOpen() has a optional ‘wait time’ parameter, which is set to 0 by default. All it does is wait (up to a maximum time) for the deposit box to be open. If I wanted to wait for a maximum of 2 seconds, I could write depositBox.isOpen(2000). I’m sure you’re aware that the 2000 is milliseconds (1000 ms = 1 second).

Sub-Tutorial 1 – Creating SPS maps and using them to walk anywhere

Before we start the runToMine procedure, I want to introduce you to SPS (The SRL Positioning System). This is a VERY useful skill to learn because SPS is the easiest, most efficient and accurate way to walk in RS3. SPS works like this: Simba loads a picture of the RuneScape minimap (a screenshot you took of the minimap). Simba can then compare your in-game minimap with that picture to calculate where your player is.

The first step is creating your SPS map. RS3 made it really easy to get your map because you can re-size your interfaces. Let’s make the minimap big so we can get our screenshot:

On windows 7 or windows 8 use the inbuilt snipping tool to get a screenshot. You can use another screen capture software as long as the quality isn't compromised.

We have to make sure that our image is big enough because if your player ends up in a location that isn't on your SPS map, Simba won’t know where your player is! However, the bigger you make your map, the longer it takes Simba to calculate where you are, so make your map big enough, but not outrageously big! If your map area is spread across multiple minimap images, you will have to take multiple screenshots and join them together. Here is a tutorial how to do it (this is old, but the same ideas still apply - it's actually easier now since the maps are square). Also note that your minimap should be alligned perfect north before you take your screenshot.

Don’t save the image directly from the snipping tool as the quality is reduced. Instead, right click the image and click copy:

Open Microsoft Paint and press Ctrl + v to paste in your screenshot. Click the crop button to get rid of all the extra white space on the canvas:

Then save the picture as a .PNG file because SPS maps always need to be in this format to work properly. Then, put this image in the runescape_other folder (C:\Simba\Includes\SPS\img\runescape_other). I named my screenshot CLAY_MAP.png.

Now that we have the map, we need to make the path we are going to walk. To do this you are going to need the SPS_path_generator tool. Download the SPS_Path_Generator.zip from this thread. Extract it, open it and click Map -> Load different map. Navigate to the SPS map you just made in the runescape_other folder. Starting from the beginning of your path, click on the map to place your points. I am making my path from the Falador Clan Camp to Remmington mine:

See all of the x and y coordinates on the right? Those are all the TPoints that make up your path. The last step is to click the “Copy Path Array” button. Now that we've copied all of the points, we are ready to paste them into Simba. My points look like this:

Simba Code:
[Point(130, 128), Point(152, 163), Point(145, 194), Point(147, 229), Point(141, 256), Point(140, 285), Point(157, 291)];

I’ll show you how to setup and use this path in the next procedure.

6.2 The runToMine procedure

Aim of the procedure:
To run from the Clan Camp to the clay rocks in Remmington mine.

The following SRL6 functions will be used in this procedure:
Simba Code:
function isLoggedIn(): boolean;function SPS.walkPath(path: TPointArray): boolean;function minimap.waitPlayerMoving(waitFlagGone: boolean): boolean;function sps.setup(map name: string, folder): Boolean;

I have written the procedure below:

Simba Code:
procedure runToMine();var   pathToMine: TPointArray;begin  if not isLoggedIn() then    exit;  pathToMine := [Point(130, 128), Point(152, 163), Point(145, 194), Point(147, 229), Point(141, 256), Point(140, 285), Point(157, 291)];  if SPS.walkPath(pathToMine) then    minimap.waitPlayerMoving()  else    writeLn('We failed to walk to the mine');end;

At the top you can see I have created a variable called pathToMine and I have declared this as a TPointArray. My path is made up of a group of TPoints (an array of points) which is why I have declared it as this (remember the TPA picture from section 2).

I start off with the normal isLoggedIn check and then I assign my array of points which I copied from the path maker tool to the pathToMine variable. I have then told Simba to walk my SPS path using the sps.walkPath command. If it walks the path successfully, it then waits until the player is not moving. This will make it easier to find the rocks! Before we can test this, we need to tell Simba to load our SPS map. I normally do this at the start of the main loop, as Simba only needs to load the map once (you could also declare the SPS path here too, but you would have to make your pathToMine variable global as it would be used in more than one procedure). Remember I called my map CLAY_MAP and I put it in the runescape_other folder:

Simba Code:
begin // main loop  clearDebug();  smartEnableDrawing := true;  disableSRLDebug := false;  setupSRL();  declarePlayers();  SPS.setup('CLAY_MAP', RUNESCAPE_OTHER);  // Setup our map  if not isLoggedIn() then  begin    players[currentPlayer].login();    exitSquealOfFortune();    mainScreen.setAngle(MS_ANGLE_HIGH);    minimap.setAngle(MM_DIRECTION_NORTH);  end;  teleToClanCamp();  runToMine();  mineRocks();  teleToPortSarim();  findDepositBox();  depositClay();end.

Let’s make sure it compiles and then test it out to make sure it works. It’s good to do this now so we don’t have to fix it later. Try starting at the Clan Camp, and press play. Don’t worry that our other procedures aren't finished yet - Simba will still run them, but since they are blank Simba won’t do anything. Press play to test it - does your player walk down to the mine? Mine does! Let’s move on!

6.3 The teleToPortSarim procedure

Aim of the procedure:
To lodestone teleport to Port Sarim and run north along the wharf to the deposit box.

The following SRL6 functions will be used in this procedure:
Simba Code:
function isLoggedIn(): boolean;function lodestoneScreen.teleportTo(location: integer): boolean;function minimap.findSymbol(var p: TPoint; symbol: integer; searchBox: TBox): boolean;function minimap.waitPlayerMoving(waitFlagGone: boolean): boolean;

This procedure is quite similar to the previous one. After the player teleports it's going to run north to the deposit box using SPS. I purposely made my previous SPS map big enough so I can use that map for this path too. My path from the lodestone to the deposit box looks like this:

Let’s start writing the procedure:

Simba Code:
procedure teleToPortSarim;var   pathToDepositBox: TPointArray;begin  if not isLoggedIn() then    exit;    lodestoneScreen.teleportTo(LOCATION_PORT_SARIM);      pathToDepositBox := [Point(287, 392), Point(302, 386), Point(331, 384), Point(346, 381), Point(349, 354), Point(351, 331), Point(353, 315), Point(379, 317), Point(403, 317), Point(423, 318)];  if SPS.walkPath(pathToDepositBox) then    minimap.waitPlayerMoving()  else    writeLn('We failed to walk to the deposit box'); end;

You can see we begin with the normal isLoggedIn check, before teleporting to Port Sarim. Like the previous procedure, we assign our TPointArray we copied from the path maker tool to the variable pathToDepositBox. I then tell it to walk the path, just like before. HOWEVER, what happens if it failed to teleport because of lag, or it tries to start walking before the teleporting is finished? It will screw up your script and your computer will explode! Like before, let’s tell it to repeat the lodestone teleport until it is at Port Sarim. How can I get my script to recognize it's at Port Sarim? Hmm... this is what my minimap looks like if I successfully teleported:

I know! If it can see the fishing shop symbol, then it knows it has been successful - let's add that in:

Simba Code:
procedure teleToPortSarim();var  pathToDepositBox: TPointArray;  p: TPoint;begin  if not isLoggedIn() then    exit;  repeat    lodestoneScreen.teleportTo(LOCATION_PORT_SARIM);    wait(randomRange(14500, 16000));  until (not isLoggedIn()) or minimap.findSymbol(p, MM_SYMBOL_SHOP_FISHING, minimap.getBounds());  pathToDepositBox := [Point(287, 392), Point(302, 386), Point(331, 384), Point(346, 381), Point(349, 354), Point(351, 331), Point(353, 315), Point(379, 317), Point(403, 317), Point(423, 318)];  if SPS.walkPath(pathToDepositBox) then    minimap.waitPlayerMoving()  else    writeLn('We failed to walk to the deposit box');end;

You can see I have now added the lodestone teleport into a repeat ... until loop. I've also added a wait so it doesn't keep trying to teleport while we are already teleporting. You'll notice it breaks out of the loop if it isn’t logged in, or if it finds the fishing shop symbol! Cool eh? Once it is out of the loop, it will continue with the rest of the code and run up to the deposit box.

Before testing this, let me explain a little more about the parameters in the findSymbol function:

Simba Code:
function minimap.findSymbol(var p: TPoint; symbol: integer; searchBox: TBox): boolean;

You can see it has 3 parameters: p (which is a TPoint), symbol (which is an integer), and searchBox (which is a TBox). You can see the symbol and the searchBox are variables that we have to INPUT, but p is an OUTPUT variable (denoted by the var before it) which is also why we had to declare it as a variable inside the procedure. When it finds the symbol, its coordinates are stored in p (which is useful if we wanted to click it or something - mouse(p, MOUSE_LEFT) ).

For the searchBox, I put minimap.getBounds(). This is a function which returns a TBox of the minimap interface. You can get a TBox of any interface using this function (mainscreen.getBounds(), tabBackpack.getBounds() etc.).

For the symbol I have put MM_SYMBOL_SHOP_FISHING. You are probably thinking what's going on here, that doesn't look like an integer?! It is actually an integer constant - go and open minimap.simba and you will see each minimap symbol has been assigned a number. The MM_SYMBOL_SHOP_FISHING is actually a number 7:

Simba Code:
const  MM_SYMBOL_SHOP_ARCHERY    = 0;  MM_SYMBOL_SHOP_AXE        = 1;  MM_SYMBOL_SHOP_CANDLE     = 2;  MM_SYMBOL_SHOP_CLOTHES    = 3;  MM_SYMBOL_SHOP_COOKERY    = 4;  MM_SYMBOL_SHOP_CRAFTING   = 5;  MM_SYMBOL_SHOP_FARMING    = 6;  MM_SYMBOL_SHOP_FISHING    = 7;  MM_SYMBOL_SHOP_FOOD       = 8;  MM_SYMBOL_SHOP_HUNTER     = 9;  // Plus another 90 or so symbols

This is exactly the same thing as the lodestoneScreen.teleportTo(location: integer): boolean; function. Each location is assigned an integer. And the same as the QUICK_DEPOSITBOX_INVENTORY in the depositClay procedure.

Let’s test this procedure. I only want to test this procedure, so I comment out the other procedures in the main loop which we have already completed, so it doesn't run them first:

Simba Code:
//teleToClanCamp();  //runToMine();  //mineRocks();  teleToPortSarim();  //findDepositBox();  //depositClay();

Start anywhere and press play! Did your player teleport and run up to the deposit box? Mine did! Let’s move on!

Sub-Tutorial 2 - Creating a DTM and then finding it

Before moving on to the teleToClanCamp procedure I want to introduce you to Deformable Template Models (commonly known as DTMs). If you know how to use DTMs you can find any item in your backpack, in the bankscreen and many other things! A DTM is a basically set of points relative to each other. These usually consist of a main-point, and a set of sub-points:

These points each have their own color and tolerance. Simba simply looks for a pattern of points that matches your DTM's points and colors. DTMs are made using the DTM editor which is built into Simba. Before it can be used it has to be enabled via the extensions menu. Click Extensions -> View -> Enable DTM Editor. Then click Tools -> DTM editor. It looks like this:

In the DTM editor window, navigate to the item you want to make a DTM of, which in my case is the clan vexillum. Item DTMs normally consist of one point in the middle of the item, and then 3 or 4 points around the edge of item on the black outline. Let’s start with the middle point first, mine looks like this:

You can see I have chosen a point in the middle of the clan vexillum, which is the blue color 11896678. You will also notice I’ve made the tolerance of this color 25, as the color might slightly change each time you login (this probably won’t happen that often, but do it just in case). Next, choose 3-4 points around the edge of the object. These points are normally the black edge color 131072, with a tolerance of 0 (we don’t need any tolerance because the black item outline color is static, meaning it doesn't change) like so:

Now that we have completed selecting our points, lets test the DTM. Click DTM -> Show matching DTMs. You should get a red cross on the vexillum (or whatever item you're doing), and nowhere else:

Now we need to turn this DTM into ‘code’ so Simba can read it. Click DTM -> DTM to String. It will print the DTM’s string into the debug box. We need to assign this DTM to a new variable. DTMs are declared as integers:

Simba Code:
procedure loadDTMs();var  vexilumDTM: integer;begin  vexilumDTM := DTMFromString('mggAAAHicY2NgYGBkZWDghmJmIP7JwsDwA4ibGBkYaoC4DYinAHErlJ/WvhWoiwkDSzJgB4w4MAQAAJLTBxg=');end;

In the following procedure I will show you how to find a DTM.

6.4 The teleToClanCamp procedure

Aim of the procedure:
Open the equipment tab, find the DTM of the equipped clan vexillum, right click it, and select the ‘teleport’ option to teleport to the clan camp.

The following SRL6 functions will be used in this procedure:
Simba Code:
function isLoggedIn(): boolean;function gameTabs.openTab(tab: integer): boolean;function findDTM(dtm: integer; var x, y: integer; searchBox: TBox): boolean; overload;procedure mouse(x, y, randX, randY, button: integer = MOUSE_MOVE); overload;function isMouseOverText(txt: TStringArray; waitTime: integer = 250): boolean;procedure fastClick(button: integer);function chooseOption.select(txt: TStringArray; waitTime: integer = 150): boolean; overload;function minimap.findSymbol(var p: TPoint; symbol: integer; searchBox: TBox): boolean;procedure TTimeMarker.start();function TTimeMarker.getTime(): LongWord;

I’ve started this procedure by opening the equipment tab. I then search for the DTM using the findDTM function. Like I explained before, the x and y are OUTPUT variables (see the var in-front), so it will store the location of the DTMs main-point in x and y. You will notice I search for the DTM inside the TBox returned from tabBackpack.getBounds() which is a box around backpack interface (I could search in the backpack the same way - I'd just have to make sure the backpack was the open tab):

Simba Code:
procedure teleToClanCamp();var  vexillumDTM, x, y: integer;begin  if not isLoggedIn() then    exit;  gameTabs.openTab(TAB_EQUIPMENT);  vexillumDTM := DTMFromString('mggAAAHicY2NgYGBkZWDghmJmIP7JwsDwA4ibGBkYaoC4DYinAHErlJ/WvhWoiwkDSzJgB4w4MAQAAJLTBxg=');   if findDTM(vexillumDTM, x, y, tabBackPack.getBounds()) then  begin    mouse(x, y, 3, 3, MOUSE_MOVE);      end else    writeLn('Failed to find the vex DTM');end;

You can see that if it finds the DTM, it stores the point where it found it in the variables x and y. I then move the mouse to this point with a randomness of 3 in either direction (which is what those 3s mean - always use an element of randomness). Now lets add in the clicking part:

Simba Code:
procedure teleToClanCamp();var  x, y, vexillumDTM: integer;  p: TPoint;  teleTimer: TTimeMarker;begin  if not isLoggedIn() then    exit;  gameTabs.openTab(TAB_EQUIPMENT);  vexillumDTM := DTMFromString('mggAAAHicY2NgYGBkZWDghmJmIP7JwsDwA4ibGBkYaoC4DYinAHErlJ/WvhWoiwkDSzJgB4w4MAQAAJLTBxg=');  if findDTM(vexillumDTM, x, y, tabBackPack.getBounds()) then  begin    mouse(x, y, 3, 3, MOUSE_MOVE);    if isMouseOverText(['Clan', 'vex']) then    begin      fastClick(MOUSE_RIGHT);      if chooseOption.select(['Tele']) then      begin         writeLn('We clicked the teleport option');        teleTimer.start();        repeat           wait(randomRange(2000, 3000));        until (not isLoggedIn())  or (minimap.findSymbol(p, MM_SYMBOL_STORE, minimap.getBounds()) or (teleTimer.getTime() > 20000));      end;    end;  end else    writeLn('Failed to find the vex DTM');end;

Now you can see after it moves the mouse, it checks if the mouseOverText matches before right clicking the item. The chooseOption menu is the one that pops up when you right click something. If the teleport option exists in the chooseOption menu it clicks it. Since my minimap looks like this at the Clan Camp:

I have told it to repeat waiting until it finds the General Store minimap symbol (or until the player is not logged in, or it's been 20 seconds), before finishing the procedure. Let's test this works, remember to comment out the main loop procedures you don't want to test.

Sub-Tutorial 3 - Using Auto Color Aid (ACA) to pick colours

In the next procedure we are going to find the deposit box using color finding techniques. Before we can do that, I have to show you how to pick colors - and I'm not talking about the color picker built into Simba, as it has very limited functionality and is only used to pick single colors. The tool named Auto Color Aid (known as ACA) has been developed by SRL members and is used for advanced color picking and testing. You should download ACA from the official thread.

It has a cool icon (idk why I decided to show this):

The following is the layout of the ACA interface:

First of all you need to pick your color tolerance speed (CTS) settings. You should always use CTS2 as it is much more accurate than CTS0 and CTS1. Next, in the color picking window, you should pick multiple colors of what ever object you want to search for. In this example I want to search for the bankers in Varrock West. After picking a few colors from the middle banker, and clicking "mark best color" button, this is what the color match looks like:

Notice I have selected CTS2. There are 4 numbers that you need to use from the output: The Color, the tolerance (HSL Tol), and the hue and sat modifiers. Before I copy my results I want to improve my color match because it obviously isn't the best. You can see from the first picture that the two other bankers are a slightly darker shade of purple. Let's pick some colors from them too:

That's much better isn't it! It is also worth logging out, changing worlds, and testing if the colors match on other worlds (because they change slightly on different worlds). If they don't, then keep adding colors to the list until all of the worlds that you login to have a good color match (usually about 4-5 worlds, the more the better).

6.5 The findDepositBox procedure

Aim of the procedure:
To find the deposit box on the main-screen and left click it.

The following SRL6 functions will be used in this procedure:
Simba Code:
function isLoggedIn(): boolean;function TRSMainscreen.findObject(var ix, iy: integer; col, tol: integer; colSettings: TColorSettings; sortFrom: TPoint; objWidth, objHeight, minCount: integer; mouseOverText: TStringArray; mouseAction: integer = MOUSE_NONE): boolean; overload;function depositBox.isOpen(waitTime: integer = 0): boolean;

In this procedure we are going to tell Simba to search for the brown color of the deposit box, move the mouse to it, and click it. First I need to pick my colors from ACA:

Not bad, lets pick a few more:

That looks better. Now I need to use the color, tolerance, hue and sat numbers from ACA in my procedure. I'll going to put them into the mainscreen.findObject function (found in mainscreen.simba). It's quite a big function with many parameters so so let me explain them:

mainscreen.findObject(var ix, iy: integer; col, tol: integer; colSettings: TColorSettings; sortFrom: TPoint; objWidth, objHeight, minCount: integer; mouseOverText: TStringArray; mouseAction: integer = MOUSE_LEFT)

• ix, iy: The coordinates of the object if found (note this is an output variable).
• col: The color to be found - this is the color from ACA.
• tol: The tolerance of the color - this is the HSL Tol from ACA.
• colSettings: The color settings are presented in parentheses (CTS, hue, sat) - these are from ACA.
• sortFrom: The TPoint where you want it to sort the array from (don't worry too much about this now - I explain this in my TPA/ATPA sub-tutorial below).
• objWidth: The width (in pixels) of the object you're trying to find.
• objHeight: The height (in pixels) of the object you're trying to find.
• minCount: The minimum number of pixel that must match your color on a single object.
• mouseOverText: The mouseOverText of the object.
• mouseAction: The action of the mouse. Default is MOUSE_LEFT, but you could also have MOUSE_RIGHT, MOUSE_MOVE.

To find the deposit box I'm going to use this:

mainscreen.findObject(x, y, 5270142, 5, colorSetting(2, 0.07, 0.15), mainscreen.playerPoint, 30, 50, 50, ['eposit', 'box'], MOUSE_LEFT)

• I am searching for the color 5270142
• with a tolerance of 5
• I'm using CTS2 with a hue of 0.07 and sat of 0.15
• I'm sorting the matching TPoints from my player
• My object has a width of about 30 pixels
• My object has a height of about 50 pixels
• I want it to find at least 50 matching pixels
• The mouseOverText is 'eposit' or 'box'
• I'm left clicking the mouse (I could leave this blank as MOUSE_LEFT is actually default)

Simba Code:
procedure findDepositBox();var  x, y, i: integer;begin  if not isLoggedIn() then    exit;  repeat    mainscreen.findObject(x, y, 5270142, 5, colorSetting(2, 0.07, 0.15), mainscreen.playerPoint, 30, 50, 50, ['eposit', 'box'], MOUSE_LEFT);    wait(randomRange(1000, 2000));    inc(i);  until depositBox.isOpen() or (i >= 15);end;

Again, I have used another repeat ... until loop. It keeps looking for the deposit box until it is open, or it has tried 15 times. I wanted to introduce you to inc(). This increases a variable by 1, so each time it loops, it increases the integer i by 1. This is useful when you want to increase the amount of loads you have done, the number of times you have banked, or whatever. It's just a shorter way of writing i := i + 1. Like always, let's test this out. Remember to comment out the other procedures you don't want to test. Stand next to the deposit box and press run. It worked!

Sub-Tutorial 4 - Understanding TPoints, TPAs and ATPAs

Before we move on to the final procedure in this script, I want to teach you more about using TPointArrays (TPAs) and Arrays of TPointArrays (ATPAs) to find objects. I could find the rocks with the mainscreen.findObject function that we used in the last procedure, but TPAs and ATPAs are so versatile you can manipulate them in many ways to suit your specific needs. In this sub-tutorial I’m going to show you what TPAs and ATPAs actually look like, how to find them, debug them, sort them, and click them.

Remember the pictures I showed you in the variables section of this tutorial? You should remember that a TPoint is a single pixel on the screen, and a TPointArray is a cluster of TPoints on the screen put into an array. I’m going to start off by using ACA to pick some colors of the bankers. This is the color matches in ACA:

The output from ACA is the following:

Color: 5644066, Tolerance: 10, Hue: 0.10, Sat: 1.02, CTS: 2

Now what we are going to do is find that color, and put all the TPoints that match the color into a TPointArray (TPA). I’m going to search for colors using the following function (located in color.simba):

Simba Code:
function findColorsSpiralTolerance(x, y: Integer; var points: TPointArray; color: integer; searchBox: TBox; tol: Integer; settings: TColorSettings): Boolean; overload;

You can see there is an output variable var points: TPointArray which tells us Simba is going to put all the TPoints that match our color into a TPointArray variable. You should remember what the color, searchBox, tol and colorSettings are from the ACA sub-tutorial and the findDepositBox procedure. I have put my results from ACA into the function, and told it to search for the color on the mainscreen:

Simba Code:
procedure findColorz();var  x, y: integer;  TPA: TPointArray;begin  findColorsSpiralTolerance(x, y, TPA, 5644066, mainScreen.getBounds(), 10, colorSetting(2, 0.10, 1.02));  if length(TPA) < 1 then    exit;end;

You can see I have declared a variable called TPA as a TPointArray, and I put this same variable into the findColorsSpiralTolerance function. I also declare x and y as integers, as the findColorsSpiralTolerance function also outputs the first TPoint it finds (but we are not using that). The:
Simba Code:
if(length) TPA < 1 then   exit;
just means that if the length of the array is less than 1, it will exit out of the procedure. Remember, you can think of an array like this:
Simba Code:
TPA := [TPoint0, TPoint1, TPoint2, TPoint3, TPoint4, TPoint5, TPoint6];
So if it didn’t find any colors, the array would be empty:
Simba Code:
TPA := [];

Now I’m going to introduce you to a procedure in drawing.simba:

Simba Code:
procedure debugTPA(tpa: TPointArray; drawPoints: boolean = true);

This procedure allows us to debug the TPA by drawing a box around it on SMART. The drawPoints parameter draws all the matching points on smart - however, just leave it false for now. Make sure you have set smartEnableDrawing to true:

Simba Code:
program exampleScript;{$DEFINE SMART}{$I SRL-6/SRL.simba}procedure findColorz();var  x, y: integer;  TPA: TPointArray;begin  findColorsSpiralTolerance(x, y, TPA, 5644066, mainScreen.getBounds(), 10, colorSetting(2, 0.10, 1.02));  if length(TPA) < 1 then    exit;  smartImage.debugTPA(TPA, false);end;begin  smartEnableDrawing := true;  setupSRL();  findColorz();end.

If I stand in front of the bankers and run this script, this is what Simba draws on SMART:

You can see it drew a box around the TPA, and printed the number of matching TPoints that made up the array. In this case, there were 1371 TPoints inside our TPA. Now set the drawPoints parameter to true and run it again, see how smart drew white points on top of all the matching TPoints:

Awesome, that is all there is to TPAs. Let’s move on to Arrays of TPointArrays (ATPAs). As you saw in the above pictures, the TPA returned a big box with all of the bankers inside it. This is no good if we want to find an individual banker. What I’m going to do now is split that big TPA into smaller TPAs, and those smaller TPAs will collectively form a new array. In other words, I’m going to split up that big TPA box into smaller boxes. Check out this:

Simba Code:
procedure findColorz();var  x, y: integer;  TPA: TPointArray;  ATPA: T2DPointArray;begin  findColorsSpiralTolerance(x, y, TPA, 5644066, mainScreen.getBounds(), 10, colorSetting(2, 0.10, 1.02));  if length(TPA) < 1 then    exit;  ATPA := TPA.toATPA(30, 30);  smartImage.debugATPA(ATPA);end;

You will see I have added new variable called ATPA and I've declared this is a T2DPointArray (I could also have declared it as Array of TPointArray which is the same thing). I have then used a function to convert my TPA into an ATPA, this function is found in tpointarrays.simba, found in the types folder (this file contains many functions that you can use to manipulate TPAs and ATPAs).

Simba Code:
function TPointArray.toATPA(const w, h: integer): T2DPointArray; overload;

The w and h is the width and height of the new TPAs you’re going to make from the original big TPA. In my code above, I’m splitting that big box into smaller boxes of 30 by 30 pixels. Basically the syntax is this:

nameOfYourTPA.toATPA(widthOfBox,heightOfBox)

You will also notice I’ve deleted the old TPA debug code, and added in:

Simba Code:
smartImage.debugATPA(ATPA);

This will draw all the individual TPAs in our ATPA on smart, and also draw their index number (i.e. their position in the array). Mine turned out like this:

You can see we now have an ATPA which consists of 5 TPAs. The TPAs are arranged from left to right in the array (as seen by the numbers in the image) like this:

ATPA := [TPA0, TPA1, TPA2, TPA3, TPA4];

If I told Simba to click the first TPA in the array, it would click the banker all the way on the left, thus making our player run all the way over there to bank. What if I wanted to make it click on the closest banker, which in this case is the 4th banker in the array. What I’m going to do now is sort the ATPA from a point, which will be the player. To do this I’m going to use the function:

Simba Code:
ATPA.sortFromMidPoint(point: TPoint);

All I've done here is add 1 line. It sorts the ATPA from the playerPoint. What I’m hoping to happen is the 4th banker in the previous image will now become the first TPA in the array:

Simba Code:
procedure findColorz();var  x, y: integer;  TPA: TPointArray;  ATPA: T2DPointArray;begin  findColorsSpiralTolerance(x, y, TPA, 5644066, mainScreen.getBounds(), 10, colorSetting(2, 0.10, 1.02));  if length(TPA) < 1 then    exit;  ATPA := TPA.toATPA(30, 30);  ATPA.sortFromMidPoint(mainscreen.playerPoint);  smartImage.debugATPA(ATPA);end;

I’m going to run this again and see how the debug output changes:

Now you can see that the order of the TPAs in the array have changed, and they are sorted from closest to me

All that I have left to do now is show you how to click on a TPA in the array. What I'm going to do is use a for … to … do loop, to loop through each index in the array, move the mouse to it and check if the mouseOverText matches - if it does match it will click it, and break out of the loop. I’ll paste the code here and then explain it:

Simba Code:
for i := 0 to high(ATPA) dobegin  mouse(middleTPA(ATPA[i]), MOUSE_MOVE);  if isMouseOverText(['anker'], 500) then  begin    fastClick(MOUSE_LEFT);    break;  end;end;

The high(ATPA) is just returning the highest index in the array. Because arrays start at 0, this would return 4, not 5 (i.e. [0, 1, 2, 3, 4] or ATPA := [TPA0, TPA1, TPA2, TPA3, TPA4]). The i is an integer variable which increases by 1 each time it loops. You can see it starts at 0. So the for… to … do loop is basically this: For 0 to 4 do, meaning it will repeat up to 5 times. I then move the mouse to the middle of each TPA in the ATPA array:

Simba Code:
mouse(middleTPA(ATPA[i]), MOUSE_MOVE);

The i represents the index in the array, which as I said before increases by 1 each time it loops. Because I starts at 0, the first time it loops, it is simply this:

Simba Code:
mouse(middleTPA(ATPA[0]), MOUSE_MOVE);

In my case, it will move the mouse to the middle of the closest banker, because remember I made the closest TPA the first in the array. You can see after it moves the mouse, it checks if the mouseOverText matches. If it does match, it will left click and break out of the loop, whereas if it doesn't match, it will begin the next loop, and move the mouse to the second index in the array ATPA[1].

And that is all there is too it! It’s not that hard when you break it down is it? Here is all the code:

Simba Code:
procedure findColorz();var  x, y, i: integer;  TPA: TPointArray;  ATPA: T2DPointArray;begin  if not isLoggedIn() then    exit;  findColorsSpiralTolerance(x, y, TPA, 5644066, mainScreen.getBounds(), 10, colorSetting(2, 0.10, 1.02));  if (Length(TPA) < 1) then    exit;  ATPA := TPA.toATPA(30, 30);  ATPA.sortFromMidPoint(mainscreen.playerPoint);  smartImage.debugATPA(ATPA);  for i := 0 to high(ATPA) do  begin    mouse(middleTPA(ATPA[i]), MOUSE_MOVE);    if isMouseOverText(['anker'], 500) then    begin      fastClick(MOUSE_LEFT);      break;    end;  end;end;

6.6 The mineRocks procedure

Aim of the procedure:
To find a clay rock, click it, wait until we have mined it, then click the next rock. We will repeat this until the player’s backpack is full.

The following SRL6 functions will be used in this procedure:
Simba Code:
function isLoggedIn(): boolean;procedure TTimeMarker.start();function TTimeMarker.getTime(): LongWord;function claimSpinTicket(): boolean;

Finally we are here - the last procedure in our script! I'm going to use very similar code to that in the TPA/ATPA tutorial above, but with a few modifications:

Simba Code:
procedure mineRocks();var  x, y, i: integer;  TPA: TPointArray;  ATPA: T2DPointArray;begin  if not isLoggedIn() then    exit;  findColorsSpiralTolerance(x, y, TPA, 7916778, mainScreen.getBounds(), 10, colorSetting(2, 0.17, 2.72));  if (Length(TPA) < 1) then    exit;  ATPA := TPA.toATPA(30, 30);  ATPA.filterBetween(0, 10); //I added this line  ATPA.sortFromMidPoint(mainscreen.playerPoint);  smartImage.debugATPA(ATPA);  for i := 0 to high(ATPA) do  begin    mouse(middleTPA(ATPA[i]), MOUSE_MOVE);    if isMouseOverText(['Clay', 'lay'], 500) then    begin      fastClick(MOUSE_LEFT);      smartImage.clear;      break;    end;  end;  tabBackpack.waitForShift(5000); // and I added this lineend;

What I have changed is the mouseOverText, the colors from ACA and I've added in 2 new lines. The first is the ATPA.filterBetween(0, 10). What this does is it filters out all the TPointArrays that have between 0 and 10 TPoints, because I don't want any tiny TPAs included in my array. Secondly I have added in tabBackpack.waitForShift(5000) which will wait for up to 5 seconds for the backpack count to change. Basically, after clicking a rock, it will wait up to 5 seconds for the clay to appear in my backpack. I've commented out the for .. to .. do loop so I can test if my ATPA is working correctly:

Yep, that looks good! All I need to do now is put the whole thing in a repeat ... until loop:

Simba Code:
procedure mineRocks();var  x, y, i: integer;  TPA: TPointArray;  ATPA: T2DPointArray;  mineTimer: TTimeMarker;begin  if not isLoggedIn() then    exit;  mineTimer.start();  repeat    findColorsSpiralTolerance(x, y, TPA, 7916778, mainScreen.getBounds(), 10, colorSetting(2, 0.17, 2.72));    if (Length(TPA) < 1) then      exit;    ATPA := TPA.toATPA(30, 30);    ATPA.filterBetween(0, 10);     ATPA.sortFromMidPoint(mainscreen.playerPoint);    smartImage.debugATPA(ATPA);    for i := 0 to high(ATPA) do    begin      mouse(middleTPA(ATPA[i]), MOUSE_MOVE);      if isMouseOverText(['Clay', 'lay'], 500) then      begin        fastClick(MOUSE_LEFT);        smartImage.clear;        break;      end;    end;    tabBackpack.waitForShift(5000);     claimSpinTicket();  until tabBackpack.isFull() or (mineTimer.getTime() > 300000);end;

I have added all of that code into a repeat loop. You can see it will keep repeating until the backpack is full, or we have been mining for more than 5 minutes (300 seconds). I've also added claimSpinTicket, which checks for a spin ticked in the backpack and claims it if found (you get tickets quite often when mining). Let's test it - it works great! It looks like we have finished writing the script...or have we? There is 1 thing left to add - the progress report of course! Since I'm in a good mood I'll put that in the next section.

6.7 Bonus procedure: progressReport

Aim of the procedure:
To calculate and print the progress report to the debug box.

The following SRL6 functions will be used in this procedure:
Simba Code:
function timeRunning(TheType: Integer = TIME_FORMAL_LONG):

What I'm going to put in the progress report is the following:

• Name of my script
• Time it has been running
• Number of clay mined
• Profit per hour

The easiest way for me to calculate the number of ore mined, is just to calculate the number of loads done and multiply it by 28. Then I can calculate the profit from the number of clay mined:

Simba Code:
procedure progressReport();var  oreMined, profit, profitPerHour: integer;begin  oreMined := LoadsDone * 28;  profit := (oreMined * 300); //assuming clay is 300 each  profitPerHour := round((profit * 60) / (getTimeRunning() / 60000));end;

You will notice I haven't declared the LoadsDone variable here. I will need to declare this globally because I'll also be using the LoadsDone variable in the depositClay procedure to increase the LoadsDone each time it deposits 28 clay. So after declaring that globally, let's revisit the depositClay procedure and add an inc():

Simba Code:
procedure depositClay();var  bankTimer: TTimeMarker;begin  if not isLoggedIn() then    exit;  if depositBox.isOpen(5000) then  begin    bankTimer.start();    repeat      if (depositBox.count > 0) then      begin        depositBox.quickDeposit(QUICK_DEPOSITBOX_INVENTORY);        wait(gaussRangeInt(500, 750));      end;    until(depositBox.isEmpty()) or (not isLoggedIn()) or (bankTimer.getTime() > 10000);        inc(LoadsDone); // increase LoadsDone by 1  end;  depositBox.close();  end;

Cool, now each time it deposits a load, it will increase the global variable LoadsDone by 1. Now, let's finish writing the writeLn statements in the progressReport:

Simba Code:
procedure progressReport();var  oreMined, profit, profitPerHour: integer;begin  oreMined := LoadsDone * 28;  profit := (oreMined * 305);  profitPerHour := round((profit * 60) / (getTimeRunning() / 60000));  writeLn('========================================================');  writeLn('The Mayor''s Clay Disintegrator Annihilator Obliterator');  writeLn('Time Run: ' + timeRunning);  writeLn('Ores Mined: ' + intToStr(oreMined));  writeLn('Loads Done: ' + intToStr(loadsDone));  writeLn('Profit Made: ' + intToStr(profit));  writeLn('Per Hour: ' + intToStr(profitPerHour));  writeLn('========================================================');end;

Remember, all of those variables are integers, so I need to convert them. I also need to add progressReport into my main loop so it updates with each load.

6.8 Cleanup and the final script

Now that the script is finished, I just want to tweak the main loop a little bit to improve the logic. Instead of having this:

Simba Code:
{Main Loop}begin  clearDebug();  smartEnableDrawing := true;  disableSRLDebug := false;  setupSRL();  declarePlayers();  SPS.setup('CLAY_MAP', RUNESCAPE_OTHER);   if not isLoggedIn() then  begin    players[currentPlayer].login();    exitTreasure();     mainScreen.setAngle(MS_ANGLE_HIGH);    minimap.setAngle(MM_DIRECTION_NORTH);  end;  teleToClanCamp();  runToMine();  mineRocks();  teleToPortSarim();  findDepositBox();  depositClay();end.

I'm changing it to this:

Simba Code:
{Main Loop}begin  clearDebug();  smartEnableDrawing := true;  setupSRL();  declarePlayers();  SPS.setup('CLAY_MAP', RUNESCAPE_OTHER);    repeat    if not isLoggedIn() then    begin      players[currentPlayer].login();      exitTreasure();       mainScreen.setAngle(MS_ANGLE_HIGH);      minimap.setAngle(MM_DIRECTION_NORTH);    end;    if tabBackpack.isFull() then    begin      teleToPortSarim();      findDepositBox();      depositClay();    end;    progressReport();    teleToClanCamp();    runToMine();    mineRocks();  until(false);end.

So, if you start with a full backpack it won't go to the mine and try and mine the rocks, it will teleport to the bank straight away. This is also useful if it logs back in after a break (or the 6 hour limit) and it has a full inventory. Awesome, we finished, here is the complete script, SPS map and a sample progress report for your pleasure:

Simba Code:
program MayorClayMiner;{$DEFINE SMART}{$I SRL-6/SRL.simba}{$I SPS/lib/SPS-RS3.Simba}var LoadsDone: integer;procedure declarePlayers();begin setLength(players, 1); with players[0] do begin loginName := 'username'; password := 'password'; isActive := true; isMember := true; end currentPlayer := 0;end;procedure teleToClanCamp();var x, y, vexillumDTM: integer; p: TPoint; teleTimer: TTimeMarker;begin if not isLoggedIn() then exit; gameTabs.openTab(TAB_EQUIPMENT); vexillumDTM := DTMFromString('mggAAAHicY2NgYGBkZWDghmJmIP7JwsDwA4ibGBkYaoC4DYinAHErlJ/WvhWoiwkDSzJgB4w4MAQAAJLTBxg='); if findDTM(vexillumDTM, x, y, tabBackPack.getBounds()) then begin mouse(x, y, 3, 3, MOUSE_MOVE); if isMouseOverText(['Clan', 'vex']) then begin fastClick(MOUSE_RIGHT); if chooseOption.select(['Tele']) then begin writeLn('We clicked the teleport option'); teleTimer.start(); repeat wait(randomRange(2000, 3000)); until (not isLoggedIn()) or (minimap.findSymbol(p, MM_SYMBOL_STORE, minimap.getBounds()) or (teleTimer.getTime() > 20000)); end; end; end else writeLn('Failed to find the vex DTM');end;procedure runToMine();var pathToMine: TPointArray;begin if not isLoggedIn() then exit; pathToMine := [Point(130, 128), Point(152, 163), Point(145, 194), Point(147, 229), Point(141, 256), Point(140, 285), Point(157, 291)]; if SPS.walkPath(pathToMine) then minimap.waitPlayerMoving() else writeLn('We failed to walk to the mine');end;procedure mineRocks();var x, y, i: integer; TPA: TPointArray; ATPA: T2DPointArray; mineTimer: TTimeMarker;begin if not isLoggedIn() then exit; mineTimer.start(); repeat findColorsSpiralTolerance(x, y, TPA, 7916778, mainScreen.getBounds(), 10, colorSetting(2, 0.17, 2.72)); if (Length(TPA) < 1) then exit; ATPA := TPA.toATPA(30, 30); ATPA.filterBetween(0, 10); ATPA.sortFromMidPoint(mainscreen.playerPoint); smartImage.debugATPA(ATPA); for i := 0 to high(ATPA) do begin mouse(middleTPA(ATPA[i]), MOUSE_MOVE); if isMouseOverText(['Clay', 'lay'], 500) then begin fastClick(MOUSE_LEFT); smartImage.clear(); break; end; end; tabBackpack.waitForShift(5000); until tabBackpack.isFull() or (mineTimer.getTime() > 300000);end;procedure teleToPortSarim();var pathToDepositBox: TPointArray; p: TPoint;begin if not isLoggedIn() then exit; repeat lodestoneScreen.teleportTo(LOCATION_PORT_SARIM); wait(randomRange(14500, 16000)); until (not isLoggedIn()) or minimap.findSymbol(p, MM_SYMBOL_SHOP_FISHING, minimap.getBounds()); pathToDepositBox := [Point(287, 392), Point(302, 386), Point(331, 384), Point(346, 381), Point(349, 354), Point(351, 331), Point(353, 315), Point(379, 317), Point(403, 317), Point(423, 318)]; if SPS.walkPath(pathToDepositBox) then minimap.waitPlayerMoving() else writeLn('We failed to walk to the deposit box');end;procedure findDepositBox();var x, y, i: integer;begin if not isLoggedIn() then exit; repeat mainscreen.findObject(x, y, 5270142, 5, colorSetting(2, 0.07, 0.15), mainscreen.playerPoint, 30, 50, 50, ['eposit', 'box'], MOUSE_LEFT); wait(randomRange(1000, 2000)); inc(i); until depositBox.isOpen() or (i >= 15);end;procedure depositClay();var bankTimer: TTimeMarker;begin if not isLoggedIn() then exit; if depositBox.isOpen() then begin bankTimer.start(); repeat if (depositBox.count > 0) then begin depositBox.quickDeposit(QUICK_DEPOSITBOX_INVENTORY); wait(gaussRangeInt(500, 750)); end; until(depositBox.isEmpty()) or (not isLoggedIn()) or (bankTimer.getTime() > 10000); inc(LoadsDone); end; depositBox.close();end;procedure progressReport();var oreMined, profit, profitPerHour: integer;begin oreMined := LoadsDone * 28; profit := (oreMined * 305); profitPerHour := round((profit * 60) / (getTimeRunning() / 60000)); writeLn('========================================================'); writeLn('The Mayor''s Clay Disintegrator Annihilator Obliterator'); writeLn('Time Run: ' + timeRunning); writeLn('Ores Mined: ' + intToStr(oreMined)); writeLn('Loads Done: ' + intToStr(loadsDone)); writeLn('Profit Made: ' + intToStr(profit)); writeLn('Per Hour: ' + intToStr(profitPerHour)); writeLn('========================================================');end;{Main Loop}begin clearDebug(); smartEnableDrawing := true; setupSRL(); declarePlayers(); SPS.setup('CLAY_MAP', RUNESCAPE_OTHER); repeat if not isLoggedIn() then begin players[currentPlayer].login(); exitTreasure(); mainScreen.setAngle(MS_ANGLE_HIGH); minimap.setAngle(MM_DIRECTION_NORTH); end; if tabBackpack.isFull() then begin teleToPortSarim(); findDepositBox(); depositClay(); end; progressReport(); teleToClanCamp(); runToMine(); mineRocks(); until(false);end. Progress Report: ======================================================== The Mayor's Clay Disintegrator Annihilator Obliterator Time Run: 13m 05s Ores Mined: 140 Loads Done: 5 Profit Made: 42700 Per Hour: 195693 ======================================================== Conclusion Hey wait a minute, that gets nearly 200k per hour on f2p, should I put this in the junior members section Last edited by The Mayor; 02-01-2015 at 03:00 AM. Reason: Removed squeelOfFortune 2. amazing! Rep+ 3. my tutorial 4. Sweet Lord Baby Jesus Mayor, you weren't kidding when you said this tut would be huge! Nice job man! I would + rep, but sadly, I must spread some more around :'( 5. Wow must have taken up a lot of time, nice job man! 6. GJ, this one defo needed 7. SRL Junior Member Join Date Jan 2012 Posts 550 Mentioned 2 Post(s) Quoted 177 Post(s) I think it's about time I stopped being lazy and actually started scripting. This actually cleared up quite a few questions I had before. +repped and above all else: THANK YOU! 8. SRL Junior Member Join Date Sep 2012 Posts 71 Mentioned 2 Post(s) Quoted 26 Post(s) An enjoyable read 9. Simply amazing. Rep for this! This will really help newcomers. Spectacular job man! How many places did you have those backed up to while you were writing it?? 10. Originally Posted by Spartan 117 Simply amazing. Rep for this! This will really help newcomers. Spectacular job man! How many places did you have those backed up to while you were writing it?? I didn't back it up as I actually wrote most of it in notepad while I was away on holiday (I didn't have access to the internet or Simba on my laptop). I just took the screenshots and fixed it up when I got back. 11. Originally Posted by The Mayor I didn't back it up as I actually wrote most of it in notepad while I was away on holiday (I didn't have access to the internet or Simba on my laptop). I just took the screenshots and fixed it up when I got back. Ballsy haha. I would have been so worried something would go wrong! 12. SRL Junior Member Join Date Feb 2012 Posts 179 Mentioned 0 Post(s) Quoted 84 Post(s) Wow thanks man! That's exactly what I was waiting for since SRL 6 came out! 13. Read through and started wishing I had this to start scripting with. Really good work breaking everything down to an understandable level. +rep btw I too think the ACA icon is awesome. 14. never noticed that icon before I hope this will bring some activity to SRL 6. An amazing tutorial anyway 15. Originally Posted by Foundry Read through and started wishing I had this to start scripting with. Really good work breaking everything down to an understandable level. +rep btw I too think the ACA icon is awesome. Originally Posted by masterBB never noticed that icon before I hope this will bring some activity to SRL 6. An amazing tutorial anyway thats why you need to watch @YoHoJo; his tutorials! http://www.youtube.com/watch?v=98wVrr6GwyU (around 4:06). 16. SRL Junior Member Join Date Jul 2006 Posts 80 Mentioned 1 Post(s) Quoted 27 Post(s) Thanks so much man, looks ace! Treasure trove of info, will come in incredibly handy. Will try to make a script thats worthy 17. This. Is. AWESOME! Very nice work, Mayor! This was really needed. 18. Originally Posted by Coh3n This. Is. AWESOME! Very nice work, Mayor! This was really needed. Thanks for the cup 19. SRL Junior Member Join Date Jan 2014 Location New Found Land Posts 108 Mentioned 3 Post(s) Quoted 21 Post(s) very thorough, nice job! hands down one of the best tutorials for scripting, period. 20. SRL Junior Member Join Date Mar 2013 Posts 94 Mentioned 0 Post(s) Quoted 22 Post(s) hey, good guide. learnt a lot from it! 21. SRL Junior Member Join Date Mar 2013 Posts 94 Mentioned 0 Post(s) Quoted 22 Post(s) couple of questions. Whenever I go to use only the browser and not SMART, the script just does nothing. I have commented out the steps for SMART. Code: program OpenAllLodestones; //{$DEFINE SMART}              // Always have this to load smart
{$I SRL-6/SRL.simba} // To load the SRL include files {$I SPS/lib/SPS-RS3.Simba}   // To load the SPS include files

procedure declarePlayers();
begin
setLength(players, 1);
with players[0] do
begin
isActive := true;
isMember := true;
end
currentPlayer := 0;
end;

// main loop
begin
clearDebug();               // Clear the debug box
//smartEnableDrawing := true; // So we can draw on SMART
setupSRL();                   // Load the SRL include files

if not isLoggedIn() then             // If player isn't logged in then
begin
exitSquealOfFortune();            // Exit squeal if found
minimap.setAngle(MM_DIRECTION_NORTH);  // Make compass north and angle high
mainScreen.setAngle(MS_ANGLE_HIGH);
end;

end.
How would I make it work on my browser instead of SMART?

22. Originally Posted by rsbots2013

How would I make it work on my browser instead of SMART?
Make sure you are using directX

Originally Posted by Coh3n
[*]Make sure you're in OpenGL mode (for SMART users) or DirectX mode for browser users.

23. SRL Junior Member
Join Date
Mar 2013
Posts
94
Mentioned
0 Post(s)
Quoted
22 Post(s)
that's it. and how do I change the default world when it goes to log in?