Results 1 to 12 of 12

Thread: Using records to create and find mainscreen objects

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

    Default Using records to create and find mainscreen objects

    Using records to create and find mainscreen objects


    In this tutorial I'm going to show you how to create and find mainscreen objects using records. This might look complicated at first, but it can shorten your scripts and make them much easier to maintain. Would you like to be able to write a script like this:

    Simba Code:
    if Copper.Find() then
      Copper.Drop()
    else
      Copper.WalkTo();




    PART 1: Records


    A record is an advanced data type which is used to group multiple variables (known as 'fields') together under the same umbrella. Each of these variables can be a different type, so a record can be very complex.

    For example, a type that you are no doubt familiar with is the TPoint. This is actually a record that contains 2 fields:

    Simba Code:
    type TPoint = record
      x, y: integer;
    end;

    Each TPoint has an x and a y coordinate. You can access each of the fields like so:

    Simba Code:
    procedure example();
    var
      p: TPoint;
    begin
      p.x := 10;   
      p.y := 20;
      writeLn(p); // Will print [10, 20]
    end;

    The fields that make up a record will appear in the codehints (see X and Y at the bottom), which is helpful:



    Because a TPoint is a type, you can create type methods. To try and explain this simply, the type becomes an object, on which the method is called (all of the procedures and functions in the above codehint are methods that act on a TPoint). Look at the following example because my explanation probably doesn't make sense:

    Simba Code:
    procedure TPoint.print();
    begin
      writeLn(Self.X); // Self refers to the TPoint which is passed to this procedure
      writeLn(Self.Y);
    end;

    procedure example();
    var
      p: TPoint;
    begin
      p := point(10, 20);
      p.print(); // Calling the above print method on p
    end;

    This picture might help you understand:



    That is basically what records and type methods looks like, and how to access fields in a record.




    PART 2: Creating a TMSObject record


    What I'm going to do now is create a new type that will represent a MainScreen Object (something I want to find on the MainScreen, such as a NPC, a Tree, or a Rock). Each object will have certain information associated with it, such as a colour and mouseOverText. Each piece of information will represent a new 'field' (a new variable) in the record.

    Simba Code:
    type TMSObject = record
      Name: String;
      Colour: TColorData; // TColorData isn't used that much, but I'll explain below
      OverText, ChooseOption: TStringArray;
    end;

    Above you can see I've created a new type which I called a 'TMSObject' ("Type MainScreen Object"). This type has 4 fields, a name, colour, overText and chooseOptions. Now I can create some variables of this new TMSObject type:

    Simba Code:
    var
      Copper, Tin, Banker: TMSObject;

    Now that I've created 3 TMSObjects, I need to assign some information to them. I could assign each field for each object one by one, like:

    Simba Code:
    procedure loadObjects();
    begin  
      Copper.Name := 'Copper Rock';
      Copper.OverText := ['opper'];
      Copper.Colour := [4808543, 7, [2, [0.14, 0.15, 0.00]]]; // TColorData structure, see note below  
      Tin.Name := 'Tin Rock';
      // Etc....
    end;


    Just a quick note: notice how I put all of the colour information (color, tol, hue, sat, cts) together? You might have guessed that the TColorData type is also a record, with fields for color, tolerance, CTS, etc. This is the TColorData type structure:

    [Color, Tolerance, [CTS, [Hue, Saturation, Sensitivity]]]

    This also means that I am using a 'record within a record', so to access the Copper object's tolerance I would write:

    Simba Code:
    writeLn(Copper.Colour.tolerance);

    This is the easy way to assign information, but imagine if I had a large number of objects, each with a large number of fields; that would take quite a few lines to write. Instead of doing it that way, I'll create a procedure which will take the field information as parameters, before assigning that information to the object:

    Simba Code:
    procedure TMSObject.Init(_Name: String; _Colour: TColorData; _OverText, _ChooseOption: TStringArray);
    begin
      Self.Name := _Name; // The procedure parameters start with '_' to differentiate them from the record fields
      Self.Colour := _Colour;
      Self.OverText := _OverText;
      Self.ChooseOption := _ChooseOption;
    end;

    Now in my loadObjects() procedure I can just pass all the information to the above .Init() method. Remember, I'm calling the .Init() method on the objects themselves:

    Simba Code:
    procedure loadObjects();
    begin  
      Copper.Init('Copper Rock', [4808543, 7, [2, [0.14, 0.15, 0.00]]], ['opper'], ['ine Cop']);
      Tin.Init('Tin Rock', [3808543, 7, [2, [0.13, 0.13, 0.00]]], ['in'], ['ine Tin']);
      Banker.Init('Banker NPC', [6508543, 3, [2, [0.11, 0.86, 0.00]]], ['ank'], ['pen Bank']);
    end;

    Now that I've entered all the information, all I have to do is run loadObjects() when my script starts, to initialise them. The last thing I need to do is write some code to actually find them.




    PART 3: Finding the TMSObject


    I'm going to use this method to find the colours:

    Simba Code:
    function findColorsTolerance(var points: TPointArray; color: integer; searchBox: TBox; tol: Integer; settings: TColorSettings): Boolean;

    If I wanted to search for the Copper, what I could do is this:
    Simba Code:
    procedure findCopper();
    var
      TPA: TPointArray;
    begin
      findColorsTolerance(TPA, Copper.Colour.color, mainScreen.getBounds(), Copper.Colour.tolerance,  Copper.Colour.settings);
      // ATPA + mouse code
    end;

    While that is somewhat effective and clean, I can take it a step further by creating a type method to find any TMSObject:

    Simba Code:
    function TMSObject.Find(): Boolean;
    var
      i: Integer;
      TPA: TPointArray;
      ATPA: T2DPointArray;
    begin
      writeLn('Searching for: ' + Self.Name); // Prints the TMSObject's name
     
      if Self.Colour.gatherIn(TPA, mainScreen.getBounds()) then // A TColourData method. Puts matching colours into 'TPA'
      begin
        ATPA := TPA.cluster(15);
        if (length(ATPA) < 1) then exit(false);

        for i := 0 to high(ATPA) do
        begin
          mouse(ATPA[i].getBounds().getRandomPoint());
          if isMouseOverText(Self.OverText) then // The TMSObject's OverText
          begin
            fastClick(MOUSE_RIGHT);
            result := chooseOption.select(Self.ChooseOption); // The TMSObject's ChooseOptions
            if result then break;
          end;
        end;

      end;

      writeLn(Self.Name + '.Find(): Result = ' + boolToStr(result));
    end;

    That is quite straight forward when you break it down. Now I can write code like:

    Simba Code:
    procedure example();
    begin
      if Copper.Find() then
        writeLn('We just clicked on a copper rock!');
       
      if Banker.Find() then
        if bankScreen.isOpen(5000) then
          writeLn('We found and opened the bank!');
    end;


    So that's all there is to it. You can add an endless number of fields to a record. I could have added things such as:

    1. Price
    2. ClickType
    3. DTM or Bitmap
    4. TPA cluster distance
    5. SPS map coordinates
    6. Etc.


    I hope you learnt something from this. Have fun with records!
    Last edited by The Mayor; 05-23-2015 at 04:54 PM.

  2. #2
    Join Date
    Feb 2012
    Location
    Canada
    Posts
    1,164
    Mentioned
    26 Post(s)
    Quoted
    433 Post(s)

  3. #3
    Join Date
    Jun 2012
    Posts
    4,867
    Mentioned
    74 Post(s)
    Quoted
    1663 Post(s)

    Default

    Makes sense for things you'd need to use in more than one way, nice tutorial

  4. #4
    Join Date
    May 2012
    Location
    Glorious Nippon
    Posts
    1,011
    Mentioned
    50 Post(s)
    Quoted
    505 Post(s)

    Default

    Nice! I remember seeing this when I dug through your gelatinous abomination script. This is perfect for a script I've been meaning to start.

  5. #5
    Join Date
    Aug 2014
    Location
    Australia
    Posts
    932
    Mentioned
    53 Post(s)
    Quoted
    495 Post(s)

    Default

    I've never used records because I never understood them properly, now I do. Thanks for another great tutorial, Maymay.

    On an unrelated note, how come there's no advanced object finding function in SRL-6? We have the basic mainScreen.findObject, so why not add a more accurate one that works in most situations?



    New to scripting? Procedures & Functions for Beginners
    Do you use your computer at night? Just get f.lux

  6. #6
    Join Date
    May 2012
    Posts
    499
    Mentioned
    23 Post(s)
    Quoted
    228 Post(s)

    Default

    Should perhaps include T2DColorData?
    I haven't seen it being used in many scripts, and combining 2 (or more) colors with low tolerances into a single TPA and then clustering them worked better then just clustering based on 1 color.
    It allowed me to cluster based on shorter distances.

    I sometimes even sort the clustered ATPA by size (color points), as that most often gives the closest TPA (more pixels/model onscreen).

    Perhaps add an example with WaitTypeFunc near the end? That is also something I love using but barely see being used.

    You could even talk a little about making includes with these records?
    Would be usefull for some if they use multiple scripts with similar functions.

  7. #7
    Join Date
    Feb 2013
    Posts
    342
    Mentioned
    8 Post(s)
    Quoted
    110 Post(s)

    Default

    Thank you, will help me tidy up my script.

    Edit: Took me a while to get my head around but I got there eventually.
    Last edited by GetHyper; 06-17-2015 at 12:40 PM.

  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)

    Default

    Quote Originally Posted by StickToTheScript View Post
    Great tutorial! Written very cleanly! Your tutorials are always great!
    Thanks

    Quote Originally Posted by BMWxi View Post
    Makes sense for things you'd need to use in more than one way, nice tutorial
    Thanks

    Quote Originally Posted by evilcitrus View Post
    Nice! I remember seeing this when I dug through your gelatinous abomination script. This is perfect for a script I've been meaning to start.
    Don't think anything like this was in GAO

    Quote Originally Posted by Incurable View Post
    I've never used records because I never understood them properly, now I do. Thanks for another great tutorial, Maymay.

    On an unrelated note, how come there's no advanced object finding function in SRL-6? We have the basic mainScreen.findObject, so why not add a more accurate one that works in most situations?
    mainScreen.findObject isn't really that basic and it will most probably work in most situations.

    Quote Originally Posted by Thomas View Post
    Should perhaps include T2DColorData?
    I haven't seen it being used in many scripts, and combining 2 (or more) colors with low tolerances into a single TPA and then clustering them worked better then just clustering based on 1 color.
    It allowed me to cluster based on shorter distances.

    I sometimes even sort the clustered ATPA by size (color points), as that most often gives the closest TPA (more pixels/model onscreen).

    Perhaps add an example with WaitTypeFunc near the end? That is also something I love using but barely see being used.

    You could even talk a little about making includes with these records?
    Would be usefull for some if they use multiple scripts with similar functions.
    Those things are beyond the scope of this tutorial

    Quote Originally Posted by GetHyper View Post
    Thank you, will help me tidy up my script.

    Edit: Took me a while to get my head around but I got there eventually.
    Good to hear!

  9. #9
    Join Date
    May 2012
    Location
    Glorious Nippon
    Posts
    1,011
    Mentioned
    50 Post(s)
    Quoted
    505 Post(s)

    Default

    Quote Originally Posted by The Mayor View Post
    Don't think anything like this was in GAO
    Ahh you're right, it was your Runespan script. GAO used mayorObjectFinder()

  10. #10
    Join Date
    Apr 2015
    Location
    FireFox
    Posts
    528
    Mentioned
    10 Post(s)
    Quoted
    227 Post(s)

    Default

    Cheers for the tutorial, I'll be implementing such features into my mining script to cut down on the if... else statements and to just tidy it up in general. Thanks again!
    Scripting with ogLib

  11. #11
    Join Date
    May 2015
    Posts
    23
    Mentioned
    0 Post(s)
    Quoted
    5 Post(s)

    Default

    Thanks for this tutorial, I will be using this soon in my next script(s)..

  12. #12
    Join Date
    Jan 2013
    Posts
    146
    Mentioned
    0 Post(s)
    Quoted
    56 Post(s)

    Default

    this is awesome.

    How different is this from classes in python?

    Im Back... Previously known as Megaleech
    [Herbalife]

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
  •