PDA

View Full Version : All-In-One RS3 and SRL6 Scripting Tutorial!



The Mayor
01-25-2014, 11:09 AM
http://puu.sh/6v4xp.png
Version: 1.10
Updated: Feb 2015 (exitSquelOfFortune() -> exitTreasure())

Introduction



UPDATE: Please also read my Simplistic Beginners Guide to RS3 Scripting (http://villavu.com/forum/showthread.php?t=109161).

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 (http://villavu.com/forum/showthread.php?t=58935) 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 (http://puu.sh/6xppb.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).


program exampleScript;

procedure chopTree();
begin
// Here would be some code to chop the tree
end;

procedure dropLogs();
begin
// Here would be some code to drop the logs
end;

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:


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:



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:



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:


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.



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.


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).


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


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).


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


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)).


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:


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:


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:


program exampleScript;

function woodCuttingLevel(): integer;
begin
// code to get the player's wood cutting level
end;

procedure chopTree();
begin
if woodCuttingLevel() > 30 then
chopWillows()
else
chopOaks();
end;

procedure dropLogs();
begin
// code to drop logs
end;

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:


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:


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.

http://puu.sh/6tr2Z.png

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:

http://puu.sh/6tTyq.png

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.

http://puu.sh/6tTBa.png


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:


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:


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:


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:

http://puu.sh/6trdk.png

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:

http://puu.sh/6trhX.png


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.

http://puu.sh/6uQoI.png




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:


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 extended

begin
// Main loop
end.


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.


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 1
end;

procedure dropLogs();
begin
// code to drop logs
end;

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:


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 tree
end;

procedure dropLogs();
begin
// code to drop logs
end;

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:


if backpackIsFull() then
walkToBank();
findBanker();
depositLogs();


And this is correct:


if backpackIsFull() then
begin
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:


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:


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:


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




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


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


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)


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:


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:


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:


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


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:


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.


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


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



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



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:


Teleport to the clan camp with Clan Vexillum
Run south to the clay rocks at Remington mine
Mine a full inventory of clay.
Lodestone teleport to Port Sarim and run north to the deposit box.
Find and open the Deposit Box.
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:


procedure teleToClanCamp();
begin
//code here
end;

procedure runToMine();
begin
//code here
end;

procedure mineRocks();
begin
//code here
end;

procedure teleToPortSarim();
begin
//code here
end;

procedure findDepositBox();
begin
//code here
end;

procedure depositClay();
begin
//code here
end;


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:

http://puu.sh/6trpZ.png

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:

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 files

procedure declarePlayers();
begin
setLength(players, 1);
with players[0] do
begin
loginName := 'username';
password := 'password';
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
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:


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 here
end;

procedure runToMine();
begin
//code here
end;

procedure mineRocks();
begin
//code here
end;

procedure teleToPortSarim();
begin
//code here
end;

procedure findDepositBox();
begin
//code here
end;

procedure depositClay();
begin
//code here
end;


{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
PowersScreen
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:

http://puu.sh/6v2q3.png

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.


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:


(*
isLoggedIn()
~~~~~~~~~~~~

.. code-block:: pascal

function isLoggedIn(): boolean;

Returns true if a player is logged in, uses the center of the compass work out
the result.

.. note::

- by Olly & Coh3n
- Last updated: 11 August 2013 by Coh3n

Example:

.. 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 (http://villavu.com/forum/forumdisplay.php?f=197), 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 (http://villavu.com/forum/showthread.php?t=109161).




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:

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

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


TDebug.DEBUG
TDebug.HEADER
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:



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:

HEADER
--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:


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




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

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:


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:


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.


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:


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:

http://puu.sh/6trua.png

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.

http://puu.sh/6trvW.png

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 (http://villavu.com/forum/showthread.php?t=84360)(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:

http://puu.sh/6trDf.png

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:

http://puu.sh/6trJr.png

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.

http://puu.sh/6trMV.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 (http://villavu.com/forum/showthread.php?t=80134). 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:

http://puu.sh/6trQu.png

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:


[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:
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:



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:


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:

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:

http://puu.sh/6ts1b.png

Let’s start writing the procedure:


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:

http://puu.sh/6vH1l.png

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


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:


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:


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:


//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:

http://puu.sh/6vJIs.png

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:

http://puu.sh/6tsaz.png

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:

http://puu.sh/6tsjj.png

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:

http://puu.sh/6tsnq.pnghttp://puu.sh/6tsos.png

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:

http://puu.sh/6tspT.png

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:

procedure loadDTMs();
var
vexilumDTM: integer;
begin
vexilumDTM := DTMFromString('mggAAAHicY2NgYGBkZWDghmJmIP7JwsDwA4 ibGBkYaoC4DYinAHErlJ/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:
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):

http://puu.sh/6vMP1.png


procedure teleToClanCamp();
var
vexillumDTM, x, y: integer;

begin
if not isLoggedIn() then
exit;

gameTabs.openTab(TAB_EQUIPMENT);

vexillumDTM := DTMFromString('mggAAAHicY2NgYGBkZWDghmJmIP7JwsDwA4 ibGBkYaoC4DYinAHErlJ/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:


procedure teleToClanCamp();
var
x, y, vexillumDTM: integer;
p: TPoint;
teleTimer: TTimeMarker;
begin
if not isLoggedIn() then
exit;

gameTabs.openTab(TAB_EQUIPMENT);

vexillumDTM := DTMFromString('mggAAAHicY2NgYGBkZWDghmJmIP7JwsDwA4 ibGBkYaoC4DYinAHErlJ/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:

http://puu.sh/6vMdk.png

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 (http://villavu.com/forum/showthread.php?t=26944).

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

http://puu.sh/6tsUQ.png


The following is the layout of the ACA interface:

http://puu.sh/6ttKD.png

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:

http://puu.sh/6vO9d.png

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:

http://puu.sh/6ttZU.png

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:

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:

http://puu.sh/6vPiJ.png

Not bad, lets pick a few more:

http://puu.sh/6vPkU.png

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)



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:

http://puu.sh/6w7FT.png

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

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:


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:

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:

TPA := [TPoint0, TPoint1, TPoint2, TPoint3, TPoint4, TPoint5, TPoint6];

So if it didn’t find any colors, the array would be empty:

TPA := [];


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

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:


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:

http://puu.sh/6w7Hq.png

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:

http://puu.sh/6w7I7.png

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:


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).

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:

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:

http://puu.sh/6w7IP.png

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:

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:


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:

http://puu.sh/6w7JH.png

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:


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;


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:

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:

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:


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:

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:


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 line

end;


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:

http://puu.sh/6vTTm

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


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:

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
Loads done
Profit made
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:


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


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:


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:


{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:


{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:


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('mggAAAHicY2NgYGBkZWDghmJmIP7JwsDwA4 ibGBkYaoC4DYinAHErlJ/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.


http://i.imgur.com/F26F9cX.png


================================================== ======
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 :garfield:

The Mayor
01-25-2014, 11:10 AM
Reserved.

The Mayor
01-25-2014, 11:11 AM
Reserved#2.

Hoodz
01-25-2014, 12:27 PM
amazing!

Rep+

Sjoe
01-25-2014, 02:04 PM
my tutorial :(

Kyle
01-25-2014, 02:13 PM
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 :'(

Ashaman88
01-25-2014, 02:13 PM
Wow must have taken up a lot of time, nice job man!

rj
01-25-2014, 02:34 PM
GJ, this one defo needed

Thanatos
01-25-2014, 02:35 PM
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!

Pavement
01-25-2014, 05:24 PM
An enjoyable read

Spartan 117
01-26-2014, 10:30 AM
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??

The Mayor
01-26-2014, 10:34 AM
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.

Spartan 117
01-26-2014, 10:44 AM
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!

Nufineek
01-26-2014, 09:49 PM
Wow thanks man! That's exactly what I was waiting for since SRL 6 came out!

Foundry
01-26-2014, 10:49 PM
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.

masterBB
01-26-2014, 10:50 PM
never noticed that icon before :o

I hope this will bring some activity to SRL 6. An amazing tutorial anyway ;)

Hoodz
01-26-2014, 11:33 PM
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.


never noticed that icon before :o

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).

http://imagizer.imageshack.us/v2/640x480q90/17/jddi.png

Kaladin
01-27-2014, 02:37 AM
Thanks so much man, looks ace!
Treasure trove of info, will come in incredibly handy.

Will try to make a script thats worthy :D

Coh3n
01-27-2014, 06:01 PM
This. Is. AWESOME!

Very nice work, Mayor! This was really needed. :)

The Mayor
01-27-2014, 08:24 PM
This. Is. AWESOME!

Very nice work, Mayor! This was really needed. :)

Thanks for the cup :o

N1234
01-27-2014, 10:13 PM
very thorough, nice job! hands down one of the best tutorials for scripting, period.

rsbots2013
02-02-2014, 08:12 PM
hey, good guide. learnt a lot from it!

rsbots2013
02-02-2014, 11:23 PM
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.


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
loginName := 'username';
password := 'password';
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
declarePlayers(); // Set up your username/pass

if not isLoggedIn() then // If player isn't logged in then
begin
players[currentPlayer].login(); // Log them in
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?

The Mayor
02-02-2014, 11:41 PM
How would I make it work on my browser instead of SMART?

Make sure you are using directX


Make sure you're in OpenGL mode (for SMART users) or DirectX mode for browser users.

rsbots2013
02-03-2014, 12:12 AM
that's it. and how do I change the default world when it goes to log in?

The Mayor
02-03-2014, 12:20 AM
that's it. and how do I change the default world when it goes to log in?


procedure declarePlayers();
begin
setLength(players, 1);
with players[0] do
begin
loginName := 'username';
password := 'password';
isActive := true;
isMember := true;
world := 108; //This
end
currentPlayer := 0;
end;

ruskoisadude
02-15-2014, 08:22 PM
i didnt even have to look i knew it be you writing this mayor you rock dude

SOUPalmighty
02-18-2014, 02:54 AM
Awesome tut, has helped me tons.

Was wondering in future updates if you're going to include painting a progress report on SMART.

The Mayor
02-18-2014, 07:04 AM
Awesome tut, has helped me tons.

Was wondering in future updates if you're going to include painting a progress report on SMART.

I guess I could a a little section about that. Drawing bitmaps + text. I might put it in one of the reserves.

SOUPalmighty
02-18-2014, 07:32 AM
I guess I could a a little section about that. Drawing bitmaps + text. I might put it in one of the reserves.

Very cool, im just looking for something that outlines the diff ways to do it. I got it figured out on my Flax spinner but i think im handling it the most complicated way lol.

Linked in my sig, if you want to take a look

RlagkRud
02-28-2014, 09:23 PM
incredible guide!

i have a couple questions regarding tpas:
1. the new aca tool has a cts option 3. do you recommend using that over option 2?

2. for the object height/width does it have to be exact? what's a good way of accurately measuring this?

3. what does findcolorspiral offer over just findcolor?

4. for mincount how does the script identify that these pixels are a 'part' of the same object?

I also get a access violation error when I attempt to use smartdebug for tpa/atpas

Im Dooby
03-01-2014, 01:51 AM
So within Simba the minimap is completely black whenever I log in and I'm not able to see any detail of the map except the mini-map markers like a mining spot, trees, bank, etc. How do I fix this? Because I don't think I'll be able to make the pathway if there is no color in the minimap although, I haven't yet tried going to the actual runescape client then taking that picture and just seeing if it'll still work although the map is colorless on the Simba RS3 client.

Thanks,
Jake

The Mayor
03-04-2014, 07:56 PM
So within Simba the minimap is completely black whenever I log in and I'm not able to see any detail of the map except the mini-map markers like a mining spot, trees, bank, etc. How do I fix this? Because I don't think I'll be able to make the pathway if there is no color in the minimap although, I haven't yet tried going to the actual runescape client then taking that picture and just seeing if it'll still work although the map is colorless on the Simba RS3 client.

Thanks,
Jake

Sounds like the openGL minimap glitch. It's a Jagex issue, but can supposedly be fixed by logging out and in again.

RlagkRud
03-05-2014, 05:51 AM
Nobody can answer my questions? :(

Olly
03-05-2014, 06:12 AM
incredible guide!

i have a couple questions regarding tpas:
1. the new aca tool has a cts option 3. do you recommend using that over option 2?

2. for the object height/width does it have to be exact? what's a good way of accurately measuring this?

3. what does findcolorspiral offer over just findcolor?

4. for mincount how does the script identify that these pixels are a 'part' of the same object?

I also get a access violation error when I attempt to use smartdebug for tpa/atpas

6am, making it quick..

No i prefer cts2, its alot faster + new aca doesn't give you the best tolerance / modifiers for cts3

No it doesn't have to be exact and its measured by pixels, this is what sizes simba will try and split the TPointArray into.

FindColorSpiral searches out from from the middle, which is a more human way than row by row although it is useless when playing with tpa's since your most likely to sort it.

mincount - It doesn't it's just useful for removing small random pixels it may find on the screen

masterBB
03-05-2014, 10:49 AM
I don't recommend CTS 3 for runescape at all. Well, maybe for some special cases. It is made to be closer to human perception, not to give more accurate results. But the calculations are so slow.

RlagkRud
03-05-2014, 10:22 PM
6am, making it quick..

No i prefer cts2, its alot faster + new aca doesn't give you the best tolerance / modifiers for cts3

No it doesn't have to be exact and its measured by pixels, this is what sizes simba will try and split the TPointArray into.

FindColorSpiral searches out from from the middle, which is a more human way than row by row although it is useless when playing with tpa's since your most likely to sort it.

mincount - It doesn't it's just useful for removing small random pixels it may find on the screen

Tahnks for the reply!

One more question. How does simba determine if a certain TPoint goes inside a certain TPA that's in a ATPA?
For example, let's see I have a green tree in the middle and random green specks around it. How does simba know that only the green tree TPoints go into the same array while the green specks go into their own, separate TPA (maybe even a separate array for each green speck?)

The Mayor
03-08-2014, 09:36 PM
Tahnks for the reply!

One more question. How does simba determine if a certain TPoint goes inside a certain TPA that's in a ATPA?
For example, let's see I have a green tree in the middle and random green specks around it. How does simba know that only the green tree TPoints go into the same array while the green specks go into their own, separate TPA (maybe even a separate array for each green speck?)

This is what the width/height parameters in most TPA/ATPA functions are for. If the green specks are a certain distance from the other green points (the ones on the tree) then they will get put into another array.

RlagkRud
03-09-2014, 01:46 AM
This is what the width/height parameters in most TPA/ATPA functions are for. If the green specks are a certain distance from the other green points (the ones on the tree) then they will get put into another array.

Ahh I see. This makes a lot of sense. Thanks!

Arseface
03-28-2014, 09:40 PM
I followed this tutorial and my clay mining script mostly works, but it won't deposit in the deposit box.
It opens the box fine, but when it goes to deposit all I get is a bunch of this.

-- TRSMainscreen.findObject()
---- No colors found
-- TRSMainscreen.findObject(): False

I've tried digging through the include and going to the functions that depositbox calls and switching out the functions. There was no change in messages and it didn't fix.

Here is my current code.

procedure depositClay();
var
bankTimer: TTimeMarker;

begin
if not isLoggedIn() then
exit;

if depositBox.isOpen(500) then
begin

bankTimer.start();

repeat
if (depositBox.count > 0) then
begin
TRSBankScreen.quickDeposit(QUICK_DEPOSIT_INVENTORY );
end;
until(depositBox.isEmpty()) or (not isLoggedIn()) or (bankTimer.getTime() > 2500);

end;

depositBox.close();

end;

I wanted to start a separate thread about this issue, but I can't manage to start any threads or find a list of admins/webmasters to contact about the issue.

The Mayor
03-29-2014, 02:29 AM
I followed this tutorial and my clay mining script mostly works, but it won't deposit in the deposit box.
It opens the box fine, but when it goes to deposit all I get is a bunch of this.

-- TRSMainscreen.findObject()
---- No colors found
-- TRSMainscreen.findObject(): False


Based on this, I'd say it isn't the depositClay procedure, but the findDepositBox procedure that is the problem. It successfully found the deposit box and opened it, but it doesn't recognize it's open. Because it doesn't think it's open, it keeps looking for the deposit box color, but it can't find it because the deposit box interface is blocking the screen (which is why you get the no color found error).

As you can see, it probably prints that error 15 times until it breaks out of the loop:

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;


If your interfaces are correctly set, then depositBox.isOpen() must be broken due to a game update. You can file a bug report here (http://villavu.com/forum/project.php?projectid=10) and one of the SRL developers will fix it ASAP.

Arseface
03-29-2014, 06:40 AM
Based on this, I'd say it isn't the depositClay procedure, but the findDepositBox procedure that is the problem. It successfully found the deposit box and opened it, but it doesn't recognize it's open. Because it doesn't think it's open, it keeps looking for the deposit box color, but it can't find it because the deposit box interface is blocking the screen (which is why you get the no color found error).

As you can see, it probably prints that error 15 times until it breaks out of the loop:

until depositBox.isOpen() or (i >= 15);

If your interfaces are correctly set, then depositBox.isOpen() must be broken due to a game update. You can file a bug report here (http://villavu.com/forum/project.php?projectid=10) and one of the SRL developers will fix it ASAP.Ah, didn't think to count the errors. I figured it was timing out because of the bankTimer.

I'm pretty sure all my interfaces are correctly set, and since the script didn't continue into the next procedure after finishing the error loop it seems like .isOpen() being busted is the most likely.

Bug posted. Thanks for the quick reply on top of the amazing tutorial.

Godless
04-18-2014, 03:00 AM
This looks like a wealth of information and a better place to start learning than I could have hoped for. Will make a mental note to give this a thorough read after the Easter break. Who knows... Something might click in this dull brain of mine! :)

jayman19981
04-22-2014, 05:10 PM
How do i make a procedure that will select an option when talking to a npc?

The Mayor
04-22-2014, 08:04 PM
On phone at the moment so this might look a little messy

If findColorTolerance(etc... ) then
If isMouseOverText([`banker`]) then
Begin
Fastclick(MOUSE_RIGHT);
ChooseOptions(['attack', 'walk']);
End;
End;


E: jayman19981 so I realised that you might be talking about the conversation box, in which case you can use the function:


if converstionBox.isOpen() then
conversationBox.selectOption(2); //what ever number the option is


I think last time I tried that it was a little buggy. You can look at the bear fur script for more ideas.

Ian
04-22-2014, 08:51 PM
On phone at the moment so this might look a little messy

If findColorTolerance(etc... ) then
If isMouseOverText([`banker`]) then
Begin
Fastclick(MOUSE_RIGHT);
ChooseOptions([`attack`, `walk ;])
End;
End;


Fixed quotes:

if findColorTolerance(etc... ) then
if isMouseOverText(['banker']) then
begin
Fastclick(MOUSE_RIGHT);
ChooseOptions(['attack', 'walk']);
end;
end;

jayman19981
04-22-2014, 11:34 PM
thanks.

And also procedure that detects black minimap on openGL and then logs out and back in.

The Mayor
04-23-2014, 12:46 AM
thanks.

And also procedure that detects black minimap on openGL and then logs out and back in.

Haven't tested this but it should work:


function isMapGlitched(): boolean;
begin
result := (round(minimap.getColorPercent(minimap.getBlackBac kground(), 0)) > 25);
end;

procedure fixGlitch();
begin
if isMapGlitched() then
begin
players[currentPlayer].exitToLobby();
wait(randomRange(7000, 15000));
players[currentPlayer].login();
end else
writeLn('The map looks normal');
end;

jayman19981
04-23-2014, 12:56 AM
Haven't tested this but it should work:


function isMapGlitched(): boolean;
begin
result := (round(minimap.getColorPercent(minimap.getBlackBac kground(), 0)) > 25);
end;

procedure fixGlitch();
begin
if isMapGlitched() then
begin
players[currentPlayer].exitToLobby();
wait(randomRange(7000, 15000));
players[currentPlayer].login();
end else
writeLn('The map looks normal');
end;


nope.. doesn't work.

The Mayor
04-23-2014, 01:19 AM
nope.. doesn't work.

Ok I just took a look and the map isn't actually black, it's the interface colour:


function isMapGlitched(): boolean;
begin
result := countColorTolerance(1774858, minimap.getBounds(), 24) > 15000;
end;


Just call fixGlitch() when you want it to check.

jayman19981
04-23-2014, 03:04 AM
Ok I just took a look and the map isn't actually black, it's the interface colour:


function isMapGlitched(): boolean;
begin
result := countColorTolerance(1774858, minimap.getBounds(), 24) > 15000;
end;


Just call fixGlitch() when you want it to check.

yea works now.. thanks man

jayman19981
04-23-2014, 05:27 PM
Exception in Script: Runtime error: "Access violation" at line 206, column 17 in file "C:\Simba\Includes\SRL-6\lib\interfaces\lodestone.simba"

get this when trying to teleport via loadstone in a procedure, i have updated srl

Ian
04-23-2014, 06:27 PM
Exception in Script: Runtime error: "Access violation" at line 206, column 17 in file "C:\Simba\Includes\SRL-6\lib\interfaces\lodestone.simba"

get this when trying to teleport via loadstone in a procedure, i have updated srl
Please post the code you are trying to use :)

jayman19981
04-23-2014, 06:47 PM
Please post the code you are trying to use :)

procedure fixGlitch();
begin
if isMapGlitched() then
begin
TRSLodestoneScreen.teleportTo(LOCATION_EDGEVILLE);
wait(randomRange(10000, 15000));
TRSLodestoneScreen.teleportTo(LOCATION_LUNAR_ISLE) ;
end else
writeLn('The map looks normal');
end;

The Mayor
04-23-2014, 10:21 PM
procedure fixGlitch();
begin
if isMapGlitched() then
begin
TRSLodestoneScreen.teleportTo(LOCATION_EDGEVILLE);
wait(randomRange(10000, 15000));
TRSLodestoneScreen.teleportTo(LOCATION_LUNAR_ISLE) ;
end else
writeLn('The map looks normal');
end;

Just get rid of the TRS, it's only used within the include.


begin
if isMapGlitched() then
begin
lodestoneScreen.teleportTo(LOCATION_EDGEVILLE);
wait(randomRange(10000, 15000));
lodestoneScreen.teleportTo(LOCATION_LUNAR_ISLE);
end else
writeLn('The map looks normal');
end;

jayman19981
04-24-2014, 01:08 AM
Just get rid of the TRS, it's only used within the include.


begin
if isMapGlitched() then
begin
lodestoneScreen.teleportTo(LOCATION_EDGEVILLE);
wait(randomRange(10000, 15000));
lodestoneScreen.teleportTo(LOCATION_LUNAR_ISLE);
end else
writeLn('The map looks normal');
end;



Yep works now.. this fixes the black minimap glitch on rs

Eejit
04-28-2014, 10:27 PM
Looks like a lot of effort has been put into this tutorial, I'll try using it to help me start with scripting and then post back about how it goes.

rapid_spitfire
05-08-2014, 08:09 PM
Hey, first off thanks for this! I've been hammering all this info into my head and have made quite a bit of progress. I need help with a couple bugs in the script.

After you use your vexillum to teleport to the clanCamp it doesnt select the "yes" option that comes up in the chat. "TELEPORT TO CLAN CAMP?" "1.yes" "2.No" How would i tell it to say yes? (I made a DTM for "yes" haha, i know its the wrong way to do it, and i failed to even implement it)

procedure teleToClanCamp();
var
x, y, vexillumDTM, yes: integer;
p: TPoint;
teleTimer: TTimeMarker;
begin
if not isLoggedIn() then
exit;

gameTabs.openTab(TAB_EQUIPMENT);

vexillumDTM := DTMFromString('mbQAAAHicY2VgYAhnZmBIAOIYIA4CYj8gng HEU4B4IRAvgLLT2rcCVTOhYEkGTMCIBYMBAAfjBqA=');

[B]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;

Also it fails to break out of the loop here, I think the fishing symbol changed or something. until (not isLoggedIn()) or (minimap.findSymbol(p, MM_SYMBOL_STORE, minimap.getBounds()) or (teleTimer.getTime() > 20000));

I hope this was clear <3

The Mayor
05-08-2014, 09:13 PM
Hey, first off thanks for this! I've been hammering all this info into my head and have made quite a bit of progress. I need help with a couple bugs in the script.

After you use your vexillum to teleport to the clanCamp it doesnt select the "yes" option that comes up in the chat. "TELEPORT TO CLAN CAMP?" "1.yes" "2.No" How would i tell it to say yes? (I made a DTM for "yes" haha, i know its the wrong way to do it, and i failed to even implement it)

Also it fails to break out of the loop here, I think the fishing symbol changed or something. until (not isLoggedIn()) or (minimap.findSymbol(p, MM_SYMBOL_STORE, minimap.getBounds()) or (teleTimer.getTime() > 20000));

I hope this was clear <3

Ahh they must have added that yes/no option in a recent update. You can just use:


if conversationBox.selectOption(1) then
writeLn('We selected the first option in the conversation box');


And yea, the mini-map symbols changed a while back, and I don't think the bitmaps have been updated in SRL yet, so it won't recognise the symbols.

rapid_spitfire
05-08-2014, 10:42 PM
Thanks, that method worked for selecting "yes or no". Just for knowledge sake, how would i use the mouse to click on one of the options?
I'm new but would you use mcx1, mcy1, mcx2, mcy2?

The Mayor
05-09-2014, 05:53 AM
Thanks, that method worked for selecting "yes or no". Just for knowledge sake, how would i use the mouse to click on one of the options?
I'm new but would you use mcx1, mcy1, mcx2, mcy2?

There are a number of ways. You could move the mouse to a point (x, y) and then click:


begin
mouse(point(50, 50));
fastClick(MOUSE_LEFT);
end;


Or you could just use a MouseBox (moves the mouse to a random place inside a box, and click if you want to). Good for buttons etc.


procedure boxExample();
var
myBox: TBox;
begin
myBox := intToBox(10, 20, 100, 200);
mouseBox(myBox, MOUSE_LEFT);
end;


Explanation:


procedure boxExample();
var
myBox: TBox; // declaring "myBox" variable as a TBox
begin

// assigning the myBox variable the following coordinates
// x1, y1, x2, y2
//(x1 & y1 top left corner of box, x2, y2 bottom right corner coordinates)
myBox := intToBox(10, 20, 100, 200);

// moving the mouse inside the box and left clicking
// you could have MOUSE_RIGHT or MOUSE_MOVE also
mouseBox(myBox, MOUSE_LEFT);
end;

rapid_spitfire
05-09-2014, 01:51 PM
Thanks dude! You're the best. This is what i came up with

procedure teleToClanCamp();
var
vexillumDTM, x, y: integer;
myBox: TBox;
begin
if not isLoggedIn() then
exit;

gameTabs.openTab(TAB_EQUIPMENT);

vexillumDTM := DTMFromString('mbQAAAHicY2VgYAhnZmBIAOIYIA4CYj8gng HEU4B4IRAvgLLT2rcCVTOhYEkGTMCIBYMBAAfjBqA=');

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
wait(randomRange(200,2400));

myBox := intToBox(258, 494, 328, 510);
mouseBox(myBox, MOUSE_LEFT);

end else
writeLn('Failed to find the vex DTM');
end;
end;

Another thing, Do you think you could explain this line of code for me a bit, i'm confused with tabBackPack.getBounds() mostly.

if findDTM(vexillumDTM, x, y, tabBackPack.getBounds());

rapid_spitfire
05-09-2014, 08:26 PM
Hey I've noticed while its mining it clicks on the same spot on the rock until the inv is full (mouse just stays there and clicks again when the rock is off cooldown), is it possible to make the mouse be a bit more random when clicking on the atpa? I have it so it stays at the same rock mining clay. I'm not trying to be a nussance

The Mayor
05-09-2014, 09:03 PM
if findDTM(vexillumDTM, x, y, tabBackPack.getBounds());

Below are the parameters of that function (if you press ctrl + space in simba the parameters of that function will pop up in a window:

http://puu.sh/8FMCk.png


function findDTM(dtm: integer; var x, y: integer; searchBox: TBox): boolean;


You can see:

The first parameter is the dtm. In this case it is our vexillumDTM. You can see that this has to be an integer (DTMs are always declared as integers).

The second parameter is the output variables x and y, also integers. The function stores the coordinatess of the location where it finds the DTM in these 2 variables (which you can then use later, i.e. move the mouse to x, y).

The third parameter is the search box, which is declared as a TBox. This is the area where you want to search for the DTM. You can make your own TBox to search in (like you did above with that button). The getBounds is a function which automatically returns a TBox around the outside of a particular interface. tabBackPack.getBounds() returns the box around the backpack interface (see picture in tutorial). backScreen.getBounds would return a TBox of the bank screen interface.


myBox := intToBox(258, 494, 328, 510);
if findDTM(vexillumDTM, x, y, myBox);


Or you could combine it to one line:


if findDTM(vexillumDTM, x, y, intToBox(258, 494, 328, 510));






Hey I've noticed while its mining it clicks on the same spot on the rock until the inv is full (mouse just stays there and clicks again when the rock is off cooldown), is it possible to make the mouse be a bit more random when clicking on the atpa? I have it so it stays at the same rock mining clay. I'm not trying to be a nussance

It just clicks the one closest to the player. It will click the 2nd rock if there is no ore on the first rock (unless the first rock spawns too quickly). I haven't looked at this script in 5 months, I'm sure there are a few bugs (and it wasn't meant to be a flawless script, just to act as a tutorial).

rapid_spitfire
05-09-2014, 09:23 PM
Thanks for the quick response. The issue is that it clicks the same spot in the ATPA each time, is there a way to tell the mouse to click in a random spot within the ATPA? This code below is as close as i got (very buggy)

begin
mouse(middleTPA(ATPA[i]), MOUSE_MOVE);

if isMouseOverText(['Clay', 'lay'], 500) then
begin
GetMousePos(x,y);
mouse(x, y, 10, 10, MOUSE_MOVE);
fastClick(MOUSE_LEFT);



smartImage.clear;
break;
end;
end;

The Mayor
05-10-2014, 06:00 AM
Thanks for the quick response. The issue is that it clicks the same spot in the ATPA each time, is there a way to tell the mouse to click in a random spot within the ATPA? This code below is as close as i got (very buggy)

begin
mouse(middleTPA(ATPA[i]), MOUSE_MOVE);

if isMouseOverText(['Clay', 'lay'], 500) then
begin
GetMousePos(x,y);
mouse(x, y, 10, 10, MOUSE_MOVE);
fastClick(MOUSE_LEFT);



smartImage.clear;
break;
end;
end;

Ahh now I understand what you mean. Well you can see I tell it to cilick in the middle of the TPA. Picture those boxes around each rock (like in the tutorial picture), it will move the mouse to the middle of those boxes.


mouse(middleTPA(ATPA[i]), MOUSE_MOVE);


The middleTPA just returns the middle TPoint in a TPA, (in this case the middle TPoint in ATPA[i]).

Instead of clicking the middle, you could click anywhere inside the TPA of the rock. You could replace the middleTPA with something like:


var
rockBounds: TBox;
begin
// colour finding TPA stuff etc..

rockBounds := getTPABounds(ATPA[i]); // Store the TPA bounds in a TBox variable
mouseBox(rockBounds, MOUSE_MOVE); // Move mouse anywhere in that box

// other stuff
end;

beefman
06-13-2014, 08:57 PM
Mayor, could you help me please?
I was setting up the default code. I got it working fine, was able to sign in to my account. However, for some reason it has stopped working.
I was adding an anti ban to the code, i added it and tried to play the script. It worked but wouldn't log me in like it would before. So i deleted it, and recopied the default code and pasted it. Now it's not working at all, even without the anti ban. I need some help. I'll post a picture. 23393

The Mayor
06-13-2014, 09:02 PM
Mayor, could you help me please?
I was setting up the default code. I got it working fine, was able to sign in to my account. However, for some reason it has stopped working.
I was adding an anti ban to the code, i added it and tried to play the script. It worked but wouldn't log me in like it would before. So i deleted it, and recopied the default code and pasted it. Now it's not working at all, even without the anti ban. I need some help. I'll post a picture. 23393

are your graphics settings correct? Check that you are in openGL mode and brightness is up max.

beefman
06-13-2014, 09:31 PM
Genius! Thanks for the fast reply. Turns out i had my graphics on Directx instead of openGL

honeyhoney
06-25-2014, 07:56 PM
Thanks for the great overview of RS3/SRL-6 Scripting. This has served as a great refresher for myself.

Appreciate the hard work - expect to see a script from me soon.

Lucidity
07-01-2014, 06:29 AM
Thanks for the great overview of RS3/SRL-6 Scripting. This has served as a great refresher for myself.

Appreciate the hard work - expect to see a script from me soon.

Welcome back to SRL.

johnjoseph09
07-21-2014, 01:50 PM
Thanks @The Mayor , I just made my first script and it works well after some tweeks that was done after first couple of runs, running good now and I referred to other similar scripts to check my mistake and correct. Working really good and I thank you for all that, I can just make more and get experienced with this in the future :)

The Mayor
07-23-2014, 10:16 AM
Thanks @The Mayor , I just made my first script and it works well after some tweeks that was done after first couple of runs, running good now and I referred to other similar scripts to check my mistake and correct. Working really good and I thank you for all that, I can just make more and get experienced with this in the future :)

Good :) I usually do the same. I watch the first version of the script run for about 20min and tweak it as it's running until it runs as it should.

Basic
07-26-2014, 08:27 AM
program walkToChest;
{$DEFINE SMART}
{$I SRL-6/SRL.simba}
{$I SPS/lib/SPS-RS3.Simba}
{$i srl-6/lib/misc/srlplayerform.simba}

procedure walkToChest();
var
walkToChest: TPointArray;
begin
if not isLoggedIn() then
exit;

walkToChest := [Point(203, 60), Point(198, 101), Point(176, 133), Point(176, 161), Point(174, 182), Point(173, 196)];

if SPS.walkPath(walkToChest) then
minimap.waitPlayerMoving()
else
writeLn('Unable to locate chest');

end;

begin
clearDebug();
smartPlugins := ['OpenGL32.dll','d3d9.dll'];
smartEnableDrawing := true;
disableSRLDebug := false;
setupSRL();
SPS.setup('Chest', RUNESCAPE_OTHER);
progressReport();
until false;

end.

IT executes but doesn't actually move, can't tell what I missed

The Mayor
07-26-2014, 10:33 AM
program walkToChest;
{$DEFINE SMART}
{$I SRL-6/SRL.simba}
{$I SPS/lib/SPS-RS3.Simba}
{$i srl-6/lib/misc/srlplayerform.simba}

procedure walkToChest();
var
walkToChest: TPointArray;
begin
if not isLoggedIn() then
exit;

walkToChest := [Point(203, 60), Point(198, 101), Point(176, 133), Point(176, 161), Point(174, 182), Point(173, 196)];

if SPS.walkPath(walkToChest) then
minimap.waitPlayerMoving()
else
writeLn('Unable to locate chest');

end;

begin
clearDebug();
smartPlugins := ['OpenGL32.dll','d3d9.dll'];
smartEnableDrawing := true;
disableSRLDebug := false;
setupSRL();
SPS.setup('Chest', RUNESCAPE_OTHER);
progressReport();
until false;

end.

IT executes but doesn't actually move, can't tell what I missed

1) You never call walkToChest in your main loop, so it will never execute.
2) In your main loop you have a procedure called progressReport which doesn't appear in your script
3) You have a 'until false' but no 'repeat'
4) That won't actually compile because of the above

Zeta Matt
07-30-2014, 04:04 PM
Damn awesome tutorial :o I've bookmarked it. I'm sure I'll come back a lot to read it >.> Thanks Mayor

The Mayor
08-03-2014, 04:42 AM
Damn awesome tutorial :o I've bookmarked it. I'm sure I'll come back a lot to read it >.> Thanks Mayor

I expect great things from you ;)

Spaceblow
08-04-2014, 12:40 AM
Very nice guide, nicely written and understandable. But I do have a little question. At the moment I'm trying to understand section 6 and I'm doing a pretty good job with that but I don't understand something very well.

What's the difference between this:
wait(randomRange(1000, 2000));

And this:
wait(gaussRangeInt(500, 750));

I already know what 'wait(randomRange(1000, 2000))' is. It waits a random amount of ms (in this case something between 1000 and 2000 ms. In your AIO guide you suddenly change it to 'wait(gaussRangeInt(500, 750))'. I hope you could answer my simple question, thank you in advance!

The Mayor
08-04-2014, 12:47 AM
Very nice guide, nicely written and understandable. But I do have a little question. At the moment I'm trying to understand section 6 and I'm doing a pretty good job with that but I don't understand something very well.

What's the difference between this:
wait(randomRange(1000, 2000));

And this:
wait(gaussRangeInt(500, 750));

I already know what 'wait(randomRange(1000, 2000))' is. It waits a random amount of ms (in this case something between 1000 and 2000 ms. In your AIO guide you suddenly change it to 'wait(gaussRangeInt(500, 750))'. I hope you could answer my simple question, thank you in advance!

I forgot I had gauss waits in this tutotial. I should probably remove them as it might confuse people. Gauss is referring to a Gaussian (normal) distribution where the majority of the values lie close to the middle.

http://puu.sh/aDGIM/fd50cc0c64.png


Basically:

randomRange(0, 1000) will have an equal chance of returning any value between 0 and 1000.

gaussRangeInt(0, 1000) will have more change of returning an integer around 500ish

Spaceblow
08-04-2014, 01:29 AM
Thank you for the quick reply, I understand it now. So there actually wouldn't be much difference between using randomRange and gaussRangeInt. I'll probably just use randomRange but it's good to know the other one too.

lanadekat
08-05-2014, 12:15 PM
Is it possible to create a more accurate path with SPS ? I'm trying to run into a building, but it just doesn't work.
here's a printscreen of sps path generator : http://prntscr.com/49rbft ( green arrows are the places it walks to )
I tried more points, fewer points, but nothing seems to work.

I have found a script using banksymbol on the minimap.But that wouldn't work for the tanner.

Spaceblow
08-05-2014, 01:02 PM
I have 3 questions:

#1 (https://villavu.com/forum/usertag.php?do=list&action=hash&hash=1) : Is it possible to somehow disable the console? I'm talking about the black window that pops up together with SMART when I press play.


#2 (https://villavu.com/forum/usertag.php?do=list&action=hash&hash=2) : At the end of your topic you can see your complete script. In the beginning of each procedure you use:
if not isLoggedIn() then
exit;

But why do you actually do that if you have this in the beginning of your main loop:
if not isLoggedIn() then
begin
players[currentPlayer].login();
exitSquealOfFortune();
mainScreen.setAngle(MS_ANGLE_HIGH);
minimap.setAngle(MM_DIRECTION_NORTH);
end;

Do you do that incase something goes wrong in the middle of a procedure? Like if your player stops running and logs out after a couple minutes? If so, why don't you use the beginning of your main loop for the beginning of every procedure? That would be max profit because instead of just exiting it logs in again to continue mining.


#3 (https://villavu.com/forum/usertag.php?do=list&action=hash&hash=3) : At the end of your main loop you can see this:
until(false);

What does it do?


I may sound stupid asking such questions but I want to understand as much as possible. I hope I'm welcome with questions like that in the future, thanks in advance! :)

The Mayor
08-08-2014, 12:22 AM
I have 3 questions:

1 : Is it possible to somehow disable the console? I'm talking about the black window that pops up together with SMART when I press play.

Yes. Just put this at the start of your main loop:

smartShowConsole := false;




2 : At the end of your topic you can see your complete script. In the beginning of each procedure you use:
if not isLoggedIn() then
exit;

But why do you actually do that if you have this in the beginning of your main loop:
if not isLoggedIn() then
begin
players[currentPlayer].login();
exitSquealOfFortune();
mainScreen.setAngle(MS_ANGLE_HIGH);
minimap.setAngle(MM_DIRECTION_NORTH);
end;

Do you do that incase something goes wrong in the middle of a procedure? Like if your player stops running and logs out after a couple minutes? If so, why don't you use the beginning of your main loop for the beginning of every procedure? That would be max profit because instead of just exiting it logs in again to continue mining.

It's just the way I structure my scripts. If your player logs out at any point in the mainloop, the rest of the procedures in the mainloop will exit instantly. Then once it's back at the top of the mainloop it will login.


repeat
if not isLoggedIn() then //then we arrive back up here, and log back in
begin
players[currentPlayer].login();
exitSquealOfFortune();
mainScreen.setAngle(MS_ANGLE_HIGH);
minimap.setAngle(MM_DIRECTION_NORTH);
end;


procedure1();
procedure2(); // e.g if I lag out here
procedure3(); //exit
procedure4(); //exit
procedure5(); //exit
procedure6(); //exit
until(false);


You are right in that you could copy and paste that login block into each procedure, but you end up with a whole bunch of code that is just repeating itself (imagine 50 + procedures). Your point about logging in to continue where it left off, it could do that depending on how you structure your mainLoop. Currently in this tutorial the mainloop is split into two halves based on if the inventory is full:


if tabBackpack.isFull() then
begin
teleToPortSarim();
findDepositBox();
depositClay();
end;

progressReport();

teleToClanCamp();
runToMine();
mineRocks();


So if it lagged out while mining rocks, once it logs back in it would tele to clan camp, run to mine, and then start mining. If I wanted it to start mining straight away (if player is already in mine) I would need to add another condition:


if tabBackpack.isFull() then
begin
teleToPortSarim();
findDepositBox();
depositClay();
end;

progressReport();

if isInMine() then
mineRocks()
else begin
teleToClanCamp();
runToMine();
end;



Then I would also need create a boolean function (isInMine) to tell if player is in mine (e.g., using SPS, or if it can see the mine minmap symbol, etc.). Basically, you can organise your mainloop depending on the state of your player (where your player is, what's in your inventory etc.)



3 : At the end of your main loop you can see this:
until(false);


until false just means it will repeat the loop forever.

The Mayor
08-08-2014, 12:28 AM
Is it possible to create a more accurate path with SPS ? I'm trying to run into a building, but it just doesn't work.
here's a printscreen of sps path generator : http://prntscr.com/49rbft ( green arrows are the places it walks to )
I tried more points, fewer points, but nothing seems to work.

I have found a script using banksymbol on the minimap.But that wouldn't work for the tanner.

That sure is a lot of points :p

you could try sps.walkToPos(TPoint)

sps.walkToPos(point(100, 150));

The tanner symbol is outdated unfortunately. I updated the bank, lodestone, mining + a few others a couple of days ago. If you are really struggling with it I could fix the tanner symbol and get it pushed.

lanadekat
08-08-2014, 08:19 AM
That sure is a lot of points :p

you could try sps.walkToPos(TPoint)

sps.walkToPos(point(100, 150));

The tanner symbol is outdated unfortunately. I updated the bank, lodestone, mining + a few others a couple of days ago. If you are really struggling with it I could fix the tanner symbol and get it pushed.
I didn't know there was one, but I found it after posting here ;( I also posted in the sps thread they said map was to small, and making it bigger at the top fixed it.

Spaceblow
08-08-2014, 08:53 AM
... so much help ... Thank you very much, you answered all my questions!

destinyxx
08-15-2014, 08:52 PM
Starting this tutorial today :) will update my progress xD

Smile
08-25-2014, 03:26 PM
Awesome guide, going through this now and making an edgeville gold smelter, after about 2-4 hrs I've got a working smelter. 10/10 Guide

TheeMason
08-25-2014, 06:47 PM
Awesome guide, going through this now and making an edgeville gold smelter, after about 2-4 hrs I've got a working smelter. 10/10 Guide

I just did the same thing last night, I used this bad boy to write a clay to soft clay in about the same time-frame. I also did it in edgeville, I was wondering if you would want to swap scripts and learn a thing or two from each-other? Once I throw in some anti-ban, and a proggy i'm going to post mine to first script section to get some feedback.

Effz
09-13-2014, 12:22 AM
How can I setup a failsafe? My script will sometimes miss a click :/
Thanks!

The Mayor
09-13-2014, 10:06 PM
Awesome guide, going through this now and making an edgeville gold smelter, after about 2-4 hrs I've got a working smelter. 10/10 Guide


I just did the same thing last night, I used this bad boy to write a clay to soft clay in about the same time-frame. I also did it in edgeville, I was wondering if you would want to swap scripts and learn a thing or two from each-other? Once I throw in some anti-ban, and a proggy i'm going to post mine to first script section to get some feedback.

Looking forward to the releases ;)



How can I setup a failsafe? My script will sometimes miss a click :/
Thanks!

Well you have to be a bit more specific, provide an example, and post some code.

Smile
09-14-2014, 08:16 AM
Looking forward to the releases ;)

Dude I wish, its so dodgy at the moment, but on a side note also have a pretty decent Yak Hide buyer now too thanks to you. I'll work on them until I feel they're worthy of public appearance :)

Note
09-22-2014, 01:21 AM
This is one of the best guides i have read in all my time being here <3 ( the last guide i read was by Yohojo when i first joined) but this guide is soo much more idk made sense in my head how everything worked.. and when it didn't The Mayor helped me understand!

sskylla
09-25-2014, 03:16 PM
Nice guide! :)

TitaniumT
10-13-2014, 11:42 AM
wow, what an amazing guide, I can tell how much time and effort went in to that; thank you so much for sharing! I hope to start coding some bots and help fix some that are a little outdated, Thanks again Mr Mayor :)

The Mayor
10-14-2014, 10:36 PM
Nice guide! :)


wow, what an amazing guide, I can tell how much time and effort went in to that; thank you so much for sharing! I hope to start coding some bots and help fix some that are a little outdated, Thanks again Mr Mayor :)'

Looking forward to those scripts ;)

slushpuppy
10-17-2014, 10:16 AM
The Mayor

How did you manage to zoom out of your minimap @.@

The Mayor
10-18-2014, 01:16 AM
The Mayor

How did you manage to zoom out of your minimap @.@

Not sure is that is an attempted Mayor mention :p You can resize the MM interface just like any other interface. If you make the MM big enough, you can see a full map "chunk".

Cerium
10-21-2014, 01:06 PM
Very nice tutorial!

I have problems walking with SPS, I think it might be because my map is big and have som blind/dead spots.

How can I use multiple maps instead of just one? And is there any best practices when using SPS?

slushpuppy
10-23-2014, 12:13 PM
Not sure is that is an attempted Mayor mention :p You can resize the MM interface just like any other interface. If you make the MM big enough, you can see a full map "chunk".

If my walking path is too long, I guess i have to splice the images :(?

The Mayor
10-23-2014, 06:42 PM
If my walking path is too long, I guess i have to splice the images :(?

Yeah. You should read the SPS section of this tutorial - there is a link to Google's tutorial for splicing maps.

Cerium
10-24-2014, 10:41 PM
What happens if I tell SPS to walk to x, and the player is already at position x, will it try to walk to x or detect that the player already is at position x and then just be done?

The Mayor
10-24-2014, 11:30 PM
What happens if I tell SPS to walk to x, and the player is already at position x, will it try to walk to x or detect that the player already is at position x and then just be done?

No you won't walk, as that is botty. The SPS functions have a line something like this:


// if distance is less than 10 then there is no real point walking.
if (distance(destinationPoint, minimap.getCenterPoint()) < 10) then
exit;

Wooty
10-26-2014, 05:23 PM
I just finished my first fully working script!
Thanks for the awesome guide!

Torol
10-27-2014, 03:32 PM
Very good guide, it's useful for those who never saw a code before too. Thanks!

Quentini
11-06-2014, 01:17 PM
I have read this tutorial nearly three times and it is an amazing resource to start scripting; however, it's missing an important section.. Implementation of Antiban. You briefly cover case statements, but don't include a scripting example using them. This is where the antiban section comes. I am curious on a few various ways to actually trigger a basic antiban every cycle. This could be an invaluable resource for this guide. Kudos Mayor! Thank you for this.

xCrazyGuyNL
11-13-2014, 09:59 PM
Like Quentini said,

I'm affraid to get banned without anti-ban

Incurable
11-14-2014, 12:42 AM
I have read this tutorial nearly three times and it is an amazing resource to start scripting; however, it's missing an important section.. Implementation of Antiban. You briefly cover case statements, but don't include a scripting example using them. This is where the antiban section comes. I am curious on a few various ways to actually trigger a basic antiban every cycle. This could be an invaluable resource for this guide. Kudos Mayor! Thank you for this.


Like Quentini said,

I'm affraid to get banned without anti-ban

Anti-ban is actually very easy to implement depending on how basic or advanced you want to go. You should just do a Google search for any old anti-ban tutorials or look at other people's scripts to see how they implemented theirs. :)

The Mayor - That is something to add to your list though. :p

The Mayor
11-14-2014, 02:17 AM
I have read this tutorial nearly three times and it is an amazing resource to start scripting; however, it's missing an important section.. Implementation of Antiban. You briefly cover case statements, but don't include a scripting example using them. This is where the antiban section comes. I am curious on a few various ways to actually trigger a basic antiban every cycle. This could be an invaluable resource for this guide. Kudos Mayor! Thank you for this.


Like Quentini said,

I'm affraid to get banned without anti-ban


Anti-ban is actually very easy to implement depending on how basic or advanced you want to go. You should just do a Google search for any old anti-ban tutorials or look at other people's scripts to see how they implemented theirs. :)

The Mayor - That is something to add to your list though. :p


just read antiban.simba and throw it in a case statement

Clarity
11-14-2014, 04:40 AM
I have read this tutorial nearly three times and it is an amazing resource to start scripting; however, it's missing an important section.. Implementation of Antiban. You briefly cover case statements, but don't include a scripting example using them. This is where the antiban section comes. I am curious on a few various ways to actually trigger a basic antiban every cycle. This could be an invaluable resource for this guide. Kudos Mayor! Thank you for this.


Like Quentini said,

I'm affraid to get banned without anti-ban

More specifically, add in whatever procedures/functions you want to activate during an "antiban" within a random output case statement procedure like so:

procedure antiban;
var
i: integer;
begin
i := random(100);
case i of
0..10: doSomething;
11..20: doSomethingElse;
21..50: doSomethingElseElse;
51..100: doSomethingElseElse;
end;
end;


Every time antiban; is called, the integer i will be assigned a random number between 0 and 100, and then based on that random number, the case statement will pick something to do. As you can see, you can adjust the ranges of each antiban however you like, or even increase the range from 100 to 1000 or anything.

Here's a more complex example from one of my scripts:

{PROCEDURE -- antiBan
Purpose: Make us look more like a human and less like a bot.
Comments: None.}
procedure antiBan;
var
i, afk, idle, mSpeed: integer;
begin
if not isLoggedIn then
exit;
i := random(antibanThreshold); //Rather than have a definite range for i, like 0 to 100, I allow the user to set the range themselves, customizing the frequencies
afk := (AFKTime + random(1500));
idle := (idleTime + random(500));
mSpeed := mouseSpeed;
failsafe.pause;
case i of
1..100:
begin
ClarityDebug('Performing antiban. (' + ToStr(i) + ') - Small Random Mouse');
scriptStatus('Performing antiban. (' + ToStr(i) + ') - Small Random Mouse');
smallRandomMouse();
end;
101..200:
begin
ClarityDebug('Performing antiban. (' + ToStr(i) + ') - Pick Up Mouse');
scriptStatus('Performing antiban. (' + ToStr(i) + ') - Pick Up Mouse');
pickUpMouse();
end;
201..300:
begin
ClarityDebug('Performing antiban. (' + ToStr(i) + ') - Sleep and Move Mouse');
scriptStatus('Performing antiban. (' + ToStr(i) + ') - Sleep and Move Mouse');
sleepAndMoveMouse(random(2000) + 500);
end;
301..380:
begin
ClarityDebug('Performing antiban. (' + ToStr(i) + ') - Idling for ' + toStr(idle) + 'ms');
scriptStatus('Performing antiban. (' + ToStr(i) + ') - Idling for ' + toStr(idle) + 'ms');
case i of
301..350:
begin
mouseOffClient(OFF_CLIENT_RANDOM);
wait(idle);
end;
351..400: sleepAndMoveMouse(idle + 500);
end;
recalcAB;
end;
381..420:
begin
ClarityDebug('Performing antiban. (' + ToStr(i) + ') - Hover Skill');
scriptStatus('Performing antiban. (' + ToStr(i) + ') - Hover Skill');
if not gameTabs.isTabActive(TAB_BACKPACK) then
exit;
hoverSkill(SKILL_RUNECRAFTING);
sleepAndMoveMouse(random(50, 450));
end;
421..428:
begin
ClarityDebug('Performing antiban. (' + ToStr(i) + ') - AFKing for ' + toStr(afk) + 'ms');
scriptStatus('Performing antiban. (' + ToStr(i) + ') - AFKing for ' + toStr(afk) + 'ms');
mouseOffClient(OFF_CLIENT_RANDOM);
wait(afk);
mouseSpeed := mspeed;
ClarityDebug('New mouse speed - ' + toStr(mspeed));
scriptStatus('New mouse speed - ' + toStr(mspeed));
recalcAB;
end;
429..450:
begin
ClarityDebug('Performing antiban. (' + ToStr(i) + ') - New mouse speed of ' + toStr(mspeed));
scriptStatus('Performing antiban. (' + ToStr(i) + ') - New mouse speed of ' + toStr(mspeed));
mouseSpeed := mspeed;
end;
451..antibanThreshold:
begin
failsafe.start;
exit;
end;
end;
failsafe.start;
end;

As you can see, I made events such as going AFK or idle less common than random mouse movement events. As mentioned by Inc and Mayor, you can also look at other scripts for examples.

If you want, you can and should write custom antiban procedures that are relevant to your script's activity! In my opinion, just a few random mouse movements and camera rotations is not very effective.

Zohan
11-14-2014, 09:13 PM
Great tutorial.

I'll see what I can make.

Torol
11-17-2014, 02:16 PM
TBoxArray


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

http://puu.sh/6trdk.png


I'm thinking about making a TBoxArray from these slots:

http://s23.postimg.org/ttoulc9bf/tbox.png

But I can't manage to do it. I have the slot's margin color (from ACA) and the size (48x52 px) but I don't know how to code it. Could someone help me with this?

Edit: What measurement does simba use as "distance"? I thought it was pixels, but as I tested-tried various funtions, like SplitTPAEx, now I don't get it. BTW it works now with SplitTPAEx(TPA, w:=2, h:=2).

The Mayor
11-18-2014, 02:14 AM
I'm thinking about making a TBoxArray from these slots:

http://s23.postimg.org/ttoulc9bf/tbox.png

But I can't manage to do it. I have the slot's margin color (from ACA) and the size (48x52 px) but I don't know how to code it. Could someone help me with this?

Edit: What measurement does simba use as "distance"? I thought it was pixels, but as I tested-tried various funtions, like SplitTPAEx, now I don't get it. BTW it works now with SplitTPAEx(TPA, w:=2, h:=2).

You can use a grid( ) for that, so look up that function. If you need help with it, post in help section.

Ecer
11-25-2014, 12:35 AM
I have been abusing these forums too long without any contribution. But after reading your informative thread, I think it's time to start. I have got some ideas for small projects and I will start from there!

Thanks for your guide.

Claymore
11-25-2014, 02:35 AM
Hey wait a minute, that gets nearly 200k per hour on f2p, should I put this in the junior members section

Dat cliffhanger.

Anyway thanks for giving an old timer a rerun on Simba. Cheers!

The Mayor
11-25-2014, 08:48 PM
I have been abusing these forums too long without any contribution. But after reading your informative thread, I think it's time to start. I have got some ideas for small projects and I will start from there!

Thanks for your guide.

Good luck ;)


Dat cliffhanger.

Anyway thanks for giving an old timer a rerun on Simba. Cheers!

It was more "i cbf writing a proper conclusion" :p

Ecer
12-06-2014, 11:04 AM
Thanks again for such an extensive tutorial. I have finally made a decent first script as a result.

I have one question though, I cannot find the DTM Editor in the Tools tab anymore? Can you point me to a direction to where I can create my own DTM?

Cheers, Ecer.

akarigar
12-06-2014, 11:35 AM
Thanks again for such an extensive tutorial. I have finally made a decent first script as a result.

I have one question though, I cannot find the DTM Editor in the Tools tab anymore? Can you point me to a direction to where I can create my own DTM?

Cheers, Ecer.

I had to do this:

View -> Extensions
Select 'dtm_editor.sex' and check the extension on
Tools -> DTM Editor


Hopefully it works for you.

Ecer
12-06-2014, 12:46 PM
I had to do this:

View -> Extensions
Select 'dtm_editor.sex' and check the extension on
Tools -> DTM Editor


Hopefully it works for you.

Oh yeah, I feel like an idiot. I forgot about extensions. Haha Thanks buddy!

Quentini
12-11-2014, 10:57 PM
Time to get back into learning to script again! :garfield:

Eoan
01-01-2015, 11:06 PM
Amazingly informative. I'm pretty proficient in Java and a lot of this seems similar. Although I'm pretty sure that's a bad thing because I feel like I'm gonna type java if else statements. Also the lack of "{" and "}" is messing with me. Thanks for the tutorial!

SlipperyPickle
01-01-2015, 11:12 PM
Amazingly informative. I'm pretty proficient in Java and a lot of this seems similar. Although I'm pretty sure that's a bad thing because I feel like I'm gonna type java if else statements. Also the lack of "{" and "}" is messing with me. Thanks for the tutorial!

Had the same, came from developing Android applications. But you'll get pretty fast familiar with this language.

The Mayor
01-02-2015, 12:07 AM
Amazingly informative. I'm pretty proficient in Java and a lot of this seems similar. Although I'm pretty sure that's a bad thing because I feel like I'm gonna type java if else statements. Also the lack of "{" and "}" is messing with me. Thanks for the tutorial!


Had the same, came from developing Android applications. But you'll get pretty fast familiar with this language.

Yeah everything is pretty similar and you will used to using begins and ends for nested code instead of { }

jrtsoget
01-07-2015, 03:29 PM
Thanks for the awesome tutorial, I think i'm gonna scripting for simba/srl a shot. I've been stuck in the .NET/javascript/css world for a long time now and this might be a nice break.

The Mayor
01-13-2015, 09:17 PM
Thanks for the awesome tutorial, I think i'm gonna scripting for simba/srl a shot. I've been stuck in the .NET/javascript/css world for a long time now and this might be a nice break.

Good luck. If you need any help, just post in the help section!

primaz
01-20-2015, 04:54 PM
Wow, really nice, very good guide thanks

uhit
01-20-2015, 05:08 PM
program uHider;
{$DEFINE SMART}
{$I SRL-6/SRL.simba}

var
XP, startingXP, loadsPH, XPH, antibanCount, actAfkCount: integer;


const
DEBUGSCRIPT = false; //Enable if you are having issues running script


procedure declarePlayers;
begin
setLength(players, 1);
with players[0] do
begin
loginName := ''; //Set username here
password := ''; //Set password here
bankPin := ''; //Set PIN here
world := 32; //Set world here
isActive := true;
isMember := true;
end
currentPlayer := 0;
end;

procedure printStatus(Jamc : String; PrintType : Integer);
begin
if DEBUGSCRIPT then
begin
if PrintType = 0 then
print(Jamc, TDebug.SUB);
if PrintType = 1 then
print(Jamc, TDebug.HEADER);
if PrintType = 2 then
print(Jamc, TDebug.SUB);
if PrintType = 3 then
print(Jamc, TDebug.FOOTER);
if PrintType = 4 then
print(Jamc, TDebug.ERROR);
if PrintType = 5 then
writeLn(Jamc);
end;
if not DEBUGSCRIPT then
begin
if PrintType = 0 then
writeLn(Jamc);
end;
end;


procedure logIn;
begin
printStatus('logIn: Starting...', 1);
if not isLoggedIn then
begin
players[currentPlayer].login();
exitTreasure();
minimap.clickCompass();
mainscreen.setZoom(false);
end;
printStatus('logIn: Finished!', 3);
end;

procedure Banking();
begin

if bankScreen.open(BANK_CHEST_LUMBRIDGE) then
bankScreen.clickButton(BANK_BUTTON_PRESET_1) // This deposits, withdraws, and closes the bank
else
writeLn('Couldn''t find the bank for some reason!');

end;

procedure makeHide();
begin

tabBackpack.mouseSlot(1, MOUSE_LEFT);

if toolScreen.isOpen(2000) then
toolScreen.select('Needle');

if productionScreen.isOpen(5000) then
begin
productionScreen.selectBox(3);
productionScreen.clickStart();

if progressScreen.isOpen(5000) then // if progressScreen is open within 5 seconds
begin
writeLn('The progressScreen is open!');

repeat
wait(1000);
until (progressScreen.getButton() <> PROGRESS_BUTTON_CANCEL);
wait(randomRange(1575, 3223));
end;

end;

end;


procedure progressReport;
begin

XP := (chatBox.getXPBar - startingXP);
XPH := round(XP * (3600.0 / (getTimeRunning / 1000.0)));
loadsPH := round((loadsDone * (3600.0 / (getTimeRunning / 1000.0))));

writeln('|======================================== ===================|');
writeln('| Proggy |');
writeln('|======================================== ===================|');
writeln(padR('| Running For: ' + timeRunning, 60) + '|');
writeln(padR('| Exp Earned: ' + groupDigits(XP, ','), 40) + padR('Exp/Hour: ' + groupDigits(XPH, ','), 20) + '|');
writeln('|________________________________________ ___________________|');
writeln('|________________________________________ ___________________|');

end;



begin
clearDebug;
setupSRL;
repeat
LogIn;
Banking;
makeHide;
progressReport;
until(false);
terminateScript;
end.


Well, my first ever attempt at trying to UNDERSTAND simba, not code. I took snippets from various scripts to see if I could make a green d'hide body maker. It's not amazing and technically I shouldn't really deserve to be credited at all for this, but it is a start :)

I don't want to be a leecher no more :3

Thanks Mayor <3

The Mayor
01-21-2015, 06:50 PM
program uHider;
{$DEFINE SMART}
{$I SRL-6/SRL.simba}

var
XP, startingXP, loadsPH, XPH, antibanCount, actAfkCount: integer;


const
DEBUGSCRIPT = false; //Enable if you are having issues running script


procedure declarePlayers;
begin
setLength(players, 1);
with players[0] do
begin
loginName := ''; //Set username here
password := ''; //Set password here
bankPin := ''; //Set PIN here
world := 32; //Set world here
isActive := true;
isMember := true;
end
currentPlayer := 0;
end;

procedure printStatus(Jamc : String; PrintType : Integer);
begin
if DEBUGSCRIPT then
begin
if PrintType = 0 then
print(Jamc, TDebug.SUB);
if PrintType = 1 then
print(Jamc, TDebug.HEADER);
if PrintType = 2 then
print(Jamc, TDebug.SUB);
if PrintType = 3 then
print(Jamc, TDebug.FOOTER);
if PrintType = 4 then
print(Jamc, TDebug.ERROR);
if PrintType = 5 then
writeLn(Jamc);
end;
if not DEBUGSCRIPT then
begin
if PrintType = 0 then
writeLn(Jamc);
end;
end;


procedure logIn;
begin
printStatus('logIn: Starting...', 1);
if not isLoggedIn then
begin
players[currentPlayer].login();
exitTreasure();
minimap.clickCompass();
mainscreen.setZoom(false);
end;
printStatus('logIn: Finished!', 3);
end;

procedure Banking();
begin

if bankScreen.open(BANK_CHEST_LUMBRIDGE) then
bankScreen.clickButton(BANK_BUTTON_PRESET_1) // This deposits, withdraws, and closes the bank
else
writeLn('Couldn''t find the bank for some reason!');

end;

procedure makeHide();
begin

tabBackpack.mouseSlot(1, MOUSE_LEFT);

if toolScreen.isOpen(2000) then
toolScreen.select('Needle');

if productionScreen.isOpen(5000) then
begin
productionScreen.selectBox(3);
productionScreen.clickStart();

if progressScreen.isOpen(5000) then // if progressScreen is open within 5 seconds
begin
writeLn('The progressScreen is open!');

repeat
wait(1000);
until (progressScreen.getButton() <> PROGRESS_BUTTON_CANCEL);
wait(randomRange(1575, 3223));
end;

end;

end;


procedure progressReport;
begin

XP := (chatBox.getXPBar - startingXP);
XPH := round(XP * (3600.0 / (getTimeRunning / 1000.0)));
loadsPH := round((loadsDone * (3600.0 / (getTimeRunning / 1000.0))));

writeln('|======================================== ===================|');
writeln('| Proggy |');
writeln('|======================================== ===================|');
writeln(padR('| Running For: ' + timeRunning, 60) + '|');
writeln(padR('| Exp Earned: ' + groupDigits(XP, ','), 40) + padR('Exp/Hour: ' + groupDigits(XPH, ','), 20) + '|');
writeln('|________________________________________ ___________________|');
writeln('|________________________________________ ___________________|');

end;



begin
clearDebug;
setupSRL;
repeat
LogIn;
Banking;
makeHide;
progressReport;
until(false);
terminateScript;
end.


Well, my first ever attempt at trying to UNDERSTAND simba, not code. I took snippets from various scripts to see if I could make a green d'hide body maker. It's not amazing and technically I shouldn't really deserve to be credited at all for this, but it is a start :)

I don't want to be a leecher no more :3

Thanks Mayor <3

Well done for putting that together, it looks you've made good use of SRL-6

giavanni6
01-26-2015, 10:07 PM
This tutorial has helped me immensely. I'm currently working on my first few scripts, thank you Mayor!

IROC-Z
02-09-2015, 09:55 PM
In the section of your guide when you talk about SPS walking you have:
SPS.setup('CLAY_MAP' , RUNESCAPE_OTHER);

I have seen in some scripts where they add in numbers to adjust tolerance and variability like this:
SPS.setup('CLAY_MAP' , RUNESCAPE_OTHER, 3, 500, 0.5);
or at least something along those lines. Could you explain that or add it to the guide?

I was also wondering about how often you should place a dot when doing the path? Would dots being closer make it more accurate or does that just lag things down?

Thanks!

jackieo500
02-12-2015, 11:47 AM
This is a fantastic tutorial! I should be posting in My First Script pretty soon! ;)

basble
02-14-2015, 11:40 PM
Thank you for the amazing tutorial!
I want to try to make my first scipt but i have no idea, what kind of script i should make.

I'll be looking through some request topics to get some idea's otherwise i just try to make some thing useless like a potato picker

KeepBotting
02-15-2015, 04:27 AM
Thank you for the amazing tutorial!
I want to try to make my first scipt but i have no idea, what kind of script i should make.

I'll be looking through some request topics to get some idea's otherwise i just try to make some thing useless like a potato picker
Don't let Wetish; hear you say that! :p

& no script is useless, not as long as you gain valuable knowledge and insight from it!

Renzanity
03-04-2015, 10:28 AM
The tutorial's very profound! Well, maybe too profound for a newbie like me, but I still got a lot of ideas from this one! Thanks a lot!

P.S. I've been to the other thread called Simplistic Beginners Guide too. :P

Clutch
03-10-2015, 03:11 AM
The Mayor;

I am trying to implement my script to unlock all lodestones. Using SPS mapping to get around would it be best (or even possible) for me just to use a picture of the full world map or should I just add in individual minimap captures?

Ex. Could I just take a Snippet of the entire area (keeping it as zoomed in as possible) going to add picture shortly.

25244

Edit: After reading through it again I don't think this will work, thought i'd double check though because it would save some time! Thanks.

The Mayor
03-10-2015, 03:36 AM
The Mayor;

I am trying to implement my script to unlock all lodestones. Using SPS mapping to get around would it be best (or even possible) for me just to use a picture of the full world map or should I just add in individual minimap captures?

Ex. Could I just take a Snippet of the entire area (keeping it as zoomed in as possible) going to add picture shortly.

25244

Edit: After reading through it again I don't think this will work, thought i'd double check though because it would save some time! Thanks.

I hope you're not using that image as your map :p

You would be best to use multiple maps and assign each one to a different spsArea. Take a look at Incurables lodestone unlocker script.

Clutch
03-10-2015, 03:57 AM
I hope you're not using that image as your map :p

You would be best to use multiple maps and assign each one to a different spsArea. Take a look at Incurables lodestone unlocker script.
Incurable;
Cannot find his lodestone unlocker. That being said i've encountered quite a few errors but found workarounds. At this point though I can't seem to get multiple SPS maps to load properly. Ex. Can't walk from 1 SPS and then continue on with the next SPS even though they both exist and are both getting called on. Individually they both work fine.

The Mayor
03-10-2015, 05:04 AM
Incurable;
Cannot find his lodestone unlocker. That being said i've encountered quite a few errors but found workarounds. At this point though I can't seem to get multiple SPS maps to load properly. Ex. Can't walk from 1 SPS and then continue on with the next SPS even though they both exist and are both getting called on. Individually they both work fine.

Looks like it's in the jr section I'm afraid.

Clutch
03-10-2015, 05:10 AM
Looks like it's in the jr section I'm afraid.
The Mayor;
Hrm :/ that being said, could you assist me in calling in multiple SPS.png files?

procedure WTL1();
var
WTL1: TPointArray;
begin;
SPS.setup('WTL1',RUNESCAPE_OTHER); //WTL1 map
WTL1 := [Point(230, 154), Point(221, 197), Point(215, 244), Point(208, 296), Point(200, 344)];

if SPS.walkPath(WTL1) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;

procedure WTL2();
var WTL2: TPointArray;
begin;
clearDebug(); // Clear the debug box
if isloggedin() then
begin;
//SPS.setup('WTL2',RUNESCAPE_OTHER); //WTL2 map
WTL2 := [Point(200, 344),Point(221, 252), Point(219, 275), Point(185, 307), Point(165, 341)];
if SPS.walkPath(WTL2) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;
end;

Right now that walks from burth lode down to tav lode but I can't have it won't continue on if I have them both being called on, it gives me the error like it hasn't loaded the image. Is there a way to at least free up the sps before I load it?

Citrus
03-10-2015, 05:38 AM
The Mayor;
Hrm :/ that being said, could you assist me in calling in multiple SPS.png files?

procedure WTL1();
var
WTL1: TPointArray;
begin;
SPS.setup('WTL1',RUNESCAPE_OTHER); //WTL1 map
WTL1 := [Point(230, 154), Point(221, 197), Point(215, 244), Point(208, 296), Point(200, 344)];

if SPS.walkPath(WTL1) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;

procedure WTL2();
var WTL2: TPointArray;
begin;
clearDebug(); // Clear the debug box
if isloggedin() then
begin;
//SPS.setup('WTL2',RUNESCAPE_OTHER); //WTL2 map
WTL2 := [Point(200, 344),Point(221, 252), Point(219, 275), Point(185, 307), Point(165, 341)];
if SPS.walkPath(WTL2) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;
end;

Right now that walks from burth lode down to tav lode but I can't have it won't continue on if I have them both being called on, it gives me the error like it hasn't loaded the image. Is there a way to at least free up the sps before I load it?

You can have as many TSPSAreas as you want, e.g.

SPS1.setup('WTL1',RUNESCAPE_OTHER);
SPS2.setup('WTL2',RUNESCAPE_OTHER);
SPS3.setup('WTL3',RUNESCAPE_OTHER);

as long as you declare them as variables first there shouldn't be a problem.
I'd recommend naming them something other than SPS though, like:

Taverly.setup('WTL1',RUNESCAPE_OTHER);

then just use it like so:

Taverly.walkPath(WTL1);


So it would look something like this:

procedure WTL1();
var
WTL1: TPointArray;
Taverly: TSPSArea;
begin;
Taverly.setup('WTL1',RUNESCAPE_OTHER); //WTL1 map
WTL1 := [Point(230, 154), Point(221, 197), Point(215, 244), Point(208, 296), Point(200, 344)];

if Taverly.walkPath(WTL1) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;

procedure WTL2();
var
WTL2: TPointArray;
Falador: TSPSArea;
begin;
clearDebug(); // Clear the debug box
if isloggedin() then
begin;
Falador.setup('WTL2',RUNESCAPE_OTHER); //WTL2 map
WTL2 := [Point(200, 344),Point(221, 252), Point(219, 275), Point(185, 307), Point(165, 341)];
if Falador.walkPath(WTL2) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;
end;

Clutch
03-10-2015, 05:48 AM
evilcitrus;

I suppose I am confused. When I try to rename them I get unknown declaration "Taverly", you mentioned to declare them as variables though, how do I declare Taverly is = to SPS?

procedure WTL1();
var
WTL1: TPointArray;
WTL2: TPointARRAY;
Taverly:= SPS;
Taverly2:= SPS;
begin;
Taverly.setup('WTL1',RUNESCAPE_OTHER); //WTL1 map
WTL1 := [Point(230, 154), Point(221, 197), Point(215, 244), Point(208, 296), Point(200, 344)];

if Taverly.walkPath(WTL1) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
begin;
Taverly2.setup('WTL2',RUNESCAPE_OTHER); //WTL2 map
WTL2 := [Point(200, 344),Point(221, 252), Point(219, 275), Point(185, 307), Point(165, 341)];
if Taverly2.walkPath(WTL2) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;
end;

Citrus
03-10-2015, 05:51 AM
I suppose I am confused. When I try to rename them I get unknown declaration "Taverly", you mentioned to declare them as variables though, how do I declare Taverly is = to SPS?

Check out the last bit of code I posted. Right under your WTL1: TPointarray; I added Taverly: TSPSArea;

Clutch
03-10-2015, 05:56 AM
Check out the last bit of code I posted. Right under your WTL1: TPointarray; I added Taverly: TSPSArea;
If you see the edit's I made that gave me the exact same results as changing them to TSPSArea. It picks them up, but once it gets to the 2nd one, it just blasts through the points but doesn't actually click. I'm not 100% sure but I think this may be due to me not having a wait function?

Citrus
03-10-2015, 06:05 AM
If you see the edit's I made that gave me the exact same results as changing them to TSPSArea. It picks them up, but once it gets to the 2nd one, it just blasts through the points but doesn't actually click. I'm not 100% sure but I think this may be due to me not having a wait function?

It's hard to say without seeing it in action, but it could be a waiting issue. I usually add short (300-400ms) waits before and after minimap.waitPlayerMoving().
Also I'd keep WTL1 and WTL2 as separate procedures. It's cleaner and allows you to isolate issues more easily.

Clutch
03-10-2015, 06:18 AM
procedure Taverly1;
var
WTL1: TPointArray;
Taverly: TSPSArea;
begin;
Taverly.setup('WTL1',RUNESCAPE_OTHER); //WTL1 map
WTL1 := [Point(230, 154), Point(221, 197), Point(215, 244), Point(208, 296), Point(200, 344)];
if Taverly.walkPath(WTL1) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;

procedure Taverly2;
var
WTL2: TPointARRAY;
Taverly2: TSPSArea;
begin;
Taverly2.setup('WTL2',RUNESCAPE_OTHER); //WTL2 map
WTL2 := [Point(200, 344),Point(221, 252), Point(219, 275), Point(185, 307), Point(165, 341)];
if Taverly2.walkPath(WTL2) then
minimap.waitPlayerMoving()
else
writeLn ('Failed to walk');
end;
Begin;
clearDebug();
smartEnableDrawing := true;
setupSRL();
if isloggedin() then
begin;
//lodestoneSetup();
Taverly1;
Taverly2;
end
else
begin
createPlayer;
SkipTutorial();
interfaceSetup();
lodestoneSetup();
end;
end.

Sorry was trying to clean up the code so it wasn't so jumbled. This is basically what I have right now. Start anywhere near burthrope lodestone, it'll run south til it gets to about the cow pen and then runs through Taverly2; (at least in the debug) it doesn't actually click to those points though.

Citrus
03-10-2015, 06:27 AM
Is it writing "Failed to walk" or does it think it walked successfully?

Clutch
03-10-2015, 06:29 AM
Is it writing "Failed to walk" or does it think it walked successfully?
---- Setup area "WTL1" in 16ms
-- .init()
-- .getPlayerPos(): result = {X = 198, Y = 326}, took 141 ms
---- Waiting while the player is moving...
-- .walkPath(): result = True
---- Waiting while the player is moving...
-- .init()
---- Path exists (C:\Simba\Includes\SPS\img\runescape_other\WTL2.pn g)
---- Setup area "WTL2" in 16ms
-- .init()
-- .getPlayerPos(): result = {X = 214, Y = 150}, took 156 ms
-- .getPlayerPos(): result = {X = 214, Y = 150}, took 156 ms
-- .getPlayerPos(): result = {X = 214, Y = 150}, took 156 ms
-- .getPlayerPos(): result = {X = 214, Y = 150}, took 156 ms
-- .getPlayerPos(): result = {X = 214, Y = 150}, took 156 ms
-- .getPlayerPos(): result = {X = 214, Y = 150}, took 156 ms
-- .getPlayerPos(): result = {X = 214, Y = 150}, took 156 ms
-- .walkPath(): result = False
Failed to walk
-- Succesfully freed SMART[2812]
Successfully executed.

Citrus
03-10-2015, 06:36 AM
Okay so your first path point in WTL2 is [200, 344], but SPS is saying your position is [214, 150]. The Y position is way off, probably because your WTL2.png file is too small. Try expanding your map by ~20%.

Clutch
03-10-2015, 06:42 AM
Okay so your first path point in WTL2 is [200, 344], but SPS is saying your position is [214, 150]. The Y position is way off, probably because your WTL2.png file is too small. Try expanding your map by ~20%.

Oh holy crap I am such an idiot. Realized what you were talking about but then when I changed it it still didn't work. Went back and compared my sps file to where I end and I AM WAY OFF! Fixing right now! Thanks a ton haha!

So, question I double checked it was in the correct location but my first input is still way off in relation to my player position. Ex. player position is X=270, Y=74 but from the SPS I created AT THE EXACT location I'm standing on it chooses point 31,183...
Proof:
25249
evilcitrus;
Please don't tell me I'm gonna have to manually input each coordinate...

Citrus
03-10-2015, 07:40 AM
I'm not very familiar with SPS and haven't used it much so I'm probably not the best person to be helping with this. I've always solved my SPS problems by making my map bigger. I'd say expand your map so that your points aren't so close to the edges. I gotta get some sleep so hopefully you can figure it out or someone else can help.

Incurable
03-10-2015, 11:33 AM
OzoneClutch

I'm on my phone at the moment and I won't have access to a computer until tomorrow, but I will PM it to you then.

Btw, I'm flattered that people keep mentioning my LSU script, I don't even think it's very good, lol. :P

Clutch
03-10-2015, 12:55 PM
OzoneClutch

I'm on my phone at the moment and I won't have access to a computer until tomorrow, but I will PM it to you then.

Btw, I'm flattered that people keep mentioning my LSU script, I don't even think it's very good, lol. :P

Haha, well good or not it'll help me out a ton cuz right now this SPS mapping thing is kicking my butt.

3Garrett3
03-10-2015, 03:21 PM
OzoneClutch

I'm on my phone at the moment and I won't have access to a computer until tomorrow, but I will PM it to you then.

Btw, I'm flattered that people keep mentioning my LSU script, I don't even think it's very good, lol. :P


Haha, well good or not it'll help me out a ton cuz right now this SPS mapping thing is kicking my butt.

He's right, it's not even that good ;)

It will get the job done for ya though, especially with helping you get the lodestones for your char creator. Like evilcitrus said, your map should have at least a full minimap of "overhang" around the area you'll be walking so that it can accurately detect where you are. There's also a few settings that you can mess around with if you need more accuracy.

This thread (https://villavu.com/forum/showthread.php?t=110924) and this post (https://villavu.com/forum/showthread.php?t=111292&p=1322409#post1322409) should be helpful in figuring out the settings for SPS maps.

Clutch
03-10-2015, 04:19 PM
He's right, it's not even that good ;)

It will get the job done for ya though, especially with helping you get the lodestones for your char creator. Like evilcitrus said, your map should have at least a full minimap of "overhang" around the area you'll be walking so that it can accurately detect where you are. There's also a few settings that you can mess around with if you need more accuracy.

This thread (https://villavu.com/forum/showthread.php?t=110924) and this post (https://villavu.com/forum/showthread.php?t=111292&p=1322409#post1322409) should be helpful in figuring out the settings for SPS maps.

I'm at work so can't look in depth at those but it sounds like I just need to overlay my maps (resulting in alot more work but shouldn't be too bad with a copy & paste) opposed to trying to piece them together. Also, haven't seen his script yet but I am curious as to how he got it to click the lodestone, I tried adding in a mouseover text function with colors but it is hit and miss (the colors seem to range too much and yes I grabbed multiple colors from the ACA) the entire middle section of the lodestone is a solid color between world hopping I only found a total of 4 colors and the end result apparently isn't working. That being said I'm wondering if it would be better to add in for it to simply search for a mousebox and then look for the mouseover text inside of the TBox (with a DTM?)

loginor
03-10-2015, 06:30 PM
I would like to say a big thank you for this tutorial. Helped me a lot. Hopefully, in a week or so my trading bot will be ready for use :P

Incurable
03-10-2015, 11:16 PM
I'm at work so can't look in depth at those but it sounds like I just need to overlay my maps (resulting in alot more work but shouldn't be too bad with a copy & paste) opposed to trying to piece them together. Also, haven't seen his script yet but I am curious as to how he got it to click the lodestone, I tried adding in a mouseover text function with colors but it is hit and miss (the colors seem to range too much and yes I grabbed multiple colors from the ACA) the entire middle section of the lodestone is a solid color between world hopping I only found a total of 4 colors and the end result apparently isn't working. That being said I'm wondering if it would be better to add in for it to simply search for a mousebox and then look for the mouseover text inside of the TBox (with a DTM?)

I used a rip off version of Mayor's object finder to find the lodestones, each of them has a unique enough set of colours that you can search for them once you know they're on screen.

I've just PM'd you the script, let me know if you don't get it. No guarantees that it still even works though, and for goodness sake, don't go down the route of static TBox's that I did through pure frustration, lol.

Clutch
03-11-2015, 01:52 AM
I used a rip off version of Mayor's object finder to find the lodestones, each of them has a unique enough set of colours that you can search for them once you know they're on screen.

I've just PM'd you the script, let me know if you don't get it. No guarantees that it still even works though, and for goodness sake, don't go down the route of static TBox's that I did through pure frustration, lol.

Got the PM, I don't care if it works still or not, I just want to see how you wrote it so maybe I can integrate something similar (to at least get it to work) and static TBox's are a no go...i'll look into that object finder (is that the DTMS thing)?

Edit: Incurable; Got it thanks alot. Slightly depressed, looks way complicated, hopefully because I haven't done it myself. We will see how this turns out... haha :P

Edit2:
The Mayor; KeepBotting; 3Garrett3;
Okay guys, let me explain again what is occuring. Basically using SPS does not work with using multiple maps. It tries to calc my player position based on the currently loaded map, in the example below you'll see that my playerpos at the end is 150,327. It then loads a NEW map and the starting position on the new map (which is directly on top of the ending position on the map) is picking my playerpos but it's detecting that the coordinates for that map are 193,153 not 150,327 even though its the same spot (I understand it's slightly different but not THAT different). That being said if you don't understand I encourage you to test it for yourself, you simply need to create your own map and copy the array path.

Notice the area is almost identical (center is close to identical as well obviously) note the positions in red though!
25264

procedure Taverly2;
var
WTL2: TPointArray;
Taverly2: TSPSArea;
begin;
Taverly2.setup('WTL2',RUNESCAPE_OTHER,3,150,0.65); //WTL2 map
WTL2 := [Point(200, 133), Point(202, 166), Point(196, 217), Point(196, 262), Point(176, 287), Point(172, 298), Point(151, 316), Point(150, 327)];
if Taverly2.walkPath(WTL2) then
begin
wait (random(300,600));
minimap.waitPlayerMoving();
wait (random(300,600));
end
else
writeLn ('Failed to walk');
end;

procedure ActivateTaverly;
var
x, y, i: integer;
begin
if not isLoggedIn() then
exit
else
mainscreen.findObject(x, y, 5660509, 1, colorSetting(2, 1.86, 0.98), mainscreen.playerPoint, 20, 20, 1, ['averly', 'lodes'], MOUSE_LEFT);
wait(randomRange(7000, 10000));
mouse(point(288,211),MOUSE_LEFT);
end;

procedure Falador;
var
WTFalador: TPointArray;
Falador: TSPSArea;
begin;
Falador.setup('WTFalador',RUNESCAPE_OTHER,3,150,0. 65);
WTFalador := [Point(193, 153), Point(214, 198), Point(215, 244), Point(238, 255), Point(270, 265), Point(295, 248), Point(332, 227), Point(353, 212), Point(361, 177)];
if Falador.walkPath(WTFalador) then
begin
wait (random(300,600));
minimap.waitPlayerMoving();
wait (random(300,600));
end
else
writeLn ('Failed to walk');
end;
Begin;
clearDebug();
smartEnableDrawing := true;
setupSRL();
if isloggedin() then
begin;
//lodestoneSetup;
//Taverly1;
Taverly2;
//ActivateTaverly;
Falador;
end
else
begin
createPlayer;
SkipTutorial;
interfaceSetup;
lodestoneSetup;
Taverly1;
Taverly2;
ActivateTaverly;
Falador;

end;
end.

Edit 3: As a workaround I suppose I could make my maps extremely small and have a single map for each point to point interaction, albeit that's going to be 600 maps (probably not close but you get the point) and alot of effort. Any other ideas/workarounds? I think I could do as Incurable; did and use a single huge map (he did it or I read a thread/post on it) and just have 2 second wait times which if that's the best route to take then so be it.

Edit 4: I have a crazy idea (currently testing failed miserably) but due to the way that it is interacting I could in theory have it go from top to bottom of the map I load, then rotate my next map so that my beginning position starts at my last ending position (for the way SPS sees it (ex. Top of Map A. ends at the bottom, Map B. Begins at the bottom and the path goes to the TOP)) although assuming this works it'll be a bit annoying but sounds like my best option unless one of you have a better idea or I am completely not understanding what is going on.

Edit 5: giving up for the night, that being said getplayerpos... does that come from the sps map? If so is there a way to force change it to detect your at location x,y and then start next map coords within that area?

chubeam
04-02-2015, 08:25 AM
Great guide! Looking forward to scripting

Coyeks
04-26-2015, 07:07 AM
Wow... amazing guide to start with!

Thank you! :D

SmallP3n0r
05-01-2015, 01:14 AM
Thanks for the awesome starting guide. Setting aside a few hours this weekend to stumble through creating a basic script.

srlMW
06-04-2015, 04:43 AM
Rep+ Mayor, this guide was extremely helpful!

dodo
06-05-2015, 11:34 AM
Thanks, Awesome Tutorial!

GetHyper
06-05-2015, 10:39 PM
This is some guide, will be having a good read this weekend.

Edit:
So, just got one more section to work through - mining the ore (or fishing the fish in my case)
I have found this very helpful and would like to thank you!

The Mayor
06-07-2015, 10:39 AM
Great guide! Looking forward to scripting


Wow... amazing guide to start with!

Thank you! :D


Thanks for the awesome starting guide. Setting aside a few hours this weekend to stumble through creating a basic script.


Rep+ Mayor, this guide was extremely helpful!


Thanks, Awesome Tutorial!


This is some guide, will be having a good read this weekend.

Edit:
So, just got one more section to work through - mining the ore (or fishing the fish in my case)
I have found this very helpful and would like to thank you!


I am glad you liked it!

R3LAX
06-07-2015, 01:19 PM
Thanks very much - will certainly assist me when I start to create my first script after exams!

klopfie
06-09-2015, 07:05 AM
Thanks Mayor !!

Incurable
06-11-2015, 09:14 AM
The Mayor, I have a suggestion for improvement. Change your references to "main loop" to "main method", because it's not a loop, it's essentially a procedure. I was helping someone today and they were getting really confused by the misuse of the phrase in your tutorial. :)

The Mayor
06-11-2015, 05:03 PM
The Mayor, I have a suggestion for improvement. Change your references to "main loop" to "main method", because it's not a loop, it's essentially a procedure. I was helping someone today and they were getting really confused by the misuse of the phrase in your tutorial. :)

I've always thought how that was a bit misleading.

coralreefer
06-23-2015, 06:45 AM
This is a brilliant tutorial. I have no coding background whatsoever, but you are an inspiration to me to start learning and get into the SRL/Simba coding world and coding world in general.

kodex
07-22-2015, 07:27 AM
program TeleTabber;
{$DEFINE SMART}
{$i srl-6/srl.simba}

procedure changeAngleBoss();
begin
mainScreen.setAngle(MS_ANGLE_HIGH);
end;

procedure clickTree();
var
x, y: integer;
begin
if mainscreen.findObject(x, y, 10266538, 19, ['ecter'], MOUSE_RIGHT) then
begin

chooseOption.select(['Study']);
if productionScreen.isOpen(5000) then

productionScreen.clickStart()

end;
end;

procedure getclay();
begin
repeat
wait(1000);
until (not progressScreen.isOpen());
end
procedure getmore();
var
x, y: integer;
begin
if mainscreen.findObject(x, y, 2039572, 10, ['utler'], MOUSE_RIGHT) then

begin
writeLn('We right clicked a tree!');
chooseOption.select(['Fetch']);
wait(500);
conversationBox.selectOption(1);
end;
end;

begin //this needs to be here, this is what starts it all, maybe you should at a "repeat repeatwhatyouwanthere until false;" so the script will keep going :D
clearDebug();
setupSRL();
changeAngleBoss();
clickTree();
getclay();
getmore();
end.
im having a problem where its not doing the repeat wait until progress screen is not open.
any help is appreciated.

Fisher
07-22-2015, 05:54 PM
Sorry if this is answered somewhere else but how do I open the ACA? None of the default programs it used to open worked and I am completely stumped on this part. I do love this tutorial though and am working on my first script :D

fady
07-22-2015, 06:03 PM
Sorry if this is answered somewhere else but how do I open the ACA? None of the default programs it used to open worked and I am completely stumped on this part. I do love this tutorial though and am working on my first script :D

download it from this thread https://villavu.com/forum/showthread.php?t=26944 the program is in a .rar file, you use WinRAR to open that, and extract the file somewhere.

Fisher
07-22-2015, 06:32 PM
download it from this thread https://villavu.com/forum/showthread.php?t=26944 the program is in a .rar file, you use WinRAR to open that, and extract the file somewhere.

Thank you! I had a feeling it was going to be something simple to make me feel stupid :)

bucko
07-23-2015, 08:04 AM
Very useful, thanks mayor

neffetz
09-09-2015, 02:23 PM
This is a lot to take in. Thanks so much for taking the time to create this. I want to get more involved with this community and this is a great place to start.

Officer
10-27-2015, 07:26 PM
Even though this guide looks great, It hasn't been updated in more than 8 months. Does that still make it relevant or no? RS3 had lots of changes since this guide was last updated, such as the new loot system.

StickToTheScript
10-27-2015, 07:53 PM
Even though this guide looks great, It hasn't been updated in more than 8 months. Does that still make it relevant or no? RS3 had lots of changes since this guide was last updated, such as the new loot system.

Its all still good!

Clarity
10-27-2015, 07:54 PM
Even though this guide looks great, It hasn't been updated in more than 8 months. Does that still make it relevant or no? RS3 had lots of changes since this guide was last updated, such as the new loot system.
SRL-6 has been constantly updated for any changes to RS3, and everything taught in this guide is still very current :)

GeezerToad
12-14-2015, 04:36 AM
Thank you for the tutorial. I am currently working on a script of my own.

jcbird
12-24-2015, 07:20 AM
Click Extensions -> View -> Enable DTM Editor. Then click Tools -> DTM editor.

It should be Click View -> Extensions -> Enable DTM Editor

jcbird
12-24-2015, 07:35 AM
Sorry to keep bugging but to find the matching DTM , it should be Image -> Show Matchig DTMs, not Click DTM -> Show matching DTMs

jcbird
12-24-2015, 06:27 PM
The thing that I am most confused about is finding the height and width of the Deposit box. I know that you have the height as 50 pixel and width as 30 pixel but I used the DTM in Simba to get the TPoints of the top and bottom, and used a calculator so calculate the distance between two coordinate, and I did it similarly for the width as well, and my height and width were 40ish and 19ish respectively. Is there any other way to calculate it since my calculation seems to be off than what you have.

fady
12-25-2015, 06:05 AM
The thing that I am most confused about is finding the height and width of the Deposit box. I know that you have the height as 50 pixel and width as 30 pixel but I used the DTM in Simba to get the TPoints of the top and bottom, and used a calculator so calculate the distance between two coordinate, and I did it similarly for the width as well, and my height and width were 40ish and 19ish respectively. Is there any other way to calculate it since my calculation seems to be off than what you have.

Hey, so when thinking about 'object' width and height, you have to think of it like this. These dimensions are not the dimensions that simba will look for, but when simba finds all the pixels that match the colors you have selected and groups them, it will group them to boxes a maximum dimension of what you decided. so lets say you set it 50x50, but simba ONLY finds the colors in an area that is 20x20 then the box that you will click will only be 20x20. However, if simba finds the colors everywhere around the screen, then it will group all that are a maximum of 50x50 pixels from the first point with the color detected from the TOP LEFT of the screen. The whole point is, the purpose of the height and the width arent for the exact height and width of the object, it is the maximum dimensions you want simba to cut off neighboring matching colors and create new "click boxes". if set too small, it might detect alot of tiny click boxes to look through, and if set too big, the object you're looking for might be grouped with other irrelevant neighboring matching colors, and you end up with a false negative.

This all has to do with TPAs and ATPAs, and there are other ways to sort this kind of stuff. If you want me to go into more detail, feel free to add me on skype and I'll try and help you understand as much as I can.

If you would rather ask here, then also feel free to do so, but make sure you quote me so I get a notification! :)

Also, Welcome to Villavu!!!

jcbird
12-26-2015, 06:48 AM
Hey, so when thinking about 'object' width and height, you have to think of it like this. These dimensions are not the dimensions that simba will look for, but when simba finds all the pixels that match the colors you have selected and groups them, it will group them to boxes a maximum dimension of what you decided. so lets say you set it 50x50, but simba ONLY finds the colors in an area that is 20x20 then the box that you will click will only be 20x20. However, if simba finds the colors everywhere around the screen, then it will group all that are a maximum of 50x50 pixels from the first point with the color detected from the TOP LEFT of the screen. The whole point is, the purpose of the height and the width arent for the exact height and width of the object, it is the maximum dimensions you want simba to cut off neighboring matching colors and create new "click boxes". if set too small, it might detect alot of tiny click boxes to look through, and if set too big, the object you're looking for might be grouped with other irrelevant neighboring matching colors, and you end up with a false negative.

This all has to do with TPAs and ATPAs, and there are other ways to sort this kind of stuff. If you want me to go into more detail, feel free to add me on skype and I'll try and help you understand as much as I can.

If you would rather ask here, then also feel free to do so, but make sure you quote me so I get a notification! :)

Also, Welcome to Villavu!!!

Thank you for the info! I got the general idea from your info. I am still doing the tutorial so, if i need anything, i will definitely let you know. I have added you as a friend and will send you the Skype details when i get more advanced.

Danielius
12-30-2015, 09:02 AM
Thanks a lot for this guide! Finally I'll be able to start scripting. :')

blank
03-28-2016, 02:49 PM
I'm very new to this and Im using ur guide to try and make my simple bot.
its a clanwars bot all i need it to do is walk in and when it dies it repeats. So far i've did the path thing for both clanwars lobby and actual clanwars i also just did the dtm, but my issue is i keep getting a error as soon as my character enters saying "------ TRSLobby.findPlayButton(): result = False"
it starts of with a true and then it keeps saying false. How do i fix this?

Thankyou

Manthur
04-16-2016, 09:38 PM
Thanks for this guide mate. This would be my first venture into programming anything.( I did some CE scripts for a couple of games but that's it).

Followed the guide, though not for mining Clay* but to do red chins in feldip hills. Had a couple of hiccups but after an hour and a half I figured most of it out.

I have to say that I'm having a lot of fun doing this. I'll venture out and try to do more scripts for myself. Maybe a Seren harp script if it's at all feasable.

I'll ask around if I need any help though. Catch ya'll laters. Off to try some stuff \o/

Dequality
10-22-2016, 03:11 PM
I got what i consider a serious problem . i can't make the map pathing system work at all.. i choose a okay path but it does always end up like 1-2minimaps away? >.<

Dequality
10-22-2016, 03:27 PM
This is a picture of where my character ended up (i stopped him before he moved any further..)
27874
http://imagizer.imageshack.us/a/img921/9373/1btuos.png

Dequality
10-22-2016, 03:28 PM
These are images of my character position ( stopped him before he moved even further away) and my SPS map ..

27875
27876


Close to giving up sadly.. i would enjoy this insanely to create my own shit but guess i'll have to stick to leeching for now ... can't really be arsed i struggled with it for like 2-3hours now can't figure out what im doing wrong , tried with like 400 dots on the map or larger distances between, new pictures etc.. none worked =(

acow
10-22-2016, 03:29 PM
These are images of my character position ( stopped him before he moved even further away) and my SPS map ..

27875
27876

try out a larger SPS map

Dequality
10-22-2016, 03:39 PM
try out a larger SPS map

Just tried this .. didnt work =(
27877


Also tried this now

http://imageshack.com/a/img923/4640/oezqhg.gif

acow
10-22-2016, 04:03 PM
Justin; is the forum software hiding posts? Second time in a few days now that I got notifications w/ no new post to check out.

Just now on this thread:
http://i.imgur.com/OZq01kL.png
http://i.imgur.com/nchqmc0.png

2 days ago:
http://i.imgur.com/D1wjO05.png
http://i.imgur.com/qsEZE0k.png

Seems like something needs to be fixed on the forums auto moderating ^^

e: a user to check out https://villavu.com/forum/member.php?u=162347

Dequality
10-22-2016, 04:09 PM
Tried this now.. ( doing the Clay one now... ) made the deposit box work but can't make this work -_-'

27878

Dequality
10-22-2016, 05:37 PM
Yet another fail try.. someone please help me .. i made a huge SPS but still not reaching the point.. =(

27879

Dequality
10-22-2016, 06:08 PM
Question is it really that important the SPS size?I mean I tried both bigger and smaller but none gets me to the spot i actually chose as end point in SPS :huh:



EDIT: Was thinking is it possible to just open up the world map and take a snapshot from there and use it or? Ain't home so can't test it just came to my mind :ninja:

Dequality
10-22-2016, 10:28 PM
Okay, so i made the SPS' work, and rest of it worked as well, is it possible someone will check my script through can't seem to find the error? it wont walk to the deposit box.

27880



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 files

procedure declarePlayers();
begin
setLength(players, 1);
with players[0] do
begin
loginName := 'USER';
password := 'PASS';
isActive := true;
isMember := false;
end
currentPlayer := 0;
end;

procedure tpToVarrock();
var
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());
end;

procedure runToClay
var
pathToMine: TPointArray;

begin
if not isLoggedIn() Then
exit;
pathToMine := [[213, 225], [198, 183], [189, 124], [172, 87], [130, 69], [78, 59], [40, 70], [47, 108], [70, 118], [80, 123]];

if SPS.walkPath(pathToMine) Then
minimap.waitPlayerMoving()
else
writeLn('We failed to walk to the clay');
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, 4298938, mainScreen.getBounds(), 6, colorSetting(2, 0.48, 1.38));

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);
claimSpinTicket();
until tabBackpack.isFull() or (mineTimer.getTime() > 30000);
end;

procedure tpToPortSarim();
var
pathToDepositBox: TPointArray;
p: TPoint;
begin
if not isLoggedIn() Then
exit;
repeat
lodestoneScreen.teleportTo(LOCATION_PORT_SARIM);
wait(randomRange(16000, 19000));

until (not isLoggedIn()) or minimap.findSymbol(p,MM_SYMBOL_SHOP_FISHING, minimap.getBounds());

pathToDepositBox := [[212, 224], [247, 222], [278, 207], [279, 171], [281, 136], [326, 134], [369, 137]];

if SPS.walkPath(pathToDepositBox) Then
minimap.waitPlayerMoving()
else
writeLn('We failed to walk to the deposit box =(');
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);

end;

depositBox.close();

end;

procedure findDepositBox();
var
x, y, i: Integer;
begin
if not isLoggedIn() Then
exit;
repeat
mainscreen.findObject(x, y, 4411742, 7, colorSetting(2, 0.22, 1.75), mainscreen.playerPoint, 30, 50, 50, ['eposit', 'box'], MOUSE_LEFT); // 4872552, 5, colorSetting(2, 1.50, 0.34)
wait(randomRange(1000, 2500));
inc(i);
until depositBox.isOpen() or (i >= 15);
end;

// main loop
begin
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

//SPS.setup('PORT_SARIM', RUNESCAPE_OTHER); // My SPS Map for Clay
SPS.setup('PORT_SARIM_MAP', RUNESCAPE_OTHER); // My SPS Map for Clay
repeat
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;
if tabBackpack.isFull() then
begin
tpToPortSarim();
findDepositBox();
depositClay();
end;

tpToVarrock();
runToClay();
mineRocks();
until(false);
end.


If i aint allowed to post it here lmk just thought it would be easiest as the creator of the tutorial is here lol

Dequality :)

Justin
10-22-2016, 11:17 PM
Justin; is the forum software hiding posts? Second time in a few days now that I got notifications w/ no new post to check out.

Just now on this thread:
http://i.imgur.com/OZq01kL.png
http://i.imgur.com/nchqmc0.png

2 days ago:
http://i.imgur.com/D1wjO05.png
http://i.imgur.com/qsEZE0k.png

Seems like something needs to be fixed on the forums auto moderating ^^

e: a user to check out https://villavu.com/forum/member.php?u=162347

The spam filter was picking them up as spam. I've set 2 users bypass this filter.

Dequality
10-23-2016, 05:54 AM
The spam filter was picking them up as spam. I've set 2 users bypass this filter.

Sorry if it was spam like :sasmokin:

jakrz
01-15-2017, 10:01 PM
Thx for this great tutorial!