Page 3 of 3 FirstFirst 123
Results 51 to 66 of 66

Thread: Development diary - Flipping script

  1. #51
    Join Date
    Oct 2011
    Location
    England
    Posts
    401
    Mentioned
    10 Post(s)
    Quoted
    176 Post(s)

    Default

    Quote Originally Posted by SlipperyPickle View Post
    Yeah, I'm building this for RS3. But I think the base of the app is probably the same. Buying, waiting, list of items, etc.
    No worries. I've got a git I have resources for it on; I'll PM you a link if you want (it's not much)
    Yer a wizard, 'oopi

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

    Default

    So many grandexchange functions seem to be broken
    Have you gotten some time to work on the include? Because I don't have much time to make changes currently...

  3. #53
    Join Date
    Sep 2014
    Location
    Netherlands
    Posts
    264
    Mentioned
    11 Post(s)
    Quoted
    130 Post(s)

    Default

    Quote Originally Posted by Thomas View Post
    So many grandexchange functions seem to be broken
    Have you gotten some time to work on the include? Because I don't have much time to make changes currently...
    I don't have that much time, but I'm still working on the ge library. Most things are fixed now, but I still have a few bugs (for example the confirm button). Will try to fix everything in the next few days. I'll pm you once I'm finished.

  4. #54
    Join Date
    Sep 2014
    Location
    Netherlands
    Posts
    264
    Mentioned
    11 Post(s)
    Quoted
    130 Post(s)

    Default

    @Thomas

    I believe most of the grand exchange library is fixed now. I've added a function that returns the confirmbox. Besides that, I've changed almost all the functions. If you want the complete list of changes pm me. Although I've tested for a few hours, you should test it too.

    Simba Code:
    (*
    Grand Exchange
    ==============

    The grandexchange file holds functions and procedures that are used to interact with the runescape Grand Exchange.

    The source for this file can be found `here <https://github.com/SRL/SRL-6/blob/master/lib/interfaces/grandexchange.simba>`_.

    *)


    {$f-}

    (*
    Consts, Types, Vars
    ~~~~~~~~~~~~~~~~~~~

    The following constants, types and variables are used throughout the collectBox methods.

    **const Grand Exchange Tabs**

      Constants that represent the two grandExchange tabs

        * GE_TAB_EXCHANGE
        * GE_TAB_HISTORY

    *)

    const
      GE_TAB_EXCHANGE = 0;
      GE_TAB_HISTORY = 1;
      GE_TAB_SETS = 2;

    (*

    **type TRSGrandExchange**

    .. code-block:: pascal

        type
          TRSGrandExchange = type TRSInterface;

    A type that stores the Grand Exchange interface properties.

    *)

    type
      TRSGrandExchange = record(TRSInterface)
        tabBoxes: TBoxArray;
        confirmBox: TBox;
    end;

    (*
    **var grandExchange**

    .. code-block:: pascal

        var
          grandExchange: TRSGrandExchange;

    A variable through which scripters can access the TRSGrandExchange type methods.

    *)

    var
      grandExchange: TRSGrandExchange;

    (*
    TRSGrandExchange methods
    ~~~~~~~~~~~~~~~~~~~~~~~~~

    The following methods should be called through the **grandExchange** variable.

    Example:

    .. code-block:: pascal

        if grandExchange.isOpen() then
          writeln('It''s open');
    *)


    {*
    __init
    ------

    .. code-block:: pascal

        procedure TRSGrandExchange.__init();

    Initializes the TRSGrandExchange.

    .. note::

        - by The Mayor
        - Last Updated: 9th October 2014 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.__init();

    *}

    {$IFNDEF CODEINSIGHT}
    procedure TRSGrandExchange.__init();
    begin
      with self do
      begin
        name := 'Grand Exchange';
        ID := ID_INTERFACE_GRANDEXCHANGE;
        parentID := -1;
        static := false;
      end;
    end;
    {$ENDIF}

    {*
    __find
    ------

    .. code-block:: pascal

        function TRSGrandExchange.__find(): boolean;

    Returns true if the grandExchange interface is detected and its bounds are set.
    Scripters should use grandExchange.isOpen() below.

    .. note::

        - by The Mayor
        - Last Updated: 6 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        if grandExchange.__find() then
          writeln('The grandExchange is open, and the bounds are set!');
    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__find(): boolean;
    const
      PINK_COLOR = [14581920, 0]; // [Col, Tol] pink item in the balance scale.
    var
      i: Integer;
      TPA: TPointArray;
      ATPA: T2DPointArray;
      b: TBox;
    begin
      findColorsTolerance(TPA, PINK_COLOR[0], getClientBounds(), PINK_COLOR[1]);

      if length(TPA) < 10 then
      begin
        print('TRSGrandExchange.__find(): Didn''t find enough PINK_COLOR', TDebug.WARNING);
        exit(false);
      end;

      ATPA := TPA.cluster(5);
      ATPA.sortBySize(true);

      for i := 0 to high(ATPA) do
      begin
        b := ATPA[i].getBounds();

        if inRange(b.getWidth(), 10, 20) and (b.getHeight() < 20) then
        begin
          b.edit(21, -10, 114, 12);

          if (pos('GRAND', upperCase(tesseract_GetText(b, TESS_FILTER_SMALL_CHARS))) > 0) then
          begin
            self.setBounds([b.x1 - 88, b.y1 - 8, b.x2 + 570, b.y2 + 515]);
            self.tabBoxes := grid(3, 1, 60, 22, 107, 0, point(x1 + 92, y1 + 113));
            self.confirmBox := [self.x1 + 218, self.y1 + 511, self.x1 + 340, self.y1 + 524];
            exit(true);
          end;
        end;

      end;
    end;
    {$ENDIF}

    (*
    isOpen
    ------

    .. code-block:: pascal

        function TRSGrandExchange.isOpen(waitTime: integer = 0): boolean;

    Returns true if the grandExchange is open. The optional **waitTime** parameter
    *(default = 0)* is the maximum time (in milliseconds) it will keep looking.

    .. note::

        - by The Mayor
        - Last Updated: 14 January 2015 by The Mayor

    Example:

    .. code-block:: pascal

        if grandExchange.isOpen() then
          writeln('The grandExchange is open!');

    *)

    function TRSGrandExchange.isOpen(waitTime: integer = 0): boolean;
    var
      t: UInt64;
    begin
      t := (getTickCount64() + waitTime);

      repeat
        if self.__find() then
        begin
          result := true;
          break();
        end;
      until (getSystemTime() >= t);
      print('TRSGrandExchange.isOpen(): Result = ' + boolToStr(result));
    end;

    (*
    close
    -----

    .. code-block:: pascal

        function TRSGrandExchange.close(escape: boolean = true): boolean;

    Returns true if the grandExchange is successfully closed. It uses the ESC key
    by default, but the **escape** parameter can be set to false to close via the mouse.

    .. note::

        - by The Mayor
        - Last Updated: 6 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        if grandExchange.close() then
          writeln('Closed the grandExchange');

    *)

    function TRSGrandExchange.close(escape: boolean = true): boolean;
    const
      __CLOSE_OFFSET: TPoint = [756, 22]; // From self(x1, y1) to middle of 'X'
    var
      timeOut: UInt64;
    begin
      if (not self.isOpen()) then
        exit(true);

      if escape then // Try the escape button first if possible
      begin
        timeOut := (getTickCount64() + randomRange(600, 900));
        repeat
          typeByte(VK_ESCAPE);
          wait(300 + random(50));
        until (not self.isOpen()) or (getTickCount64() > timeOut);

        if (not self.isOpen()) then
          exit(true);
      end;

      if self.isOpen(100 + random(50)) then // Wait a bit in case it closes
      begin
        mouse(point(self.x1 + __CLOSE_OFFSET.x, self.y1 + __CLOSE_OFFSET.y).rand(3), MOUSE_LEFT);
        timeOut := (getTickCount64() + randomRange(5000, 6000));

        while (timeOut > getTickCount64()) do
        begin
          if (not self.isOpen()) then
          begin
            result := true;
            break();
          end;
          wait(50 + random(50));
        end;
      end else
        result := true;

      print('TRSGrandExchange.close(): result = ' + boolToStr(result), TDebug.SUB);
    end;

    {*
    __getActiveTab
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__getActiveTab(): Integer;

    Returns the current tab number (0 - Grand Exchange | 1 - Sale History).

    .. note::

        - by The Mayor
        - Last Updated: 9 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__getActiveTab());

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getActiveTab(): Integer;
    var
      i: Integer;
    begin
      for i := 0 to high(self.tabBoxes) do
        if (not (getColor(self.tabBoxes[i].X2, self.tabBoxes[i].Y2) = 9078134)) then
          exit(i);
    end;
    {$ENDIF}

    (*
    openTab
    -------

    .. code-block:: pascal

        function TRSGrandExchange.openTab(tab: Integer): Boolean;

    Opens the grandExchange tab **tab** . The **tab** parameter should be one of the
    two tab constants at the top of this page.

    .. note::

        - by The Mayor
        - Last Updated: 9 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.openTab(GE_TAB_HISTORY);

    *)

    function TRSGrandExchange.openTab(tab: Integer): Boolean;
    begin
      if (not self.isOpen()) then
        exit(false);

      if (self.__getActiveTab() = tab) then
        exit(true);

      for 0 to 3 do
      begin
        multiClick(self.tabBoxes[tab].getGaussPoint(), 30, 3);
        wait(random(800, 1200));
        if (self.__getActiveTab() = tab) then exit(true);
      end;
    end;

    (*
    getPackSlotBox
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.getPackSlotBox(slot: integer): TBox;

    Returns a TBox of the pack slot **slot** in the grandExchange interface.

    .. note::

        - by The Mayor
        - Last Updated: 6 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        var
          b: TBox;
        begin
          b := grandExchange.getPackSlotBox(1);
          mouseBox(b, MOUSE_MOVE);
        end;

    *)

    function TRSGrandExchange.getPackSlotBox(slot: integer): TBox;
    const
      __PACK_OFFSET: TPoint = [582, 174]; // From self(x1, y1) to middle of first pack slot
    begin
      result := gridBox(slot - 1, 4, 7, 36, 32, 46, 36, point(self.x1 + __PACK_OFFSET.x, self.y1 + __PACK_OFFSET.y));
    end;

    {*
    __getSlotBoxes
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__getSlotBoxes(): TBoxArray;

    Returns a TBoxArray of the 8 Grand Exchange slots.

    .. note::

        - by The Mayor
        - Last Updated: 19 November 2015 by SlipperyPickle

    Example:

    .. code-block:: pascal

        tba := grandExchange.__getSlotBoxes();

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getSlotBoxes(): TBoxArray;
    const
      __GE_SLOT_OFFSET: TPoint = [104, 203]; // From self(x1, y1) to middle of first GE slot
    var
      tba: TBoxArray;
    begin
      tba := grid(3, 3, 169, 121, 177, 128, point(self.x1 + __GE_SLOT_OFFSET.x, self.y1 + __GE_SLOT_OFFSET.y));
      tba.deleteIndex(8);
      result := tba;
    end;
    {$ENDIF}

    {*
    __getBuyBoxes
    -------------

    .. code-block:: pascal

        function TRSGrandExchange.__getBuyBoxes(): TBoxArray;

    Returns a TBoxArray of the Grand Exchange buy boxes.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        tba := grandExchange.__getBuyBoxes();

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getBuyBoxes(): TBoxArray;
    const
      __BUY_OFFSET: TPoint = [74, 213]; // From self(x1, y1) to middle of first buy button
    var
      tba: TBoxArray;
    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.__getBuyBoxes(): Cannot click a buy box as the GE is not open', TDebug.ERROR);
        exit();
      end;
      tba := grid(3, 3, 44, 44, 177, 128, point(self.x1 + __BUY_OFFSET.x, self.y1 + __BUY_OFFSET.y));
      tba.deleteIndex(8);
      result := tba;
    end;
    {$ENDIF}

    {*
    __getSellBoxes
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__getSellBoxes(): TBoxArray;

    Returns a TBoxArray of the Grand Exchange sell boxes.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        tba := grandExchange.__getSellBoxes();

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getSellBoxes(): TBoxArray;
    const
      __SELL_OFFSET: TPoint = [134, 213]; // From self(x1, y1) to middle of first sell button
    var
      tba: TBoxArray;
    begin
      tba := grid(3, 3, 44, 44, 177, 128, point(self.x1 + __SELL_OFFSET.x, self.y1 + __SELL_OFFSET.y));
      tba.deleteIndex(8);
      result := tba;
    end;
    {$ENDIF}

    {*
    __getInputBoxes
    ---------------

    .. code-block:: pascal

        function TRSGrandExchange.__getInputBoxes(): TBoxArray;

    Returns a TBoxArray of the Grand Exchange input boxes, where you can type.

    .. note::

        - by Clarity
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        tba := grandExchange.__getInputBoxes();

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getInputBoxes(): TBoxArray;
    var
      TPA: TPointArray;
      ATPA: T2DPointArray;
      i: integer;
    begin
      grandExchange.__find;
      if findColors(TPA, 1388125, self.getBounds()) then
      begin
        ATPA := TPA.cluster(1);
        ATPA.sortFromFirstPoint(Point(233, 261)); //changed this
        result := ATPA.getEachBounds();
      end;

      writeLn(result);
    end;
    {$ENDIF}

    {*
    __isOfferOpen
    -------------

    .. code-block:: pascal

        function TRSGrandExchange.__isOfferOpen(waitTime: integer = 500): boolean;

    Returns true if the buy or sell offer screen is open.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isOfferOpen());

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isOfferOpen(waitTime: integer = 500): boolean;
    var
      timeOut: UInt64;
      TPA: TPointArray;
    begin
      timeOut := getTickCount64() + waitTime;

      while (getTickCount64() < timeOut) do
        if findColors(TPA, 6247745, self.getBounds()) then
        begin
          if (length(TPA) = 2862) then
            exit(true);
        end;
    end;
    {$ENDIF}

    {*
    __isProgressOpen
    ----------------

    .. code-block:: pascal

        function TRSGrandExchange._isProgressOpen(waitTime: integer = 500): boolean;

    Returns true if the offer in progress screen is open.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isProgressOpen());

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isProgressOpen(waitTime: integer = 500): boolean;
    var
      timeOut: integer;
      TPA: TPointArray;
    begin
      timeOut := getTickCount64() + waitTime;

      while (getTickCount64() < timeOut) do
        if findColors(TPA, 6247745, self.getBounds()) then
        begin
          if (length(TPA) = 3501) then
            exit(true);
        end;
    end;
    {$ENDIF}

    {*
    __isSlotActive
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotActive(geSlot: integer): boolean;

    Returns true if the slot **geSlot** is active. This is necessary
    because slots 3 to 8 are inactive when you are not a member.

    .. note::

        - by The Mayor
        - Last Updated: 10 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotActive(1));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotActive(geSlot: integer): boolean;
    var
      TPA: TPointArray;
      TBA : TBoxArray := self.__getSlotBoxes();
    begin
      findColors(TPA, 5063989, TBA[geSlot - 1]);
      result := length(TPA) < 5000;
    end;
    {$ENDIF}

    {*
    __isSlotEmpty
    -------------

    .. code-block:: pascal

        function TRSGrandExchange._isSlotEmpty(geSlot: integer): boolean;

    Returns true if the offer slot **geSlot** is empty and avaliable to use.

    .. note::

        - by The Mayor
        - Last Updated: 10 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotEmpty(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotEmpty(geSlot: integer): boolean;
    var
      TPA: TPointArray;
      TBA : TBoxArray := self.__getSlotBoxes();
    begin
      if self.__isSlotActive(geSlot) then
      begin
        findColors(TPA, 2694922, TBA[geSlot - 1]);
        result := length(TPA) > 10000;
      end;

      print('TRSGrandExchange._isSlotEmpty(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __isSlotComplete
    ----------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotComplete(geSlot: integer): boolean;

    Returns true if the offer is slot **geSlot** is complete.

    .. note::

        - by The Mayor
        - Last Updated: 15 January 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotComplete(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotComplete(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
    begin
      result := (countColorTolerance(1799224, TBA[geSlot - 1], 17) > 1700);
      print('TRSGrandExchange.isSlotComplete(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __isSlotAborted
    ---------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotAborted(geSlot: integer): boolean;

    Returns true if the offer is slot **geSlot** is aborted.

    .. note::

        - by The Mayor
        - Last Updated: 15 January 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotAborted(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotAborted(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
    begin
      result := (countColorTolerance(983163, TBA[geSlot - 1], 16) > 1700);
      print('TRSGrandExchange.isSlotAborted(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __isSlotBuying
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotBuying(geSlot: integer): boolean;

    Returns true if the offer is slot **geSlot** is currently buying.

    .. note::

        - by The Mayor
        - Last Updated: 31 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotBuying(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotBuying(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      TPA, TPA2: TPointArray;
    begin
      if self.__isSlotAborted(geSlot) or self.__isSlotComplete(geSlot)
        then exit(false);
      findColors(TPA, 2433824, TBA[geSlot - 1]);
      findColors(TPA2, 3815734, TBA[geSlot - 1]); // If hovering the box
      TPA.combine(TPA2);
      result := (length(TPA) > 10000);
      print('TRSGrandExchange.isSlotBuying(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __isSlotSelling
    ---------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotSelling(geSlot: integer): boolean;

    Returns true if the offer is slot **geSlot** is currently selling.

    .. note::

        - by The Mayor
        - Last Updated: 31 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange._isSlotSelling(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotSelling(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      TPA, TPA2: TPointArray;
    begin
      if self.__isSlotAborted(geSlot) or self.__isSlotComplete(geSlot)
        then exit(false);
      findColors(TPA, 3287837, TBA[geSlot - 1]);
      findColors(TPA2, 4603955, TBA[geSlot - 1]); // If hovering the box
      TPA.combine(TPA2);
      result := (length(TPA) > 10000);
      print('TRSGrandExchange.isSlotSelling(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __findInsertionCursor
    ---------------------

    .. code-block:: pascal

        TRSGrandExchange.__findInsertionCursor(searchBox: TBox; waitTime: integer = 4000): boolean;

    Returns true is the insertion cursor is found inside **searchBox** within the **waitTime**
    *(default = 4000)* .

    .. note::

        - by Clarity
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__findInsertionCursor(b));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__findInsertionCursor(searchBox: TBox; waitTime: integer = 4000): boolean;
    var
      timeOut: UInt64;
      TPA: TPointArray;
    begin
      timeOut := getTickCount64() + waitTime;

      while getTickCount64() < timeOut do
      begin
        findColors(TPA, 14606050, searchBox);
        if length(TPA) > 0 then
          exit(true);
      end;
    end;
    {$ENDIF}

    {*
    __enterQuantity
    ---------------

    .. code-block:: pascal

        procedure TRSGrandExchange.__enterQuantity(quantity: string);

    Returns true if it successfully enters the desired item quantity **quantity**
    into the input box.

    .. note::

        - by The Mayor
        - Last Updated: 19 November 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.__enterQuantity('1500'); // To buy/sell 1500 of an item
        grandExchange.__enterQuantity('all'); // To SELL all of the item

    *}

    {$IFNDEF CODEINSIGHT}
    procedure TRSGrandExchange.__enterQuantity(quantity: string);
    var
      i: integer;
      strArr : TStringArray;
      inputBox: TBoxArray;
      amountBox: TBoxArray := grid(4, 1, 34, 24, 44, 0, point(self.x1 + 84, self.y1 + 298));
    begin
      strArr := ['1', '10', '100', 'all'];

      i := strArr.returnInArray(lowercase(quantity));

      if inRange(i, 0, 3) then
        mouseBox(amountBox[i], MOUSE_LEFT)
      else
      begin
        inputBox := self.__getInputBoxes();
        mouseBox(inputBox[0], MOUSE_LEFT);
        if self.__findInsertionCursor(inputBox[0]) then
        begin
          typeSend(toStr(quantity), true);
          wait(randomRange(1000, 1500));
        end;
      end;
    end;
    {$ENDIF}

    {*
    __enterPrice
    ------------

    .. code-block:: pascal

        procedure TRSGrandExchange.__enterPrice(price: string);

    Returns true if it successfully enters the desired item price **price**
    into the input box.

    .. note::

        - by The Mayor
        - Last Updated: 19 November 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.__enterPrice('+5');    // Will click the +5% button
        grandExchange.__enterPrice('mid');   // Will leave at mid price
        grandExchange.__enterPrice('32500'); // Will type in 32500

    *}

    {$IFNDEF CODEINSIGHT}
    procedure TRSGrandExchange.__enterPrice(price: string);
    var
      i: integer;
      b: TBox;
      strArr : TStringArray;
      priceBox, inputBox: TBoxArray;
    begin
      priceBox := grid(3, 1, 34, 24, 45, 0, point(self.x1 + 367, self.y1 + 298));

      strArr := ['-5', 'mid', '+5'];

      i := strArr.returnInArray(lowercase(price));

      if (i = 0) or (i = 2) then
        mouseBox(priceBox[i], MOUSE_LEFT)
      else if (i <> 1) then  // Don't click mid button as it's set by default
      begin
        inputBox := self.__getInputBoxes();
        mouseBox(inputBox[1], MOUSE_LEFT);
        if self.__findInsertionCursor(inputBox[1]) then
        begin
          typeSend(toStr(price), true);
          wait(randomRange(1000, 1500));
        end;
      end;
    end;
    {$ENDIF}

    {*
    __enterName
    -----------

    .. code-block:: pascal

        procedure TRSGrandExchange.__enterName(itemName: string)

    Returns true if it successfully types the item name **itemName** into the search
    box and clicks it.

    .. note::

        - by The Mayor
        - Last Updated: 24 Decenber 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.__enterName('Swamp toad');

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__enterName(itemName: string): boolean;
    const
      TESS_FILTER_GE_CHARS: TTesseractFilter = [4, 4, [False, 20, TM_Mean]];
    var
      i: integer;
      timeOut: UInt64;
      resultsBox: TBoxArray := grid(3, 2, 166, 49, 172, 55, point(self.x1 + 104, self.y1 + 405));
      resultsTextBox: TBoxArray := grid(3, 2, 122, 16, 172, 55, point(self.x1 + 121, self.y1 + 396));
      inputBox: TBoxArray;
    begin
      timeOut := getTickCount64() + randomRange(3000, 4000);
      inputBox := self.__getInputBoxes();

      if not self.__findInsertionCursor(inputBox[2]) then
        mouseBox(inputBox[2], MOUSE_LEFT);

      if self.__findInsertionCursor(inputBox[2]) then
        typeSend(itemName, false);

      if waitColorCountRange(9214319, 10, resultsTextBox[0], 5000, 10) then
        for i := 0 to 5 do
          if stringMatch(trim(tesseractGetText(resultsTextBox[i], TESS_FILTER_GE_CHARS)), itemName) >= 0.7 then
          begin
            mouseBox(resultsBox[i], MOUSE_LEFT);
            waitColorCountRange(16777215, 3, inputBox[2], 5000, 507, 509);
            exit(true);
          end;

      print('TRSGrandExchange.__enterName(): Found no matches for item: ' + itemName, TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __returnToSummary
    -----------------

    .. code-block:: pascal

        procedure TRSGrandExchange._returnToSummary();

    If the GE offer screen or GE progress screen is currently open, it will click
    the back arrow to return to the summary screen.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.__returnToSummary();

    *}

    {$IFNDEF CODEINSIGHT}
    procedure TRSGrandExchange.__returnToSummary();
    var
      backButton: TPoint := [self.x1 + 33, self.y1 + 515];
      timeOut: UInt64;
    begin
      if self.__isOfferOpen() or self.__isProgressOpen() then
      begin
        print('TRSGrandExchange._returnToSummary(): returning to summary screen', TDebug.SUB);
        multiClick(backButton.rand(5), 30, 3);

        timeOut := getTickCount64() + randomRange(2500, 3500);
        while getTickCount64() < timeOut do
        begin
          if ((not self.__isOfferOpen()) and (not self.__isProgressOpen())) then
            break();
        end;
      end;
    end;
    {$ENDIF}

    (*
    collectSlot
    -----------

    .. code-block:: pascal

        function TRSGrandExchange.collectSlot(geSlot: integer): boolean;

    Returns true if it collects coins and/or items from the completed or aborted slot
    **geSlot** .

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.collectSlot(2);

    *)

    function TRSGrandExchange.collectSlot(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      collectBox: TBoxArray := grid(2, 1, 37, 32, 49, 0, point(self.x1 + 463, self.y1 + 385));
      timeOut: UInt64;
      i: integer;
    begin
      if not self.__isProgressOpen() then
      begin
        self.__returnToSummary();

        if (not self.__isSlotActive(geSlot)) or self.__isSlotEmpty(geSlot) then
        begin
          print('TRSGrandExchange.collectSlot(): Cannot collect as offer slot ' + toStr(geSlot) + ' is empty', TDebug.ERROR);
          exit(false);
        end;

        timeOut := getTickCount64() + randomRange(3000, 4000);

        repeat
          mouseBox(TBA[geSlot - 1], MOUSE_LEFT);
          if self.__isProgressOpen(2000 + random(500)) then
            break();
        until (getTickCount64() < timeOut);
      end;

      for i := high(collectBox) downto 0 do
        for  0 to 2 do // Attempt up to 3 times in case of lag
          if isItemIn(collectBox[i]) then
          begin
            mouseBox(collectBox[i], MOUSE_LEFT);
            wait(randomRange(750, 1250));

            if not self.__isProgressOpen() then
            begin
              result := true;
              break(1);
            end;
          end;

      self.__returnToSummary();

      print('TRSGrandExchange.collectSlot(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result));
    end;

    (*
    waitCollectSlot
    ---------------

    .. code-block:: pascal

        function TRSGrandExchange.waitCollectSlot(geSlot, maxTime: integer): boolean;

    Returns true if it collects coins and/or items from the completed or aborted slot
    **geSlot** . Waits up to **maxTime** for **geSlot** to finish selling.

    .. note::

        - by The Mayor
        - Last Updated: 12 March 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.waitCollectSlot(2, 60000); // Wait up to 1 minute to collect slot 2

    *)

    function TRSGrandExchange.waitCollectSlot(geSlot, maxTime: Integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      timeOut: UInt64;
    begin
      self.__returnToSummary();

      if (not self.__isSlotActive(geSlot)) or self.__isSlotEmpty(geSlot) then
      begin
        print('TRSGrandExchange.waitCollectSlot(): Cannot collect as offer slot ' + toStr(geSlot) + ' is empty', TDebug.ERROR);
        exit(false);
      end;

      timeOut := getTickCount64() + maxTime;

      while (getTickCount64() < timeOut) do
        if self.__isSlotComplete(geSlot) then
        begin
          if self.collectSlot(geSlot) then
          begin
            result := true;
            break();
          end;
        end else
          wait(500);

      print('TRSGrandExchange.waitCollectSlot(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;

    (*
    collectAllSlots
    ---------------

    .. code-block:: pascal

        procedure TRSGrandExchange.collectAllSlots(toInventory: boolean = true): boolean;

    Collects all coins and items to either the inventory or the bank depending on the
    **toInventory** paramter *(default = true)* via the collect buttons.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.collectAllSlots(false); // Collect all to bank

    *)

    procedure TRSGrandExchange.collectAllSlots(toInventory: boolean = true);
    const
      _OFFSET: TPoint = [653, 481];
    var
      TBA: TBoxArray;
    begin
      TBA := grid(1, 2, 180, 20, 0, 36, point(self.x1 + _OFFSET.x, self.y1 + _OFFSET.y));
      case ToInventory of
        true: multiClick(TBA[0].getMiddle().rand(5), 25, 3);
        false: multiClick(TBA[1].getMiddle().rand(5), 25, 3);
      end;
    end;

    (*
    abortSlot
    ---------

    .. code-block:: pascal

        function TRSGrandExchange.abortSlot(geSlot: integer; collect: boolean = true): boolean;

    Returns true if it aborts the slot **geSlot**. If the **collect** parameter is
    set to true it will also collect the items and gold from the aborted offer.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.abortSlot(2);
        grandExchange.abortSlot(2, false); // To leave items in the aborted offer slot

    *)

    function TRSGrandExchange.abortSlot(geSlot: integer; collect: boolean = true): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      abortButton: TPoint := [self.x1 + 402, self.y1 + 383];
      redBox: TBox := [self.x1 + 29, self.y1 + 404, self.x1 + 423, self.y1 + 410];
    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.abortSlot(): Cannot abort as the GE is not open', TDebug.ERROR);
        exit(false);
      end;

      self.__returnToSummary();

      if self.__isSlotEmpty(geSlot) or (not self.__isSlotActive(geSlot)) then
      begin
        print('TRSGrandExchange.abortSlot(): Cannot abort as offer slot ' + toStr(geSlot) + ' is empty', TDebug.ERROR);
        exit(false);
      end;

      if self.__isSlotAborted(geSlot) then
      begin
        print('TRSGrandExchange.abortSlot(): Offer slot ' + toStr(geSlot) + ' is already aborted');
        exit(true);
      end;

      if self.__isSlotComplete(geSlot) then
      begin
        print('TRSGrandExchange.abortSlot(): Cannot abort as offer slot ' + toStr(geSlot) + ' is already completed', TDebug.ERROR);
        exit(false);
      end;

      mouseBox(TBA[geSlot - 1], MOUSE_LEFT, MOUSE_ACCURATE);

      if self.__isProgressOpen(3000) then
      begin
        multiClick(abortButton.rand(5), 30, 3);
        waitColorCountRange(1048714, 5, redBox, 4000, 2000);

        if collect then
          result := self.collectSlot(geSlot)
        else
        begin
          result := self.__isSlotAborted(geSlot);
          self.__returnToSummary();
        end;
      end;

      print('TRSGrandExchange.abortSlot(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result));
    end;

    (*
    abortAllSlots
    -------------

    .. code-block:: pascal

        procedure TRSGrandExchange.abortAllSlots(collect: boolean);

    Aborts all slots that are not currently empty. If the **collect** parameter is
    set to true, it will also collect all items and gold.

    .. note::

        - by The Mayor
        - Last Updated: 12 March 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.abortAllSlots();

    *)

    procedure TRSGrandExchange.abortAllSlots(collect: boolean = true);
    var
      i: integer;
      TBA: TBoxArray := self.__getSlotBoxes();
    begin
      for i := 1 to length(TBA) do
        if (not self.__isSlotEmpty(i)) and self.__isSlotActive(i) then
          self.abortSlot(i, collect);
    end;

    (*
    getPercentDone
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.getPercentDone(geSlot: integer): integer;

    Returns the percentage toward completion for the offer in **geSlot** .

    .. note::

        - by turpinator
        - Last Updated: 19 November 2015 by SlipperyPickle

    Example:

    .. code-block:: pascal

        var
          per: Integer;
        begin
          per := grandExchange.getPercentDone(2);
          writeLn('Slot 2 is ' + toStr(per) + ' percent complete!');
        end;

    *)

    function TRSGrandExchange.getPercentDone(geSlot: integer): integer;
    const
      BG_COLORS = [2565929, 2039584, 2237482, 1776673];
    var
      i, x, y: integer;
      TBA: TBoxArray := self.__getSlotBoxes();
    begin
      if self.__isSlotEmpty(geSlot) or (not self.__isSlotActive(geSlot)) then exit(-1);

      x := TBA[geSlot -1].x1 + 8;
      y := TBA[geSlot -1].y1 + 100;

      for result := 153 downto 1 do
        if (getColor(x + result, y) <> BG_COLORS[0]) and (getColor(x + result, y) <> BG_COLORS[1]) then
          exit(round(0.6897 * result));
    end;

    (*
    confirmBox
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.confirmBox(): TBox;

    Returns the confirm TBox in the Grand Exchange screen.

    .. note::

        - by SlipperyPickle
        - Last Updated: 05 June 2016 by SlipperyPickle

    Example:

    .. code-block:: pascal

        var
          confirm: TBox;
        begin
          mouseBox(grandExchange.confirmBox(), MOUSE_LEFT);
        end;

    *)


    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.confirmBox(): TBox;
    var
      x, y, i: integer;
      TPA: TPointArray;
      ATPA: T2DPointArray;
      b: TBox;

    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.confirmBox(): Cannot abort as the GE is not open', TDebug.ERROR);
        exit();
      end;

      findColorsSpiralTolerance(x, y, TPA, 1942256, grandExchange.getBounds(), 23, colorSetting(2, 0.11, 0.49));
      if (Length(TPA) < 1) then
        exit;

      ATPA := TPA.cluster(20);
      ATPA.filterBetween(0, 500);
      ATPA.sortFromMidPoint(Point(145, 525));
      b := ATPA[0].getBounds();
      result := IntToBox(b.X1 + 5, b.Y1 + 3, b.X2 - 5, b.Y2 - 3);
    end;
    {$ENDIF}

    (*
    sellItem
    --------

    .. code-block:: pascal

        function TRSGrandExchange.sellItem(packSlot: integer; price, quantity: string; waitCollect: boolean = false; waitTime: integer = 10000): boolean;

    Returns true if it sells the item in backpack slot **packSlot** . If **waitCollect**
    is set to true, it will wait the specified waitTime for the offer to complete
    before collecting the resulting gold.

      The **price** parameter is a string - valid options are:

        * 'mid'             : GE mid price button
        * '-5'              : 5% below mid price button
        * '+5'              : 5% above mid price button
        * Any other number  : It will enter the price

      The **quantity** parameter is a string - valid options are:

        * '1'               : '1' button
        * '10'              : '10' button
        * '100'             : '100' button
        * 'all'             : 'All' button (Selling ONLY)
        * Any other number  : It will enter the quantity

    .. note::

        - by The Mayor
        - Last Updated: 13 November 2015 by SlipperyPickle

    Example:

    .. code-block:: pascal

          // Sell all of item in backPack slot 1 for mid price
        grandExchange.sellItem(1, 'mid', 'all');

          // To sell 100 of the item in backPack slot 1, for 1500gp each
        grandExchange.sellItem(1, '1500', '100');

          // As above, but waits up to 20 seconds for completion before collecting the coins
        grandExchange.sellItem(1, '1500', '100', true, 20000);

    *)

    function TRSGrandExchange.sellItem(packSlot: integer; price, quantity: string; waitCollect: boolean = false; waitTime: integer = 10000): boolean;
    var
      i, nextSlot: integer;
      confirm: TBox := [self.x1 + 218, self.y1 + 508, self.x1 + 345, self.y1 + 526];
    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.sellItem(): Cannot abort as the GE is not open', TDebug.ERROR);
        exit(false);
      end;

      self.__returnToSummary();

      for i := 1 to 8 do
        if self.__isSlotEmpty(i) and self.__isSlotActive(i) then
        begin
          nextSlot := i;
          break();
        end;

      if nextSlot < 1 then
      begin
        print('TRSGrandExchange.sellItem(): Cannot sell item as there are no empty offer slots', TDebug.ERROR);
        exit(false);
      end;

      if isItemIn(self.getPackSlotBox(packSlot)) then
        mouseBox(self.getPackSlotBox(packSlot), MOUSE_LEFT, MOUSE_ACCURATE)
      else
      begin
        print('TRSGrandExchange.sellItem(): No item in pack slot: ' + intToStr(packSlot), TDebug.ERROR);
        exit(false);
      end;

      if self.__isOfferOpen(3000) then
      begin
        self.__enterQuantity(quantity);
        self.__enterPrice(price);
        //confirm := self.confirmBox() ;
        mouseBox(confirm, MOUSE_LEFT, MOUSE_ACCURATE);


        wait(randomRange(1000, 1500));
      end;

      result:= self.__isSlotSelling(nextSlot);
      print('TRSGrandExchange.sellItem(): ' + boolToStr(result), TDebug.SUB);

      if waitCollect then
        self.waitCollectSlot(nextSlot, waitTime);
    end;

    (*
    buyItem
    -------

    .. code-block:: pascal

        function TRSGrandExchange.buyItem(itemName, price, quantity: string; waitCollect: boolean = false; waitTime: integer = 10000): boolean;

    Returns true if it buys the item **itemName** . If **waitCollect** is set to true,
    it will wait the specified waitTime for the offer to complete before collecting
    the resulting gold and items.

      The **price** parameter is a string - valid options are:

        * 'mid'             : GE mid price button
        * '-5'              : 5% below mid price button
        * '+5'              : 5% above mid price button
        * Any other number  : It will enter the price

      The **quantity** parameter is a string - valid options are:

        * '1'               : '1' button
        * '10'              : '10' button
        * '100'             : '100' button
        * Any other number  : It will enter the quantity

    .. note::

        - by The Mayor
        - Last Updated: 13 November 2015 by SlipperyPickle

    Example:

    .. code-block:: pascal

          // To buy 10000 oak logs at 5% over the mid price
        grandExchange.buyItem('Oak log', '+5', '10000');

          // To buy 10000 oak logs for 150gp each
        grandExchange.buyItem('Oak log', '150', '10000');

          // As above, but waits up to 20 seconds for completion before collecting items
        grandExchange.buyItem('Oak log', '150', '10000', true, 20000);

    *)

    function TRSGrandExchange.buyItem(itemName, price, quantity: string; waitCollect: boolean = false; waitTime: integer = 10000): boolean;
    var
      i, nextSlot, x, y: integer;
      b: TBox;
      p: TPoint;
      TBA : TBoxArray := self.__getBuyBoxes();
      confirm: TBox := [self.x1 + 218, self.y1 + 508, self.x1 + 345, self.y1 + 526];
    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.sellItem(): Cannot abort as the GE is not open', TDebug.ERROR);
        exit(false);
      end;

      self.__returnToSummary();

      for i := 1 to 8 do
        if self.__isSlotEmpty(i) and self.__isSlotActive(i) then
        begin
          nextSlot := i;
          break();
        end;

      if nextSlot < 1 then
      begin
        print('TRSGrandExchange.sellItem(): Cannot sell item as there are no empty offer slots', TDebug.ERROR);
        exit(false);
      end;

      mouseBox(TBA[nextSlot - 1], MOUSE_LEFT, MOUSE_ACCURATE);

      if self.__isOfferOpen(3000) then
      begin
        self.__enterName(itemName);
        self.__enterQuantity(quantity);
        self.__enterPrice(price);
        mouseBox(confirm, MOUSE_LEFT);
        wait(randomRange(1000, 1500));
      end else
        self.__returnToSummary();


      result := self.__isSlotBuying(nextSlot);
      print('TRSGrandExchange.buyItem(): ' + boolToStr(result), TDebug.SUB);

      if waitCollect then
        self.waitCollectSlot(nextSlot, waitTime);
    end;

    (*
    getPrice
    --------

    .. code-block:: pascal

        TRSGrandExchange.getPrice(item: integer): integer;

    Returns the current market price of any item in the Grand Exchange. The **item**
    parameter must be the item's ID number.

    IDs can be found on the Grand Exchange website at the end of the URL. For example,
    the ID in the below URL is 2150 (Swamp toad)

    http://services.runescape.com/m=itemdb_rs/viewitem.ws?obj=2150

    .. note::

        - by The Mayor
        - Last Updated: 16 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        var
          toadPrice: Integer;
        begin
          toadPrice := grandExchange.getPrice(2150);  // The ID for Swamp toads
          profit := (toadPrice * toadsCollected);
        end;

    *)

    function TRSGrandExchange.getPrice(ID: integer): integer;
    var
      webPage: string;
      TSA: TStringArray;
    begin
      webPage := getPage('http://services.runescape.com/m=itemdb_rs/viewitem.ws?obj=' + toStr(ID));
      TSA := multiBetween(webPage, 'average30.push([new Date(',']);');

      if length(TSA) < 1 then
      begin
        print('TRSGrandExchange.getPrice(): Unable to retrieve price for ID: ' + toStr(ID), TDebug.ERROR);
        exit(-1);
      end;

      result := strToInt(Between('), ', ',', TSA[High(TSA)]));
      print('TRSGrandExchange.getPrice(' + toStr(ID) + '): ' + toStr(result));
    end;

    begin
      grandExchange.__init();
    end;

    {$f+}
    Last edited by SlipperyPickle; 06-06-2016 at 11:08 PM.

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

    Default

    I hope I can find some free time soon to test this. Perhaps next weekend

  6. #56
    Join Date
    Sep 2014
    Location
    Netherlands
    Posts
    264
    Mentioned
    11 Post(s)
    Quoted
    130 Post(s)

    Default

    Quote Originally Posted by Thomas View Post
    I hope I can find some free time soon to test this. Perhaps next weekend
    I've updated the code, check my previous post. Most of it is working except for the confirm button (sometimes it misclicks). Could you check whats wrong? If I've got some spare time in the next few days, I'll do my best to fix the rest.

    EDIT: Long night, but I believe most is fixed now. Should be tested tough.
    Last edited by SlipperyPickle; 06-06-2016 at 11:09 PM.

  7. #57
    Join Date
    Sep 2014
    Location
    Netherlands
    Posts
    264
    Mentioned
    11 Post(s)
    Quoted
    130 Post(s)

    Default

    This project is currently on hold, postponed until my holiday. Was getting headaches from such a big project. I think I'm about 75% done with this project, and it's already almost 1000 lines long.

    Currently am working on a farming script (tree runner), it's almost finished. Even made it save everything to a file, so you can pause and restart the script. Thinking about releasing this script as soon as it's stable. My first goal with this script is a 2 week proggy. Should be possible since it just have to make the run once every 6 hours.

  8. #58
    Join Date
    Sep 2014
    Location
    Netherlands
    Posts
    264
    Mentioned
    11 Post(s)
    Quoted
    130 Post(s)

    Default

    Had some time to work on the grand exchange library. Updated it yesterday to the github, but today I saw there were still a few minor bugs. I'm not really familiar with github so I'll upload it here. This version works like a charm. Perhaps the library can be updated after testing.

    This project is going pretty good right now. The grand exchange library is fixed. I rewrote the entire script. It's now much simpler and the script hasn't failed as of jet. For now this is an example of the script output:

    Code:
    fishing bait buy price: 5 sell price: 4
    Profit for fishing bait: 1
    willow logs buy price: 23 sell price: 22
    Profit for willow logs: 1
    raw herring buy price: 31 sell price: 17
    Profit for raw herring: 14
    feather buy price: 42 sell price: 41
    Profit for feather: 1
    maple logs buy price: 26 sell price: 24
    Profit for maple logs: 2
    Here is the code for the grand exchange library:
    Simba Code:
    (*
    Grand Exchange
    ==============

    The grandexchange file holds functions and procedures that are used to interact with the runescape Grand Exchange.

    The source for this file can be found `here <https://github.com/SRL/SRL-6/blob/master/lib/interfaces/grandexchange.simba>`_.

    *)


    {$f-}

    (*
    Consts, Types, Vars
    ~~~~~~~~~~~~~~~~~~~

    The following constants, types and variables are used throughout the collectBox methods.

    **const Grand Exchange Tabs**

      Constants that represent the two grandExchange tabs

        * GE_TAB_EXCHANGE
        * GE_TAB_HISTORY

    *)

    const
      GE_TAB_EXCHANGE = 0;
      GE_TAB_HISTORY = 1;
      GE_TAB_SETS = 2;

    (*

    **type TRSGrandExchange**

    .. code-block:: pascal

        type
          TRSGrandExchange = type TRSInterface;

    A type that stores the Grand Exchange interface properties.

    *)

    type
      TRSGrandExchange = record(TRSInterface)
        tabBoxes: TBoxArray;
        confirmBox: TBox;
    end;

    (*
    **var grandExchange**

    .. code-block:: pascal

        var
          grandExchange: TRSGrandExchange;

    A variable through which scripters can access the TRSGrandExchange type methods.

    *)

    var
      grandExchange: TRSGrandExchange;

    (*
    TRSGrandExchange methods
    ~~~~~~~~~~~~~~~~~~~~~~~~~

    The following methods should be called through the **grandExchange** variable.

    Example:

    .. code-block:: pascal

        if grandExchange.isOpen() then
          writeln('It''s open');
    *)


    {*
    __init
    ------

    .. code-block:: pascal

        procedure TRSGrandExchange.__init();

    Initializes the TRSGrandExchange.

    .. note::

        - by The Mayor
        - Last Updated: 9th October 2014 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.__init();

    *}

    {$IFNDEF CODEINSIGHT}
    procedure TRSGrandExchange.__init();
    begin
      with self do
      begin
        name := 'Grand Exchange';
        ID := ID_INTERFACE_GRANDEXCHANGE;
        parentID := -1;
        static := false;
      end;
    end;
    {$ENDIF}

    {*
    __find
    ------

    .. code-block:: pascal

        function TRSGrandExchange.__find(): boolean;

    Returns true if the grandExchange interface is detected and its bounds are set.
    Scripters should use grandExchange.isOpen() below.

    .. note::

        - by The Mayor
        - Last Updated: 6 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        if grandExchange.__find() then
          writeln('The grandExchange is open, and the bounds are set!');
    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__find(): boolean;
    const
      PINK_COLOR = [14581920, 0]; // [Col, Tol] pink item in the balance scale.
    var
      i: Integer;
      TPA: TPointArray;
      ATPA: T2DPointArray;
      b: TBox;
    begin
      findColorsTolerance(TPA, PINK_COLOR[0], getClientBounds(), PINK_COLOR[1]);

      if length(TPA) < 10 then
      begin
        print('TRSGrandExchange.__find(): Didn''t find enough PINK_COLOR', TDebug.WARNING);
        exit(false);
      end;

      ATPA := TPA.cluster(5);
      ATPA.sortBySize(true);

      for i := 0 to high(ATPA) do
      begin
        b := ATPA[i].getBounds();

        if inRange(b.getWidth(), 10, 20) and (b.getHeight() < 20) then
        begin
          b.edit(21, -10, 114, 12);

          if (pos('GRAND', upperCase(tesseract_GetText(b, TESS_FILTER_SMALL_CHARS))) > 0) then
          begin
            self.setBounds([b.x1 - 88, b.y1 - 8, b.x2 + 570, b.y2 + 515]);
            self.tabBoxes := grid(3, 1, 60, 22, 107, 0, point(x1 + 92, y1 + 113));
            self.confirmBox := [self.x1 + 218, self.y1 + 511, self.x1 + 340, self.y1 + 524];
            exit(true);
          end;
        end;

      end;
    end;
    {$ENDIF}

    (*
    isOpen
    ------

    .. code-block:: pascal

        function TRSGrandExchange.isOpen(waitTime: integer = 0): boolean;

    Returns true if the grandExchange is open. The optional **waitTime** parameter
    *(default = 0)* is the maximum time (in milliseconds) it will keep looking.

    .. note::

        - by The Mayor
        - Last Updated: 14 January 2015 by The Mayor

    Example:

    .. code-block:: pascal

        if grandExchange.isOpen() then
          writeln('The grandExchange is open!');

    *)

    function TRSGrandExchange.isOpen(waitTime: integer = 0): boolean;
    var
      t: UInt64;
    begin
      t := (getTickCount64() + waitTime);

      repeat
        if self.__find() then
        begin
          result := true;
          break();
        end;
      until (getSystemTime() >= t);
      print('TRSGrandExchange.isOpen(): Result = ' + boolToStr(result));
    end;

    (*
    close
    -----

    .. code-block:: pascal

        function TRSGrandExchange.close(escape: boolean = true): boolean;

    Returns true if the grandExchange is successfully closed. It uses the ESC key
    by default, but the **escape** parameter can be set to false to close via the mouse.

    .. note::

        - by The Mayor
        - Last Updated: 6 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        if grandExchange.close() then
          writeln('Closed the grandExchange');

    *)

    function TRSGrandExchange.close(escape: boolean = true): boolean;
    const
      __CLOSE_OFFSET: TPoint = [756, 22]; // From self(x1, y1) to middle of 'X'
    var
      timeOut: UInt64;
    begin
      if (not self.isOpen()) then
        exit(true);

      if escape then // Try the escape button first if possible
      begin
        timeOut := (getTickCount64() + randomRange(600, 900));
        repeat
          typeByte(VK_ESCAPE);
          wait(300 + random(50));
        until (not self.isOpen()) or (getTickCount64() > timeOut);

        if (not self.isOpen()) then
          exit(true);
      end;

      if self.isOpen(100 + random(50)) then // Wait a bit in case it closes
      begin
        mouse(point(self.x1 + __CLOSE_OFFSET.x, self.y1 + __CLOSE_OFFSET.y).rand(3), MOUSE_LEFT);
        timeOut := (getTickCount64() + randomRange(5000, 6000));

        while (timeOut > getTickCount64()) do
        begin
          if (not self.isOpen()) then
          begin
            result := true;
            break();
          end;
          wait(50 + random(50));
        end;
      end else
        result := true;

      print('TRSGrandExchange.close(): result = ' + boolToStr(result), TDebug.SUB);
    end;

    {*
    __getActiveTab
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__getActiveTab(): Integer;

    Returns the current tab number (0 - Grand Exchange | 1 - Sale History).

    .. note::

        - by The Mayor
        - Last Updated: 9 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__getActiveTab());

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getActiveTab(): Integer;
    var
      i: Integer;
    begin
      for i := 0 to high(self.tabBoxes) do
        if (not (getColor(self.tabBoxes[i].X2, self.tabBoxes[i].Y2) = 9078134)) then
          exit(i);
    end;
    {$ENDIF}

    (*
    openTab
    -------

    .. code-block:: pascal

        function TRSGrandExchange.openTab(tab: Integer): Boolean;

    Opens the grandExchange tab **tab** . The **tab** parameter should be one of the
    two tab constants at the top of this page.

    .. note::

        - by The Mayor
        - Last Updated: 9 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.openTab(GE_TAB_HISTORY);

    *)

    function TRSGrandExchange.openTab(tab: Integer): Boolean;
    begin
      if (not self.isOpen()) then
        exit(false);

      if (self.__getActiveTab() = tab) then
        exit(true);

      for 0 to 3 do
      begin
        multiClick(self.tabBoxes[tab].getGaussPoint(), 30, 3);
        wait(random(800, 1200));
        if (self.__getActiveTab() = tab) then exit(true);
      end;
    end;

    (*
    getPackSlotBox
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.getPackSlotBox(slot: integer): TBox;

    Returns a TBox of the pack slot **slot** in the grandExchange interface.

    .. note::

        - by The Mayor
        - Last Updated: 6 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        var
          b: TBox;
        begin
          b := grandExchange.getPackSlotBox(1);
          mouseBox(b, MOUSE_MOVE);
        end;

    *)

    function TRSGrandExchange.getPackSlotBox(slot: integer): TBox;
    const
      __PACK_OFFSET: TPoint = [582, 174]; // From self(x1, y1) to middle of first pack slot
    begin
      result := gridBox(slot - 1, 4, 7, 36, 32, 46, 36, point(self.x1 + __PACK_OFFSET.x, self.y1 + __PACK_OFFSET.y));
    end;

    {*
    __getSlotBoxes
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__getSlotBoxes(): TBoxArray;

    Returns a TBoxArray of the 8 Grand Exchange slots.

    .. note::

        - by The Mayor
        - Last Updated: 19 November 2015 by SlipperyPickle

    Example:

    .. code-block:: pascal

        tba := grandExchange.__getSlotBoxes();

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getSlotBoxes(): TBoxArray;
    const
      __GE_SLOT_OFFSET: TPoint = [104, 203]; // From self(x1, y1) to middle of first GE slot
    var
      tba: TBoxArray;
    begin
      tba := grid(3, 3, 169, 121, 177, 128, point(self.x1 + __GE_SLOT_OFFSET.x, self.y1 + __GE_SLOT_OFFSET.y));
      tba.deleteIndex(8);
      result := tba;
    end;
    {$ENDIF}

    {*
    __getBuyBoxes
    -------------

    .. code-block:: pascal

        function TRSGrandExchange.__getBuyBoxes(): TBoxArray;

    Returns a TBoxArray of the Grand Exchange buy boxes.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        tba := grandExchange.__getBuyBoxes();

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getBuyBoxes(): TBoxArray;
    const
      __BUY_OFFSET: TPoint = [74, 213]; // From self(x1, y1) to middle of first buy button
    var
      tba: TBoxArray;
    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.__getBuyBoxes(): Cannot click a buy box as the GE is not open', TDebug.ERROR);
        exit();
      end;
      tba := grid(3, 3, 44, 44, 177, 128, point(self.x1 + __BUY_OFFSET.x, self.y1 + __BUY_OFFSET.y));
      tba.deleteIndex(8);
      result := tba;
    end;
    {$ENDIF}

    {*
    __getSellBoxes
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__getSellBoxes(): TBoxArray;

    Returns a TBoxArray of the Grand Exchange sell boxes.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        tba := grandExchange.__getSellBoxes();

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getSellBoxes(): TBoxArray;
    const
      __SELL_OFFSET: TPoint = [134, 213]; // From self(x1, y1) to middle of first sell button
    var
      tba: TBoxArray;
    begin
      tba := grid(3, 3, 44, 44, 177, 128, point(self.x1 + __SELL_OFFSET.x, self.y1 + __SELL_OFFSET.y));
      tba.deleteIndex(8);
      result := tba;
    end;
    {$ENDIF}

    {*
    __getInputBoxes
    ---------------

    .. code-block:: pascal

        function TRSGrandExchange.__getInputBoxes(): TBoxArray;

    Returns a TBoxArray of the Grand Exchange input boxes, where you can type.

    .. note::

        - by Clarity
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        tba := grandExchange.__getInputBoxes();

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__getInputBoxes(): TBoxArray;
    var
      TPA: TPointArray;
      ATPA: T2DPointArray;
      i: integer;
    begin
      grandExchange.__find;
      if findColors(TPA, 1388125, self.getBounds()) then
      begin
        ATPA := TPA.cluster(1);
        ATPA.sortFromFirstPoint(Point(233, 261)); //changed this
        result := ATPA.getEachBounds();
      end;
    end;
    {$ENDIF}

    {*
    __isOfferOpen
    -------------

    .. code-block:: pascal

        function TRSGrandExchange.__isOfferOpen(waitTime: integer = 500): boolean;

    Returns true if the buy or sell offer screen is open.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isOfferOpen());

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isOfferOpen(waitTime: integer = 500): boolean;
    var
      timeOut: UInt64;
      TPA: TPointArray;
    begin
      timeOut := getTickCount64() + waitTime;

      while (getTickCount64() < timeOut) do
        if findColors(TPA, 1388125, self.getBounds()) then
        begin
          if (length(TPA) = 1532) or (length(TPA) = 492) then
            exit(true);
        end;
    end;
    {$ENDIF}

    {*
    __isProgressOpen
    ----------------

    .. code-block:: pascal

        function TRSGrandExchange._isProgressOpen(waitTime: integer = 500): boolean;

    Returns true if the offer in progress screen is open.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isProgressOpen());

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isProgressOpen(waitTime: integer = 500): boolean;
    var
      timeOut: integer;
      TPA: TPointArray;
    begin
      timeOut := getTickCount64() + waitTime;

      while (getTickCount64() < timeOut) do
        if findColors(TPA, 6247745, self.getBounds()) then
        begin
          if (length(TPA) = 3501) then
            exit(true);
        end;
    end;
    {$ENDIF}

    {*
    __isSlotActive
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotActive(geSlot: integer): boolean;

    Returns true if the slot **geSlot** is active. This is necessary
    because slots 3 to 8 are inactive when you are not a member.

    .. note::

        - by The Mayor
        - Last Updated: 10 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotActive(1));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotActive(geSlot: integer): boolean;
    var
      TPA: TPointArray;
      TBA : TBoxArray := self.__getSlotBoxes();
    begin
      findColors(TPA, 5063989, TBA[geSlot - 1]);
      result := length(TPA) < 5000;
    end;
    {$ENDIF}

    {*
    __isSlotEmpty
    -------------

    .. code-block:: pascal

        function TRSGrandExchange._isSlotEmpty(geSlot: integer): boolean;

    Returns true if the offer slot **geSlot** is empty and avaliable to use.

    .. note::

        - by The Mayor
        - Last Updated: 10 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotEmpty(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotEmpty(geSlot: integer): boolean;
    var
      TPA: TPointArray;
      TBA : TBoxArray := self.__getSlotBoxes();
    begin
      if self.__isSlotActive(geSlot) then
      begin
        findColors(TPA, 2694922, TBA[geSlot - 1]);
        result := length(TPA) > 10000;
      end;

      print('TRSGrandExchange._isSlotEmpty(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __isSlotComplete
    ----------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotComplete(geSlot: integer): boolean;

    Returns true if the offer is slot **geSlot** is complete.

    .. note::

        - by The Mayor
        - Last Updated: 15 January 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotComplete(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotComplete(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
    begin
      result := (countColorTolerance(1999423, TBA[geSlot - 1], 17) > 1450);
      print('TRSGrandExchange.isSlotComplete(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __isSlotAborted
    ---------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotAborted(geSlot: integer): boolean;

    Returns true if the offer is slot **geSlot** is aborted.

    .. note::

        - by The Mayor
        - Last Updated: 15 January 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotAborted(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotAborted(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
    begin
      result := (countColorTolerance(983163, TBA[geSlot - 1], 16) > 1700);
      print('TRSGrandExchange.isSlotAborted(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __isSlotBuying
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotBuying(geSlot: integer): boolean;

    Returns true if the offer is slot **geSlot** is currently buying.

    .. note::

        - by The Mayor
        - Last Updated: 31 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__isSlotBuying(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotBuying(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      TPA, TPA2: TPointArray;
    begin
      if self.__isSlotAborted(geSlot) or self.__isSlotComplete(geSlot)
        then exit(false);
      findColors(TPA, 2433824, TBA[geSlot - 1]);
      findColors(TPA2, 3815734, TBA[geSlot - 1]); // If hovering the box
      TPA.combine(TPA2);
      result := (length(TPA) > 10000);
      print('TRSGrandExchange.isSlotBuying(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __isSlotSelling
    ---------------

    .. code-block:: pascal

        function TRSGrandExchange.__isSlotSelling(geSlot: integer): boolean;

    Returns true if the offer is slot **geSlot** is currently selling.

    .. note::

        - by The Mayor
        - Last Updated: 31 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        writeLn(grandExchange._isSlotSelling(2));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__isSlotSelling(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      TPA, TPA2: TPointArray;
    begin
      if self.__isSlotAborted(geSlot) or self.__isSlotComplete(geSlot)
        then exit(false);
      findColors(TPA, 3287837, TBA[geSlot - 1]);
      findColors(TPA2, 4603955, TBA[geSlot - 1]); // If hovering the box
      TPA.combine(TPA2);
      result := (length(TPA) > 10000);
      print('TRSGrandExchange.isSlotSelling(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __findInsertionCursor
    ---------------------

    .. code-block:: pascal

        TRSGrandExchange.__findInsertionCursor(searchBox: TBox; waitTime: integer = 4000): boolean;

    Returns true is the insertion cursor is found inside **searchBox** within the **waitTime**
    *(default = 4000)* .

    .. note::

        - by Clarity
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        writeLn(grandExchange.__findInsertionCursor(b));

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__findInsertionCursor(searchBox: TBox; waitTime: integer = 4000): boolean;
    var
      timeOut: UInt64;
      TPA: TPointArray;
    begin
      timeOut := getTickCount64() + waitTime;

      while getTickCount64() < timeOut do
      begin
        findColors(TPA, 14606050, searchBox);
        if length(TPA) > 0 then
          exit(true);
      end;
    end;
    {$ENDIF}

    {*
    __enterQuantity
    ---------------

    .. code-block:: pascal

        procedure TRSGrandExchange.__enterQuantity(quantity: string);

    Returns true if it successfully enters the desired item quantity **quantity**
    into the input box.

    .. note::

        - by The Mayor
        - Last Updated: 19 November 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.__enterQuantity('1500'); // To buy/sell 1500 of an item
        grandExchange.__enterQuantity('all'); // To SELL all of the item

    *}

    {$IFNDEF CODEINSIGHT}
    procedure TRSGrandExchange.__enterQuantity(quantity: string);
    var
      i: integer;
      strArr : TStringArray;
      inputBox: TBoxArray;
      amountBox: TBoxArray := grid(4, 1, 34, 24, 44, 0, point(self.x1 + 84, self.y1 + 298));
    begin
      strArr := ['1', '10', '100', 'all'];

      i := strArr.returnInArray(lowercase(quantity));

      if inRange(i, 0, 3) then
        mouseBox(amountBox[i], MOUSE_LEFT)
      else
      begin
        inputBox := self.__getInputBoxes();
        mouseBox(inputBox[0], MOUSE_LEFT);
        if self.__findInsertionCursor(inputBox[0]) then
        begin
          typeSend(toStr(quantity), true);
          wait(randomRange(1000, 1500));
        end;
      end;
    end;
    {$ENDIF}

    {*
    __enterPrice
    ------------

    .. code-block:: pascal

        procedure TRSGrandExchange.__enterPrice(price: string);

    Returns true if it successfully enters the desired item price **price**
    into the input box.

    .. note::

        - by The Mayor
        - Last Updated: 19 November 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.__enterPrice('+5');    // Will click the +5% button
        grandExchange.__enterPrice('mid');   // Will leave at mid price
        grandExchange.__enterPrice('32500'); // Will type in 32500

    *}

    {$IFNDEF CODEINSIGHT}
    procedure TRSGrandExchange.__enterPrice(price: string);
    var
      i: integer;
      b: TBox;
      strArr : TStringArray;
      priceBox, inputBox: TBoxArray;
    begin
      priceBox := grid(3, 1, 34, 24, 45, 0, point(self.x1 + 367, self.y1 + 298));

      strArr := ['-5', 'mid', '+5'];

      i := strArr.returnInArray(lowercase(price));

      if (i = 0) or (i = 2) then
        mouseBox(priceBox[i], MOUSE_LEFT)
      else if (i <> 1) then  // Don't click mid button as it's set by default
      begin
        inputBox := self.__getInputBoxes();
        mouseBox(inputBox[1], MOUSE_LEFT);
        if self.__findInsertionCursor(inputBox[1]) then
        begin
          typeSend(toStr(price), true);
          wait(randomRange(1000, 1500));
        end;
      end;
    end;
    {$ENDIF}

    {*
    __enterName
    -----------

    .. code-block:: pascal

        procedure TRSGrandExchange.__enterName(itemName: string)

    Returns true if it successfully types the item name **itemName** into the search
    box and clicks it.

    .. note::

        - by The Mayor
        - Last Updated: 24 Decenber 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.__enterName('Swamp toad');

    *}

    {$IFNDEF CODEINSIGHT}
    function TRSGrandExchange.__enterName(itemName: string): boolean;
    const
      TESS_FILTER_GE_CHARS: TTesseractFilter = [4, 4, [False, 20, TM_Mean]];
    var
      i: integer;
      timeOut: UInt64;
      resultsBox: TBoxArray := grid(3, 2, 166, 49, 172, 55, point(self.x1 + 104, self.y1 + 405));
      resultsTextBox: TBoxArray := grid(3, 2, 122, 16, 172, 55, point(self.x1 + 121, self.y1 + 396));
      inputBox: TBoxArray;
    begin
      timeOut := getTickCount64() + randomRange(3000, 4000);
      inputBox := self.__getInputBoxes();

      if not self.__findInsertionCursor(inputBox[2]) then
        mouseBox(inputBox[2], MOUSE_LEFT);

      if self.__findInsertionCursor(inputBox[2]) then
        typeSend(itemName, false);

      if waitColorCountRange(9214319, 10, resultsTextBox[0], 5000, 10) then
        for i := 0 to 5 do
          if stringMatch(trim(tesseractGetText(resultsTextBox[i], TESS_FILTER_GE_CHARS)), itemName) >= 0.7 then
          begin
            mouseBox(resultsBox[i], MOUSE_LEFT);
            waitColorCountRange(16777215, 3, inputBox[2], 5000, 507, 509);
            exit(true);
          end;

      print('TRSGrandExchange.__enterName(): Found no matches for item: ' + itemName, TDebug.SUB);
    end;
    {$ENDIF}

    {*
    __returnToSummary
    -----------------

    .. code-block:: pascal

        procedure TRSGrandExchange._returnToSummary();

    If the GE offer screen or GE progress screen is currently open, it will click
    the back arrow to return to the summary screen.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.__returnToSummary();

    *}

    {$IFNDEF CODEINSIGHT}
    procedure TRSGrandExchange.__returnToSummary();
    var
      backButton: TPoint := [self.x1 + 33, self.y1 + 515];
      timeOut: UInt64;
    begin
      if self.__isOfferOpen() or self.__isProgressOpen() then
      begin
        print('TRSGrandExchange._returnToSummary(): returning to summary screen', TDebug.SUB);
        multiClick(backButton.rand(5), 30, 3);

        timeOut := getTickCount64() + randomRange(2500, 3500);
        while getTickCount64() < timeOut do
        begin
          if ((not self.__isOfferOpen()) and (not self.__isProgressOpen())) then
            break();
        end;
      end;
    end;
    {$ENDIF}

    (*
    collectSlot
    -----------

    .. code-block:: pascal

        function TRSGrandExchange.collectSlot(geSlot: integer): boolean;

    Returns true if it collects coins and/or items from the completed or aborted slot
    **geSlot** .

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.collectSlot(2);

    *)

    function TRSGrandExchange.collectSlot(geSlot: integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      collectBox: TBoxArray := grid(2, 1, 37, 32, 49, 0, point(self.x1 + 463, self.y1 + 385));
      timeOut: UInt64;
      i: integer;
    begin
      if not self.__isProgressOpen() then
      begin
        self.__returnToSummary();

        if (not self.__isSlotActive(geSlot)) or self.__isSlotEmpty(geSlot) then
        begin
          print('TRSGrandExchange.collectSlot(): Cannot collect as offer slot ' + toStr(geSlot) + ' is empty', TDebug.ERROR);
          exit(false);
        end;

        timeOut := getTickCount64() + randomRange(3000, 4000);

        repeat
          mouseBox(TBA[geSlot - 1], MOUSE_LEFT);
          if self.__isProgressOpen(2000 + random(500)) then
            break();
        until (getTickCount64() < timeOut);
      end;

      for i := high(collectBox) downto 0 do
        for  0 to 2 do // Attempt up to 3 times in case of lag
          if isItemIn(collectBox[i]) then
          begin
            mouseBox(collectBox[i], MOUSE_LEFT);
            wait(randomRange(750, 1250));

            if not self.__isProgressOpen() then
            begin
              result := true;
              break(1);
            end;
          end;

      self.__returnToSummary();

      print('TRSGrandExchange.collectSlot(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result));
    end;

    (*
    waitCollectSlot
    ---------------

    .. code-block:: pascal

        function TRSGrandExchange.waitCollectSlot(geSlot, maxTime: integer): boolean;

    Returns true if it collects coins and/or items from the completed or aborted slot
    **geSlot** . Waits up to **maxTime** for **geSlot** to finish selling.

    .. note::

        - by The Mayor
        - Last Updated: 12 March 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.waitCollectSlot(2, 60000); // Wait up to 1 minute to collect slot 2

    *)

    function TRSGrandExchange.waitCollectSlot(geSlot, maxTime: Integer): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      timeOut: UInt64;
    begin
      self.__returnToSummary();

      if (not self.__isSlotActive(geSlot)) or self.__isSlotEmpty(geSlot) then
      begin
        print('TRSGrandExchange.waitCollectSlot(): Cannot collect as offer slot ' + toStr(geSlot) + ' is empty', TDebug.ERROR);
        exit(false);
      end;

      timeOut := getTickCount64() + maxTime;

      while (getTickCount64() < timeOut) do
        if self.__isSlotComplete(geSlot) then
        begin
          if self.collectSlot(geSlot) then
          begin
            result := true;
            break();
          end;
        end else
          wait(500);

      print('TRSGrandExchange.waitCollectSlot(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result), TDebug.SUB);
    end;

    (*
    collectAllSlots
    ---------------

    .. code-block:: pascal

        procedure TRSGrandExchange.collectAllSlots(toInventory: boolean = true): boolean;

    Collects all coins and items to either the inventory or the bank depending on the
    **toInventory** paramter *(default = true)* via the collect buttons.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.collectAllSlots(false); // Collect all to bank

    *)

    procedure TRSGrandExchange.collectAllSlots(toInventory: boolean = true);
    const
      _OFFSET: TPoint = [653, 481];
    var
      TBA: TBoxArray;
    begin
      TBA := grid(1, 2, 180, 20, 0, 36, point(self.x1 + _OFFSET.x, self.y1 + _OFFSET.y));
      case ToInventory of
        true: multiClick(TBA[0].getMiddle().rand(5), 25, 3);
        false: multiClick(TBA[1].getMiddle().rand(5), 25, 3);
      end;
    end;

    (*
    abortSlot
    ---------

    .. code-block:: pascal

        function TRSGrandExchange.abortSlot(geSlot: integer; collect: boolean = true): boolean;

    Returns true if it aborts the slot **geSlot**. If the **collect** parameter is
    set to true it will also collect the items and gold from the aborted offer.

    .. note::

        - by The Mayor
        - Last Updated: 27 July 2015 by Clarity

    Example:

    .. code-block:: pascal

        grandExchange.abortSlot(2);
        grandExchange.abortSlot(2, false); // To leave items in the aborted offer slot

    *)

    function TRSGrandExchange.abortSlot(geSlot: integer; collect: boolean = true): boolean;
    var
      TBA: TBoxArray := self.__getSlotBoxes();
      abortButton: TPoint := [self.x1 + 402, self.y1 + 383];
      redBox: TBox := [self.x1 + 29, self.y1 + 404, self.x1 + 423, self.y1 + 410];
    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.abortSlot(): Cannot abort as the GE is not open', TDebug.ERROR);
        exit(false);
      end;

      self.__returnToSummary();

      if self.__isSlotEmpty(geSlot) or (not self.__isSlotActive(geSlot)) then
      begin
        print('TRSGrandExchange.abortSlot(): Cannot abort as offer slot ' + toStr(geSlot) + ' is empty', TDebug.ERROR);
        exit(false);
      end;

      if self.__isSlotAborted(geSlot) then
      begin
        print('TRSGrandExchange.abortSlot(): Offer slot ' + toStr(geSlot) + ' is already aborted');
        exit(true);
      end;

      if self.__isSlotComplete(geSlot) then
      begin
        print('TRSGrandExchange.abortSlot(): Cannot abort as offer slot ' + toStr(geSlot) + ' is already completed', TDebug.ERROR);
        exit(false);
      end;

      mouseBox(TBA[geSlot - 1], MOUSE_LEFT, MOUSE_ACCURATE);

      if self.__isProgressOpen(3000) then
      begin
        multiClick(abortButton.rand(5), 30, 3);
        waitColorCountRange(1048714, 5, redBox, 4000, 2000);

        if collect then
          result := self.collectSlot(geSlot)
        else
        begin
          result := self.__isSlotAborted(geSlot);
          self.__returnToSummary();
        end;
      end;

      print('TRSGrandExchange.abortSlot(): Slot ' + toStr(geSlot) + ' = ' + boolToStr(result));
    end;

    (*
    abortAllSlots
    -------------

    .. code-block:: pascal

        procedure TRSGrandExchange.abortAllSlots(collect: boolean);

    Aborts all slots that are not currently empty. If the **collect** parameter is
    set to true, it will also collect all items and gold.

    .. note::

        - by The Mayor
        - Last Updated: 12 March 2015 by The Mayor

    Example:

    .. code-block:: pascal

        grandExchange.abortAllSlots();

    *)

    procedure TRSGrandExchange.abortAllSlots(collect: boolean = true);
    var
      i: integer;
      TBA: TBoxArray := self.__getSlotBoxes();
    begin
      for i := 1 to length(TBA) do
        if (not self.__isSlotEmpty(i)) and self.__isSlotActive(i) then
          self.abortSlot(i, collect);
    end;

    (*
    getPercentDone
    --------------

    .. code-block:: pascal

        function TRSGrandExchange.getPercentDone(geSlot: integer): integer;

    Returns the percentage toward completion for the offer in **geSlot** .

    .. note::

        - by turpinator
        - Last Updated: 19 November 2015 by SlipperyPickle

    Example:

    .. code-block:: pascal

        var
          per: Integer;
        begin
          per := grandExchange.getPercentDone(2);
          writeLn('Slot 2 is ' + toStr(per) + ' percent complete!');
        end;

    *)

    function TRSGrandExchange.getPercentDone(geSlot: integer): integer;
    const
      BG_COLORS = [2565929, 2039584, 2237482, 1776673];
    var
      i, x, y: integer;
      TBA: TBoxArray := self.__getSlotBoxes();
    begin
      if self.__isSlotEmpty(geSlot) or (not self.__isSlotActive(geSlot)) then exit(-1);

      x := TBA[geSlot -1].x1 + 8;
      y := TBA[geSlot -1].y1 + 100;

      for result := 153 downto 1 do
        if (getColor(x + result, y) <> BG_COLORS[0]) and (getColor(x + result, y) <> BG_COLORS[1]) then
          exit(round(0.6897 * result));
    end;

    (*
    sellItem
    --------

    .. code-block:: pascal

        function TRSGrandExchange.sellItem(packSlot: integer; price, quantity: string; waitCollect: boolean = false; waitTime: integer = 10000): boolean;

    Returns true if it sells the item in backpack slot **packSlot** . If **waitCollect**
    is set to true, it will wait the specified waitTime for the offer to complete
    before collecting the resulting gold.

      The **price** parameter is a string - valid options are:

        * 'mid'             : GE mid price button
        * '-5'              : 5% below mid price button
        * '+5'              : 5% above mid price button
        * Any other number  : It will enter the price

      The **quantity** parameter is a string - valid options are:

        * '1'               : '1' button
        * '10'              : '10' button
        * '100'             : '100' button
        * 'all'             : 'All' button (Selling ONLY)
        * Any other number  : It will enter the quantity

    .. note::

        - by The Mayor
        - Last Updated: 13 November 2015 by SlipperyPickle

    Example:

    .. code-block:: pascal

          // Sell all of item in backPack slot 1 for mid price
        grandExchange.sellItem(1, 'mid', 'all');

          // To sell 100 of the item in backPack slot 1, for 1500gp each
        grandExchange.sellItem(1, '1500', '100');

          // As above, but waits up to 20 seconds for completion before collecting the coins
        grandExchange.sellItem(1, '1500', '100', true, 20000);

    *)

    function TRSGrandExchange.sellItem(packSlot: integer; price, quantity: string; waitCollect: boolean = false; waitTime: integer = 10000): boolean;
    var
      i, nextSlot: integer;
      confirm: TBox := [self.x1 + 218, self.y1 + 508, self.x1 + 345, self.y1 + 526];
    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.sellItem(): Cannot abort as the GE is not open', TDebug.ERROR);
        exit(false);
      end;

      self.__returnToSummary();

      for i := 1 to 8 do
        if self.__isSlotEmpty(i) and self.__isSlotActive(i) then
        begin
          nextSlot := i;
          break();
        end;

      if nextSlot < 1 then
      begin
        print('TRSGrandExchange.sellItem(): Cannot sell item as there are no empty offer slots', TDebug.ERROR);
        exit(false);
      end;

      if isItemIn(self.getPackSlotBox(packSlot)) then
        mouseBox(self.getPackSlotBox(packSlot), MOUSE_LEFT, MOUSE_ACCURATE)
      else
      begin
        print('TRSGrandExchange.sellItem(): No item in pack slot: ' + intToStr(packSlot), TDebug.ERROR);
        exit(false);
      end;

      if self.__isOfferOpen(3000) then
      begin
        self.__enterQuantity(quantity);
        self.__enterPrice(price);
        mouseBox(confirm, MOUSE_LEFT, MOUSE_ACCURATE);


        wait(randomRange(1000, 1500));
      end;

      result:= self.__isSlotSelling(nextSlot);
      print('TRSGrandExchange.sellItem(): ' + boolToStr(result), TDebug.SUB);

      if waitCollect then
        self.waitCollectSlot(nextSlot, waitTime);
    end;

    (*
    buyItem
    -------

    .. code-block:: pascal

        function TRSGrandExchange.buyItem(itemName, price, quantity: string; waitCollect: boolean = false; waitTime: integer = 10000): boolean;

    Returns true if it buys the item **itemName** . If **waitCollect** is set to true,
    it will wait the specified waitTime for the offer to complete before collecting
    the resulting gold and items.

      The **price** parameter is a string - valid options are:

        * 'mid'             : GE mid price button
        * '-5'              : 5% below mid price button
        * '+5'              : 5% above mid price button
        * Any other number  : It will enter the price

      The **quantity** parameter is a string - valid options are:

        * '1'               : '1' button
        * '10'              : '10' button
        * '100'             : '100' button
        * Any other number  : It will enter the quantity

    .. note::

        - by The Mayor
        - Last Updated: 13 November 2015 by SlipperyPickle

    Example:

    .. code-block:: pascal

          // To buy 10000 oak logs at 5% over the mid price
        grandExchange.buyItem('Oak log', '+5', '10000');

          // To buy 10000 oak logs for 150gp each
        grandExchange.buyItem('Oak log', '150', '10000');

          // As above, but waits up to 20 seconds for completion before collecting items
        grandExchange.buyItem('Oak log', '150', '10000', true, 20000);

    *)

    function TRSGrandExchange.buyItem(itemName, price, quantity: string; waitCollect: boolean = false; waitTime: integer = 10000): boolean;
    var
      i, nextSlot, x, y: integer;
      b: TBox;
      p: TPoint;
      TBA : TBoxArray := self.__getBuyBoxes();
      confirm: TBox := [self.x1 + 218, self.y1 + 508, self.x1 + 345, self.y1 + 526];
    begin
      if not self.isOpen() then
      begin
        print('TRSGrandExchange.sellItem(): Cannot abort as the GE is not open', TDebug.ERROR);
        exit(false);
      end;

      self.__returnToSummary();

      for i := 1 to 8 do
        if self.__isSlotEmpty(i) and self.__isSlotActive(i) then
        begin
          nextSlot := i;
          break();
        end;

      if nextSlot < 1 then
      begin
        print('TRSGrandExchange.sellItem(): Cannot sell item as there are no empty offer slots', TDebug.ERROR);
        exit(false);
      end;

      mouseBox(TBA[nextSlot - 1], MOUSE_LEFT, MOUSE_ACCURATE);

      if self.__isOfferOpen(3000) then
        if self.__enterName(itemName) then
        begin
          self.__enterQuantity(quantity);
          self.__enterPrice(price);
          mouseBox(confirm, MOUSE_LEFT);
          wait(randomRange(1000, 1500));
        end else
          self.__returnToSummary();


      result := self.__isSlotBuying(nextSlot);
      print('TRSGrandExchange.buyItem(): ' + boolToStr(result), TDebug.SUB);

      if waitCollect then
        self.waitCollectSlot(nextSlot, waitTime);
    end;

    (*
    getPrice
    --------

    .. code-block:: pascal

        TRSGrandExchange.getPrice(item: integer): integer;

    Returns the current market price of any item in the Grand Exchange. The **item**
    parameter must be the item's ID number.

    IDs can be found on the Grand Exchange website at the end of the URL. For example,
    the ID in the below URL is 2150 (Swamp toad)

    http://services.runescape.com/m=itemdb_rs/viewitem.ws?obj=2150

    .. note::

        - by The Mayor
        - Last Updated: 16 July 2015 by The Mayor

    Example:

    .. code-block:: pascal

        var
          toadPrice: Integer;
        begin
          toadPrice := grandExchange.getPrice(2150);  // The ID for Swamp toads
          profit := (toadPrice * toadsCollected);
        end;

    *)

    function TRSGrandExchange.getPrice(ID: integer): integer;
    var
      webPage: string;
      TSA: TStringArray;
    begin
      webPage := getPage('http://services.runescape.com/m=itemdb_rs/viewitem.ws?obj=' + toStr(ID));
      TSA := multiBetween(webPage, 'average30.push([new Date(',']);');

      if length(TSA) < 1 then
      begin
        print('TRSGrandExchange.getPrice(): Unable to retrieve price for ID: ' + toStr(ID), TDebug.ERROR);
        exit(-1);
      end;

      result := strToInt(Between('), ', ',', TSA[High(TSA)]));
      print('TRSGrandExchange.getPrice(' + toStr(ID) + '): ' + toStr(result));
    end;

    begin
      grandExchange.__init();
    end;

    {$f+}

  9. #59
    Join Date
    Jun 2016
    Location
    New Braunfels, Texas
    Posts
    21
    Mentioned
    1 Post(s)
    Quoted
    9 Post(s)

    Default

    oh my, this is neat.

  10. #60
    Join Date
    Dec 2013
    Location
    Pitcairn Island
    Posts
    288
    Mentioned
    20 Post(s)
    Quoted
    166 Post(s)

    Default

    Quote Originally Posted by SlipperyPickle View Post
    Had some time to work on the grand exchange library. Updated it yesterday to the github, but today I saw there were still a few minor bugs. I'm not really familiar with github so I'll upload it here. This version works like a charm. Perhaps the library can be updated after testing.

    This project is going pretty good right now. The grand exchange library is fixed. I rewrote the entire script. It's now much simpler and the script hasn't failed as of jet. For now this is an example of the script output:

    Code:
    fishing bait buy price: 5 sell price: 4
    Profit for fishing bait: 1
    willow logs buy price: 23 sell price: 22
    Profit for willow logs: 1
    raw herring buy price: 31 sell price: 17
    Profit for raw herring: 14
    feather buy price: 42 sell price: 41
    Profit for feather: 1
    maple logs buy price: 26 sell price: 24
    Profit for maple logs: 2
    Here is the code for the grand exchange library:
    You should make sure you change the 'updated date', so all the other users know if something has been worked on since an RS update (as all this is displayed in the docs: http://docs.villavu.com/srl-6/grandexchange.html). If you fix all that up, then send in a pull request, or post it here and I will forward it on.

  11. #61
    Join Date
    Sep 2014
    Location
    Netherlands
    Posts
    264
    Mentioned
    11 Post(s)
    Quoted
    130 Post(s)

    Default

    Quote Originally Posted by Laquisha View Post
    You should make sure you change the 'updated date', so all the other users know if something has been worked on since an RS update (as all this is displayed in the docs: http://docs.villavu.com/srl-6/grandexchange.html). If you fix all that up, then send in a pull request, or post it here and I will forward it on.
    Will try to do that today.

  12. #62
    Join Date
    Sep 2014
    Location
    Netherlands
    Posts
    264
    Mentioned
    11 Post(s)
    Quoted
    130 Post(s)

    Default

    Update:
    This project is now about 80% complete. I have made some great progress this week. The only part of the script that I can't get to work is the form to add items. But that's reserved for after my four week holiday.
    Current functions/procedures in my include for this project:

    Simba Code:
    { ============================================================================ }
    {  FUNCTIONS:   > TItems                                                       }
    {                 > TItems.create()                                            }
    {                 > TItems.buyCheck()                                          }
    {                 > TItems.getLimit()                                          }
    {               > TItemArray                                                   }
    {                 > TItemArray.checkSelling()                                  }
    {                 > TItemArray.takeBreak()                                     }
    {                 > TItemArray.append()                                        }
    {                 > TItemArray.returnInArray()                                 }
    {                 > TItemArray.buyList()                                       }
    {                 > TItemArray.saveData()                                      }
    {                 > TItemArray.loadData()                                      }
    {                 > TItemArray.updateItem                                      }
    {                 > TItemArray.deleteIndex()                                   }
    {                 > TItemArray.addIndex()                                      }
    {                 > TItemArray.swap()                                          }
    {                 > TItemArray.compare()                                       }
    {                 > TItemArray.quickSort()                                     }
    {                 > TItemArray.checkAll()                                      }
    {               > TRSGrandExchange                                             }
    {                 > TRSGrandExchange.open()                                    }
    {                 > TRSGrandExchange.getCurrentPrice()                         }
    {                 > TRSGrandExchange.openBox()                                 }
    {                 > TRSGrandExchange.getMoney()                                }
    { ============================================================================ }

    Current TODO list:
    • Main loop;
    • Form to choose items;
    • Paint;
    • Whatever I haven't thought about.

  13. #63
    Join Date
    Jun 2016
    Posts
    37
    Mentioned
    0 Post(s)
    Quoted
    7 Post(s)

    Default

    Show us some prog screens (if there's any) :P

    As a lazy person that really dislike sitting at GE that script sounds like heaven.

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

    Default

    Quote Originally Posted by SlipperyPickle View Post
    ...
    Have you been able to update the grand exchange include?

    *edit*
    I have been able to make some edits to the GE include, all the functions I use are now working. Haven't tested the others. But my scripts are able to resupply themselves.

  15. #65
    Join Date
    Apr 2017
    Posts
    10
    Mentioned
    0 Post(s)
    Quoted
    2 Post(s)

    Default

    Any progress?

  16. #66
    Join Date
    Dec 2016
    Posts
    31
    Mentioned
    0 Post(s)
    Quoted
    8 Post(s)

    Default

    Hey Pickle, any updates on this? I've been keeping an eye out for a release as I love flipping/merching but don't have time to do it all day.

Page 3 of 3 FirstFirst 123

Thread Information

Users Browsing this Thread

There are currently 3 users browsing this thread. (0 members and 3 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
  •