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. 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:
Simba Code:
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:
Simba 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.
Simba Code:
//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:
Simba Code:
{*******************************************************************************
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:
Simba Code:
{*******************************************************************************
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:
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:
Functions do not only need to return boolean values. They can return any type of variable that you want. For example:
Simba Code:
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:
Simba Code:
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:
Code:
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 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. 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:
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.
Simba Code:
{*******************************************************************************
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. 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:
Simba Code:
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:
Simba Code:
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:
Code:
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:
Simba Code:
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:
Code:
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:
Simba 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:
Simba Code:
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:
Simba Code:
{*******************************************************************************
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:
Simba Code:
{*******************************************************************************
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:
Simba 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: 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!

Part 5: Walking via RSWalker
Getting Your Points
Walking via RSWalker is fortunately fairly easy. We'll start off with our
SPS Path Generator. 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:

This means that our paths should look like this:
Simba Code:
//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:
I have written a procedure that we can use that will accept a path and call the
WalkPath function:
Simba Code:
{*******************************************************************************
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:
Simba 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:
Simba Code:
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:
Simba Code:
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:
Running to the Bank:
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:
Simba Code:
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:
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:
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:
Simba Code:
{*******************************************************************************
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:
Simba 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: 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:
Simba Code:
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:
Simba Code:
{*******************************************************************************
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:
Simba Code:
{*******************************************************************************
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:
Simba 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
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.