Results 1 to 15 of 15

Thread: SRL-6 Script Walkthrough

  1. #1
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default SRL-6 Script Walkthrough

    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:


    Suggested Prerequisites

    First off, you need to have Simba, SMART, and SRL6 installed and working! (Guide)

    Any scripter should be familiar with two tools and concepts.

    • The Auto Color Aid 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 forums.

    @YoHoJo; made some videos covering ACA and DTMs. I recommend these to anyone needing to learn more.

    Other links:

    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 documentation lists a function for that:
    Simba Code:
    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.

    Simba Code:
    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:
    Simba Code:
    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.

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

    begin
      clearDebug();
      setupSRL();
    end.

    SRL usage in this script:

    Simba Code:
    {$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.

    Simba Code:
    {$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".

    Simba Code:
    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().

    Simba Code:
    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: makestuff1.simba

    Simba Code:
    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.

    Simba Code:
    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().

    Simba Code:
    smartEnableDrawing := true;
    There are many functions available 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.

    Simba Code:
    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 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.

    Simba Code:
    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.

    Simba Code:
    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.

    Simba Code:
    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() 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() 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.

    Simba Code:
    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: makestuff2.simba

    Simba Code:
    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 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: makestuff3.simba

    Simba Code:
    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('mggAAAHicY2NgYNjBxMCwDYj3APFhIN4JxGuAuIyRgSEXikHsBihdEmjEsGvTJoap/X0MTnqyDDne+gw9SbYMIkCzsGFGHBgCAAkGDwo=');
       potOfFlour := DTMFromString('mggAAAHicY2NgYOBhgABeIBYHYgEg5gJiTigWhtIwUBJoxNCTZMuQ463P4KQnyzC1v49h16ZNDBpAOWyYEQeGAABCKwja');
    //   bowlOfWater := DTMFromString('mrAAAAHic42BgYFBiZmAQAmININYDYi0gVgNiWSAWB+LfjAwMv4D4CxD/AGJGJgYGVigGsQ3mz2boTRNm6E8XZuhKFmZIdudliHDgYSgOFmCYmCnCIAK0Ax9mJIBhAACbAw2I');
       bowlOfWater := DTMFromString('mrAAAAHic42BgYBAAYlYg5gZiESCWAGIZIBZjgAB2IOYFYkEoBrFZoHJsQGwwfzbDxEwRhuJgAYYIBx6GZHdehq5kYYb+dGGG3jRhBjmgGnyYkQCGAQBkmQmE');
       pastryDough := DTMFromString('mwQAAAHic42RgYFjAxMAwG4rnAfFCIF4KxMuh9HwgVgBiWSBWBmIVIFaDYhBfHirX21vFMGNGM8PKlZMYZs9uA5rMCMdhoV4MLS1FDCJAHiHMSASGAwCF9hEY');
       
       // 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().

    Simba Code:
    potOfFlour := DTMFromString('mggAAAHicY2NgYNjBxMCwDYj3APFhIN4JxGuAuIyRgSEXikHsBihdEmjEsGvTJoap/X0MTnqyDDne+gw9SbYMIkCzsGFGHBgCAAkGDwo=');
    bowlOfWater := DTMFromString('mrAAAAHic42BgYFBiZmAQAmININYDYi0gVgNiWSAWB+LfjAwMv4D4CxD/AGJGJgYGVigGsQ3mz2boTRNm6E8XZuhKFmZIdudliHDgYSgOFmCYmCnCIAK0Ax9mJIBhAACbAw2I');
    pastryDough := DTMFromString('mwQAAAHic42RgYFjAxMAwG4rnAfFCIF4KxMuh9HwgVgBiWSBWBmIVIFaDYhBfHirX21vFMGNGM8PKlZMYZs9uA5rMCMdhoV4MLS1FDCJAHiHMSASGAwCF9hEY');
    The DTMs are freed up in our scriptTerminate() function so we are most likely to be polite and give the memory back.
    Simba Code:
    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!
    Simba Code:
    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 and tabBackpack 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() 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.
    Simba Code:
    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.
    Simba Code:
    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.

    Simba Code:
    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() 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).
    Simba Code:
    // 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()
    Simba Code:
    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() to check for the button. I believe getSystemTime is inherited from simba (docs not found).
    Simba Code:
    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() with the pastry dough DTM to locate the selection for making pastry dough. It clicks that icon and clicks the blue Make button.
    Simba Code:
    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.
    Simba Code:
    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() to dump the inventory into the bank.
    Simba Code:
    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.
    Simba Code:
    // 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:
    Simba Code:
    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() to locate and click on it. That should open the bank.

    It waits in a timeout loop for the bank to fully open.
    Simba Code:
    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(), mouse(), isMouseOverText() and fastclick() to do this.
    Simba Code:
    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 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!
    Last edited by bonsai; 11-01-2013 at 10:14 PM.

  2. #2
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default SRL6 Globals

    Globals
    This is a list of all the globals from the SRL6 include files.

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

    globals.simba
    Simba Code:
    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
    Simba Code:
    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
    Simba Code:
    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
    Simba Code:
    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
    Simba Code:
    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
    Simba Code:
    const
      SKILL_STATIC = 1;
      SKILL_DYNAMIC = 0;
    type
      TRSTabStats = record(TRSInterface)
        tabIndex: integer;
      end;
    var
      tabStats: TRSTabStats;

    lobby.simba
    Simba Code:
    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
    Simba Code:
    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
    Simba Code:
    var
      actionBar: TRSActionBar;
    const
      ACTION_BAR_SLOT_LOW = 1;
      ACTION_BAR_SLOT_HIGH = 14;

    bankscreen.simba
    Simba Code:
    const
      QUICK_DEPOSIT_INVENTORY   = 0;
      QUICK_DEPOSIT_EQIUPMENT   = 1;
      QUICK_DEPOSIT_BOB         = 2;
      QUICK_DEPOSIT_MONEY_POUCH = 3;
    var
      bankScreen: TRSBankScreen;

    chatbox.simba
    Simba Code:
    var
      chatbox: TRSChatbox;

    conversationbox.simba
    Simba Code:
    var
      conversationBox: TRSConversationBox;

    interfaces.simba
    Simba Code:
    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
    Simba Code:
    const
      MS_ANGLE_HIGH  = 0;
      MS_ANGLE_LOW   = 1;
      MS_ANGLE_NONE  = 2;
    var
      mainscreen: TRSMainscreen;

    minimap.simba
    Simba Code:
    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
    Simba Code:
    var
      options: TRSOptions;

    pinscreen.simba
    Simba Code:
    var
      pinScreen: TRSPinScreen;

    items.simba
    Simba Code:
    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
    Simba Code:
    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
    Simba Code:
    var
      statsUsername, statsPassword, statsScriptID: string;

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

    math.simba
    Simba Code:
    var
      maxInt = high(integer);

    time.simba
    Simba Code:
    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;

  3. #3
    Join Date
    Mar 2007
    Posts
    5,125
    Mentioned
    275 Post(s)
    Quoted
    901 Post(s)

    Default

    Wow, Nice work @bonsai;! Keep it up

    Forum account issues? Please send me a PM

  4. #4
    Join Date
    Nov 2011
    Posts
    335
    Mentioned
    0 Post(s)
    Quoted
    68 Post(s)

    Default

    Kudos, mate! been looking all over for a tut like this . Time to start scripting in rs3 again!

  5. #5
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default

    Added a download for phase 3 that works with mouseovertextcount so it can function while we're having issues reading the mouseover text.

  6. #6
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default

    removed temporary download for phase 3, posted new phase 3 program with correct backpack slots call, updated post to match change.

  7. #7
    Join Date
    Apr 2012
    Location
    Vancouver, BC
    Posts
    291
    Mentioned
    1 Post(s)
    Quoted
    84 Post(s)

    Default

    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!

  8. #8
    Join Date
    Jun 2007
    Location
    The land of the long white cloud.
    Posts
    3,702
    Mentioned
    261 Post(s)
    Quoted
    2006 Post(s)

  9. #9
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default

    Quote Originally Posted by The Mayor View Post
    @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.

  10. #10
    Join Date
    Jul 2006
    Posts
    80
    Mentioned
    1 Post(s)
    Quoted
    27 Post(s)

    Default

    Thank you.

  11. #11
    Join Date
    Feb 2012
    Posts
    179
    Mentioned
    0 Post(s)
    Quoted
    84 Post(s)

    Default

    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?

    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?

  12. #12
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default

    Quote Originally Posted by Nufineek View Post
    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?

    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.

  13. #13
    Join Date
    Sep 2014
    Posts
    25
    Mentioned
    0 Post(s)
    Quoted
    15 Post(s)

    Default

    will be reading this tonight thanks man

  14. #14
    Join Date
    Oct 2013
    Location
    East Coast USA
    Posts
    770
    Mentioned
    61 Post(s)
    Quoted
    364 Post(s)

    Default

    Quote Originally Posted by intradaydude View Post
    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.

  15. #15
    Join Date
    Sep 2014
    Posts
    25
    Mentioned
    0 Post(s)
    Quoted
    15 Post(s)

    Default

    Quote Originally Posted by bonsai View Post
    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!

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •