PDA

View Full Version : SRL-6 Script Walkthrough



bonsai
10-19-2013, 11:34 AM
SRL6 Script Walkthrough

Introduction

My goal is to help people looking for some basic exposure and introduction to coding scripts for Runescape3 using the SRL6 library. The main focus will be on SRL6 usage within the script(s). We will only be looking at a small subset of the library functionality. Hopefully enough foundation and concepts will be shared to enable you to branch into the other areas independently.

This paper will walk through developing a script that makes pastry dough at a bank chest. The program will be presented in stages with discussion about SRL usage in the presented code.

Forgive me if I refer to calls as SRL when some of them actually come from the base Simba program. If you can't find a function in the SRL documentation check the Simba documentation to see if it is inherited.

Scripts will have a download link so you can try them out. It may be best to read the paper with the code opened up in another window for reference.

Audience

The target audience for this paper is familiar with basic programming concepts and hopefully with the Lape language used in SRL6. Seasoned SRL5 scripters may not find much value, especially if you have already worked through the basic gist of SRL6.

Novice programmers may be better served by starting with other tutorials here on villavu or elsewhere. Lape is very similar to Pascal so these online tutorials might be of help to beginning programmers:


http://www.tutorialspoint.com/pascal/
http://www.taoyue.com/tutorials/pascal

Suggested Prerequisites

First off, you need to have Simba, SMART, and SRL6 installed and working! (Guide) (http://villavu.com/forum/showthread.php?t=47714)

Any scripter should be familiar with two tools and concepts.


The Auto Color Aid (http://villavu.com/forum/showthread.php?t=26944) tool is used for choosing colors for your script.
The DTM editor is built into simba (you need to enable it in the View->Extensions menu). There are many DTM tutorials in the Scripting Help and Tutorials (http://villavu.com/forum/forumdisplay.php?f=490) forums.

YoHoJo; made some videos covering ACA (http://villavu.com/forum/showthread.php?t=71074) and DTMs (http://villavu.com/forum/showthread.php?t=564). I recommend these to anyone needing to learn more.

Other links:

SRL6 Beta announcement (http://villavu.com/forum/showthread.php?t=105997)
SRL6 Documentation (http://docs.villavu.com/srl-6/index.html)
Simba 1.0 Documentation (http://docs.villavu.com/simba/)

A key concept

Many of the SRL include files use an object oriented aproach. They define a type to hold the data stucture needed to manage the object. Then they implement a number of functions that work on the type to perform the task at hand.

They often define an instance of this type, a global variable that you will use in your code to work with that datatype.

When you look in the documentation you will see the function listed as type.function() but you will use it as globalvar.function(). This is true for most things that would only have one instance like an inventory, minimap, or bankscreen.

For example, let's say we want to set the minimap to point south. The minimap (http://docs.villavu.com/srl-6/minimap.html) documentation lists a function for that:
function TRSMinimap.setAngle(angleDegrees: integer): boolean;

Near the top of the minimap doc page, you will find "var minimap". This is the global TRSMinimap variable that SRL defined for us.

var minimap
The variable that holds all minimap information. It used when calling any functions in this file.

So, to implement our call, we call setAngle on the minimap variable:
minimap.setAngle(MM_DIRECTION_SOUTH);

Some types are more generic, like a TPoint, and you will make your own variable to work with. There are no defined global instances.

I am posting a listing of these globals after the main article.

Phase 0: Using SRL to open a Runescape window

This is the most basic script. It opens a SMART window and starts a Runscape session.

You can use this script to play the game in the SMART window instead of a web browser. Run the script, wait for RS to load, then press the "Disable SMART" button. This takes mouse and keyboard control away from Simba and puts them back in control of the user.

Then you can log in and play manually.

program new;
{$DEFINE SMART}
{$i srl-6/srl.simba}

begin
clearDebug();
setupSRL();
end.

SRL usage in this script:

{$DEFINE SMART}
Setting this flag indicates you will use SMART as your browser for RS. It must be defined before including the SRL library.

Without it you need to use the crosshair icon in Simba to choose another program that is running the RS client. As far as I know this is not currently supported on SRL6.

{$i srl-6/srl.simba}
This line includes the SRL library files into your script. Include files are located in SIMBADIR/Includes. You should become familiar with these script libraries.

Most of the code is brief and understandable. This is an early release of a rewritten library so don't be suprised if you bump into a few glitches along the way. It would be helpful if you try to figure out the root cause. Detailed bug reports are a lot more helpful than "xyz doesn't work".

clearDebug();
clearDebug() isn't required but it is usually called. This clears out the debug box at the bottom of your Simba window. I did not find documentation for clearDebug().

setupSRL();
This initializes the SRL data structures and launches a SMART window running the RS client. It must be called and should probably be called very early in your script.

If you already have a SMART window open setupSRL() will use that window instead of opening a new one.

I did not find documentation for setupSRL().

Phase 1: Logging in

The next script will open RS, log your player in, paint some boxes on the screen and log out.

Download script for phase 1: 22319

program makestuff1;
{$DEFINE SMART}
{$i srl-6/srl.simba}

const
scriptName = 'makestuff1';
playerNames = ['WillyWonka']; // change this to your username or nickname
playerFile = 'default'; // change this to your playerFile name
desiredWorld = 0; // set this to 0 for any world
var
i : integer;

procedure scriptTerminate();
begin
print('****** ' + scriptName + ': Script shutting down', TDebug.DEBUG);
takeScreenshot(scriptName + '.png');
if isLoggedIn() then
players[currentPlayer].logout();
end;

procedure doSomeStuff();
var
x,y : integer;
begin
for x := 10 to 50 with 10 do
for y := 10 to 50 with 10 do
begin
smartImage.drawBox(intToBox(x, y, x+100, y+100), true, clFuchsia);
smartImage.drawBox(intToBox(x, y, x+100, y+100), clLime);
wait(1000);
smartImage.clear();
end;
players[currentPlayer].isActive := false;
end

begin
// initialize and prepare things
//
addOnTerminate('scriptTerminate');
ClearDebug();
smartEnableDrawing := true;
SetupSRL();
players.setup(playerNames, playerFile);
currentPlayer := 0;
for i := 0 to high(players) do
begin
players[i].world := desiredWorld;
players[i].isActive := true;
end;
// do the work
//
while (players.getActive() > 0) do
begin
if (not isLoggedIn()) then
begin
if (not players[currentPlayer].login()) then break;
mainscreen.setangle(MS_ANGLE_HIGH);
exitSquealOfFortune();
end;
doSomeStuff();
end;
end.

You need to add a player to your default player store with the alias WillyWonka. Open Simba and the player manager (SRL->Player Manager). Choose File->Open and navigate to SIMBADIR/includes/players to open default.xml. Add your entry and save it.

Note: I've bumped into a bug where my player store gets cleared out. For now I recommend maintaining a manual backup of the xml file for a safety copy.

Alternatively, you can edit the sample scripts and change the playerNames constant at the top to reflect your user name or alias.

SRL usage in this script:

We're going to skip the procedures for now and start with the main program.

addOnTerminate('scriptTerminate');
addOnTerminate adds a function to the list of tasks when a script is shutting down. This can be triggered by pressing the stop button in Simba, a function calling scriptTerminate(), or the program may have simply reached the end of it's main begin/end.

It's a good idea to have a terminate function to ensure you free up any allocated items like bitmaps or dtms, log out the user, etc. You can add more than one function to the list by calling addOnTerminate more than once. This doesn't have much value in your main program but if you have a number of includes it's handy for each of them to have their own cleanup function registered.

I did not find documentation for addOnTerminate().

smartEnableDrawing := true;
There are many functions available (http://docs.villavu.com/srl-6/drawing.html) for writing or drawing on top of the client window. You need to set this flag if you want to utilize these functions. This is helpful for debugging and can be used to display status information or jazz up your script by displaying a logo when it runs.

You call these functions against the smartImage global variable (as seen in the doSomeStuff() procedure).

Note: smartImage is listed as an internal variable in smart.simba so it does not show up on the documentation page.

players.setup(playerNames, playerFile);
currentPlayer := 0;
for i := 0 to high(players) do
begin
players[i].world := desiredWorld;
players[i].isActive := true;
end;

This code segment loads the data from your player file, sets the currentPlayer indicator and a couple of fields in the array that was loaded.

Recall the discussion near the top about "key concepts". SIMBADIR/includes/srl-6/core/players.simba (http://docs.villavu.com/srl-6/players.html) defines the global variable players for us, which is an instance of TPlayerArray. When we call players.setup() this array is initialized from our stored XML file for us.

The functions in players.simba can be used to manage a pool of players. They enable you to control switching from one to another. If you code your script for it, you can have one character log in and do some work, log out, the next character log in, and so on.

The global variable currentPlayer is used to indicate which player in the players array is in current use.

Here we are setting the world and isActive fields for our player. If you set the world field it will use that specific world (0 will pick one randomly). If you set the isActive field to false the other functions will not use the player, so we set it to true.

Personally, I don't recommend using the multiple player capability. It's been made clear that they look into more than one account logging into a given machine/client and this leaves a highly suspicious login trail that's pretty easy to spot. Just my opinion; do what you want.

while (players.getActive() > 0) do
begin
...
end;

The main loop of the script keeps repeating until all players in the players array are marked as inactive (isActive=false). Other parts of the script will have to do this for us or it will loop around forever.

if (not isLoggedIn()) then
begin
if (not players[currentPlayer].login()) then break;
mainscreen.setangle(MS_ANGLE_HIGH);
exitSquealOfFortune();
end;
doSomeStuff();

Next the program checks to see if the current player is logged in. If not, it logs it in, sets the screen angle to the overhead view, and closes that annoying squeal of fortune panel. Finally, it calls the worker function, doSomeStuff().

exitSquealOfFortune() is in antiban.simba, which seems to be missing from the documentation at the moment. This include file has a number of functions which are helpful in making your script seem more human. You should check it out!

Let's go to the top and take a look at the functions now.

procedure scriptTerminate();
begin
print('****** ' + scriptName + ': Script shutting down', TDebug.DEBUG);
takeScreenshot(scriptName + '.png');
if isLoggedIn() then
players[currentPlayer].logout();
end;

This is the function we registered with addOnTerminate() to be called at shutdown time.

It uses the print() (http://docs.villavu.com/srl-6/debug.html#print) procedure from debug.simba to write a message to the simba debug window (and the log file in SIMBADIR/includes/srl-6/logs).

It calls takeScreenshot() (http://docs.villavu.com/srl-6/debug.html?highlight=takescreenshot) to save an image to the SIMBADIR/includes/srl6-/logs folder. This might be helpful to see why the script was quitting.

The last thing this procedure does is log out the current player.

procedure doSomeStuff();
var
x,y : integer;
begin
for x := 10 to 50 with 10 do
for y := 10 to 50 with 10 do
begin
smartImage.drawBox(intToBox(x, y, x+100, y+100), true, clFuchsia);
smartImage.drawBox(intToBox(x, y, x+100, y+100), clLime);
wait(1000);
smartImage.clear();
end;
players[currentPlayer].isActive := false;
end

The doSomeStuff() procedure is just to make the script do something other than a quick login/logout. It uses the drawing functions referenced earlier to paint some boxes on the screen.

After that it marks the current player as inactive (which will end up making our main loop quit since there is only one player being used).

Phase 2: Putting some structure in place

Download script for phase 2: 22320

program makestuff2;
{$DEFINE SMART}
{$i srl-6/srl.simba}

const
scriptName = 'makestuff2';
playerNames = ['WillyWonka']; // change this to your username or nickname
playerFile = 'default'; // change this to your playerFile name
desiredWorld = 0; // set this to 0 for any world

type
Tstate = (MAKING, BANKING, UNKNOWN);
TstateRec = record
state : Tstate;
stateCheck : function:boolean;
stateExec : function:Tstate;
end;

var
i, stateIndex : integer;
expectedNextState : Tstate;
stateList : array[0..1] of TstateRec;
firstTime : boolean;
unexpectedCount : integer;

// these are temporary so we can simulate the work
FAKE_INV_CONTAINS_RAW_GOODS : boolean = false;
FAKE_COUNTER : integer;

function checkIfMaking() : boolean;
begin
if (FAKE_INV_CONTAINS_RAW_GOODS) then
result := true
else
result := false;
end;
function doMaking() : Tstate;
begin
print('****** ' + scriptName + ': Pretending to make things', TDebug.DEBUG);
wait(2000);
result := Tstate.BANKING;

FAKE_INV_CONTAINS_RAW_GOODS := false;
inc(FAKE_COUNTER)
if (FAKE_COUNTER > 10) then
begin
print('****** ' + scriptName + ': Simulating fatal issue', TDebug.DEBUG);
terminateScript();
end;
end;

function checkIfBanking() : boolean
begin
if (not FAKE_INV_CONTAINS_RAW_GOODS) then
result := true
else
result := false;
end;
function doBanking() : Tstate;
begin
print('****** ' + scriptName + ': Pretending to deposit and withdraw things', TDebug.DEBUG);
wait(2000);
result := Tstate.MAKING;

FAKE_INV_CONTAINS_RAW_GOODS := true;
end;

procedure scriptTerminate();
begin
print('****** ' + scriptName + ': Script shutting down', TDebug.DEBUG);
takeScreenshot(scriptName + '.png');
if isLoggedIn() then
players[currentPlayer].logout();
end;

begin
// initialize and prepare things
//
addOnTerminate('scriptTerminate');
ClearDebug();
smartEnableDrawing := true;
SetupSRL();
players.setup(playerNames, playerFile);
currentPlayer := 0;
for i := 0 to high(players) do
begin
players[i].world := desiredWorld;
players[i].isActive := true;
end;

with stateList[0] do
begin
state := Tstate.MAKING;
stateCheck := @checkIfMaking;
stateExec := @doMaking;
end;
with stateList[1] do
begin
state := Tstate.BANKING;
stateCheck := @checkIfBanking;
stateExec := @doBanking;
end;

// do the work
//
firstTime := true;
while (players.getActive() > 0) do
begin
if (not isLoggedIn()) then
begin
if (not players[currentPlayer].login()) then break;
mainscreen.setangle(MS_ANGLE_HIGH);
exitSquealOfFortune();
end;
for stateIndex := 0 to high(stateList) do
with stateList[stateIndex] do
if stateCheck() then
begin
if ((not firstTime) and (expectedNextState <> state)) then
begin
print('****** ' + scriptName + ': Unexpected state condition detected!', TDebug.DEBUG);
if (inc(unexpectedCount) > 5) then
begin
print('****** ' + scriptName + ': Too many unexpected state conditions. Aborting.', TDebug.DEBUG);
terminateScript();
end;
end;
expectedNextState := stateExec();
break; // stop looping through states, we found and executed the current one
end;
if (expectedNextState = Tstate.UNKNOWN) then
begin
// at this point we should probably try to boot ourselves into a known state.
print('****** ' + scriptName + ': We ended up in an unknown state', TDebug.DEBUG);
terminateScript();
end;
firstTime := false;
end;
end.
As stated in the beginning, the example script will make pastry dough. This version puts real structure in place instead of calling doSomeStuff() to draw boxes. It logs the player in, simulates the process of making the dough, then logs out.

There are no new SRL functions being called. Given this, I'm not going to go into detail on the code changes. If people have questions I can address them in the thread.

The script structure is based on using states to determine what condition the script is currently in and what should be performed next. I read a tutorial (http://villavu.com/forum/showthread.php?t=58300) that @Blumblebee posted a while back about this topic and it's a very sensible approach to bot design. A good implementation can make your script very tolerant of surprises, especially when first starting up.

Phase 3: A functional script

Download script for phase 3: 22375

program makestuff3;
{$DEFINE SMART}
{$i srl-6/srl.simba}

const
scriptName = 'makestuff3';
playerNames = ['WillyWonka']; // change this to your username or nickname
playerFile = 'default'; // change this to your playerFile name
desiredWorld = 0; // set this to 0 for any world

type
Tstate = (MAKING, BANKING, UNKNOWN);
TstateRec = record
state : Tstate;
stateCheck : function:boolean;
stateExec : function:Tstate;
end;

var
i, stateIndex : integer;
expectedNextState : Tstate;
stateList : array[0..1] of TstateRec;
potOfFlour, bowlOfWater, pastryDough : integer;
firstTime : boolean;
unexpectedCount : integer;

function openBank() : boolean;
var
x, y, t : integer;
begin
if (mainscreen.findObject(x, y, 9207917, 12, colorSetting(2, 0.16, 0.68),
mainscreen.getCenterPoint(), 50, 50, 50, ['ank'], MOUSE_LEFT)) then
begin
t := getSystemTime() + 10000;
repeat
wait(250);
until (bankscreen.isOpen() or (getSystemTime() >= t));
result := bankscreen.isOpen();
end
else
result := false;
end;

function withDrawItem(dtmId: integer; mouseText: TStringArray; numToWithdraw: integer) : boolean;
var
x, y : integer;
withdrawStr : string;
begin
withdrawStr := 'Withdraw-' + intToStr(numtoWithdraw);
result := findDTM(dtmId, x, y, bankscreen.getBankSlotBoxes().getBounds());
if result then
begin
mouse(Point(x,y).rand(5));
if isMouseOverText(mouseText) then
begin
fastclick(MOUSE_RIGHT);

if chooseOption.optionsExist([withdrawStr]) then
chooseOption.select([withdrawStr])
else if chooseOption.select(['Withdraw-X']) then
begin
wait(randomRange(600,1200));
typeSend(intToStr(numToWithdraw), true);
end
else
result := false;

// give the bank a sec to do it, it lags a little
// should really wait until DTM is on inventory side of bank
wait(randomRange(700,1400));
end
else
result := false;
end;
end;

function checkIfMaking() : boolean;
var
flourCount, waterCount : integer = 0;
begin
// if the bank is sitting open we will presume to be banking, not making.
// it would be more accurate to check the bank inventory for flour/water
if (not bankscreen.isOpen()) then
begin
if (not tabBackpack.isOpen()) then
tabBackpack.open();
flourCount := tabBackpack.countDTM(potOfFlour);
waterCount := tabBackpack.countDTM(bowlOfWater);
end;
result := ((flourCount > 0) and (waterCount > 0));
end;

function doMaking() : Tstate;
var
craftBox, blueButton : TBox;
x, y, t, flourCount, waterCount : integer;
flourSlots, waterSlots : TIntegerArray;
tpa : TPointArray;
begin
if (bankscreen.isOpen()) then // probably not needed but just in case
bankscreen.close();
if (not tabBackpack.isOpen()) then
tabBackpack.open();

flourSlots := findItem(potOfFlour, tabBackpack.getSlotBoxes(), true);
waterSlots := findItem(bowlOfWater, tabBackpack.getSlotBoxes(), true);
if ((length(flourSlots) = 0) or (length(waterSlots) = 0)) then
begin
result := Tstate.UNKNOWN;
exit;
end;

// have to add 1 to the slot index to get the slot number
tabBackpack.mouseSlot(flourSlots[0]+1, MOUSE_LEFT); // "use flour"
wait(randomRange(1000,1800));
tabBackpack.mouseSlot(waterSlots[0]+1, MOUSE_LEFT); // "with pot of water"

blueButton := intToBox( trunc(smartClientWidth/2),
trunc(smartClientHeight/2)+136,
trunc(smartClientWidth/2)+226,
trunc(smartClientHeight/2)+161);
t := getSystemTime() + 10000;
repeat
wait(250);
// detect the big blue button on the craft menu
findColorsTolerance(tpa, 8938247, blueButton, 10, colorSetting(2, 0.02, 0.20))
until ((high(tpa) > 100) or (getSystemTime() >= t));
if (high(tpa) < 100) then
begin
result := Tstate.UNKNOWN;
exit;
end;

craftBox := intToBox( trunc(smartClientWidth/2)-250,
trunc(smartClientHeight/2)-136,
trunc(smartClientWidth/2)-37,
trunc(smartClientHeight/2)+150);
findDTM(pastryDough, x, y, craftBox);
mouse(point(x,y).rand(8), MOUSE_LEFT); // choose the pastry dough
wait(randomRange(800,1500));
blueButton.mouse(MOUSE_LEFT); // and press the blue button to make it

t := getSystemTime() + 120000;
repeat
wait(400);
flourCount := tabBackpack.countDTM(potOfFlour);
waterCount := tabBackpack.countDTM(bowlOfWater);
until (((flourCount = 0) or (waterCount = 0)) or (getSystemTime() >= t));

if ((flourCount = 0) or (waterCount = 0)) then
begin
wait(randomRange(400,800));
result := Tstate.BANKING;
end
else
result := Tstate.UNKNOWN;
end;

function checkIfBanking() : boolean
begin
// if we're not making then we are banking.
result := (not checkIfMaking());
end;

function doBanking() : Tstate;
var
t : integer;
begin
if (not bankscreen.isOpen()) then
openBank();

wait(randomRange(500,800));
bankscreen.quickDeposit(QUICK_DEPOSIT_INVENTORY);
wait(randomRange(500,800));

if (not withDrawItem(potOfFlour, ['lour'], 9)) then
begin
print('****** ' + scriptName + ': Could not locate flour in bank', TDebug.DEBUG);
result := Tstate.UNKNOWN;
exit;
end;

if (not withDrawItem(bowlOfWater, ['ater'], 9)) then
begin
print('****** ' + scriptName + ': Could not locate water in bank', TDebug.DEBUG);
result := Tstate.UNKNOWN;
exit;
end;


// bumped into case where bank took longer to close than bankscreen.close() allowed for.
// wait an additional 20 seconds if needed.
bankscreen.close();
t := getSystemTime() + 20000;
while ((bankscreen.isOpen()) and (getSystemTime() <= t)) do
begin
wait(250);
typeByteWait(VK_ESCAPE,150);
end;

if bankscreen.isOpen() then
result := Tstate.UNKNOWN
else
begin
result := Tstate.MAKING;
wait(randomRange(1200,1800));
end;
end;

procedure scriptTerminate();
begin
print('****** ' + scriptName + ': Script shutting down', TDebug.DEBUG);
takeScreenshot(scriptName + '.png');
freeDTM(potOfFlour);
freeDTM(bowlOfWater);
freeDTM(pastryDough);
if isLoggedIn() then
players[currentPlayer].logout();
end;

begin
// initialize and prepare things
//
addOnTerminate('scriptTerminate');
ClearDebug();
smartEnableDrawing := true;
SetupSRL();
players.setup(playerNames, playerFile);
currentPlayer := 0;
for i := 0 to high(players) do
begin
players[i].world := desiredWorld;
players[i].isActive := true;
end;

with stateList[0] do
begin
state := Tstate.MAKING;
stateCheck := @checkIfMaking;
stateExec := @doMaking;
end;
with stateList[1] do
begin
state := Tstate.BANKING;
stateCheck := @checkIfBanking;
stateExec := @doBanking;
end;
// potOfFlour := DTMFromString('mggAAAHicY2NgYNjBxMCwDYj3APFhIN4JxG uAuIyRgSEXikHsBihdEmjEsGvTJoap/X0MTnqyDDne+gw9SbYMIkCzsGFGHBgCAAkGDwo=');
potOfFlour := DTMFromString('mggAAAHicY2NgYOBhgABeIBYHYgEg5gJiTi gWhtIwUBJoxNCTZMuQ463P4KQnyzC1v49h16ZNDBpAOWyYEQeG AABCKwja');
// bowlOfWater := DTMFromString('mrAAAAHic42BgYFBiZmAQAmININYDYi0gVg NiWSAWB+LfjAwMv4D4CxD/AGJGJgYGVigGsQ3mz2boTRNm6E8XZuhKFmZIdudliHDgYSgOFm CYmCnCIAK0Ax9mJIBhAACbAw2I');
bowlOfWater := DTMFromString('mrAAAAHic42BgYBAAYlYg5gZiESCWAGIZIB ZjgAB2IOYFYkEoBrFZoHJsQGwwfzbDxEwRhuJgAYYIBx6GZHde hq5kYYb+dGGG3jRhBjmgGnyYkQCGAQBkmQmE');
pastryDough := DTMFromString('mwQAAAHic42RgYFjAxMAwG4rnAfFCIF4KxM uh9HwgVgBiWSBWBmIVIFaDYhBfHirX21vFMGNGM8PKlZMYZs9u A5rMCMdhoV4MLS1FDCJAHiHMSASGAwCF9hEY');

// do the work
//
firstTime := true;
while (players.getActive() > 0) do
begin
if (not isLoggedIn()) then
begin
if (not players[currentPlayer].login()) then break;
mainscreen.setangle(MS_ANGLE_HIGH);
exitSquealOfFortune();
end;
for stateIndex := 0 to high(stateList) do
with stateList[stateIndex] do
if stateCheck() then
begin
if ((not firstTime) and (expectedNextState <> state)) then
begin
print('****** ' + scriptName + ': Unexpected state condition detected!', TDebug.DEBUG);
if (inc(unexpectedCount) > 5) then
begin
print('****** ' + scriptName + ': Too many unexpected state conditions. Aborting.', TDebug.DEBUG);
terminateScript();
end;
end;
expectedNextState := stateExec();
break; // stop looping through states, we found and executed the current one
end;
if (expectedNextState = Tstate.UNKNOWN) then
begin
// at this point we should probably try to boot ourselves into a known state.
print('****** ' + scriptName + ': We ended up in an unknown state', TDebug.DEBUG);
terminateScript();
end;
firstTime := false;
end;
end.
Phase 2 presented a working skeleton. In phase 3 the state functions (checkIfMaking, doMaking, checkIfBanking, and doBanking) are implemented so the program actually makes dough.

To run the script, make sure you have Pots of Flour and Bowls of Water visible in your bank when you open it. Stand in front of a one-click bank chest and run the script. I tested it in Burthorpe, Lumbridge, and north of the Dueling arena.

Other than the state functions, there is little change from the Phase 2 program. I created DTMs for the Pot of Flour, Bowl of Water, and Pastry Dough. These are loaded in the main program initialization with DTMFromString() (http://docs.villavu.com/simba/scriptref/dtm.html?highlight=dtmfromstring#dtmfromstring).

potOfFlour := DTMFromString('mggAAAHicY2NgYNjBxMCwDYj3APFhIN4JxG uAuIyRgSEXikHsBihdEmjEsGvTJoap/X0MTnqyDDne+gw9SbYMIkCzsGFGHBgCAAkGDwo=');
bowlOfWater := DTMFromString('mrAAAAHic42BgYFBiZmAQAmININYDYi0gVg NiWSAWB+LfjAwMv4D4CxD/AGJGJgYGVigGsQ3mz2boTRNm6E8XZuhKFmZIdudliHDgYSgOFm CYmCnCIAK0Ax9mJIBhAACbAw2I');
pastryDough := DTMFromString('mwQAAAHic42RgYFjAxMAwG4rnAfFCIF4KxM uh9HwgVgBiWSBWBmIVIFaDYhBfHirX21vFMGNGM8PKlZMYZs9u A5rMCMdhoV4MLS1FDCJAHiHMSASGAwCF9hEY');
The DTMs are freed up in our scriptTerminate() function so we are most likely to be polite and give the memory back.
freeDTM(potOfFlour);
freeDTM(bowlOfWater);
freeDTM(pastryDough);
The state functions use SRL calls to perform the work. I'm going to describe them at a high level, hopefully you're able to poke at the documentation and make sense of the details!
function checkIfMaking() : boolean;
var
flourCount, waterCount : integer = 0;
begin
// if the bank is sitting open we will presume to be banking, not making.
// it would be more accurate to check the bank inventory for flour/water
if (not bankscreen.isOpen()) then
begin
if (not tabBackpack.isOpen()) then
tabBackpack.open();
flourCount := tabBackpack.countDTM(potOfFlour);
waterCount := tabBackpack.countDTM(bowlOfWater);
end;
result := ((flourCount > 0) and (waterCount > 0));
end;
checkIfMaking() uses a couple of functions from the bankscreen (http://docs.villavu.com/srl-6/bankscreen.html) and tabBackpack (http://docs.villavu.com/srl-6/backpack.html#) global variables.

It makes sure the bank is not open, checks if the backpack tab is open, and opens it if needed (bankscreen.isOpen(), tabBackpack.isOpen(), tabBackpack.open()).

The tabBackpack.countDTM() (http://docs.villavu.com/srl-6/backpack.html#trstabbackpack-countdtm) function is used to get a count of how many flours and waters are in the inventory.

If it finds at least one flour and one water, it returns true, indicating we are indeed in the MAKING state.
function checkIfBanking() : boolean
begin
// if we're not making then we are banking.
result := (not checkIfMaking());
end;
checkIfBanking() is overly simple. As the comment says, if we're not making, we are banking.

doMaking() has a lot more logic. If doMaking() gets called this means we have raw materials to make at least one pastry dough.
function doMaking() : Tstate;
var
craftBox, blueButton : TBox;
x, y, t, flourCount, waterCount : integer;
flourSlots, waterSlots : TIntegerArray;
tpa : TPointArray;
begin
if (bankscreen.isOpen()) then // probably not needed but just in case
bankscreen.close();
if (not tabBackpack.isOpen()) then
tabBackpack.open();
First it makes sure the bank is closed and the backpack is open.

flourSlots := findItem(potOfFlour, tabBackpack.getSlotBoxes(), true);
waterSlots := findItem(bowlOfWater, tabBackpack.getSlotBoxes(), true);
if ((length(flourSlots) = 0) or (length(waterSlots) = 0)) then
begin
result := Tstate.UNKNOWN;
exit;
end;
Then it locates flour and water in the inventory using findItem() (http://docs.villavu.com/srl-6/items.html?highlight=finditem#finditem) from SIMBADIR/includes/srl-6/lib/misc/items.simba. These calls search through tabBackpack.getSlotBoxes() (an array of Tboxes defining each of the inventory slots).
// have to add 1 to the slot index to get the slot number
tabBackpack.mouseSlot(flourSlots[0]+1, MOUSE_LEFT); // "use flour"
wait(randomRange(1000,1800));
tabBackpack.mouseSlot(waterSlots[0]+1, MOUSE_LEFT); // "with pot of water"
Next it clicks on a flour and then a water using tabBackpack.mouseSlot() (http://docs.villavu.com/srl-6/backpack.html#trstabbackpack-mouseslot)
blueButton := intToBox( trunc(smartClientWidth/2),
trunc(smartClientHeight/2)+136,
trunc(smartClientWidth/2)+226,
trunc(smartClientHeight/2)+161);
t := getSystemTime() + 10000;
repeat
wait(250);
// detect the big blue button on the craft menu
findColorsTolerance(tpa, 8938247, blueButton, 10, colorSetting(2, 0.02, 0.20))
until ((high(tpa) > 100) or (getSystemTime() >= t));
if (high(tpa) < 100) then
begin
result := Tstate.UNKNOWN;
exit;
end;
That causes the cooking window pop up. The function waits until it detects the large blue button on that window. It uses getSystemTime() to implement a timeout and findColorsTolerance() (http://docs.villavu.com/srl-6/color.html#findcolorstolerance-overload) to check for the button. I believe getSystemTime is inherited from simba (docs not found).
craftBox := intToBox( trunc(smartClientWidth/2)-250,
trunc(smartClientHeight/2)-136,
trunc(smartClientWidth/2)-37,
trunc(smartClientHeight/2)+150);
findDTM(pastryDough, x, y, craftBox);
mouse(point(x,y).rand(8), MOUSE_LEFT); // choose the pastry dough
wait(randomRange(800,1500));
blueButton.mouse(MOUSE_LEFT); // and press the blue button to make it
Once the blue button has been detected, it calls findDTM() (http://docs.villavu.com/srl-6/wrappers.html?highlight=finddtm) with the pastry dough DTM to locate the selection for making pastry dough. It clicks that icon and clicks the blue Make button.
t := getSystemTime() + 120000;
repeat
wait(400);
flourCount := tabBackpack.countDTM(potOfFlour);
waterCount := tabBackpack.countDTM(bowlOfWater);
until (((flourCount = 0) or (waterCount = 0)) or (getSystemTime() >= t));

if ((flourCount = 0) or (waterCount = 0)) then
begin
wait(randomRange(400,800));
result := Tstate.BANKING;
end
else
result := Tstate.UNKNOWN;
end;
Finally, it sits in a loop counting the number of flours and waters in the inventory until one of them reaches 0. If we ran out of raw materials, we're done making!

Let's move onto doBanking() and see some of the SRL calls involved there.
function doBanking() : Tstate;
var
t : integer;
begin
if (not bankscreen.isOpen()) then
openBank();

wait(randomRange(500,800));
bankscreen.quickDeposit(QUICK_DEPOSIT_INVENTORY);
wait(randomRange(500,800));
It makes sure the bank is open using an internal openBank() function we didn't look at yet. Then it uses bankscreen.quickDeposit() (http://docs.villavu.com/srl-6/bankscreen.html#trsbankscreen-quickdeposit) to dump the inventory into the bank.
if (not withDrawItem(potOfFlour, ['lour'], 9)) then
begin
print('****** ' + scriptName + ': Could not locate flour in bank', TDebug.DEBUG);
result := Tstate.UNKNOWN;
exit;
end;

if (not withDrawItem(bowlOfWater, ['ater'], 9)) then
begin
print('****** ' + scriptName + ': Could not locate water in bank', TDebug.DEBUG);
result := Tstate.UNKNOWN;
exit;
end;
Then it withdraws 9 each of flour and water using another internal function withDrawItem() that we'll look at later.
// bumped into case where bank took longer to close than bankscreen.close() allowed for.
// wait an additional 10 seconds if needed.
t := getSystemTime() + 20000;
repeat
wait(250);
bankscreen.close();
until ((not bankscreen.isOpen()) or (getSystemTime() >= t));

if bankscreen.isOpen() then
result := Tstate.UNKNOWN
else
result := Tstate.MAKING;
end;
Finally, it closes the bank. The player should now have raw meterials in their inventory.

The openBank() function we saw is pretty simple:
function openBank() : boolean;
var
x, y, t : integer;
begin
if (mainscreen.findObject(x, y, 9207917, 12, colorSetting(2, 0.16, 0.68),
mainscreen.getCenterPoint(), 50, 50, 50, ['ank'], MOUSE_LEFT)) then
begin
t := getSystemTime() + 10000;
repeat
wait(250);
until (bankscreen.isOpen() or (getSystemTime() >= t));
result := bankscreen.isOpen();
end
else
result := false;
end;
I used ACA to find a good color for the bank chest straps. This uses mainscreen.findObject() (http://docs.villavu.com/srl-6/mainscreen.html#trsmainscreen-findobject) to locate and click on it. That should open the bank.

It waits in a timeout loop for the bank to fully open.
function withDrawItem(dtmId: integer; mouseText: TStringArray; numToWithdraw: integer) : boolean;
var
x, y : integer;
withdrawStr : string;
begin
withdrawStr := 'Withdraw-' + intToStr(numtoWithdraw);
result := findDTM(dtmId, x, y, bankscreen.getBankSlotBoxes().getBounds());
if result then
begin
mouse(Point(x,y).rand(5));
if isMouseOverText(mouseText) then
begin
fastclick(MOUSE_RIGHT);
First withdrawItem() finds the item using the DTM passed in and right clicks it.

It uses findDTM() (http://docs.villavu.com/srl-6/wrappers.html?highlight=finddtm#finddtm-overload), mouse() (http://docs.villavu.com/srl-6/mouse.html#id1), isMouseOverText() (http://docs.villavu.com/srl-6/text.html?highlight=chooseoption#ismouseovertext) and fastclick() (http://docs.villavu.com/srl-6/mouse.html#fastclick) to do this.
if chooseOption.optionsExist([withdrawStr]) then
chooseOption.select([withdrawStr])
else if chooseOption.select(['Withdraw-X']) then
begin
wait(randomRange(600,1200));
typeSend(intToStr(numToWithdraw), true);
end
else
result := false;

// give the bank a sec to do it, it lags a little
// should really wait until DTM is on inventory side of bank
wait(randomRange(700,1400));
end
else
result := false;
end;
end;
Then it tries to choose Withdraw-9. If it can't find that in the list, it chooses Withdraw-X and types in the 9 (so we ought to find it the next time around).

chooseOption (http://docs.villavu.com/srl-6/text.html?highlight=chooseoption#trschooseoption-close) is a global variable set in SIMBADIR/includes/srl-6/lib/core/text.simba

Wrap up
That covers the whole sample script. With any luck you gained some insight into using the SRL library to write your scripts.

You may notice how easy it would be to turn the example script into many more useful scripts. The same base could be used to cut up pineapples, clean herbs, and even fletch bows. It wouldn't take too much modification to perform any task where you sit at the bank and withdraw/make.

The future I see for it is to make it data driven so one code base could perform all these tasks.

This paper has grown larger than I expected. I hope it didn't bore you too much!

bonsai
10-19-2013, 11:35 AM
Globals
This is a list of all the globals from the SRL6 include files.

debug.simba
var
logPath = includePath + 'SRL-6/logs/';
disableSRLLog = false;
disableSRLDebug = false;
addTimeStamp = false;

globals.simba
const
VK_ENTER = {$IFDEF LINUX}10{$ELSE}VK_RETURN{$ENDIF};
var
mbOk = 0;
mbOkCancel = 1;
mbAbortRetryIgnore = 2;
mbYesNoCancel = 3;
mbYesNo = 4;
mbCancelRetry = 5;
mrYes = 6;
mrNo = 7;
var
clWhite = 16777215;
clBlack = 0;
clRed = 255;
clGreen = 32768;
clBlue = 16711680;
clPurple = 8388736;
clYellow = 65535;
clAqua = 16776960;
clOrange = 26367;
clFuchsia = 16711935;
clTeal = 8421376;
clNavy = 8388608;
clGray = 8421504;
clLime = 65280;
clMaroon = 128;
clSilver = 12632256;
clPink = 11772650;
const
EVENT_COUNT = 5;
EVENT_RS_UPDATE = 0;
EVENT_LOGOUT = 1;
EVENT_LOGIN = 2;
EVENT_PLAYER_NEXT = 3;
EVENT_ANTIBAN = 4;
var
SRL_Events: array[0..(EVENT_COUNT - 1)] of procedure;

mouse.simba
var
mouseSpeed: Integer = 20;
const
MOUSE_BREAK = 8;
MOUSE_ACCURATE = 14;
MOUSE_HUMAN = 7;
const
MOUSE_NONE = -1;
MOUSE_MOVE = 3;
Also available from Simba are MOUSE_LEFT, MOUSE_MIDDLE, and MOUSE_RIGHT.

players.simba
const
SKILL_COUNT = 26;
SKILL_ATTACK = 0;
SKILL_HITPOINTS = 1;
SKILL_MINING = 2;
SKILL_STRENGTH = 3;
SKILL_AGILITY = 4;
SKILL_SMITHING = 5;
SKILL_DEFENCE = 6;
SKILL_HERBLORE = 7;
SKILL_FISHING = 8;
SKILL_RANGE = 9;
SKILL_THIEVING = 10;
SKILL_COOKING = 11;
SKILL_PRAYER = 12;
SKILL_CRAFTING = 13;
SKILL_FIREMAKING = 14;
SKILL_MAGIC = 15;
SKILL_FLETCHING = 16;
SKILL_WOODCUTTING = 17;
SKILL_RUNECRAFTING = 18;
SKILL_SLAYER = 19;
SKILL_FARMING = 20;
SKILL_CONSTRUCTION = 21;
SKILL_HUNTER = 22;
SKILL_SUMMONING = 23;
SKILL_DUNGEONEERING = 24;
SKILL_DIVINATION = 25;
type
TPlayer = record
loginName: string;
displayName: string;
nickname: string;
password: string;
bankPin: string;
location: string;
isActive: boolean;
isMember: boolean;
findMod: boolean;
findTrade: boolean;
reincarnate: boolean;
secureLogin: boolean;
worked: TTimeMarker; // automatically calculated if SRL's login methods are used
world: integer;
skillLevel: array[0..(SKILL_COUNT - 1)] of integer;
booleans: array[0..99] of boolean;
integers: array[0..99] of integer;
strings: array[0..99] of string;
extendeds: array[0..99] of extended;
variants: array[0..99] of variant;
end;
TPlayerArray = array of TPlayer;
var
players: TPlayerArray;
currentPlayer: integer;
disableIPScreenshots: boolean;

backpack.simba
const
BACKPACK_SLOT_LOW = 1;
BACKPACK_SLOT_HIGH = 28;
const
DROP_PATTERN_REGULAR: TIntegerArray = [1..28];
DROP_PATTERN_BACKWARDS: TIntegerArray = [28..1];
DROP_PATTERN_SNAKE: TIntegerArray = [1, 2, 3, 4, 5, 10, 9, 8, 7, 6, 11, 12, 13, 14, 15, 20, 19, 18, 17, 16, 21, 22, 23, 24, 25, 28, 27, 26];
DROP_PATTERN_UP_DOWN: TIntegerArray = [1, 6, 11, 16, 21, 26, 2, 7, 12, 17, 22, 27, 3, 8, 13, 18, 23, 28, 4, 9, 14, 19, 24, 5, 10, 15, 20, 25];
const
QUICK_INVENTORY_A = 50; {red}
QUICK_INVENTORY_B = 100; {blue}
type
TRSTabBackpack = record(TRSInterface)
tabIndex: integer;
slots: TBoxArray;
__slots: array [0..1] of TBoxArray;
areSlotsLoaded: boolean;
end;
var
tabBackpack: TRSTabBackpack;

gametab.simba
const
TAB_HERO = 40;
TAB_TASK = 32;
TAB_STATS = 24;
TAB_GEAR = 41;
TAB_EQUIPMENT = 33;
TAB_BACKPACK = 25;
TAB_ADVENTURES = 42;
TAB_COMPASS_TASK = 34;
TAB_POWERS = 43;
TAB_DEFENSIVE = 35;
TAB_RANGED = 27;
TAB_MELEE = 19;
TAB_MAGIC = 11;
TAB_PRAYER = 3;
TAB_SOCIAL = 44;
TAB_CLAN_CHAT = 36;
TAB_FRIENDS_CHAT = 28;
TAB_FRIENDS = 20;
TAB_EXTRAS = 45;
TAB_HELP = 46;
TAB_OTHER = 47;
TAB_MUSIC = 39;
TAB_NOTES = 31;

var
gameTabs: TRSGameTabs;

stats.simba
const
SKILL_STATIC = 1;
SKILL_DYNAMIC = 0;
type
TRSTabStats = record(TRSInterface)
tabIndex: integer;
end;
var
tabStats: TRSTabStats;

lobby.simba
var
lobby: TRSLobby;
const
LOBBY_COUNT = 6;
LOBBY_PLAYER = 0;
LOBBY_WORLDS = 1;
LOBBY_FRIENDS = 2;
LOBBY_CHAT = 3;
LOBBY_CLAN = 4;
LOBBY_OPTIONS = 5;
worlds.simba
const
WORLD_ORDER_WORLDS = 0;
WORLD_ORDER_PLAYERS = 1;
WORLD_ORDER_ACTIVITY = 2;
WORLD_ORDER_LOCATION = WORLD_ORDER_ACTIVITY;
WORLD_ORDER_TYPE = 3;
WORLD_ORDER_PING = 4;
var
lobbyWorlds: TRSLobbyWorlds;

actionbar.simba
var
actionBar: TRSActionBar;
const
ACTION_BAR_SLOT_LOW = 1;
ACTION_BAR_SLOT_HIGH = 14;

bankscreen.simba

const
QUICK_DEPOSIT_INVENTORY = 0;
QUICK_DEPOSIT_EQIUPMENT = 1;
QUICK_DEPOSIT_BOB = 2;
QUICK_DEPOSIT_MONEY_POUCH = 3;
var
bankScreen: TRSBankScreen;

chatbox.simba
var
chatbox: TRSChatbox;

conversationbox.simba
var
conversationBox: TRSConversationBox;

interfaces.simba
const
// gametabs
ID_INTERFACE_GAMETABS = 0;
ID_INTERFACE_TAB_BACKPACK = 1;
ID_INTERFACE_TAB_MELEE = 2;
ID_INTERFACE_TAB_MAGIC = 3;
ID_INTERFACE_TAB_RANGED = 4;
ID_INTERFACE_TAB_DEFENSIVE = 5;
ID_INTERFACE_TAB_STATS = 6;
ID_INTERFACE_TAB_EQUIPMENT = 7;
ID_INTERFACE_TAB_PRAYER = 8;
ID_INTERFACE_TAB_ABILITY_BOOK = 9;
ID_INTERFACE_TAB_FRIENDS = 10;
ID_INTERFACE_TAB_FRIENDS_CHAT = 11;
ID_INTERFACE_TAB_CLAN_CHAT = 12;
ID_INTERFACE_TAB_OPTIONS = 13;
ID_INTERFACE_TAB_EMOTES = 14;
ID_INTERFACE_TAB_MUSIC = 15;
ID_INTERFACE_TAB_NOTES = 16;
// client - logged in
ID_INTERFACE_ACTION_BAR = 30;
ID_INTERFACE_CHAT_BOX = 31;
ID_INTERFACE_MINIMAP = 32;
ID_INTERFACE_MAINSCREEN = 33;
ID_INTERFACE_BANKSCREEN = 34;
ID_INTERFACE_OPTIONS = 35;
ID_INTERFACE_CONVERSATION_BOX = 36;
ID_INTERFACE_PINSCREEN = 37;
// client - logged out
ID_INTERFACE_LOBBY = 40;
ID_INTERFACE_LOBBY_WORLDS = 41;

mainscreen.simba
const
MS_ANGLE_HIGH = 0;
MS_ANGLE_LOW = 1;
MS_ANGLE_NONE = 2;
var
mainscreen: TRSMainscreen;

minimap.simba
const
MM_DIRECTION_NORTH = 0;
MM_DIRECTION_EAST = 90;
MM_DIRECTION_SOUTH = 180;
MM_DIRECTION_WEST = 270;
const
MM_DOT_NPC = 4369;
MM_DOT_ITEM = 23;
MM_DOT_PLAYER = 1907997;
MM_DOT_FRIEND = 5376;
MM_DOT_TEAM = 2171941;
const
MM_PIXEL_COUNT = 35785;
const
LOCATION_LUNAR_ISLE = 0;
LOCATION_EAGLES_PEAK = 1;
LOCATION_TIRANNWN = 2;
LOCATION_FREMENNIK = 3;
LOCATION_SEERS_VILLAGE = 4;
LOCATION_ARDOUGNE = 5;
LOCATION_YANILLE = 6;
LOCATION_OOGLOG = 7;
LOCATION_BURTHORPE = 8;
LOCATION_CATHERBY = 9;
LOCATION_TRAVERLEY = 10;
LOCATION_KARAMJA = 11;
LOCATION_WILDERNESS = 12;
LOCATION_EDGEVILLE = 13;
LOCATION_FALADOR = 14;
LOCATION_PORT_SARIM = 15;
LOCATION_VARROCK = 16;
LOCATION_DRAYNOR_VILLAGE = 17;
LOCATION_LUMBRIDGE = 18;
LOCATION_BANDIT_CAMP = 19;
LOCATION_AL_KHARID = 20;
LOCATION_CANIFIS = 21;
LOCATION_PREVIOUS = 1337;
const
MM_SYMBOL_SHOP_ARCHERY = 0;
MM_SYMBOL_SHOP_AXE = 1;
MM_SYMBOL_SHOP_CANDLE = 2;
MM_SYMBOL_SHOP_CLOTHES = 3;
MM_SYMBOL_SHOP_COOKERY = 4;
MM_SYMBOL_SHOP_CRAFTING = 5;
MM_SYMBOL_SHOP_FARMING = 6;
MM_SYMBOL_SHOP_FISHING = 7;
MM_SYMBOL_SHOP_FOOD = 8;
MM_SYMBOL_SHOP_HUNTER = 9;
MM_SYMBOL_SHOP_KEBAB = 10;
MM_SYMBOL_SHOP_MACE = 11;
MM_SYMBOL_SHOP_MAGIC = 12;
MM_SYMBOL_SHOP_PET = 13;
MM_SYMBOL_SHOP_PLATEBODY = 14;
MM_SYMBOL_SHOP_PLATESKIRT = 15;
MM_SYMBOL_SHOP_SCIMITAR = 16;
MM_SYMBOL_SHOP_SHIELD = 17;
MM_SYMBOL_SHOP_MINING = 18;
MM_SYMBOL_SHOP_SWORD = 19;
MM_SYMBOL_SHOP_STAFF = 20;
MM_SYMBOL_SHOP_SUMMONING = 21;

MM_SYMBOL_STALL_SPICE = 30;
MM_SYMBOL_STALL_GEM = 31;
MM_SYMBOL_STALL_SILK = 32;
MM_SYMBOL_STALL_SILVER = 33;

MM_SYMBOL_TREE = 40;
MM_SYMBOL_FARMING = 41;
MM_SYMBOL_FISHING = 42;
MM_SYMBOL_RUNECRAFTING = 43;
MM_SYMBOL_HUNTING = 44;
MM_SYMBOL_HOUSE = 45;
MM_SYMBOL_POTTERY = 46;
MM_SYMBOL_MINING = 47;
MM_SYMBOL_JEWELERY = 48;
MM_SYMBOL_SLAYER_CONTRACT = 49;
MM_SYMBOL_SLAYER_MASTER = 50;
MM_SYMBOL_HERBALIST = 51;
MM_SYMBOL_WHEEL = 52;
MM_SYMBOL_OBELISK = 53;
MM_SYMBOL_TANNER = 54;
MM_SYMBOL_TRAINING_DUMMY = 55;
MM_SYMBOL_STORE = 56;
MM_SYMBOL_SHORTCUT = 57;
MM_SYMBOL_WEAVE = 58;
MM_SYMBOL_COOK = 59;
MM_SYMBOL_AGILITY = 60;
MM_SYMBOL_FURNACE = 61;
MM_SYMBOL_ALTAR = 62;
MM_SYMBOL_ANVIL = 63;

MM_SYMBOL_APOTHECARY = 70;
MM_SYMBOL_ARROW = 71;
MM_SYMBOL_BAR = 72;
MM_SYMBOL_BANK = 73;
MM_SYMBOL_LODESTONE = 74;
MM_SYMBOL_CHURN = 75;
MM_SYMBOL_DUNGEON = 76;
MM_SYMBOL_TRADER_FUR = 77;
MM_SYMBOL_SPOT_REST = 78;
MM_SYMBOL_GUIDE = 79;
MM_SYMBOL_HAIR_DRESSER = 80;
MM_SYMBOL_MAKEOVER_MAGE = 81;
MM_SYMBOL_MILL = 82;
MM_SYMBOL_MINIGAME = 83;
MM_SYMBOL_OBELISK_MINI = 84;
MM_SYMBOL_PORTAL = 85;
MM_SYMBOL_QUEST = 86;
MM_SYMBOL_WINDMILL = 87;
MM_SYMBOL_SAND = 88;
MM_SYMBOL_SAWMILL = 89;
MM_SYMBOL_TRANSPORTATION = 90;
MM_SYMBOL_UNDERGROUND = 91;
MM_SYMBOL_WATER = 92;
const
MM_BUTTON_COMPASS = 0;
MM_BUTTON_RUN = 1;
MM_BUTTON_LODESTONE = 2;
MM_BUTTON_MAP = 3;
var
minimap: TRSMinimap;

options.simba
var
options: TRSOptions;

pinscreen.simba
var
pinScreen: TRSPinScreen;

items.simba
const
ITEM_OUTLINE_BLACK = 131072;
ITEM_OUTLINE_WHITE = 16777215;
ITEM_TEXT_YELLOW = 65535;
ITEM_TEXT_WHITE = ITEM_OUTLINE_WHITE;
ITEM_TEXT_GREEN = 8453888;

smart.simba
const
SMART_URL = 'http://www.runescape.com/game.ws?j=1';
var
smartPlugins: TStringArray = ['OpenGL32.dll'];
var
smartClientWidth: UInt32 := 960;
smartClientHeight: UInt32 := 640;
smartGetJavaPath: boolean := true;
smartShowConsole: boolean := true;
smartForceNewClient: boolean := false;
smartEnableDrawing: boolean := false;
smartInitSeq: string := '';
smartImage: TMufasaBitmap;


srlstats.simba
var
statsUsername, statsPassword, statsScriptID: string;

color.simba
type
TColorSettings = record
CTS: Integer;
modifier: record
hue, saturation, sensitivity: Extended;
end;
end;

math.simba
var
maxInt = high(integer);


time.simba
const
TIME_FORMAL = 0;
TIME_SHORT = 1;
TIME_ABBREV = 2;
TIME_BARE = 3;
TIME_FSTOP = 4;

DATE_FORMAL = 1;
DATE_MONTH = 2;
DATE_DAY = 3;

Justin
10-19-2013, 11:48 AM
Wow, Nice work bonsai;! Keep it up

l6bustank
10-21-2013, 10:05 AM
Kudos, mate! been looking all over for a tut like this :) . Time to start scripting in rs3 again!

bonsai
11-01-2013, 10:15 PM
Added a download for phase 3 that works with mouseovertextcount so it can function while we're having issues reading the mouseover text.

bonsai
11-07-2013, 09:18 AM
removed temporary download for phase 3, posted new phase 3 program with correct backpack slots call, updated post to match change.

digitalninja
11-12-2013, 08:51 PM
Great job Bonsai! I have been hoping some scripts would be released for non-members but its been really quiet as a whole on the script front. I am self-taught and find it MUCH easier to learn from scripts that people have made rather than learning programming from scratch! Great tutorial!

The Mayor
12-08-2013, 08:00 PM
bonsai put your code in SIMBA tags, its hard to read :)

[SIMBA] [./SIMBA]

bonsai
12-08-2013, 08:46 PM
bonsai put your code in SIMBA tags, its hard to read :)

[SIMBA] [./SIMBA]

Personally I find the colorized code to be much harder to read. But since this is the second person complaining to me about it, I changed it.

Kaladin
01-22-2014, 02:30 AM
Thank you. :)

Nufineek
09-12-2014, 01:17 AM
Huge probs Bonsai! It's exactly what I needed. Will have a look into it as soon as I have some free time. I just wonder why do you link to Pascal tutorials when there's a nice Lape tut? (http://blog.wizzup.org/blog/lape)

Not critizing at all, just wondering if it isn't exactly what beginners (like me) need to go through before they start using SRL includes?

bonsai
09-12-2014, 01:51 AM
Huge probe Bonsai! It's exactly what I needed. Will have a look into it as soon as I have some free time. I just wonder why do you link to Pascal tutorials when there's a nice Lape tut? (http://blog.wizzup.org/blog/lape)

Not critizing at all, just wondering if it isn't exactly what beginners (like me) need to go through before they start using SRL includes?

Great point, I should edit that in. It didn't exist when I wrote this. This reminded me it's getting close to 1yr since I found this place :)

I'm not sure how well the code here runs any more. I can't even tell you how many of those pastry doughs I made.

intradaydude
09-13-2014, 01:30 PM
will be reading this tonight thanks man

bonsai
09-13-2014, 01:41 PM
will be reading this tonight thanks man

If you didn't go through the mayor's tutorials yet, do those first.

This tut is ok but his two are way better for learners.

intradaydude
09-13-2014, 04:09 PM
If you didn't go through the mayor's tutorials yet, do those first.

This tut is ok but his two are way better for learners.

will do thx!