# Thread: [SRL]How To Write Your First Script: Collecting and Banking Cabbages!

1. ## [SRL]How To Write Your First Script: Collecting and Banking Cabbages!

How To Write Your First Script: Collecting and Banking Cabbages
Verified Working On: January 31, 2019

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. 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 Constantsconst 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 variablesvar 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 Constantsconst  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 variablesvar  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:
Code:
: 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:
Simba Code:
Result := True;
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 Integerfunction example: String;      //Returns a Stringfunction example: TBox;        //Returns a TBoxfunction 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 ATPAbegin 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 Membervar  //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 fullend.
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 fulluntil(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 outend;
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 Membervar //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 outend;{******************************************************************************* 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 foreverend. 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: Simba Code: Walk.WalkPath(path); 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 procedureend; 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 Membervar  //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 procedureend;{*******************************************************************************  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 outend;{*******************************************************************************  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 foreverend.

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 Patchwhile (not Inventory.IsFull) do  findCabbages();   //Collect Cabbages until inv is fullwalkTo(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:
Simba Code:
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:
Simba Code:
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:
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 Membervar //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 procedureend;{******************************************************************************* 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 outend;{******************************************************************************* 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 foreverend. 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 antibanend; 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 Membervar  //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 antibanend;{*******************************************************************************  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 procedureend;{*******************************************************************************  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 outend;{*******************************************************************************  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 foreverend.

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.
Last edited by StickToTheScript; 01-31-2019 at 04:53 PM. Reason: Updated.

2. 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!

3. Awesome tutorial! Great for noob scripters and also scripters who have been away for a while... Rated this thread 5 stars

Keep it up!

4. Very well written and thought out.

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

5. Wow you're on a tutorial-writing rampage! Keep it up!

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

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

7. Originally Posted by Citrus
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.
Last edited by slacky; 04-25-2018 at 06:31 PM.

8. Originally Posted by yourule97
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.

9. Originally Posted by slacky
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.

10. Originally Posted by Citrus
... 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:
Simba Code:
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...

11. Originally Posted by StickToTheScript
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:
Simba Code:
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.

12. Originally Posted by Citrus
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.

13. Registered User
Join Date
May 2018
Posts
2
Mentioned
0 Post(s)
Quoted
1 Post(s)
i dotn know how

14. Originally Posted by teachme2script
i dotn know how
What do you need help with?

15. BankScreen.Open(blDrynor); im playing around with this script in seers, do i just change it to BankScreen.Open(blSeers); ?

16. Registered User
Join Date
Feb 2018
Posts
22
Mentioned
1 Post(s)
Quoted
3 Post(s)
Originally Posted by randy marsh
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
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.

17. 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?

java.PNG

18. Originally Posted by randy marsh
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?

java.PNG
Install java 8 (32 bit) and use https://github.com/TheTS/SPSToolbox/releases
Last edited by slacky; 07-21-2018 at 02:40 PM.

19. Ty bro

20. The jar or zip?

SPSToolbox.jar
Source code (zip)

21. Originally Posted by randy marsh
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/mast...imba#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.

Originally Posted by randy marsh
The jar or zip?

SPSToolbox.jar
Source code (zip)
The jar.
Last edited by slacky; 05-09-2018 at 09:29 PM.

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

23. Originally Posted by randy marsh
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.
Last edited by slacky; 05-09-2018 at 09:14 PM.

24. Originally Posted by randy marsh
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:
Simba Code:
TRSBankScreen._OpenNPC(Typ: EBankerColor; Area: TBox): Int8;

Which can be called like this:
Simba Code:
BankScreen._OpenNPC(bcGray, MainScreen.GetBounds);

And this should open the bank for you.

Edit: Oops.. I'm late to the party...
Last edited by StickToTheScript; 05-09-2018 at 09:17 PM.

25. Hmm java console isnt turning on now grrrr

Edit thanks by running this program it fixed jar issue :

https://johann.loefflmann.net/en/sof...fix/index.html
Last edited by randy marsh; 05-10-2018 at 09:36 AM.