1. ## [Aerolib] Creating your first script

Hi all!

I have decided to create a tutorial that is targeted at people who are new to scripting in Old School Runescape.

Lets begin

1. Getting started

2. Introduction - Starting out
1. Creating your first main block
3. Variables and how to use them!
4. Creating a procedure and moving the mouse
5. Aerolib functions and where to find them

1. What you will learn
2. Creating the first block again
3. Creating an object
4. Using an object
5. Making the script loop
6. Creating and using a custom function
7. Dropping the ore: for..to..do loop

Getting started:

Requirements:

Aerolib 2.0 Setup:
Due to the new release of Aerolib 2.0, I thought it would be appropriate to add a small guide to ensure it is installed correctly. If you are confident you have installed Aerolib correctly, and are not getting any Access Violation errors, then you can skip this step.

• Close Simba if it is open.
• Extract Aerolib to C:\Simba\Includes, then extract the Plugins folder to C:\Simba\Plugins.
• Once the new Simba file has been downloaded, go to C:\Simba and find Simba.exe and rename it to Simba Old.exe or delete it. Get the new Simba file you downloaded and drag it into this folder, and rename it to Simba.exe.

Open Simba and paste the following code into a new script and click run.
Simba Code:
program new;{$i AeroLib/AeroLib.Simba}begin InitAL;end. If you receive no errors, then the installation was successful. If you received errors, go through the steps again. Introduction - Starting out Creating your first main block To start a script, we need to create the basic script to work with. On simba, you will see a screen with the following code: Simba Code: program new;beginend. This is the start of a new script and everything here is required, but we need to add a few more bits to get us on our way. First we will decide if we want this script to run in smart. If so, add the following to the script: Simba Code: program new;{$DEFINE SMART}beginend.

Another thing that we will need to do is define the Aerolib include so everything works properly.

Add the following into our code:
Code:
program new;
{$DEFINE SMART} {$i AeroLib/AeroLib.Simba}
begin
end.
This alone isn't enough for Aerolib to work. We need to initiate it. Add the following code:
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}begin  initAL;end.

Be sure to add the indent after initAL.

This is the core foundations of our script. Everything here is require for the script to work, and you will more than likely start any future projects off with this template.

The next part of a script I normally add is the Player Setup. This handles the username and password fields so the script can log a player in.

Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}Procedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;end.

Ok so what did we add?!
This has added some fields for a player to input their username and password in. This information can be used with Aerolib's login functions to log the account into Runescape.

This currently doesn't work though, as we haven't called for this procedure to be used, so lets do that now:
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}Procedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;end.

As you can see, we added PlayerSetup (the same name as our procedure) to this list. You can name this anything (PlayerLoginDoowakki) so long as you change the procedure name to match.

The Me.Active, Me.Name, Me.Pass etc are actually variables that are programmed into the Aerolib include already. We are simply allowing for the variables to be set to our players login details, but won't actually action a login.
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}Procedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;  loginPlayer(false);end.
Where on earth did I find this random loginPlayer variable?!
Well it is another function built into Aerolib of course (Thanks Flight!).

If you were to run this script (with the login details put in) it would log your character into Runescape.

The only problem with the above code, is that it won't check to see if we are already logged in, so we need to add a if/then check prior to trying to execute this command:
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}Procedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);end.

As you can see, the loginPlayer function has been indented forward, and another line is above.
I will explain this as best I can.
When a line starts with If, it is telling the script that there are conditions to this line. Usually at the end of an if line, there is a then. This tells the script that if the conditions are met, you execute the next indented line.
Example:
Simba Code:
If YouWantToContinueReading then  Continue;

The order of execution is determinted by the final begin/end of the script. As you have probably noticed, the lines that we are adding between our begin/end is being executed in order. This is no coincidence!
There is a specific order that needs to be achieved though. You can't try and log a player in before you have declared their login details, or before Initializing Aerolib (IntAL).

There are multiple conditions that you will come across in your scripting travels!
These include boolean's(True/false), integers(numbers), strings(words) etc. I will explain these later.

Variables and how to use them!

When scripting, a lot of stuff is stored temporarily or permanently inside of a variable. A variable is a word that you make up which has a specific data type (see boolean, integer and string above).

In our script, we need to add a new heading, above our procedure called var. See script:
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}varProcedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);end.

This basically allows us to create variables at a global level. There are 2 types of variables: Global and local. Global can be used inside of any procedure, function etc, where as local are restricted to their procedure/function and forgotten then the procedure/function has finished.

To build on our a script a little more, we will be creating a string variable so we can store some text!

Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var  OurWords: String;Procedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);end.

The variable OurWords is just a name I made up. You can make this anything you want, but it is best practice to name it something to do with its role.

At the moment, there is nothing assigned to our variable. If we were to get Simba to print this, it would simply print a blank space.

So lets assign the age old words: Hello World!

You assign values to variables like so:
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var  OurWords: String;Procedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);  OurWords := 'Hello World!';end.

This assigns the variable: Hello World to our variable OurWords.
Now we want it to print in Simba's debug box. Do the following:
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var  OurWords: String;Procedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);  OurWords := 'Hello World!';  Writeln(OurWords);end.
Writeln is a default command that prints to the debug box. You can type things in manually like writeln('This is my words'); or you could do what we have done and use it to write text from a variable instead.
This will print Hello World! in the debug box (under your script) in Simba.

Now what if we wanted to assign a new name to OurWorld?
We would do the exactly the same thing below:
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var  OurWords: String;Procedure PlayerSetup;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);  OurWords := 'Hello World!';  Writeln(OurWords);  OurWords := 'Goodbye World!';  Writeln(OurWords);end.

This would write Hello World! in our debug box, followed quickly by Goodbye World!

Now we will learn how to add variables at a local level. Do the following:
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var  OurWords: String;Procedure PlayerSetup;var  AlsoOurWords: string;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);  OurWords := 'Hello World!';  Writeln(OurWords);  OurWords := 'Goodbye World!';  Writeln(OurWords);end.

This creates another blank variable that we can put words into.
So what is the difference?
Global variables remember the data that is put into them until they are changed. Local variables remember the data for as long as the procedure is firing. Once the procedure PlayerSetup finishes, it will delete the variable and all of its contents.
If you have data that you want to maintain between procedures, you need to store it as a global variable. This is stuff like item information, break information (when a player wants the script to take a break), experience points gained etc.
Local variables are used when you want to store data onto something temporarily. This will make more sense further on.

Creating a procedure and moving the mouse

Now lets create a new procedure for us to get into the good stuff!
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var  OurWords: String;Procedure PlayerSetup;var  AlsoOurWords: string;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;Procedure LetsDoStuff;beginend;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);  OurWords := 'Hello World!';  Writeln(OurWords);  OurWords := 'Goodbye World!';  Writeln(OurWords);end.

When you create a new procedure, you always have to have a begin and end; under it. The end should ALWAYS end with a semicolon ( ; ) after it, as this tells the compiler that the line has finished. The only exception to the rule is the final end in your script, which should be a full stop(.)

Now we are going to make the mouse move!

For this next part, we will be using the Runescape client. Open your runescape client and have Simba and the client visible on the same screen, but not overlapping.
At the top of the Simba client is a crosshair. Click and hold this crosshair, and move it to the centre of the Runescape screen (once the client is loaded and you see the login screen). A red image will appear around this, and when it does, let go of your mouse button.
The debugger will now say: New window: (number). This means that you have targted a specific window for the script to use. This means that even if there is another runescape window next to the one you targeted, it won't click it.

Now that your window is targeted, I want you to put your mouse on the inventory of your screen (centre of the icon). Also take note of the bottom left corner of Simba as it will have numbers that will change whenever you move the mouse.

If you moved your mouse to the centre of the inventory icon, it should show a number close to: 648, 183. This is the co-ordinates of the mouse on the Runescape screen, and this location is static (never changes). If it is showing something significantly different, then you might not have targeted the Runescape screen correctly with the crosshair tool.

Now we will adjust our script to move the mouse there and then terminate the script.
Simba Code:
program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var  OurWords: String;Procedure PlayerSetup;var  AlsoOurWords: string;begin  Me.Active := True;  Me.Name := '';  Me.Pass := '';  Me.Member := True;end;Procedure LetsDoStuff;var  pnt:Tpoint;begin  pnt := [648, 183];  HumanMMouse(pnt, 5, 5);end;begin  initAL;  PlayerSetup;  if (not isLoggedIn()) then    loginPlayer(false);  OurWords := 'Hello World!';  Writeln(OurWords);  OurWords := 'Goodbye World!';  Writeln(OurWords);  LetsDoStuff;end.

Now I have added a few things there. The first is the Var below our new procedure, with a variable called pnt, tied to a data type called tpoint. Tpoints are x and y co-ordinates (for lack of a better explination). They store 2 numbers in them, usually related to the x and y co-ordinates you saw in Simba before.

Under begin, we have assigned a value to pnt of [648, 183]. The reason we put them in square brackets is because we are assigning multiple numbers as part of one variable. This is only required with a select few variables.

Under that we have our built in Aerolib mouse function: HumanMMouse. This function moves the mouse (human like!) to the destination point (Our Tpoint). The numbers 5 and 5 at the end of this are required by the function to add a varied rate of randomness to the movement. This means that the mouse will randomize the exact location 648, 183 by 5 on the x axis and 5 on the y axis. Good for minimizing chances of being banned.
The reason the values are put in brackets next to HumanMMouse is because it has arguments that it needs information for before it can execute. More on that later.
Finally, we have added our procedure to the list of stuff to execute.

For the purposes of testing this out, I would recommend commenting out Smart and using the official Runescape client. To do this, add // in front of {$DEFINE SMART} so it looks like: Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba} Give this a test in Runescape now! Your debug box should have spoken to you again, and your real mouse should have moved to the centre of the screen. Well done, you have now official botted Runescape! #Banhammer ! Aerolib functions and where to find them Aerolib has already done a lot of the hard yards in terms of navigating through menus and interacting with things like your inventory and bank. Lets learn a little more about that shall we? We are going to use a built in function to swap to the inventory tab, then to the skills tab, then back to the inventory tab. Add this code: Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var OurWords: String;Procedure PlayerSetup;var AlsoOurWords: string;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := False;end;Procedure LetsDoStuff;var pnt:Tpoint;begin pnt := [648, 183]; HumanMMouse(pnt, 5, 5); wait(1000); GameTab(TAB_INV); GameTab(TAB_STATS); if (GameTab(TAB_INV)) then WriteLn(GetInvCount);end;begin initAL; PlayerSetup; if (not isLoggedIn()) then loginPlayer(false); OurWords := 'Hello World!'; Writeln(OurWords); OurWords := 'Goodbye World!'; Writeln(OurWords); LetsDoStuff;end. Now we added a few things here. First we use the function GameTab to move to the inventory tab (it would attempt to click inventory even if your inventory is open), then used it to open the skills tab, then did used and if/then statement to fire a writeln command once the inventory was selected. So lets break it down! Firstly, GameTab is a built in function within Aerolib (Aerolib/core/gametabs/GameTab.simba) which has a boolean (true or false) statement at the end. This means that it works well with an if/then statement, as it will fire a true or false (indicating if it was successful in opening the inventory) allowing us to offer difference responses. For example, if we tried to open the inventory, but the icon was missing or we were in an instance where we couldn't see it, it would come back saying we failed, but if it could see it and it clicks on it, it comes back to us saying success. In this case, I have made it use another Aerolib built-in function called GetInvCount, wrapped in a writeln command. When run, this will automatically open the inventory if its not already, count the slots that are being used (stores it as a number/integer), and writes the number in the debug box. Now we are going to learn how to find a function in Aerolib and use it in our scripts. Aerolib has a lot of different procedures and functions that you can call into your scripts. They are catagorised into multi subjects (pretty self explainatory) in your Includes folder. To view the Aerolib include (and explore the functions) go to C:/Simba/Includes/Aerolib/. Go there now. You will see 4 folders: Core, entities, maps and misc. Feel free to explore all of them as they include some pretty awesome functions. For this tutorial, we are going to look for a function to identify uptext (the text that appears in top left corner of RS when you mouse over anything). Go into the core folder, then look for a file called text.simba. Open it and it will launch another window of Simba. [SIZE=4]Important note: Don't edit any of these files as they are replaced when Aerolib is updated. Now that we have text.simba open, look on the left hand side of the simba window for a list of all of the functions. The function we are looking for is isUpTextMulti - double click on it when you find it. It will take you to the line that has the function and highlight it for you. You should see something like this: Simba Code: function isUptextMulti(Text: TStringArray): Boolean;var TheText : string; i,n : integer;begin ocr_SetClient(ClientATIA(7,7,500,16)); Result := ocr_IsTextMulti(Text, UpFont);end; This is the actual function that executes when its called. Study the IsUpTextMulti and look at the variable between the brackets. It is a TStringArray. TStringArray's is multiple String data types in the one variable. For example - A regular string can hold a sentence of text, as many as you like, but only 1 value. So if you wanted to store something like: 'Herb1 Herb2' it is still seen as a single variable. TStringArray's allow us to store multiple Strings in the one line, then check each of them for a match. The function is also a boolean, meaning we can check to see if it returns true or false and act accordingly. Add the following to your script: Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var OurWords: String;Procedure PlayerSetup;var AlsoOurWords: string;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := False;end;Procedure LetsDoStuff;var pnt:Tpoint;begin pnt := [648, 183]; HumanMMouse(pnt, 5, 5); wait(1000); GameTab(TAB_INV); GameTab(TAB_STATS); if (GameTab(TAB_INV)) then WriteLn(GetInvCount); if (GetInvCount > 0) then begin HumanMMouse(Point(574, 224), -5, 5); if IsUpTextMulti(['Bronze', 'pickaxe', 'ronze pickaxe']) then WriteLn('Bronze pick is in inventory!'); end;end;begin initAL; PlayerSetup; if (not isLoggedIn()) then loginPlayer(false); OurWords := 'Hello World!'; Writeln(OurWords); OurWords := 'Goodbye World!'; Writeln(OurWords); LetsDoStuff;end. Ok so we have added a few things here. I will tackle them in order! First thing you will notice is that we added begin/end inside our procedure that already has begin/end! The reason for this is that when adding multiple commands after an if/then statement on the same indent, you need to have the begin/end, or else the compiler will classify it as a previous indent (I believe?). Example: Simba Code: Procedure fake;begin if (getInvCount > 0) then Command1; Command2; Command3;end; Would act like: Simba Code: Procedure fake;begin if (getInvCount > 0) then Command1; // will fire if getInvCount > 0. Command2; // will fire regardless whether getInvCount is > 0 or not Command3; // will fire regardless whether getInvCount is > 0 or notend; The correct way to do it is like this: Simba Code: Procedure fake;begin if (getInvCount > 0) then begin Command1; // will fire if getInvCount > 0. Command2; // will fire if getInvCount > 0. Command3; // will fire if getInvCount > 0. end;end; The next thing you will notice is that we used getInvCount in an if/then statement. Since getInvCount returns an integer (number), we need to ask whether or not it is equal (=) greater than (>) or less than (<) the value we input. This value can also be another integer variable. If the number meets the requirements, the next indent(s) are fired, in this case moving the mouse to the first inventory slot and checking the uptext. The IsUpTextMulti I have included on the script matches the requirements from Aerolib. IsUpTextMulti is the function name, (['Bronze', 'pickaxe', 'ronze pickaxe']) is the TStringArray variables, and then we have it check to see if the boolean returns true or false (by adding then at the end of the line). Any array that you enter into the script must be put between the square bracket symbols ([]). This is so the compiler can tell that this is an array, instead of moving to the next arg in the function. Example time: Simba Code: if IsUpTextMulti('Bronze', 'pickaxe', 'ronze pickaxe') then This one would come back saying that there are too many parameters in the function. Since the function really only has 1, we have exceeded it by 2. If we put the text between the square brackets instead, it will fire correctly, seeing only 1 parameter. Simba Code: if IsUpTextMulti(['Bronze', 'pickaxe', 'ronze pickaxe']) then The last thing you will notice is that it will use the writeLn command to write that the Bronze pick was found. If it wasn't, it will skip that line. We did not add a begin/end to this line as it only needed to fire 1 line of code. If you were to surround this in begin/end, it would work, but its bad scripting standards. Ok now that we have learnt a bit of Aerolib and the basics of scripting, we are going to do something meaningful. Making your first script Now we are going to look at creating a functioning script using the skills that we learnt above (and some new ones!). The script we will be creating is a power mining script. It won't be glamorous by any definition of the word, but you should have some competency around Aerolib and OSRS color scripting by the end. What you will learn • How to create, identify and interact with an object using color • How to loop your procedures • How to implement antiban • How to track your inventory space and then use a custom function to drop your inventory • How to use a series of different loops within your procedures. • How to create and use a custom function. Lets begin! Creating the first block again First, we will use the same start to our script as in the previous post. Simba Code: program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True;end;begin initAL;end. Creating an object Now that we have the shell of our script started, we need to plan what we want our script to do. Since this is a power miner, it is going to be pretty straight forward: Mine, drop. This means that we are going to have a minimum of 2 procedures to achieve our goals. We will start by identifying a rock that we want to mine. We will be using Aerolib's Find Object functions to do this. Keep in mind that this is one of countless ways to identify an object using Color in Aerolib. There are other more complex ways, but this is the most beginner friendly and solid way to learn. So now we want to look at the function in Aerolib. To do this, go to ...Simba\Includes\AeroLib\entities\object\Object.s imba You will see a few functions and procedures that you can utilize on the left hand side of Simba ranging from create to FindMSObjectSimple. The method to setup an Object is quite simple: create a variable associated with TMSObject and then assign the data to it. First, we want to create a variable under our global variables. Simba Code: program new;{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var TinRock: TMSObject;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True;end;begin initAL;end. Now that we have created the variable, we want to assign some data to it. We will simply add a line under the PlayerSetup procedure. Under this procedure, we will start by type TinRock.create. You will notice a popup telling you the different arguments that can be populated in this function. Navigate to the Objects.simba include that we have open and look for the procedure TMSObject.create. You will notice that there are multiple functions, all of which are sharing the same name, but have different amounts of arguments. This allows us to populate as much (or as little) data as we need. Now we are going to want to open up our trusty Auto Color Aid v2 program. We will be using this to identify the colors for our rock and inputting the information into our object variable so it knows what to look for. Follow the above guide until you have found a nice color for our rocks (remember to set the CTS on ACA2 to 2). You may need to log out and in, refresh ACA2 (F2) and mark best color again to ensure that the colors you selected are still the same. The information we need for our Object is as follows: • Rock name • Uptext strings • Color, tolerence, Hue/sat mods • Min color count This is the basic requirements for finding an object effectively. Now we have our color, tol, hue and sat values, we have our rocks name (Mine rocks) and our uptext (Mine rocks), we just need to find the minimum color quantities in the rock. There are 2 ways to do this. First way is to guess and adjust. You set the value, try it out and then adjust if it stuffs up. Second way is to take a screen shot of the rock, open paint, crop everything but the rock out, drag the simba crosshair to paint, run a function that counts a particular color and writes the value to the debug box, and do this on a few different rocks on different angles for a good accuracy. I prefer the first option We will set this value to 50 to start with. Now that we have all of our values, we need to format it correctly. The function in Object.simba requires the following order: Simba Code: TMSObject.create(_Name: string; _UpText: TStringArray; _InnerCols: Array of TColEx; _MinCount, _Height, _Width, _SizeTol: Integer); overload; I will go through them individually and explain what each does: Name: Mine Rocks //Just the name of the object UpText: ['ine rocks', 'Mine', 'rock', 'ine r'] //The array of uptext that exists when we mouse over the rock. You will see there are a few options for it to make a match on. If it matches any of that text it will return as true. Color: [createCol(5263705, 14, 0.14, 0.07)] //This is the color we got with ACA2. This value requires an array (multiple) colors, hence the square brackets. CreateCol is another function within Aerolib (notice the function within a function - Funception hehe) that assigns the color using CTS2. This is [color, tol, hue, sat]. Min count: 50 //We are guessing this value. If the function clicks the wrong thing, we need to raise or lower the value accordingly. Height, width, size tol etc: 0 //We won't be populating these values so we will simply put 0. So lets put this in our script. Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var TinRock: TMSObject;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0);end;begin initAL; PlayerSetup;end. I also added the PlayerSetup to our list at the bottom of the script. Using an object Now that we have created our object. We need to work out a method of searching the screen for a match. To do this, we will create a new procedure called Procedure FindRock; This is where we will put any functions or checks to do with mining the rock. We will be using variables in the TinRock object that we created by doing the following: Simba Code: if TinRock.Find(pnt) then This will use a boolean to return true or false if the script finds the object we are looking for. It will mouse over the closest object to the center of the screen that matches our variables, check the uptext and report true if found, or move onto the next closes object if the Uptext doesn't match. Once it has all of the boxes checked, it will return a value of true and we can opt to click on the rock. Lets add this to our script. Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}var TinRock: TMSObject;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0);end;Procedure FindRock;var pnt:tpoint;begin if TinRock.Find(pnt) then FastClick(Mouse_left);end;begin initAL; PlayerSetup; FindRock;end. You can give this a test on the Runescape page with some Tin ore in sight on the screen if you like. Making the script loop Once you have confirmed it's working, we can move on. If it is not working, make sure your color is valid and that you followed the steps above correctly, and try adjusting the min count variable. Now that we have managed to successfully find our ore, we need to make our script loop. As it stands, the script will execute each line once and then terminate. We want it to loop through our current MineRock procedure and our soon to exist DropInv procedure. To do this, we will be using a script state, repeat/until and a case to identify where the script is up to. See the updated script here. I will explain it all after: Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); CurrentTask := MINEORE;end;Procedure FindRock;var pnt:tpoint;begin if TinRock.Find(pnt) then FastClick(Mouse_left);end;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. Ok so we changed it a fair amount. We added a new procedure called MainLoop. We removed FindRock from the list at the bottom and added a repeat/Until to surround the MainLoop. We also added a Type above var at the top of the script and added a new variable called CurrentTask and assigned it to the newly created datatype: scriptstate. This is a lot to take in so lets start from top to bottom. A type is a custom data type that you can create in Simba. An example of things that are created using this are: TMSObjects, TColEx, etc. They are custom datatypes created by Flight in Aerolib that allow for data to be stored and interacted with later. The datatype we have created is called a ScriptState. This stores the variables of our loop. This means, we can identify what part of the script out character is up to (mining, dropping etc) and ensure they are set on the right path for their next action. Example: If the script has 3 procedures that we want to loop (Mine, Drop, break), it will check the ScriptState to identify which procedure to run. If the ScriptState says that Mine is the next thing we need to run, it will run the procedure to mine. If Drop is the next in line, it will run the procedure Drop. If an inventory check is performed (to count how many slots are left), it can be set to Mine or Drop, depending on the result, then the procedure is actioned. Very handy. Under that we have created a variable to assign to the ScriptState data type. This is called CurrentTask. You will see this further down the script. The first instance of CurrentTask is found under PlayerSetup. It is assigning the first task MINEORE which you will see towards the bottom of the script. The next change is the new procedure MainLoop. This is how we determine the next procedure we are going to execute. This is done using a Case statement. The case statement identifies the variable nominated after it and allows for us to trigger a function or procedure if a certain variable is ascertained. An example of case: Simba Code: procedure CaseTest;var Numbers: integer;begin Numbers := 1; case Numbers of 1: Writeln('Value is 1!'); 2: Writeln('Value is 2!'); 3: Writeln('Value is 3!'); 4: Writeln('Value is 4!'); 5: Writeln('Value is 5!'); end;end; The Numbers variable is set to 1, then we use a case statement to identify which value is assigned to it. If the value is 1, then it will fire the WriteLn command saying that the value is 1. So back to our script; our case statement has MINEORE: FindRock(); This means that if the ScriptState has the assigned value: MINEORE, it will fire the procedure FindRock. We will be adding more ScriptState options to this as the script is developed. The last thing we have added is the Repeat, MainLoop, Until(false). Since Simba executed procedures 1 by 1 between this begin and end. statement, we need to add a way for our mainloop to actually...loop... The repeat Until statement will repeat the lines that are between them, until a condition is met. An example of this: Simba Code: procedure Example;var Numbers: integer;begin Numbers := 1; repeat Inc(Numbers); Until(Numbers = 5); WriteLn('Our repeat has finished');end; This creates an integer variable called numbers, assigns a value of 1 to it, repeats the function inc(numbers); (which increases the number by 1) until Numbers returns a value of 5, then breaks the repeat block and continues on to the WriteLn command. Our Repeat Until block is a little different to this. We have simple set the Until value to True, meaning that the repeat is not going to stop, unless we stop it manually in the script. This means that the loop continues on until we want the script to stop. Now to really provide an understanding of how the ScriptState and case work, we are going to create another procedure that we are going to use down the track. See code: Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); CurrentTask := MINEORE;end;Procedure FindRock;var pnt:tpoint;begin if TinRock.Find(pnt) then FastClick(Mouse_left);end;Procedure DropInv;beginend;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); DROPORE: DropInv(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. As you can see, we created the procedure, but we also added a new line under our MainLoop. This means that we can use CurrentTask := DROPORE to run the DropInv procedure when we need it. It is important to note that anything that is added to the main loop, must also be included in the ScriptState at the top of your script. If you wanted to add a third procedure to the loop like a break handler, you would need to add a variable that reflects that name at the top (such as BREAKING). You can then add BREAKING: <procedure name> in the MainLoop. Creating and using a custom function Ok so we have created an object, put a procedure in place to identify and click that object, and created a loop to keep clicking the object. The problem with our current code is that there is nothing telling the loop that we are still mining. It will keep clicking over and over again. So with that in mind, we need to figure out a way to identify if the rock is still being mined or not and provide a failsafe in case it times out. Like most tasks that we are scripting, there are many different methods that allow us to achieve our goals. For the purpose of simplicity in this tutorial, we will be using color to identify it. The way this will work is: 1. Our script will find the rock to mine. 2. It will then provide a TPoint back to us. 3. We will create a function that identifies if the color is still found inside of our box, and if it isn't, move on with the script. So lets begin! First thing we need to do is create a function that identifies the area in which we will test the color. Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); CurrentTask := MINEORE;end;function ColorGone(TestCol: TColEx; Box: TBox; MaxTime: integer): Boolean;var T: Timer;begin Result := False; T.start(); while T.timeElapsed < MaxTime do begin if not TestCol.findIn(Box) then Exit(True); wait(randomrange(10, 200)); end;end;Procedure FindRock;var pnt:tpoint; TempBox: TBox;begin if TinRock.Find(pnt) then FastClick(Mouse_left);end;Procedure DropInv;beginend;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); DROPORE: DropInv(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. You will notice the function: ColorGone. This is a custom function that we will be using to identify when a color in a certain box is gone. Lets walk through it. Functions differ from procedures in the way that the variables can be declared in the arguments. Look at the line: Simba Code: Function ColorGone(TestCol: TColEx; Box: TBox; MaxTime: integer): Boolean; TestCol, Box and MaxTime are variables we would normally declare under the Var header of a procedure, or the global Var at the top of the script, but functions allow us to declare them directly. For example, if you wanted to make a function that used a string and an integer, it would look like: Simba Code: function OurCustFunction(Arg1: string; Arg2: integer): boolean; Arg1 and Arg2 are just variable names that I assigned. These could be anything you wish (as long as it doesn't conflict with a variable name in any includes you are using). The purpose of declaring the variables like this is so that we can input data for our function somewhere else in the script. It is also important to note that this function must be on a line that is higher to when it was called, meaning functions are good to put towards the top of your scripts. Looking further down the function block, you will noticed that, despite already having variables declared for us, we still declared a variable: T: Timer; This is because we are not inputting any data for this; this will be a static variable that is used only in this function and does not need to pass back any information. The Timer type is exactly what it implies; it's a timer (counts up from 0 ms). After the variables, we have moved onto our begin/end statement. The first line is our Result being set to false. This may look strange, but it is done purposefully. We set this to false in case our function isn't able to resolve, meaning that the boolean at the end of the function returns false as its result. The next line is our Timer variable (T) being started. Since this is a type, we use the variable name T and follow it with a .start. A hint box will usually appear in Simba if you have done it correctly giving you the options when you type T. . The next line is something you probably haven't seen. It is a type of loop (like repeat/until but a little different) called While/Do. The line basically says that While the timer is less than the max search time (MaxTime), Do/repeat the following. As soon as Maxtime is exceeded, the function stops the repeat and moves on. The reason we do this is to perform our check on the rock on the rock for a maximum of x milliseconds (MaxTime) and stops the function based on the result. I will explain it more after this next section. The next lines are basically checks to see if our rock color is found in the Tbox. If it is still existing in the Tbox,the script will keep looping until the Maxtime variable is exceeded (resulting in false) or the color no longer exists (resulting in true). There is also a wait command to stop the function from checking too frequently. The randomrange between the Wait() is a random number between the range (in this case between 10 and 200). This function can be put anywhere that you could put an integer; Now to finish explaining the While/do loop for our script: 1. Timer is started. 2. While/Do block is called. 3. Script continutes to check to see if the color is still in our TBox ever Random(10 to 200) seconds. 4. If the color no longer exists in the TBox, it returns a True boolean to our procedure and exits the script back to where we called the function in the first place (Exit(true)). 5. If the MaxTime limit is exceeded, the While/Do block simply ends and the function finishes on the last end statement. This means that the function will return false, because we set the result to false at the top of the function, and nothing changed it. So now that the function has been declared in the script, we need to call for it to be used. Since this function will be checking to see if our mining rock is still there, it would be a good idea to call this after interacting with the rock. See the following code: Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState; RockCol: TColEx;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); RockCol.create(5263705, 14, 0.14, 0.07); CurrentTask := MINEORE;end;function ColorGone(TestCol: TColEx; Box: TBox; MaxTime: integer): Boolean;var T: Timer;begin Result := False; T.start(); while T.timeElapsed < MaxTime do begin if not TestCol.findIn(Box) then Exit(True); wait(randomrange(10, 200)); end;end;Procedure FindRock;var pnt:tpoint; TempBox: TBox;begin if TinRock.Find(pnt) then FastClick(Mouse_left); TempBox := ToBox(pnt.X -5, pnt.y -5, pnt.x +5, pnt.y +5); if ColorGone(RockCol, TempBox, 10000) then Exit;end;Procedure DropInv;beginend;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); DROPORE: DropInv(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. Ok so a few lines were added here. Lets work top to bottom. The first line added was a global var called RockCol which uses the type: TColEx. This is the same data type that the Object finding method uses. The next line is in our PlayerSetup procedure. We are assigning information to the RockCol type. This is achieved by typing RockCol.Create. This creates the color and stores it in the TColEx variable for later use. This color should be the same color as what you declared in your TMSObject (TinRock). The next addition to the script is under the FindRock procedure. We added a new variable: TempBox which is a TBox datatype. This is where we will store our TBox co-ordinates for use in our ColorGone function. The next line is the TempBox variable again, but instead of declaring it, we are storing data in it. The data that we are storing in this variable is the pnt variable +/- some size. I will explain as best I can below: The structure of a TBox is: X1, Y1, X2, Y2. Explanation: x1 and y1 are the top left point of our box. x2 and y2 are the bottom right of our point. The structure of a TPoint is: X, Y. Explanation: X and Y are simply a point on the screen. If you look at the Simba client and move the mouse, you will see at the bottom left corner there are 2 numbers in brackets changing every pixel that you move the mouse. This is the the X any Y axis of a Tpoint and represents the point on the screen. With this in mind, we want to use the TPoint values from our variable: pnt and make them into a box. To do this, we will need to use a little math. The first variable in our TBox is going to be pnt.X -5. This means that it is assigning the X value of the pnt Tpoint and detracting the value by 5. For example, a TPoint returns a value of (240, 120), the value of X would be 240. The value of pnt.X -5 would be 235. We will do the same for the second variable in our TBox: pnt.y -5. So far our TBox looks like this: (pnt.x -5, pnt.y -5, 0, 0). So now we need to get the values of the bottom right hand side of the box. We will follow the same process, but instead of taking 5 away, we will be adding 5. The third variable in our Tbox will be: pnt.x +5, and the forth variable in our Tbox will be pnt.y +5. This leaves us with the following for our TBox: (pnt.x -5, pnt.y -5, pnt.x +5, pnt.y +5). If pnt returned a value of (240, 120), the Tbox would look like (235, 115, 245, 125). Simple right? With our TBox co-ordinates set, we proceed to declaring the function between an if/then statement (because it returns a boolean). Simba Code: if ColorGone(RockCol, TempBox, 10000) then RockCol = The TColEx color we created in PlayerSetup. TempBox = The Tbox we just created. 10000 = the amount of time (ms) before the variable returns false and tries again. Finally, after the variable is declared true, we want to Exit the block. The reason for this is so we aren't waiting for the procedure to finish (faster). If the function returns false, it will finish the procedure. Regardless what happens (as the script currently stands) it will finish the procedure, move to the procedure MainLoop and check to see what the CurrentTask is. Since we didn't change the CurrentTask in the FindRock procedure, it will repeat the FindRock procedure again (hence the working loop yay!). Dropping the ore: for..to..do loop Now this is great and all, but what about when your inventory is full?! It's just going to keep clicking, waiting 10 seconds and repeating! Well, we are going to use the procedure we created: DropInv to drop our inventory when it's full. Again, like EVERYTHING we have done in this tutorial, there are a million ways to accomplish this. Rather than go step by step, I am going to write up the bulk and explain it. Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState; RockCol: TColEx; PickInv: boolean;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; PickInv := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); RockCol.create(5263705, 14, 0.14, 0.07); CurrentTask := MINEORE;end;function ColorGone(TestCol: TColEx; Box: TBox; MaxTime: integer): Boolean;var T: Timer;begin Result := False; T.start(); while T.timeElapsed < MaxTime do begin if not TestCol.findIn(Box) then Exit(True); wait(randomrange(10, 200)); end;end;Procedure FindRock;var pnt:tpoint; TempBox: TBox;begin if TinRock.Find(pnt) then FastClick(Mouse_left); TempBox := ToBox(pnt.X -5, pnt.y -5, pnt.x +5, pnt.y +5); if ColorGone(RockCol, TempBox, 10000) then Exit;end;Procedure DropInv;var i, SSlot: integer;begin if PickInv then SSlot := 2 else SSlot := 1; if GameTab(TAB_INV) then for i := SSlot to 28 do begin if itemInSlot(i) then begin InteractSlot(i, MOUSE_RIGHT); if WaitOption('Drop', 1000) then ChooseOption('Drop'); wait(randomrange(50, 250)); end; end;end;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); DROPORE: DropInv(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. So lets dissect the new additions to our script! So at the top of the script, we added a new global var called PickInv and assigned the datatype Boolean to it. This variable is going to be true or false as to whether or not the player has a pickaxe in their first slot. True = Pickaxe in their first slot False = No Pickaxe in their first slot This is set under the PlayerSetup procedure. The next additions are all i the DropInv procedure. This procedure will basically go through each inventory slot, check to see if an item exists there (doesn't discriminate against items) and then drops them (left to right). Lets delve a little deeper into the code. We have 2 variables against this code. i and SSlot. Despite these being on the same line, they are actually 2 seperate variables. Example: Simba Code: Variable1: integer;Variable2: integer;Variable3: integer;Variable1, Variable2, Variable3: integer; Both variable declarations work. You can put them on seperate lines, but if the datatype is the same (integer, string, TBox etc) then it is best practice to put them on the same line. The first line under Begin/End is a boolean check. We are checking to see if our PickInv variable was set to true of false. If so, it sets the SSlot value to 2 (meaning that we start dropping from inventory slot 2), but under that we have an else statement. This means that if the if/then statement returns any other value than what it was after, it will trigger the next line(s), in this case setting SSlot to 1. Example time! Simba Code: // Will write "The number is 1" in the debug box.procedure Testvar Number: integer;begin Number := 1; if (Number = 1) then WriteLn('The number is 1') else WriteLn('The number isnt 1');end;// Will write "The number isnt 1" in the debug box.procedure Testvar Number: integer;begin Number := 4; if (Number = 1) then WriteLn('The number is 1') else WriteLn('The number isnt 1');end; You will also notice the lack of ; This is because it is essentially processed on the one line. We put it into separate lines for readability and standards. Simba Code: procedure Testvar Number: integer;begin Number := 4; if (Number = 1) then WriteLn('The number is 1') else WriteLn('The number isnt 1');end; Would also work, but it is bad standards. This can also be done with begin/end statements. Example: Simba Code: procedure Testvar Number: integer;begin Number := 1; if (Number = 1) then begin WriteLn('The number is 1'); WriteLn('The system works'); end else begin WriteLn('The number isnt 1'); WriteLn('The system doesnt work. We are all going to die!'); end;end; You will notice the ; is after each line there. This is because items in between a begin/end statement are processed individually. SO after the SSlot variable is assigned it's value, it begins a for..to..do statement (yet another repeat!!). Now this really got me when I was learning, so I will explain it as best I can. The i is an integer and it is assigned a variable as per normal. Simba Code: for i := SSlot to 28 do This means that the following begin/end is going to repeat 27-28 times (1 or 2 to 28). If it was 1 to 36, it would repeat 36 times. In this case, it is the inventory slot number (28 inventory slots). The reason for SSLot is to identify which number we are starting at. The next line checks to see if the inventory is open, and if not, opens it. Again, its a function built into Aerolib. I covered this in the previous post so I won't go any further with this. Now moving down the script, you will notice the next function: ItemInSlot(i). ItemInSlot is a function built into Aerolib that checks to see if an item exists in a particular slot. For example, we want to check slot 1 to see if it's empty or not: Simba Code: if ItemInSlot(1) then Would perform a check and return a boolean indicating true or false. This is the same, except instead of a number, we are using i. Each time it cycles through the code, the value of i is being changed to the next in line (1, 2, 3, 4, 5, 6 etc..). It will check Inventory slot 1, process the code below, inventory slot 2, process the code below etc until it is told to Exit, or it reaches its high range (in this case 28). This is a critical part of scripting so I will provide another example: Simba Code: procedure testvar i: integer;begin for i := 1 to 8 do begin WriteLn('The value of i is: ' +IntToStr(i)); end;end; Would output: Code: Output: The value of i is: 1 Output: The value of i is: 2 Output: The value of i is: 3 Output: The value of i is: 4 Output: The value of i is: 5 Output: The value of i is: 6 Output: The value of i is: 7 Output: The value of i is: 8 So if ItemInSlot(i) returns a true value, this means that there is an item in that particular slot. The next line will then use a function called InteractSlot to...interact with the slot...Uncanny! InteractSlot has 2 variables that need to be filled out: var 1 is the slot number, which we are simply going to put i. This ensures that if we are checking inventory slot 2, we are interacting slot 2 as well! The next var is the mouse variation. The variations available are: MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MOVE. They do exactly what you think: moves the mouse and left clicks, right clicks or does nothing. Once we have interacted with the slot (in this case MOUSE_RIGHT), we have put in place a WaitOption function to check the right click menu when it appears. This is found in the menu.simba file in Simba/Core/. What this function does is waits for the menu option specified to appear. Example: Simba Code: if WaitOption('drop', 1000) then //returns as true if the word drop exists in the menu, otherwise skips. Case sensitive.if WaitOption('use', 1000) then //returns as true if the word use exists in the menu, otherwise skips. Case sensitive.if WaitOption('examine', 1000) then //returns as true if the word examine exists in the menu, otherwise skips. Case sensitive. The 1000 is the amount of ms you want it to check before auto returning false. Finally, once WaitOption returns true and confirms that drop does indeed exist in the menu, we are going to use ChooseOption to select the option. Simba Code: ChooseOption('drop'); This will move the mouse to the first option with drop in it and then left click. Now that our procedure seems to compile ok, we need to link it to the mainloop so that it runs the procedure when the inventory is full, and then runs the FindRock procedure when its finished dropping. To do this, add the following: Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState; RockCol: TColEx; PickInv: boolean;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; PickInv := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); RockCol.create(5263705, 14, 0.14, 0.07); CurrentTask := MINEORE;end;function ColorGone(TestCol: TColEx; Box: TBox; MaxTime: integer): Boolean;var T: Timer;begin Result := False; T.start(); while T.timeElapsed < MaxTime do begin if not TestCol.findIn(Box) then Exit(True); wait(randomrange(10, 200)); end;end;Procedure FindRock;var pnt:tpoint; TempBox: TBox;begin if (GetInvCount = 28) then begin CurrentTask := DROPORE; Exit; end; if TinRock.Find(pnt) then FastClick(Mouse_left); TempBox := ToBox(pnt.X -5, pnt.y -5, pnt.x +5, pnt.y +5); if ColorGone(RockCol, TempBox, 10000) then Exit;end;Procedure DropInv;var i, SSlot: integer;begin if PickInv then SSlot := 2 else SSlot := 1; if GameTab(TAB_INV) then for i := SSlot to 28 do begin if itemInSlot(i) then begin InteractSlot(i, MOUSE_RIGHT); if WaitOption('Drop', 1000) then ChooseOption('Drop'); wait(randomrange(50, 250)); end; end; CurrentTask := MINEORE;end;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); DROPORE: DropInv(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. Now what we have added was a check in the FindRock procedure, at the top of the line, to get the inventory count. If the count returns an integer of 28 (meaning our inventory is full), then it will set the variable: CurrentTask to DROPORE (from our script state at the top of the script), and exit the procedure. When it exits the procedure, it doesn't fire anything else in that procedure after Exit;. It simply goes back to the MainLoop. The reason we put it at the top is so it doesn't try to mine while the inventory is full. Note: GetInvCount will automatically open your inventory if it isn't already open. When the MainLoop procedure is run again, it will see that CurrentTask has the variable DROPORE assigned to it, so it will run the DropInv procedure instead. On the DropInv procedure, at the end of the procedure, we simply set the variable for CurrentTask to MINEORE and then let the procedure finish. It will again pass back to MainLoop and check the variable of CurrentTask and assign the procedure based on the result. You can add another fail safe to this if you wanted to and have it GetInvCount again before it sets CurrentState to MINEORE. Ok so now our script will perform the following task: 1. Create the global variables 2. Execute the PlayerSetup procedure 3. Log the player in if they aren't already 4. Find the object that we created 5. Interact with the object (mine rock) 6. Wait for the rock to be mined 7. Check the inventory count 8. Drop the inventory when it is full 9. Repeat steps 4-8 until its turned off. Antiban in your scripts Another thing that is probably worth adding is Antiban. Antiban is a generic term for doing things that humans would do like moving the mouse randomly, missing the object when your moving the mouse to it. Occasionally right clicking on the object instead of left clicking. I won't show you everything because that will take forever, but I will show you how to integrate some antiban into your script. First thing we want to do is create a procedure called Antiban. Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState; RockCol: TColEx; PickInv: boolean;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; PickInv := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); RockCol.create(5263705, 14, 0.14, 0.07); CurrentTask := MINEORE;end;function ColorGone(TestCol: TColEx; Box: TBox; MaxTime: integer): Boolean;var T: Timer;begin Result := False; T.start(); while T.timeElapsed < MaxTime do begin if not TestCol.findIn(Box) then Exit(True); wait(randomrange(10, 200)); end;end;Procedure Antiban;beginend;Procedure FindRock;var pnt:tpoint; TempBox: TBox;begin if (GetInvCount = 28) then begin CurrentTask := DROPORE; Exit; end; if TinRock.Find(pnt) then FastClick(Mouse_left); TempBox := ToBox(pnt.X -5, pnt.y -5, pnt.x +5, pnt.y +5); if ColorGone(RockCol, TempBox, 10000) then Exit;end;Procedure DropInv;var i, SSlot: integer;begin if PickInv then SSlot := 2 else SSlot := 1; if GameTab(TAB_INV) then for i := SSlot to 28 do begin if itemInSlot(i) then begin InteractSlot(i, MOUSE_RIGHT); if WaitOption('Drop', 1000) then ChooseOption('Drop'); wait(randomrange(50, 250)); end; end; CurrentTask := MINEORE;end;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); DROPORE: DropInv(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. I like to put it under the custom functions personally. It doesn't matter where you put it, as long as its above any procedures that call for it to be used. I will add content to the Antiban and go through it with you. Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState; RockCol: TColEx; PickInv: boolean;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; PickInv := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); RockCol.create(5263705, 14, 0.14, 0.07); CurrentTask := MINEORE;end;function ColorGone(TestCol: TColEx; Box: TBox; MaxTime: integer): Boolean;var T: Timer;begin Result := False; T.start(); while T.timeElapsed < MaxTime do begin if not TestCol.findIn(Box) then Exit(True); wait(randomrange(10, 200)); end;end;Procedure Antiban;begin case random(1500) of 0..2: begin WriteLn('Antiban: Hovering Random Skill'); hoverSkill('random', false); end; 6..8: begin WriteLn('Antiban: Examining random item.'); examineInv(); end; end;end;Procedure FindRock;var pnt:tpoint; TempBox: TBox;begin if (GetInvCount = 28) then begin CurrentTask := DROPORE; Exit; end; if TinRock.Find(pnt) then FastClick(Mouse_left); TempBox := ToBox(pnt.X -5, pnt.y -5, pnt.x +5, pnt.y +5); if ColorGone(RockCol, TempBox, 10000) then Exit;end;Procedure DropInv;var i, SSlot: integer;begin if PickInv then SSlot := 2 else SSlot := 1; if GameTab(TAB_INV) then for i := SSlot to 28 do begin if itemInSlot(i) then begin InteractSlot(i, MOUSE_RIGHT); if WaitOption('Drop', 1000) then ChooseOption('Drop'); wait(randomrange(50, 250)); end; end; CurrentTask := MINEORE;end;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); DROPORE: DropInv(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. Ok so I have used a few Antiban functions from my NMZ script to show you. The first thing you will notice in the procedure is Simba Code: Case Random(1500) of This is the script picking a random number out of 1500. Under it, you will see 0..2: with a begin/end, and 6..8: with a begin/end. These numbers trigger their respective begin/end statements when the Random number returned is equal or between their range. 0..2 = 0 to 2. 1..100 would be 0 to 100. If the number returns the same as any number between the values, it will trigger the antiban function. This means that there is a 6/1500 chance (1/250) that Antiban will be triggered when the procedure is called. So lets look into the 2 functions that we have added. The first one is a function that hovers over a Random Skill (hoverskill('random', false). This will simply move your mouse, open the skills tab, mouse over a random skill for a random amount of ms, then return to the script. The second one is a function that randomly examines an item in your inventory (ExamineInv()). It is another Antiban function that is built into Aerolib. Other Antiban functions can be found in (..Simba/Aerolib/core/Antiban.simba). Now that we have created the procedure, we need to slip it somewhere it can trigger efficiently without breaking the script. For this script, I would put it at the beginning of the FindRock procedure, and again at the end of DropInv procedure. These will have the least impact on our script. Lets do that now: Simba Code: program new;//{$DEFINE SMART}{$i AeroLib/AeroLib.Simba}type ScriptState = (MINEORE, DROPORE);var TinRock: TMSObject; CurrentTask: ScriptState; RockCol: TColEx; PickInv: boolean;Procedure PlayerSetup;begin Me.Active := True; Me.Name := ''; Me.Pass := ''; Me.Member := True; PickInv := True; TinRock.create('Mine Rocks', ['ine rocks', 'Mine', 'rock', 'ine r'], [createCol(5263705, 14, 0.14, 0.07)], 50, 0, 0, 0); RockCol.create(5263705, 14, 0.14, 0.07); CurrentTask := MINEORE;end;function ColorGone(TestCol: TColEx; Box: TBox; MaxTime: integer): Boolean;var T: Timer;begin Result := False; T.start(); while T.timeElapsed < MaxTime do begin if not TestCol.findIn(Box) then Exit(True); wait(randomrange(10, 200)); end;end;Procedure Antiban;begin case random(1500) of 0..2: begin WriteLn('Antiban: Hovering Random Skill'); hoverSkill('random', false); end; 6..8: begin WriteLn('Antiban: Examining random item.'); examineInv(); end; end;end;Procedure FindRock;var pnt:tpoint; TempBox: TBox;begin Antiban(); if (GetInvCount = 28) then begin CurrentTask := DROPORE; Exit; end; if TinRock.Find(pnt) then FastClick(Mouse_left); TempBox := ToBox(pnt.X -5, pnt.y -5, pnt.x +5, pnt.y +5); if ColorGone(RockCol, TempBox, 10000) then Exit;end;Procedure DropInv;var i, SSlot: integer;begin if PickInv then SSlot := 2 else SSlot := 1; if GameTab(TAB_INV) then for i := SSlot to 28 do begin if itemInSlot(i) then begin InteractSlot(i, MOUSE_RIGHT); if WaitOption('Drop', 1000) then ChooseOption('Drop'); wait(randomrange(50, 250)); end; end; Antiban(); CurrentTask := MINEORE;end;Procedure MainLoop;begin if not isLoggedIn then TerminateScript; case CurrentTask of MINEORE: FindRock(); DROPORE: DropInv(); end;end;begin initAL; PlayerSetup; repeat MainLoop(); Until(False);end. To call a procedure, simply add the name of the procedure, followed by ();. It will trigger the procedure, then return back to the line in which it was called. Example: Simba Code: program new;procedure One;begin WriteLn('This will trigger second.');end;procedure two;begin WriteLn('This will trigger first.'); One(); WriteLn('This will trigger third.');end;begin two();end. Now you have completed your first script in Aerolib. It is a very crude script, but it has hopefully provided you with enough to get you going on your next projects Next tutorial If you are comfortable with the above lesson, you can move onto my second tutorial: Creating and using items. That tutorial will teach you how to identify objects in your inventory/bank and interact with them. Last edited by Dan the man; 09-04-2017 at 12:28 AM. 2. SRL Junior Member Join Date Jul 2015 Posts 80 Mentioned 1 Post(s) Quoted 22 Post(s) WOW, you must have put a lot of time into this. Beginners - LEARN. AWSOME! 3. SRL Junior Member Join Date Jan 2013 Posts 86 Mentioned 0 Post(s) Quoted 25 Post(s) You are amazing, already thanked you via PM a few days ago, but thanks again this is awesome. 4. Thanks for the kind words guys. Have wanted to do something like this for a while but needed some motivation. 5. Excellent job sir 6. Informative! Good starting point for 07. 7. Registered User Join Date Jan 2017 Posts 1 Mentioned 0 Post(s) Quoted 0 Post(s) Jesus. Best guide out there. Wish I saw this when I was a little more green. Great work, man 8. Registered User Join Date Jan 2017 Posts 5 Mentioned 0 Post(s) Quoted 4 Post(s) Read the whole tutorial, was very well written and has very useful information for a beginner like me. Thank you very much OP, would definitely like to see more tutorials coming from you. Also, instead of using the 'ColorGone' function, would it be better to use 'pixelshift', when rotating the camera the box that you created for the 'ColorGone' function would be in a different place right? or is there something better to use than pixelshift? 9. Originally Posted by Musaa Read the whole tutorial, was very well written and has very useful information for a beginner like me. Thank you very much OP, would definitely like to see more tutorials coming from you. Also, instead of using the 'ColorGone' function, would it be better to use 'pixelshift', when rotating the camera the box that you created for the 'ColorGone' function would be in a different place right? or is there something better to use than pixelshift? Oh 100% it would be better. I use that in my own power mining scripts. I did ColorGone as an alternative option to explain how color finding works. Figured it would be easier for a green scripter to understand. I plan on doing more intermediate tutorials in the future. 10. Registered User Join Date Jan 2017 Posts 5 Mentioned 0 Post(s) Quoted 4 Post(s) Originally Posted by Dan the man Oh 100% it would be better. I use that in my own power mining scripts. I did ColorGone as an alternative option to explain how color finding works. Figured it would be easier for a green scripter to understand. I plan on doing more intermediate tutorials in the future. Also, are there any negatives to using reflection? imo it's way more reliable and easier, why not use it to make things easier? 11. SRL Junior Member Join Date Apr 2013 Posts 680 Mentioned 13 Post(s) Quoted 341 Post(s) Great work! =D 12. Originally Posted by Musaa Also, are there any negatives to using reflection? imo it's way more reliable and easier, why not use it to make things easier? Reflection can't be used outside of smart. Reflection is more accurate, but most believe that the SMART client has been detected by Jagex, so using color on the official client or OSBuddy would be assumed safer. Last edited by Dan the man; 02-06-2017 at 01:35 AM. 13. SRL Junior Member Join Date Dec 2011 Location Netherlands Posts 140 Mentioned 1 Post(s) Quoted 8 Post(s) Thanks this will be so usefull after my break of simba and (os)rs. Trying on finishing/(releasing) a script this week! P.s. Those functions used in aerolib are fully working in color right, so if I use it in the official client I need to do a bad Job to get banner? -Skywalk 14. Originally Posted by Skywalk Thanks this will be so usefull after my break of simba and (os)rs. Trying on finishing/(releasing) a script this week! P.s. Those functions used in aerolib are fully working in color right, so if I use it in the official client I need to do a bad Job to get banner? -Skywalk They are certainly in color and can be used in the official client. Bans in OSRS seem higher than in RS3 from what the banned section tells me. This could be due to a few reasons, but I suspect it has a lot to do with player reports. As long as you bot smart, don't bot for profit on your main and mix your play between legit/botting you should be ok. 15. Registered User Join Date Jan 2013 Posts 11 Mentioned 0 Post(s) Quoted 4 Post(s) This is extremely appreciated. To code for the first time is damn near impossible without having a few guidelines and this really helps with that. 16. SRL Junior Member Join Date Feb 2017 Posts 30 Mentioned 0 Post(s) Quoted 12 Post(s) Nice guide, I'm hoping to make a wine grabber so i can make profit from f2p accounts. 17. Was just doing the same thing myself haha. 18. Registered User Join Date Jun 2016 Posts 17 Mentioned 0 Post(s) Quoted 4 Post(s) I know this is off topic, but is a wine grabber really worth it? Is there not stupid amounts of players already doing the same thing? Contesting the spot and significantly dropping the gp/hour? 19. Registered User Join Date Feb 2017 Posts 5 Mentioned 0 Post(s) Quoted 1 Post(s) ## hi hey, nice tutorial man but ccan you help me with a woodcutter bot or a fisher bot pls using the official client 20. Originally Posted by Rangerxmage I know this is off topic, but is a wine grabber really worth it? Is there not stupid amounts of players already doing the same thing? Contesting the spot and significantly dropping the gp/hour? Is worth it because you can script it to be quite quick, increasing your chances, and even at lower grabs/hr its still one of the best bot-able incomes in F2P with stuff all requirements. Originally Posted by orlinowns hey, nice tutorial man but ccan you help me with a woodcutter bot or a fisher bot pls using the official client Utilise what you have learnt here and adapt it to your desired project. I make it a habit to help people who at least attempt to do it themselves. You are more than welcome to create help posts if you come across issues and I can guarantee you (if you have attempted to fix the issue yourself or fail to understand a problem) that most people in this community will jump to help you. 21. SRL Junior Member Join Date Nov 2009 Posts 48 Mentioned 0 Post(s) Quoted 5 Post(s) Great guide Dan the man! Learnt some basics very quickly here. Currently writing my first AL script which is going well but stuck on effectively opening a bank. I found the function openBankPoint but can't get it working. Don't laugh too hard but here's what I understand so far... Code: program Bank; {$i AeroLib/AeroLib.Simba}

procedure OpenBank;
var
BankPoint : Tpoint;
LeftClick : Boolean;

begin
begin
openBankPoint(BankPoint, LeftClick);
end
end

begin
ClearDebug;
initAL;
mouseSpeed := Random(16, 28);
OpenBank;
end;
The script compiles successfully but does nothing! Please can anyone tell me what I'm missing and how to make this work so it will open the bank?

Thank you, this will help me improve my knowledge. I'm obviously a beginner!

22. Originally Posted by Grimtoker
Great guide Dan the man! Learnt some basics very quickly here.

Currently writing my first AL script which is going well but stuck on effectively opening a bank.
I found the function openBankPoint but can't get it working.
Don't laugh too hard but here's what I understand so far...

Code:
program Bank;
{$i AeroLib/AeroLib.Simba} procedure OpenBank; var BankPoint : Tpoint; LeftClick : Boolean; begin begin openBankPoint(BankPoint, LeftClick); end end begin ClearDebug; initAL; mouseSpeed := Random(16, 28); OpenBank; end; The script compiles successfully but does nothing! Please can anyone tell me what I'm missing and how to make this work so it will open the bank? Thank you, this will help me improve my knowledge. I'm obviously a beginner! Hi mate, Glad to see your giving it a go! The function OpenBankPoint will actually use a Tpoint that you feed it using the findObj functions Lets talk through what you have now: First, you declared the BankPoint variable as a Tpoint. It has a default value of 0,0 (or is it -1, -1...i forget). You when set the variable LeftClick as a boolean (which I believe defaults to true). On the procedure, you have told the script to open a bankpoint with the co-ordinates 0, 0 (or -1, -1), which I believe it will dismiss and return a failed boolean. So what we need to do to fix this is use a function that actually finds the bank booth, stores its location into your BankPoint variable, then use that with the OpenBankPoint function. Use the tutorial above, but instead of creating a mining rock, apply the skills to finding a bankbooth. Look for a color that exists primarily on the bank booths using ACA2, then create the type (TBank and add the same variables as we did for TRock in the tutorial) and essentially follow the exact same process. Give that a try and if you have any issues, post again Edit: It is also noteworthy that the function OpenBankPoint has 2 parameters: a Tpoint and a boolean. You were right to create a variable for the Tpoint, but with the boolean, you can simple write true or false. True will left click on the point, false will right click. Last edited by Dan the man; 03-02-2017 at 09:30 AM. 23. SRL Junior Member Join Date Nov 2009 Posts 48 Mentioned 0 Post(s) Quoted 5 Post(s) Thank you for the feedback. Suppose still don't fully understand. I understand that I need to setup an object for the function to find, which tried to do following your guide above. I think it's still not storing the location properly for when the function is called, so it's still not clicking it? Here is my progress so far.. simply trying to click the red headed banker to test the function. I can implement into a script and progress from there once I fully understand what I'm doing. Also for LeftClick.. replacing it with Mouse_left seems to compile successfully, will that work too? I tried true and false to no success. I'm beginning to think this may not be necessary for opening a bank, is there a more efficient way or is this the way to go? Sorry for being such a noob, appreciate any feedback. Code: program Bank; {$i AeroLib/AeroLib.Simba}

var
BankPoint : TMSObject;

Procedure PlayerSetup;
begin
Me.Active := True;
Me.Name := '';
Me.Pass := '';
Me.Member := True;

BankPoint.create('Talk-to Banker', ['Talk-to', 'Banker', 'to Banker'], [createCol(409208, 9, 0.02, 0.25)], 10, 0, 0, 0);
end

procedure OpenBank;
var
BankPoint:TPoint;

begin
openBankPoint(BankPoint, Mouse_left);
end

begin
ClearDebug;
initAL;
OpenBank;
end;

24. Originally Posted by Grimtoker
....
Okay so first of all, only stuff inside the last set of begin end. will be executed. So currently there isn't anything calling to your PlayerSetup function, therefore the BankPoint TMSObject is still empty. Make use of Writeln(); which will write whatever is between the brakcets into the Simba debug area beneath the script code. For example you can do Writeln(BankPoint); which will allow you to see what the contents currently are.

Also change the name of BankPoint to something like BankObject, point suggests it's going to hold a Point(x,y). Save BankPoint for its current use in the OpenBank procedure where it actually holds a Point.

Okay, so openBankPoint just handles the opening of the bank, it's handy as you don't need to worry about the type of bank it is bla bla, every type is handled, but it needs to be told where the bank is. AeroLib has functions that will attempt to find your object, it's only as good as your colors. We need to use one of these functions to get a TPoint returned of our object location that we can then give to openBankPoint.

Looking through TMSObject, the function "find" fits the bill. The find function will fill a TPoint variable that you pass to it with a matched object point, the function also has its own result which is a Boolean. This will let you know if it succeeded in finding an object, we'll want to make sure it has before we attempt to open a bank that hasn't been found.

With the above said, your OpenBank procedure now looks like this:

Simba Code:
procedure OpenBank;var  BankPoint: TPoint;begin  if BankObject.find(BankPoint) then    //this function will fill our BankPoint variable if it can find anything    openBankPoint(BankPoint, Mouse_left); //we're only doing this is the above find function found something.end; //don't forget semi colons on end