PDA

View Full Version : [SRL]How To Write Your First Script: Collecting and Banking Cabbages!



StickToTheScript
04-24-2018, 04:59 PM
How To Write Your First Script: Collecting and Banking Cabbages
Verified Working On: January 31, 2019

Table of Contents:
Part 1: Introduction
Part 2: Script Basics
Part 3: Colour Finding
Part 4: The Wait Loop
Part 5: Walking via RSWalker
Part 6: Banking
Part 7: The Antiban
Part 8: Final Words




Part 1: Introduction

What We Will Learn


In this tutorial, you will learn the basics of how the Old School SRL include works. We will create a fairly basic script that will allow us to collect the cabbages in the cabbage patch north-west of Draynor and bank them in the Draynor bank. If you haven't already properly installed Simba or the SRL Old School include, please go and read the Complete Guide to Setting Up Simba and SRL (https://villavu.com/forum/showthread.php?t=118223&p=1391739#post1391739). If you are new to programming, some of these ideas can be a little difficult to wrap your head around. If this is the case, you are encouraged to go back and read over the steps and descriptions again. If you are still having problems after that, you are more than welcome to post your questions below and I will do my best to answer them for you.

Now that you are ready, let's get started!




Part 2: Script Basics

Script Skeleton


Every script has a basic set of necessities that need to be implemented in order for it to function. These necessities are the 'bare bones' of the script and normally the starting point to every script (this is why we call it the skeleton). To start us off, this is generally what a skeleton will look like:


program scriptSkeleton;
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}

//Declare our Constants
const
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password
RS_WORLD = -1; //Desired World (-1 = Random)
IS_MEMBER = false; //True if your player is a Member

//Declare our variables
var
Walk: TRSWalker; //Used for RSWalker (to walk paths)

{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;

{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
SRL.Setup([]); //Setup SRL to allow us to access it's functions.
Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use
declarePlayers(); //Declare the player we are using

if (not SRL.isLoggedIn) then //If not logged in then..
begin
Players.LoginCurrent(); //Log player in
MainScreen.setAngle(True); //Sets the camera angle to the highest point
end;

Result := True;
end;

begin //Main
if setUp then
writeln('We are set up and ready to go!');
end.


This may look a little bit daunting but bear with me. I'll go through and explain each part. Let's start at the top and work our way down.

First, you will notice that we have this little section of code:
program scriptSkeleton;
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}
Each program ever created needs to have a name. All that the first line is doing is simply giving our script a name.

On line two, we simply define SMART. This means that when we run the script, we are telling the include that we would like to run an instance of SMART. Therefore, the include will create an instance of SMART that is running Old School Runescape and will only allow the script to interact with that instance of SMART.

Then we have our two include statements. By writing these two lines, we are telling Simba that we want to compile our program with the contents of both SRL/OSR.simba and RSWalker/WAlker.simba, which are the main files for the SRL Old School Include and the RSWalker Include.

Next, you will see two sections where we declare our global constants and variables.
//Declare our Constants
const
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password
RS_WORLD = -1; //Desired World (-1 = Random)
IS_MEMBER = false; //True if your player is a Member

//Declare our variables
var
Walk: TRSWalker; //Used for RSWalker (to walk paths)

Constants are values that will remain constant throughout the entirety of the script. Their value/contents should never change. A variable, on the other hand, is something that can be changed and normally needs to be initiallized to something while the script is running to be able to be used. In this case, our constants contain our login information, our desired world number, and if our account is a member or not. The variables are made up of a TRSWalker. By creating and using this variable later on allows us to be able to use RSWalker and all of the functions that come along wiht it. You will see more about this in the a second.

We then have our declarePlayers procedure:
{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;

A procedure is a set of code that, when executed, will only execute the code inside its section. In this case, our declarePlayers procedure will tell the SRL include what the current account login information is, as well as if it a member and what world we want to use.

You should note that the declarePlayers procedure does not return anything. This is because we use functions to return values. You can see that happening here:
{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
SRL.Setup([]); //Setup SRL to allow us to access it's functions.
Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use
declarePlayers(); //Declare the player we are using

if (not SRL.isLoggedIn) then //If not logged in then..
begin
Players.LoginCurrent(); //Log player in
MainScreen.setAngle(True); //Sets the camera angle to the highest point
end;

Result := True;
end;
The setUp function is what we call to initialize our includes, any variables we have globally created, declare our player, and do the beginning work of the script (i.e. log the player in). If you notice the first line of code where we declare the name of the function, you will notice a little tag that shows:

: boolean;
This means that we are want to return a boolean value (True or False) when this section of code is finished executing. By default, the return value will be false unless we tell it to return true. This can be done by setting the result to true like this:
Result := True;

Functions do not only need to return boolean values. They can return any type of variable that you want. For example:

function example: Integer; //Returns an Integer
function example: String; //Returns a String
function example: TBox; //Returns a TBox
function example: TPointArray; //Returns a TPointArray
...


Finally, we have our main area which looks like this:

begin //Main
if setUp then
writeln('We are set up and ready to go!');
end.
This final begin...end statement is where the brains of the operation is. If this begin...end statement is left empty, then nothing will happen. You can see that I put an if...then... statement in there and used our setUp function as our variable. In pseudo-code, this statement is read as:

if setUp is True, then
write a line saying "We are set up and ready to go!"


I hope this gives you a basic understanding of some of the general ideas and how they work, along with the script skeleton. It might be a little confusing since I mixed a bunch of concepts into one section, so feel free to go back and read over things again until you understand the ideas. If you don't like the way I tried describing them, there is an excellent tutorial on them over here (https://villavu.com/forum/showthread.php?t=107757) that I would encourage you to take a look through.




Part 3: Colour Finding

Grabbing The Colours


To grab the colours, we will be using the ACA Colour Finding Tool that you can download here (https://villavu.com/forum/showthread.php?t=98368). I still use the outdated version, but the ideas should still be the same.

Let's log in and go to the cabbage patch and then open up our ACA tool. You will then want to select the colours of the cabbage to the point where your screen looks like something similar to this:
https://i.imgur.com/Y2GXAx4.png

Make sure you are using the CTS2 mode because we want to get the best colour, tolerance, hue, and saturation values! I have selected unique colours to the cabbages and was able to get most of the cabbage recognized. This is normally what you want to go for when you are doing any sort of colour finding. Now that we have those values, we'll plug them into our colour finding procedure.


The Colour Finding Procedure


Now that we have the basis of the script down and we can successfully get a SMART window loaded, lets start with a method of finding the cabbages to pick up. Before we start to get the colours of the cabbages, we will go through the main colour finding procedure.
{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages();
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
begin
if not SRL.isLoggedIn() then //If not logged in, then terminate script
TerminateScript;

if (SRL.FindColors(TPA, CTS2(3127688, 27, 0.04, 0.87), MainScreen.GetBounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DrawATPA(ATPA); //Draws the ATPA's on the screen.
//smart.Image.DebugATPA(ATPA) works as well
{$ENDIF} //End SMART IF

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
waitLoop(); //Call to our waitLoop because we want to wait while picking.
Break; //If found red 'x', then break because we clicked it
end;
end;
end;
end;
{$IFDEF SMART}
Smart.Image.Clear; //Clears the ATPA's from screen
{$ENDIF}
end;

Don't panic. Yes, there is a lot there, but I have added a lot of comments in it to help explain what each line does. To grasp a complete understanding of everything that is happening in this procedure, I am going to recommend you read The core of colorfinding tutorial (https://villavu.com/forum/showthread.php?p=1391783). That tutorial will explain TPA's, ATPA's, and how to manipulate them to get the object you are looking for. The majority of this code is taken from that tutorial to allow you to get an understanding of it when applied to a specific object.

Basically, this procedure will do the finding of the colours of the cabbage and will group them, filter them, and then sort them to allow us to find our cabbages and our cabbages only! It will then procede to click on them.

To explain a bit, we will look at this line:
if (SRL.FindColors(TPA, CTS2(XXXX, XX, X.XX, X.XX), MainScreen.GetBounds) > 0) then //If we find colours at all then...
This is an if...then... statement that we covered earlier. Inside of it, we have a FindColors function that returns an Integer value. We check to see if this return value is greater than zero. If it is then we continue with at the begin...end statement directly below this line since it means we have found at least one colour, otherwise we will skip the begin...end statement completely.

Inside the if...then... statement, we have the following:
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DrawATPA(ATPA); //Draws the ATPA's on the screen.
//smart.Image.DebugATPA(ATPA) works as well
{$ENDIF} //End SMART IF
This is where we have the grouping, filtering, and sorting happening that I mentioned earlier. You can read the comments next to each line as they describe how each call affects the entire ATPA. The only spot that may need explaining is the unique looking $IFDEF statement. This works in a similar manner to our if...then... but it applied to if we have defined SMART or not. By this, I mean:

If SMART has been defined then
Draw our ATPA on ths screen
End If
This means that if SMART is not defined at the top of our script (maybe you commented it out), then there will be no drawing on the RSClient that you are using, but if you are using SMART, you will see random colours overtop of each object the our script thinks are cabbages based on the information we have given it.

We then have this:
for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
Break; //If found red 'x', then dont go through all the others because we already clicked one
end;
end;
end;

This section uses a for...do... loop. To explain what is going on, we must note that 'Cabbage' is a TPointArray variable that points to TPA[0] to TPA[MAX] in the ATPA. The pseudo-code for this is:

For every TPA that can be a cabbage in ATPA do...
The rest of it should be pretty self explanitory from the comments since we are then using some built-in functions from the SRL include to move the mouse, check the uptext of the cabbage and then click it and see if our click was the red 'x' or not.


Putting It Together


To test this, we can run the following code:
program new;
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}

const //This is where we declare our constants
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password
RS_WORLD = -1; //Desired World (-1 = Random)
IS_MEMBER = false; //True if your player is a Member

var //This is where we declare our variables
Walk: TRSWalker; //Used for RSWalker (to walk paths)

{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;

{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages();
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
begin
if not SRL.isLoggedIn() then //If not logged in, then terminate script
TerminateScript;

if (SRL.FindColors(TPA, CTS2(3127688, 27, 0.04, 0.87), MainScreen.GetBounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DrawATPA(ATPA); //Draws the ATPA's on the screen.
//smart.Image.DebugATPA(ATPA) works as well
{$ENDIF} //End SMART IF

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
Break; //If found red 'x', then break because we clicked it
end;
end;
end;
end;
{$IFDEF SMART}
Smart.Image.Clear; //Clears the ATPA's from screen
{$ENDIF}
end;

{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
{$IFDEF SMART} //If we are using SMART, then...
Smart.EnableDrawing := True; //let us draw on SMART
{$ENDIF} //end SMART IF

SRL.Setup([]); //Setup SRL to allow us to access it's functions.

Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use

declarePlayers(); //Declare the player we are using

if (not SRL.isLoggedIn) then //If not logged in then..
begin
Players.LoginCurrent(); //Log player in
MainScreen.setAngle(True); //Sets the camera angle to the highest point
end;
end;

begin //Main
if setUp then //Calls the setup of the script
writeln('We are set up and ready to go!');

findCabbages(); //Collect Cabbages until inv is full
end.

By running this, you will see the computer find a cabbage on the ground and then click it to pick it up. This means that we have successfully been able to locate an object and interact with it! This can now be applied to any other object that you wish to find while writting scripts!




Part 4: The Wait Loop

Forming Your Wait Loop


Since our cabbage is able to be found on the ground, you can try running the program with a repeat...until... loop in the main area like such:
repeat
findCabbages(); //Collect Cabbages until inv is full
until(false);

Without a wait loop when finding your cabbages, you will notice that your mouse will be constantly attempting to find cabbages and you will never actually pick one up. We need to construct a procedure/function that will allow us to be able to wait until we have picked up the cabbage we clicked before attempting to find the next one. To do this, I have constructed this procedure:
{************************************************* ******************************
Name: waitLoop();
Function: Waits until we have collected our cabbage
************************************************** *****************************}
procedure waitLoop();
var
InvCount: Integer;
T: TTimeMarker;
begin
if not SRL.isLoggedIn() then
Exit;

InvCount := Inventory.Count(); //Gets the count in our inventory
T.Start; //Start our timer
repeat
wait(randomRange(75, 250)); //Wait a random amount of time
until((Inventory.Count() > InvCount) or (T.GetTime > 7000)); //Stop repeating once inv count changes or we time out
end;

There are a few new elements in here, so let's go over them.

For starters, you will notice that we have initialized some local variables. This is done similarily to how we did it with the global variables, but we place the var label inside of the procedure. We did the same thing in the colour finding section too. The two variables we have created are an invCount integer to keep track of our inventory count before we jump into the repeat, as well as a T variable which is a timer.

To start, we initialize the invCount variable before we get into the loop. We do this because we need a reference point to check how many slots in our inventory are filled before we actually make it to the cabbage to pick it up. We then start the timer. This timer is used because we don't want to accidentally get stuck in an infinite loop. After this, we jump into the repeat...until... statement where we repeat waiting until our inventory count has increased from when we set invCount, or when we have been in the loop for 7 seconds because it should only take a couple seconds to actually make it to the cabbage.


Calling Your Wait Loop


Calling your wait loop can happen in multiple different ways. For this tutorial, I will call it in our findCabbages procedure like such:
{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages();
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
begin
if not SRL.isLoggedIn() then //If not logged in, then terminate script
TerminateScript;

if (SRL.FindColors(TPA, CTS2(3127688, 27, 0.04, 0.87), MainScreen.GetBounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DrawATPA(ATPA); //Draws the ATPA's on the screen.
//smart.Image.DebugATPA(ATPA) works as well
{$ENDIF} //End SMART IF

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
waitLoop(); //Call to our waitLoop because we want to wait while picking.
Break; //If found red 'x', then break because we clicked it
end;
end;
end;
end;
{$IFDEF SMART}
Smart.Image.Clear; //Clears the ATPA's from screen
{$ENDIF}
end;

Notice how waitLoop is called before the break? This is because if it is called after the break in this procedure, it will not actually get called.


Putting It Together


Now let's run this script:

program new;
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}

const //This is where we declare our constants
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password
RS_WORLD = -1; //Desired World (-1 = Random)
IS_MEMBER = false; //True if your player is a Member

var //This is where we declare our variables
Walk: TRSWalker; //Used for RSWalker (to walk paths)

{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;

{************************************************* ******************************
Name: waitLoop();
Function: Waits until we have collected our cabbage
************************************************** *****************************}
procedure waitLoop();
var
InvCount: Integer;
T: TTimeMarker;
begin
if not SRL.isLoggedIn() then
Exit;

InvCount := Inventory.Count(); //Gets the count in our inventory
T.Start; //Start our timer
repeat
wait(randomRange(75, 250)); //Wait a random amount of time
until((Inventory.Count() > InvCount) or (T.GetTime > 7000)); //Stop repeating once inv count changes or we time out
end;

{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages;
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
begin
if not SRL.isLoggedIn() then //If not logged in, then terminate script
TerminateScript;

if (SRL.FindColors(TPA, CTS2(3127688, 27, 0.04, 0.87), MainScreen.GetBounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DebugATPA(ATPA);
{$ENDIF} //End SMART IF

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
waitLoop(); //Call to our waitLoop because we want to wait while picking.
Break; //If found red 'x', then break because we clicked it
end;
end;
end;
end;
{$IFDEF SMART}
Smart.Image.Clear; //Clears the ATPA's from screen
{$ENDIF}
end;

{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
{$IFDEF SMART} //If we are using SMART, then...
Smart.EnableDrawing := True; //let us draw on SMART
{$ENDIF} //end SMART IF

SRL.Setup([]); //Setup SRL to allow us to access it's functions.

Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use

declarePlayers(); //Declare the player we are using

if (not SRL.isLoggedIn) then //If not logged in then..
begin
Players.LoginCurrent(); //Log player in
MainScreen.setAngle(True); //Sets the camera angle to the highest point
end;
end;

begin //Main
if setUp then //Calls the setup of the script
writeln('We are set up and ready to go!');
repeat
findCabbages(); //Collect Cabbages until inv is full
until(false); //Repeats forever
end.

You will notice that it picks up cabbages forever. This is great! It means we're making progress! Let's continue working on making it walk to the bank and bank all of the cabbages so we can grab more!
https://i.imgur.com/KPlViaX.gif




Part 5: Walking via RSWalker

Getting Your Points


Walking via RSWalker is fortunately fairly easy. We'll start off with our SPS Path Generator (https://villavu.com/forum/showthread.php?t=80134). Using this program and the 'world.png' found in "C:\Simba\Includes\RSWalker\maps", you'll be able to create your own paths! For this tutorial, the path I have created is the following:
https://i.imgur.com/jo2IhWr.png
This means that our paths should look like this:
//Both paths that we plan to walk (pBank = Patch -> Bank | pPatch = Bank -> Patch)
pBank := [Point(4022, 3289), Point(4022, 3332), Point(4059, 3342), Point(4096, 3347), Point(4105, 3394), Point(4127, 3431), Point(4153, 3457), Point(4178, 3478)];
pPatch := [Point(4178, 3478), Point(4153, 3457), Point(4127, 3431), Point(4105, 3394), Point(4096, 3347), Point(4059, 3342), Point(4022, 3332), Point(4022, 3289)];


You can create your own path and replace mine if you so desire! Feel free to experiment.


Walking The Path


Now that we actually have the path, we need to walk it! We can do that by using the WalkPath function:
Walk.WalkPath(path);
I have written a procedure that we can use that will accept a path and call the WalkPath function:
{************************************************* ******************************
Name: walkTo(path);
Function: Walks the path given by the 'path' variable.
************************************************** *****************************}
procedure walkTo(path: TPointArray);
begin
Walk.WalkPath(path); //Walk our path passed to the procedure
end;

This might seem a little unnecessary that there is only one line of code in this procedure. It will make sense once we get to Part 7 (it's a little bit of foreshadowing).


Putting It Together


This means that we can walk our current path by using the following code:
program new;
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}

const //This is where we declare our constants
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password
RS_WORLD = -1; //Desired World (-1 = Random)
IS_MEMBER = false; //True if your player is a Member

var //This is where we declare our variables
Walk: TRSWalker; //Used for RSWalker (to walk paths)
pBank, pPatch: TPointArray; //Paths from Patch to Bank, and Bank to Path

{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;

{************************************************* ******************************
Name: walkTo(path);
Function: Walks the path given by the 'path' variable.
************************************************** *****************************}
procedure walkTo(path: TPointArray);
begin
Walk.WalkPath(path); //Walk our path passed to the procedure
end;

{************************************************* ******************************
Name: waitLoop();
Function: Waits until we have collected our cabbage
************************************************** *****************************}
procedure waitLoop();
var
InvCount: Integer;
T: TTimeMarker;
begin
if not SRL.isLoggedIn() then
Exit;

InvCount := Inventory.Count(); //Gets the count in our inventory
T.Start; //Start our timer
repeat
wait(randomRange(75, 250)); //Wait a random amount of time
until((Inventory.Count() > InvCount) or (T.GetTime > 7000)); //Stop repeating once inv count changes or we time out
end;

{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages();
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
begin
if not SRL.isLoggedIn() then //If not logged in, then terminate script
TerminateScript;

if (SRL.FindColors(TPA, CTS2(3127688, 27, 0.04, 0.87), MainScreen.GetBounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DrawATPA(ATPA); //Draws the ATPA's on the screen.
//smart.Image.DebugATPA(ATPA) works as well
{$ENDIF} //End SMART IF

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
waitLoop(); //Call to our waitLoop because we want to wait while picking.
Break; //If found red 'x', then break because we clicked it
end;
end;
end;
end;
{$IFDEF SMART}
Smart.Image.Clear; //Clears the ATPA's from screen
{$ENDIF}
end;

{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
{$IFDEF SMART} //If we are using SMART, then...
Smart.EnableDrawing := True; //let us draw on SMART
{$ENDIF} //end SMART IF

SRL.Setup([]); //Setup SRL to allow us to access it's functions.

Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use

//Both paths that we plan to walk (pBank = Patch -> Bank | pPatch = Bank -> Patch)
pBank := [Point(4022, 3289), Point(4022, 3332), Point(4059, 3342), Point(4096, 3347), Point(4105, 3394), Point(4127, 3431), Point(4153, 3457), Point(4178, 3478)];
pPatch := [Point(4178, 3478), Point(4153, 3457), Point(4127, 3431), Point(4105, 3394), Point(4096, 3347), Point(4059, 3342), Point(4022, 3332), Point(4022, 3289)];

declarePlayers(); //Declare the player we are using

if (not SRL.isLoggedIn) then //If not logged in then..
begin
Players.LoginCurrent(); //Log player in
MainScreen.setAngle(True); //Sets the camera angle to the highest point
end;

Result := True;
end;

begin //Main
if setUp then //Calls the setup of the script
writeln('We are set up and ready to go!');
repeat
walkTo(pPatch); //Walk to Patch
while (not Inventory.IsFull) do
findCabbages(); //Collect Cabbages until inv is full
walkTo(pBank); //Walk to Bank
until(false); //Repeats forever
end.


You should notice that I've added a couple of things here. Let's go through them, shall we?

In our global variables, we have created two new TPointArray's with the names of our paths:
pBank, pPatch: TPointArray; //Paths from Patch to Bank, and Bank to Path
These are the two paths that we generated above. Along with that, you will see some changes to setup where we added the two paths that we generated.

Finally, in our main area, we added a few things:
walkTo(pPatch); //Walk to Patch
while (not Inventory.IsFull) do
findCabbages(); //Collect Cabbages until inv is full
walkTo(pBank); //Walk to Bank

Here, we initially want to walk our path to our patch in the case we are not there yet. Otherwise we will be looking for cabbages somewhere where we won't be able to find them. There is also a while...do... loop which allows us to fill our inventory full of cabbages before we actually begin to walk to the bank to bank them all. Then we finalize it with our walk to the bank once we have gathered a full inventory of cabbages!

Running to the field:
https://i.imgur.com/2H1mYTC.gif

Running to the Bank:
https://i.imgur.com/uDQA2L3.gif

Now we need to learn how to bank!




Part 6: Banking

Basics of Banking


When it comes to banking, there are multiple ways you can do it. You can create your own methods for finding the bankers/bank booths/chests/etc or you can use the SRL include's methods that do most of the work for you! Today, we will be covering how to use the include's built in functions.

For starters, we need to be able to open the bank once we have walked to it. We can do this by calling:
BankScreen.Open(blDrynor);
This function automatically find the banker and right click on them to open the bank! Easy, eh?

Now, the unfortunate part is that sometimes things can fail. When it comes to opening the bank, we will want to double check that the bank is open. To do this, we can use the following:
BankScreen.isOpen(5000);
This function will wait for 5 seconds to see if the bank's screen opens up. If it doesn't, it will return false, otherwise it will return true.

Once the bank screen in open, we will also want to be able to deposit our objects into the bank. To do so, we can use the following:
BankScreen.DepositAll();
This will press the 'Deposit All' button on the banking interface to deposite all the objects in the inventory.

Using these three functions, we can put them together and get a function that looks like this:
{************************************************* ******************************
Name: doBank();
Function:
************************************************** *****************************}
function doBank(): boolean;
begin
myAntiban(); //Do antiban
BankScreen.Open(blDrynor); //Open bank using SRL's built in banker function
if BankScreen.IsOpen(5000) then //If bank screen is open sometime within the 5 sec wait
begin
wait(randomRange(150, 500)); //Have a realistic wait time before we actually do anything
BankScreen.DepositAll(); //Deposit all cabbages
Result := True; //We want to return true when the function finishes, so we set Result to True
end;
end;


Putting It Together


This function will do everything that we need it to do for the bank. To test it, we can run the following:
program new;
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}

const //This is where we declare our constants
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password
RS_WORLD = -1; //Desired World (-1 = Random)
IS_MEMBER = false; //True if your player is a Member

var //This is where we declare our variables
Walk: TRSWalker; //Used for RSWalker (to walk paths)
pBank, pPatch: TPointArray; //Paths from Patch to Bank, and Bank to Path

{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;

{************************************************* ******************************
Name: doBank();
Function:
************************************************** *****************************}
function doBank(): boolean;
begin
BankScreen.Open(blDrynor); //Open bank using SRL's built in banker function
if BankScreen.IsOpen(5000) then //If bank screen is open sometime within the 5 sec wait
begin
wait(randomRange(150, 500)); //Have a realistic wait time before we actually do anything
BankScreen.DepositAll(); //Deposit all cabbages
Result := True; //We want to return true when the function finishes, so we set Result to True
end;
end;

{************************************************* ******************************
Name: walkTo(path);
Function: Walks the path given by the 'path' variable.
************************************************** *****************************}
procedure walkTo(path: TPointArray);
begin
Walk.WalkPath(path); //Walk our path passed to the procedure
end;

{************************************************* ******************************
Name: waitLoop();
Function: Waits until we have collected our cabbage
************************************************** *****************************}
procedure waitLoop();
var
InvCount: Integer;
T: TTimeMarker;
begin
if not SRL.isLoggedIn() then
Exit;

InvCount := Inventory.Count(); //Gets the count in our inventory
T.Start; //Start our timer
repeat
wait(randomRange(75, 250)); //Wait a random amount of time
until((Inventory.Count() > InvCount) or (T.GetTime > 7000)); //Stop repeating once inv count changes or we time out
end;

{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages();
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
begin
if not SRL.isLoggedIn() then //If not logged in, then terminate script
TerminateScript;

if (SRL.FindColors(TPA, CTS2(3127688, 27, 0.04, 0.87), MainScreen.GetBounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DrawATPA(ATPA); //Draws the ATPA's on the screen.
//smart.Image.DebugATPA(ATPA) works as well
{$ENDIF} //End SMART IF

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
waitLoop(); //Call to our waitLoop because we want to wait while picking.
Break; //If found red 'x', then break because we clicked it
end;
end;
end;
end;
{$IFDEF SMART}
Smart.Image.Clear; //Clears the ATPA's from screen
{$ENDIF}
end;

{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
{$IFDEF SMART} //If we are using SMART, then...
Smart.EnableDrawing := True; //let us draw on SMART
{$ENDIF} //end SMART IF

SRL.Setup([]); //Setup SRL to allow us to access it's functions.

Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use

//Both paths that we plan to walk (pBank = Patch -> Bank | pPatch = Bank -> Patch)
pBank := [Point(4022, 3289), Point(4022, 3332), Point(4059, 3342), Point(4096, 3347), Point(4105, 3394), Point(4127, 3431), Point(4153, 3457), Point(4178, 3478)];
pPatch := [Point(4178, 3478), Point(4153, 3457), Point(4127, 3431), Point(4105, 3394), Point(4096, 3347), Point(4059, 3342), Point(4022, 3332), Point(4022, 3289)];

declarePlayers(); //Declare the player we are using

if (not SRL.isLoggedIn) then //If not logged in then..
begin
Players.LoginCurrent(); //Log player in
MainScreen.setAngle(True); //Sets the camera angle to the highest point
end;

Result := True;
end;

begin //Main
if setUp then //Calls the setup of the script
writeln('We are set up and ready to go!');
repeat
walkTo(pPatch); //Walk to Patch
while (not Inventory.IsFull) do
findCabbages(); //Collect Cabbages until inv is full
walkTo(pBank); //Walk to Bank
while (not doBank) do //Deposit all Cabbages
wait(randomRange(75, 250));
until(false); //Repeats forever
end.
And there we go! We now have a functioning bot that can pick up cabbages and bank them.




Part 7: The Antiban

The Way of The Antiban


Congradulations on making it this far! We're almost done! We just have to include an Antiban now! If you're not sure what an antiban is, it is a collection of different activities that are activated by the script that make the bot seem like it is a genuine human playing the game. It can do things like check stats, hover over random players, change the camera angle, and even take breaks. You always will want something like this built into your script, otherwise you can get your account banned fairly easily. So, how do we implement it?


Setting Up The Antiban


In order to use the antiban correctly, we need to declare a global variable of type TAntiban. This will allow us to initialize our antibans and add different types of tasks. We can do this by:
var //This is where we declare our variables
Walk: TRSWalker; //Used for RSWalker (to walk paths)
pBank, pPatch: TPointArray; //Paths from Patch to Bank, and Bank to Path
Antiban: TAntiban; //Used for Antiban procedures

We then need to have a procedure to where we tell the script what kinds of things we want to do during our antiban. We will call the procedure SetupAntiban and it looks like this:
{************************************************* ******************************
Name: setupAntiban();
Function: Sets up the built-in antiban included with the SRL include.
NOTE: Please feel free to customize this and make it unique to you.
************************************************** *****************************}
procedure setupAntiban();
begin
Antiban.Init(SKILL_TOTAL, 4);

Antiban.AddTask([@Antiban.LoseFocus, ONE_MINUTE*5]);
Antiban.AddTask([@Antiban.HoverPlayers, ONE_MINUTE*8]);
Antiban.AddTask([@Antiban.CheckStats, ONE_MINUTE*10]);
Antiban.AddTask([@Antiban.OpenRandomTab, ONE_MINUTE*10]);
Antiban.AddTask([@Antiban.VeryShortBreak,ONE_MINUTE*25]);
Antiban.AddTask([@Antiban.DoMiscStuff, ONE_MINUTE*25]);
Antiban.AddTask([@Antiban.RandomCompass, ONE_MINUTE*45]);

Antiban.AddBreak([35 * ONE_MINUTE, 05 * ONE_MINUTE, 0.05]);
Antiban.AddBreak([02 * ONE_HOUR, 15 * ONE_MINUTE, 0.20]);
Antiban.AddBreak([05 * ONE_HOUR, 45 * ONE_MINUTE, 0.85]);
Antiban.AddBreak([16 * ONE_HOUR, 08 * ONE_HOUR, 0.99]);
end;

The way this works is that we start off by initializing the antiban to our skill of choice. Since picking up cabbages does not train any skill, I have put 'SKILL_TOTAL' in there but you can put any skill in there that you would like since we are not going to be checking a specific skill.

Then we have the AddTask functions. This is where we add different types of tasks for the antiban to do and the times when we want to have them execute. As you can see, we have 7 different tasks added here. These can be adjusted or changed, as well as their duration. If you are curious about the different types of antiban procedures you have access to, feel free to check out "C:\Simba\Includes\SRL\osr\antiban.simba".

We also have the ability to add breaks. This is done using the AddBreak function. The first variable is how long until you take your break, the second is how long you plan to break for, and the last one is the chance that you log out for your break. You can also read up about this in "C:\Simba\Includes\SRL\osr\antiban.simba".


Calling The Antiban


We will now create an Antiban procedure that we can call in every spot that we want to run an antiban. Do note that just because we call the procedure does not mean that an antiban will occur.

Our antiban procedure can look like this:
{************************************************* ******************************
Name: myAntiban();
Function: Executes the antiban and checks for random events.
************************************************** *****************************}
Procedure myAntiban;
begin
if not SRL.isLoggedIn() then
Exit;

SRL.DismissRandom(); //Dismiss random events if any are found
Antiban.DoAntiban(); //Do the antiban
end;
You can see that we call two unique functions here. We call SRL.DismissRandom and Antiban.DoAntiban. SRL.DismissRandom will do exactly what it sounds like. It will dismiss a random event that shows up around you. Antiban.DoAntiban will call all of the antiban tasks that you created before and will run them based on if they are ready to be run.


Putting It Together


Now that we have our antiban built and ready to go, we can test out the completed script:
program new;
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}

const //This is where we declare our constants
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password
RS_WORLD = -1; //Desired World (-1 = Random)
IS_MEMBER = false; //True if your player is a Member

var //This is where we declare our variables
Walk: TRSWalker; //Used for RSWalker (to walk paths)
pBank, pPatch: TPointArray; //Paths from Patch to Bank, and Bank to Path
Antiban: TAntiban; //Used for Antiban procedures

{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;

{************************************************* ******************************
Name: setupAntiban();
Function: Sets up the built-in antiban included with the SRL include.
NOTE: Please feel free to customize this and make it unique to you.
************************************************** *****************************}
procedure setupAntiban();
begin
Antiban.Init(SKILL_TOTAL, 4);

Antiban.AddTask([@Antiban.LoseFocus, ONE_MINUTE*5]);
Antiban.AddTask([@Antiban.HoverPlayers, ONE_MINUTE*8]);
Antiban.AddTask([@Antiban.CheckStats, ONE_MINUTE*10]);
Antiban.AddTask([@Antiban.OpenRandomTab, ONE_MINUTE*10]);
Antiban.AddTask([@Antiban.VeryShortBreak,ONE_MINUTE*25]);
Antiban.AddTask([@Antiban.DoMiscStuff, ONE_MINUTE*25]);
Antiban.AddTask([@Antiban.RandomCompass, ONE_MINUTE*45]);

Antiban.AddBreak([35 * ONE_MINUTE, 05 * ONE_MINUTE, 0.05]);
Antiban.AddBreak([02 * ONE_HOUR, 15 * ONE_MINUTE, 0.20]);
Antiban.AddBreak([05 * ONE_HOUR, 45 * ONE_MINUTE, 0.85]);
Antiban.AddBreak([16 * ONE_HOUR, 08 * ONE_HOUR, 0.99]);
end;

{************************************************* ******************************
Name: myAntiban();
Function: Executes the antiban and checks for random events.
************************************************** *****************************}
Procedure myAntiban;
begin
if not SRL.isLoggedIn() then
Exit;

SRL.DismissRandom(); //Dismiss random events if any are found
Antiban.DoAntiban(); //Do the antiban
end;

{************************************************* ******************************
Name: doBank();
Function:
************************************************** *****************************}
function doBank(): boolean;
begin
myAntiban(); //Do antiban
BankScreen.Open(blDrynor); //Open bank using SRL's built in banker function
if BankScreen.IsOpen(5000) then //If bank screen is open sometime within the 5 sec wait
begin
wait(randomRange(150, 500)); //Have a realistic wait time before we actually do anything
BankScreen.DepositAll(); //Deposit all cabbages
Result := True; //We want to return true when the function finishes, so we set Result to True
end;
end;

{************************************************* ******************************
Name: walkTo(path);
Function: Walks the path given by the 'path' variable.
************************************************** *****************************}
procedure walkTo(path: TPointArray);
begin
myAntiban(); //Do Antiban
Walk.WalkPath(path); //Walk our path passed to the procedure
end;

{************************************************* ******************************
Name: waitLoop();
Function: Waits until we have collected our cabbage
************************************************** *****************************}
procedure waitLoop();
var
InvCount: Integer;
T: TTimeMarker;
begin
if not SRL.isLoggedIn() then
Exit;

InvCount := Inventory.Count(); //Gets the count in our inventory
T.Start; //Start our timer
repeat
myAntiban(); //Do Antiban
wait(randomRange(75, 250)); //Wait a random amount of time
until((Inventory.Count() > InvCount) or (T.GetTime > 7000)); //Stop repeating once inv count changes or we time out
end;

{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages();
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
begin
if not SRL.isLoggedIn() then //If not logged in, then terminate script
TerminateScript;

if (SRL.FindColors(TPA, CTS2(3127688, 27, 0.04, 0.87), MainScreen.GetBounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DrawATPA(ATPA); //Draws the ATPA's on the screen.
//smart.Image.DebugATPA(ATPA) works as well
{$ENDIF} //End SMART IF

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
waitLoop(); //Call to our waitLoop because we want to wait while picking.
Break; //If found red 'x', then break because we clicked it
end;
end;
end;
end;
{$IFDEF SMART}
Smart.Image.Clear; //Clears the ATPA's from screen
{$ENDIF}
end;

{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
{$IFDEF SMART} //If we are using SMART, then...
Smart.EnableDrawing := True; //let us draw on SMART
{$ENDIF} //end SMART IF

SRL.Setup([]); //Setup SRL to allow us to access it's functions.

Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use

//Both paths that we plan to walk (pBank = Patch -> Bank | pPatch = Bank -> Patch)
pBank := [Point(4022, 3289), Point(4022, 3332), Point(4059, 3342), Point(4096, 3347), Point(4105, 3394), Point(4127, 3431), Point(4153, 3457), Point(4178, 3478)];
pPatch := [Point(4178, 3478), Point(4153, 3457), Point(4127, 3431), Point(4105, 3394), Point(4096, 3347), Point(4059, 3342), Point(4022, 3332), Point(4022, 3289)];

setupAntiban(); //Setup our antiban
declarePlayers(); //Declare the player we are using

if (not SRL.isLoggedIn) then //If not logged in then..
begin
Players.LoginCurrent(); //Log player in
MainScreen.setAngle(True); //Sets the camera angle to the highest point
end;

Result := True;
end;

begin //Main
if setUp then //Calls the setup of the script
writeln('We are set up and ready to go!');
repeat
walkTo(pPatch); //Walk to Patch
while (not Inventory.IsFull) do
findCabbages(); //Collect Cabbages until inv is full
walkTo(pBank); //Walk to Bank
while (not doBank) do //Deposit all Cabbages
wait(randomRange(75, 250));
until(false); //Repeats forever
end.


Before running this program, you may notice a couple of small changes. You may notice that I call myAntiban in different parts of the script. This is because we want to run the antiban in random places to seem a little less predictable. You may also see that we call the SetupAntiban procedure in the setUp function. We do this to allow us to be able to actually do the antibans.




Part 8: Final words

The Completion of Your First Script


Congradulations! We have now reached the end! This means that you have successfully been able to write your own script to collect and bank cabbages! You are more than welcome to take this code and modify it to your own personal liking. Feel free to dig through the include and find a way of getting creative if your own ways with writting scripts that do other tasks.

If you have any questions or if you need any help, you are more than welcome to post below and I will do my best to get back to you! Also, if you notice anything than needs to be corrected, feel free to let me know as well.

ineedbot
04-24-2018, 05:30 PM
Great work! Goes in depth into everything to making a script with the tools (ACA and SPS pathing). The demo gifs are very nice aswell. The antiban portion is great and is a necessity for every script!

P1nky
04-24-2018, 05:52 PM
Awesome tutorial! Great for noob scripters and also scripters who have been away for a while... Rated this thread 5 stars :)

Keep it up!

Dan the man
04-25-2018, 01:32 AM
Very well written and thought out.

Will be OSRS millionaire with all of my cabbage farming bots now muhahaha!

Citrus
04-25-2018, 03:10 AM
Wow you're on a tutorial-writing rampage! Keep it up! :thumbsup:

The deposit box at Port Sarim might be a bit closer, but it probably doesn't matter. If you wanted to go a step further and make the behavior a bit less bot-like, you could pick the cabbages in a pattern instead of randomly.

I made a cabbage script a while ago, but all my accounts got banned pretty fast :spot:

yourule97
04-25-2018, 03:39 AM
Great tutorial! Just what we need. Normally I wouldn't comment on this, but would you consider editing it a bit to make the casing more consistent? I remember being an absolute newcomer to code and being thrown off by it. For example, sometimes it's SRL and other times its srl (mainScreen vs MainScreen as well).

It also looks like there are some camel case versus pascal case inconsistencies. I normally am lazy about this in my scripts and changing the entire thing to be one way of the other would probably be more annoying than it's worth, but I think that maybe having a consistent choice when calling functions would also help ease access for newcomers.

slacky
04-25-2018, 10:01 AM
The deposit box at Port Sarim might be a bit closer, but it probably doesn't matter. If you wanted to go a step further and make the behavior a bit less bot-like, you could pick the cabbages in a pattern instead of randomly.
There's no code in SRL that handles depositboxes for you, so one would have to handle that manually. Oh, and there's actually a pattern in OP, it will prefer the cabbages visually closer to us, you can see how it will go east->south, or west->south (depending on how it started off) to pick as long as there's a cabbage in that direction, as a result of the visual distance, and how it's sorted.

StickToTheScript
04-25-2018, 11:06 AM
Great tutorial! Just what we need. Normally I wouldn't comment on this, but would you consider editing it a bit to make the casing more consistent? I remember being an absolute newcomer to code and being thrown off by it. For example, sometimes it's SRL and other times its srl (mainScreen vs MainScreen as well).

It also looks like there are some camel case versus pascal case inconsistencies. I normally am lazy about this in my scripts and changing the entire thing to be one way of the other would probably be more annoying than it's worth, but I think that maybe having a consistent choice when calling functions would also help ease access for newcomers.

I definitely agree. I got a little bit lazy when dealing with the code. I'll do my best to clean it up.

Citrus
04-25-2018, 03:26 PM
There's no code in SRL that handles depositboxes for you, so one would have to handle that manually. Oh, and there's actually a pattern in OP, it will prefer the cabbages visually closer to us, you can see how it will go east->south to pick as long as there's a cabbage in that direction, as a result of the visual distance, and how it's sorted.

That's fair, and creating new functions for the deposit box is justifiably beyond the scope of this tutorial.
Yeah, my comment was poorly worded. An ideal script would follow a more logical, human pattern. e.g. Pick a whole row of cabbages before moving up to the next row. This way you don't even have to move the mouse more than a few times. But again, that's probably beyond the scope of a first script tutorial.

StickToTheScript
04-25-2018, 05:30 PM
... An ideal script would follow a more logical, human pattern. e.g. Pick a whole row of cabbages before moving up to the next row. This way you don't even have to move the mouse more than a few times. But again, that's probably beyond the scope of a first script tutorial.

You can actually make the row happen in a pretty simple manner.

In the case you activate an antiban that involved mouse movements, you could simply just store the point directly after you click the cabbage by:
GetMousePos(x,y);

and then you could check that position (+/- a few pixels for randomization) and simply check the uptext. This could work theoretically since most of those cabbages are all the same distance from each other. Therefore, your mouse could technically never move and you could pick up an entire row/column. The only problem is that it is not super reliable. So you could possibly end up going diagonal...

Citrus
04-26-2018, 07:33 AM
You can actually make the row happen in a pretty simple manner.

In the case you activate an antiban that involved mouse movements, you could simply just store the point directly after you click the cabbage by:
GetMousePos(x,y);

and then you could check that position (+/- a few pixels for randomization) and simply check the uptext. This could work theoretically since most of those cabbages are all the same distance from each other. Therefore, your mouse could technically never move and you could pick up an entire row/column. The only problem is that it is not super reliable. So you could possibly end up going diagonal...

You don't really need to store the mouse position, just check the uptext before you search colors. Although you could check if the mouse is far away from the player to avoid weird behavior like skipping cabbages. To avoid diagonals you can either limit your search region or just filter the whole thing by different regions.

StickToTheScript
04-27-2018, 02:36 PM
You don't really need to store the mouse position, just check the uptext before you search colors. Although you could check if the mouse is far away from the player to avoid weird behavior like skipping cabbages. To avoid diagonals you can either limit your search region or just filter the whole thing by different regions.

That will definately work too. My idea was that in the case an antiban was initiated where you check your stats or examine an item in your inventory, then your cursor will be over your inventory, so this way we can check the location we last clicked on the Main Screen.

teachme2script
05-08-2018, 10:37 PM
i dotn know how

P1nky
05-09-2018, 01:16 PM
i dotn know how

What do you need help with?

randy marsh
05-09-2018, 07:13 PM
BankScreen.Open(blDrynor); im playing around with this script in seers, do i just change it to BankScreen.Open(blSeers); ?

6b49WR7VbUjs9Hqeq5Etr
05-09-2018, 07:47 PM
BankScreen.Open(blDrynor); im playing around with this script in seers, do i just change it to BankScreen.Open(blSeers); ?

Don't think there is a seers location setup that you can call,

blYanille
blAlKharid
blLumbridge
blDrynor
blEdgeville
blVarrockWest
blVarrockEast
blFaladorEast
blFaladorWest
bcBlue
bcGray

Those are the only options for opening a bank using the function that i can find, But i have only just started myself so could be wrong.

randy marsh
05-09-2018, 08:28 PM
Another issue im having is when i try open sps path genrator its asking how to open it, what java version do i use?

Because i read the sps thread and it says to use jdk6 which i did , i then selected java.exe but the program just black screens and shuts straight away?

28450

slacky
05-09-2018, 08:42 PM
Another issue im having is when i try open sps path genrator its asking how to open it, what java version do i use?

Because i read the sps thread and it says to use jdk6 which i did , i then selected java.exe but the program just black screens and shuts straight away?

28450

Install java 8 (32 bit) and use https://github.com/TheTS/SPSToolbox/releases

randy marsh
05-09-2018, 08:43 PM
Ty bro

randy marsh
05-09-2018, 08:47 PM
The jar or zip?

SPSToolbox.jar
Source code (zip)

slacky
05-09-2018, 08:52 PM
BankScreen.Open(blDrynor); im playing around with this script in seers, do i just change it to BankScreen.Open(blSeers); ?
There are three options avialable:

1) Write a custom finder for the banker, use what you learnt in this tutorial and write a function to find the banker. And then pass the location (TPoint) to our function:
> function TRSBankScreen.OpenAt(P: TPoint): Boolean;
It's safe to pass invalid locations, it will return True if it was able to open the bank at that location.

2) I advice against this, as this is actually an internal method (note how it's prefixed with an underscore), so it can change, be removed or whatever, and could very well be unreliable (not really meant for full mainscreen search), just a last option kinda deal, and assuming the banker is either standard gray, or standard blue:
> function TRSBankScreen._OpenNPC(Typ: EBankerColor; Area: TBox): Int8;

3) I advice against this (see above reasons), but to use the internal generalized bank finder like we did internally, see:
https://github.com/SRL/SRL/blob/master/osr/interfaces/bankscreen.simba#L332-L339
Example:
> Bankscreen._MagicalBankerFinder([color, tolerance, huemod, satmod], bcBlue, [xoffset, yoffset]);
Where the last parameter is an offset based off north angle, assuming you use the booth to find the banker, or a object that's beside him for example, so the banker is ? points to the left or down etc.


The jar or zip?

SPSToolbox.jar
Source code (zip)
The jar.

randy marsh
05-09-2018, 08:55 PM
Ok i downloaded the 32 bit java and installed it , what pathway do i do to open it? I have tried the various java.exe ect still getting black screen grrr

slacky
05-09-2018, 09:09 PM
Ok i downloaded the 32 bit java and installed it , what pathway do i do to open it? I have tried the various java.exe ect still getting black screen grrr

open terminal, navigate to where you have the SPSToolBox and enter
C:\Progra~2\Java\<insert java version here>\bin\java.exe -jar SPSToolbox.jar

Example:
C:\Progra~2\Java\jre1.8.0_131\bin\java.exe -jar SPSToolbox.jar

Should work, and fyi, "Progra~2" refers to "Program Files (x86)", just trickery.

StickToTheScript
05-09-2018, 09:13 PM
BankScreen.Open(blDrynor); im playing around with this script in seers, do i just change it to BankScreen.Open(blSeers); ?

As of right now, there is no option for opening the bank in Seers Village. You should be able to use the following function:

TRSBankScreen._OpenNPC(Typ: EBankerColor; Area: TBox): Int8;


Which can be called like this:

BankScreen._OpenNPC(bcGray, MainScreen.GetBounds);


And this should open the bank for you.

Edit: Oops.. I'm late to the party...

randy marsh
05-09-2018, 11:21 PM
Hmm java console isnt turning on now grrrr

Edit thanks by running this program it fixed jar issue :

https://johann.loefflmann.net/en/software/jarfix/index.html

Define Define
06-21-2018, 11:59 PM
Thanks for this guide, its appreciated !

Do you have any plans of making more guides ?

StickToTheScript
06-22-2018, 05:19 PM
Thanks for this guide, its appreciated !

Do you have any plans of making more guides ?

I definitely can if you are interested. I am planning on doing one that builds off of this one and is a bit more complex.

Define Define
06-22-2018, 06:40 PM
I definitely can if you are interested. I am planning on doing one that builds off of this one and is a bit more complex.

Yea I am most certainly interested :)

This guide really helped me so far. Looking forward to your next guide.

KeepBotting
06-22-2018, 08:46 PM
I definitely can if you are interested. I am planning on doing one that builds off of this one and is a bit more complex.

Our resident SRL Tutorial Writer has been doing lots of good work lately, the forums are the perfect place for documentation and your posts are invaluable. Thanks!

lolskilla
06-28-2018, 02:36 AM
Thank you very much for this. Have linked it to a mate as well... this is how we get more people writing scripts

hellian46
07-21-2018, 07:44 AM
Would be awesome if you made another guide, on different parts of Srl.

StickToTheScript
07-22-2018, 06:24 PM
Would be awesome if you made another guide, on different parts of Srl.

I plan to make another in about a month or so. Gotta free up some time first.

symbiosis
08-24-2018, 02:11 PM
This is a great tutorial! Thanks for sharing :)

For those how have troubles with the ACA v3 Extension, I made a quick guide on how to "install" it: https://villavu.com/forum/showthread.php?t=118410

KeepBotting
09-19-2018, 07:55 PM
I have referenced this tutorial countless times while learning SRL, thank you very much for this valuable resource.

Hellserver
11-07-2018, 08:43 PM
Hey man great guide! Really helped me a lot! I'm using this tutorial to make a fishing script, but i'm trouble with finding the fishing spots. Any Suggestions?

StickToTheScript
11-09-2018, 02:10 PM
Hey man great guide! Really helped me a lot! I'm using this tutorial to make a fishing script, but i'm trouble with finding the fishing spots. Any Suggestions?

slacky Created a pretty accurate method which did this. You can take a look at what he did below and attempt to replicate it yourself by figuring out what is going on and seeing if you can put your own spin on it. Otherwise, if you plan on using it, please do not forget to give him credit.

// Find fishingspots by finding the edges of the water, over and over again
// Then do some fancy stuff to remove land->water borders.
// what's left is an accurate TPA of the fishingspot
function TFisher.FindFishingSpot(scanTime: Int32=450): T2DPointArray;
var
i: Int32;
SUM,TPA: TPointArray;
R: TRectangle;
t: TCountDown;
begin
t.Init(scanTime);
while not t.IsFinished do
begin
srl.FindColors(TPA, CTS2(8875103,16,0.2,0.7), Mainscreen.GetBounds);
SUM += TPA.Edges();
end;

SUM.ClearDuplicates();
SUM := ClearTPAFromTPA(Sum, Sum.Edges());
Result := SUM.Cluster(5);
Result.FilterSize(12, __GT__);

{$ifdecl TWindowOverlay}
Debug.Clear();
for i:=0 to High(Result) do
Debug.DrawTPA(Result[i], Random($FFFFFF));
{$endif}
end;

Azir
05-28-2019, 11:49 AM
For search reference, you probably got this error or something close to it.

xcorr := WorldSample.MatchTemplate(mmsample, Self.TMFormula);

Runtime error: "Access violation" at line 209, column 41 in file "C:\Simba 1.3\Includes\RSWalker\Walker.simba"
Succesfully executed in 28297 ms.
The following bitmaps were not freed: [0, Minimap mask, Smart[13256] Image, 3, 4]


Something that took me a while to figure out, but ended up finding it in the discord (Thanks Olly)
Is that the init method changed, from now on just call Walker.Init('mapname') and no more parameters.

In the tutorial there is still a -1 parameter written.

Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use


So if you just remove the -1 it works as it is expected from the tutorial.


Walk.Init('world.png'); //Setup RSWalker by initializing the map we want to use

bobbersssss
06-28-2019, 07:24 PM
is there any way to use this on a osrs sourced private server

felparers
06-28-2019, 07:59 PM
is there any way to use this on a osrs sourced private server

If the client and the version is the same as OSRS it should work

bobbersssss
06-30-2019, 04:36 PM
If the client and the version is the same as OSRS it should work

is there a way to define my rsps client instead of the osrs client?

felparers
07-02-2019, 03:20 PM
Drag the target( green + on toolbar) on the client you want to use.

otavioafm
05-09-2020, 05:06 PM
I've Put You script to kill Flesh crawlers lol, but the mouse is moving to fast, any Ideas to made the mouse move more naturaly, and how to put some antiban?
program new;
{$define SMART}
{$I SRL/OSR.simba}
{$I RSWalker/Walker.simba}

const //This is where we declare our constants
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password
RS_WORLD = -1; //Desired World (-1 = Random)
IS_MEMBER = false; //True if your player is a Member

var //This is where we declare our variables
Walk: TRSWalker; //Used for RSWalker (to walk paths)

{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;

{************************************************* ******************************
Name: waitLoop();
Function: Waits until we have collected our cabbage
************************************************** *****************************}
procedure waitLoop();
var
InvCount: Integer;
T: TTimeMarker;
begin
if not SRL.isLoggedIn() then
Exit;

InvCount := Inventory.Count(); //Gets the count in our inventory
T.Start; //Start our timer
repeat
wait(randomRange(75, 250)); //Wait a random amount of time
until((Inventory.Count() > InvCount) or (T.GetTime > 7000)); //Stop repeating once inv count changes or we time out
end;

{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages;
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
begin
if not SRL.isLoggedIn() then //If not logged in, then terminate script
TerminateScript;

if (SRL.FindColors(TPA, CTS2(6688, 2, 0.29, 0.00), MainScreen.GetBounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.GetMiddle); //Sort by closest to Middle of the screen

{$IFDEF SMART} //If we are using SMART, then...
Smart.Image.DebugATPA(ATPA);
{$ENDIF} //End SMART IF

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Attack') then //If the uptext is 'Cabbage', try to click it
begin
if Mouse.Click(ctRed) then //Clicks the mouse and looks to see if red 'x' appeard when cicked
begin
waitLoop(); //Call to our waitLoop because we want to wait while picking.
Break; //If found red 'x', then break because we clicked it
end;
end;
end;
end;

{$IFDEF SMART}
Smart.Image.Clear; //Clears the ATPA's from screen
{$ENDIF}
end;

{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
{$IFDEF SMART} //If we are using SMART, then...
Smart.EnableDrawing := True; //let us draw on SMART
{$ENDIF} //end SMART IF

SRL.Setup([]); //Setup SRL to allow us to access it's functions.

Walk.Init('world.png', -1); //Setup RSWalker by initializing the map we want to use

declarePlayers(); //Declare the player we are using

if (not SRL.isLoggedIn) then //If not logged in then..
begin
Players.LoginCurrent(); //Log player in
MainScreen.setAngle(True); //Sets the camera angle to the highest point
end;
end;

begin //Main
if setUp then //Calls the setup of the script
writeln('We are set up and ready to go!');
repeat
findCabbages(); //Collect Cabbages until inv is full
until(false); //Repeats forever
end.
begin
FindNormalRandoms;
case Random(90) of
0: RandomRClick;
2: PickUpMouse;
3: RandomMovement;
4: BoredHuman;
5: ExamineInv;
6: MakeCompass('N');
7: SetAngle(SRL_ANGLE_HIGH);
8: Wait(5000+random(2000));
9: HoverSkill(skill_attack,false);
end;

vizzyy
06-04-2021, 08:24 PM
This was a valuable learning exercise for me, to try and rework this script to work with latest SRL-Dev and simba from olly's github.

I've noticed a ton of things don't quite work for me:
1) Smart doesn't work at all
2) Include log in function doesn't hit the "Login" button after typing in information
3) Include doesn't change camera angle
4) RSWalker is included in SRL-Dev so no need for separate dependency
5) Open bank at tile wasn't working for me, maybe I was using tile coords instead of screen coords, but don't know how to tranlate that without reflection method
6) Lots of little syntax changes between the old and new include, most of the antiban section for example.
7) The ACA bit of the tutorial with the color picker tool still works perfectly well

I was able to piece together the components and this is what I came up with -- it may be sloppy but at least I got it to run again as it was intended. Sharing it here for anyone who may follow the main link path for getting introduced to this community:


program cabbage;
{$define SMART}
{$I SRL/OSR.simba}

//Declare our Constants
const
LOGIN_NAME = ''; //Username/Email
LOGIN_PASS = ''; //Password

//Declare our variables
var
Walk: TRSWalker; //Used for RSWalker (to walk paths)
pathToPatch: TPointArray;


{************************************************* ******************************
Name: declarePlayers();
Function: Sets the proper variables using the constants above to allow
a successful login.
************************************************** *****************************}
procedure declarePlayers();
begin
Login.AddPlayer(LOGIN_NAME, LOGIN_PASS);
end;

{************************************************* ******************************
Name: setupAntiban();
Function: Sets up the built-in antiban included with the SRL include.
NOTE: Please feel free to customize this and make it unique to you.
************************************************** *****************************}
procedure setupAntiban();
begin

Antiban.AddTask(ONE_MINUTE*5, @Antiban.LoseFocus);
Antiban.AddTask(ONE_MINUTE*10, @Antiban.HoverSkills);
Antiban.AddTask(ONE_MINUTE*10, @Antiban.RandomTab);
//Antiban.AddTask(ONE_MINUTE*25, @Antiban.VeryShortBreak);
//Antiban.AddTask(ONE_MINUTE*25, @Antiban.DoMiscStuff);
//Antiban.AddTask(ONE_MINUTE*45, @Antiban.RandomCompass);

Antiban.AddBreak(35*ONE_MINUTE,05*ONE_MINUTE,0.05, 0.03);
Antiban.AddBreak(02*ONE_HOUR,05*ONE_MINUTE,0.20, 0.85);
Antiban.AddBreak(05*ONE_HOUR,05*ONE_MINUTE,0.85, 0.85);
Antiban.AddBreak(16*ONE_HOUR,05*ONE_MINUTE,0.99, 0.99);
end;

{************************************************* ******************************
Name: setUp();
Function: Sets up the script by initializing everything and logging player in.
************************************************** *****************************}
function setUp(): boolean;
begin
SRL.Setup(); //Setup SRL to allow us to access it's functions.
Walk.Setup('world'); //Setup RSWalker by initializing the map we want to use
declarePlayers(); //Declare the player we are using
pathToPatch := [[4177, 3463], [4159,3449], [4135, 3436], [4128, 3402], [4121, 3364], [4089, 3335], [4049, 3335], [4024, 3310], [4025, 3288], [4025, 3288]];
setupAntiban(); //Setup our antiban

if not Login.LoginPlayer() then
TerminateScript('Failed to login!');
MainScreen.SetHighestPitch(); //this doesn't actually do anything atm

Result := True;
end;

{************************************************* ******************************
Name: myAntiban();
Function: Executes the antiban and checks for random events.
************************************************** *****************************}
Procedure myAntiban;
begin
if (not RSClient.IsLoggedIn) then
Exit;

Antiban.DismissRandom(); //Dismiss random events if any are found
Antiban.DoAntiban(); //Do the antiban
end;

{************************************************* ******************************
Name: waitLoop();
Function: Waits until we have collected our cabbage
************************************************** *****************************}
procedure waitLoop();
var
InvCount: Integer;
T: TStopwatch;
begin
if (not RSClient.IsLoggedIn) then
Exit;

InvCount := Inventory.Count(); //Gets the count in our inventory
T.Start; //Start our timer
repeat
myAntiban();
wait(randomRange(75, 250)); //Wait a random amount of time
until((Inventory.Count() > InvCount) or (T.ElapsedTime > 7000)); //Stop repeating once inv count changes or we time out
end;

{************************************************* ******************************
Name: findCabbages();
Function: Locates cabbage in the field. Will print on screen if using SMART.
************************************************** *****************************}
procedure findCabbages();
var
TPA, Cabbage: TPointArray;
ATPA: T2DPointArray;
CabbageColor: TCTS2Color;
begin
if (not RSClient.IsLoggedIn) then //If not logged in, then terminate script
TerminateScript;

CabbageColor := CTS2(2727797, 20, 0.05, 1.15);
if (SRL.FindColors(TPA, CabbageColor, MainScreen.Bounds) > 0) then //If we find colours at all then...
begin
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.FilterSize(100, 500); //Remove and ATPA of size < 100, or > 500.
ATPA.SortByIndex(MainScreen.Center); //Sort by closest to Middle of the screen

for Cabbage in ATPA do //For every possible cabbage in our ATPA
begin
Mouse.Move(Cabbage[Random(Length(Cabbage))]); //Move the mouse to the cabbage

if MainScreen.IsUpText('Cabbage') then //If the uptext is 'Cabbage', try to click it
begin
Mouse.Click(MOUSE_LEFT);
if (not MainScreen.DidRedClick) then Exit;
waitLoop(); //Call to our waitLoop because we want to wait while picking.
Break;
end;
end;
end;
end;

function manualBank(): boolean;
var
TPA, BankBooth: TPointArray;
ATPA: T2DPointArray;
BankColor: TCTS2Color;
begin
if (not RSClient.IsLoggedIn) then //If not logged in, then terminate script
TerminateScript;

BankColor := CTS2(5527903, 5, 0.71, 0.53);
writeln("Looking for bank via ATPA");
if (SRL.FindColors(TPA, BankColor, MainScreen.Bounds) > 0) then //If we find colours at all then...
begin
writeln("found some potential banks");
ATPA := TPA.Cluster(2); //Group them within a max pixel distance of 2
ATPA.SortByIndex(MainScreen.Center); //Sort by closest to Middle of the screen

for BankBooth in ATPA do //For every possible BankBooth in our ATPA
begin
writeln(BankBooth);
Mouse.Move(BankBooth[Random(Length(BankBooth))]); //Move the mouse to the BankBooth

if MainScreen.IsUpText('Bank booth') then //If the uptext is 'BankBooth', try to click it
begin
Mouse.Click(MOUSE_LEFT);
Result:= True;
Exit;
end;
end;
end;
end;

begin //Main
if setUp then
writeln('We are set up and ready to go!');

repeat
if not Inventory.IsFull then
begin
Writeln("Walking to cabbage patch!");
Walk.WalkPath(pathToPatch);
end

while (not Inventory.IsFull) do
begin
findCabbages(); //Collect Cabbages until inv is full
end

Writeln("Walking to bank!");
Walk.WebWalk(WorldWeb.LOCATION_DRYNOR_BANK); //Walk to Bank

while (not manualBank) do //open bank
begin
Writeln("Trying to open bank");
wait(randomRange(75, 250));
end;

while Bank.IsOpen(5000) do
begin
writeln("trying to deposit");
wait(randomRange(75, 250));
Bank.DepositAll();
wait(randomRange(75, 250));
Bank.Close();
end
until(false);
end.

x0xh3llx0x
12-14-2021, 07:14 PM
Big thanks for this tutorial! And also thanks to Vizzyy for his post above :)