Package org.rsbot.script.methods

Source Code of org.rsbot.script.methods.Menu

package org.rsbot.script.methods;

import org.rsbot.client.MenuGroupNode;
import org.rsbot.client.MenuItemNode;
import org.rsbot.event.EventMulticaster;
import org.rsbot.event.listeners.PaintListener;
import org.rsbot.script.internal.wrappers.Deque;
import org.rsbot.script.internal.wrappers.Queue;

import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.regex.Pattern;

/**
* Context menu related operations.
*/
public class Menu extends MethodProvider {
  private static final Pattern HTML_TAG = Pattern.compile("(^[^<]+>|<[^>]+>|<[^>]+$)");

  private final Object menuCacheLock = new Object();

  private String[] menuOptionsCache = new String[0];
  private String[] menuActionsCache = new String[0];

  private boolean menuListenerStarted = false;

  Menu(final MethodContext ctx) {
    super(ctx);
  }

  /**
   * Clicks the menu option. Will left-click if the menu item is the first,
   * otherwise open menu and click the option.
   *
   * @param action The action (or action substring) to click.
   * @return <tt>true</tt> if the menu item was clicked; otherwise
   *         <tt>false</tt>.
   */
  public boolean click(final String action) {
    return click(action, null);
  }

  /**
   * Clicks the menu option. Will left-click if the menu item is the first,
   * otherwise open menu and click the option.
   *
   * @param action The action (or action substring) to click.
   * @param option The option (or option substring) of the action to click.
   * @return <tt>true</tt> if the menu item was clicked; otherwise
   *         <tt>false</tt>.
   */
  public boolean click(final String action, final String option) {
    final int idx = getIndex(action, option);
    if (!isOpen()) {
      if (idx == -1) {
        return false;
      }
      if (idx == 0) {
        methods.mouse.click(true);
        return true;
      }
      methods.mouse.click(false);
      return clickIndex(idx);
    } else if (idx == -1) {
      while (isOpen()) {
        methods.mouse.moveRandomly(750);
        sleep(random(100, 500));
      }
      return false;
    }
    return clickIndex(idx);
  }

  /**
   * Checks whether or not a given action (or action substring) is present in
   * the menu.
   *
   * @param action The action or action substring.
   * @return <tt>true</tt> if present, otherwise <tt>false</tt>.
   */
  public boolean contains(final String action) {
    return getIndex(action) != -1;
  }

  /**
   * Checks whether or not a given action with given option is present
   * in the menu.
   *
   * @param action The action or action substring.
   * @param option The option or option substring.
   * @return <tt>true</tt> if present, otherwise <tt>false</tt>.
   */
  public boolean contains(final String action, final String option) {
    return getIndex(action, option) != -1;
  }

  /**
   * Left clicks at the given index.
   *
   * @param i The index of the item.
   * @return <tt>true</tt> if the mouse was clicked; otherwise <tt>false</tt>.
   */
  public boolean clickIndex(final int i) {
    if (!isOpen()) {
      return false;
    }
    final String[] items = getItems();
    if (items.length <= i) {
      return false;
    }
    if (isCollapsed()) {
      final Queue<MenuGroupNode> groups = new Queue<MenuGroupNode>(methods.client.getCollapsedMenuItems());
      int idx = 0, mainIdx = 0;
      for (MenuGroupNode g = groups.getHead(); g != null; g = groups.getNext(), ++mainIdx) {
        final Queue<MenuItemNode> subItems = new Queue<MenuItemNode>(g.getItems());
        int subIdx = 0;
        for (MenuItemNode item = subItems.getHead(); item != null; item = subItems.getNext(), ++subIdx) {
          if (idx++ == i) {
            return subIdx == 0 ? clickMain(items, mainIdx) : clickSub(items, mainIdx, subIdx);
          }
        }
      }
      return false;
    } else {
      return clickMain(items, i);
    }
  }

  private boolean clickMain(final String[] items, final int i) {
    final Point menu = getLocation();
    final int xOff = random(4, items[i].length() * 4);
    final int yOff = 21 + 16 * i + random(3, 12);
    methods.mouse.move(menu.x + xOff, menu.y + yOff, 2, 2);
    if (isOpen()) {
      methods.mouse.click(true);
      return true;
    }
    return false;
  }

  private boolean clickSub(final String[] items, final int mIdx, final int sIdx) {
    final Point menuLoc = getLocation();
    int x = random(4, items[mIdx].length() * 4);
    int y = 21 + 16 * mIdx + random(3, 12);
    methods.mouse.move(menuLoc.x + x, menuLoc.y + y, 2, 2);
    sleep(random(125, 150));
    if (isOpen()) {
      final Point subLoc = getSubMenuLocation();
      final Point start = methods.mouse.getLocation();
      int subOff = subLoc.x - start.x;
      int moves = random(subOff, subOff + random(0, items[sIdx].length() * 2));
      x = random(4, items[sIdx].length() * 4);
      if (subOff > 0) {
        final int speed = methods.mouse.getSpeed() / 3;
        for (int c = 0; c < moves; c++) {
          methods.mouse.hop(start.x + c, start.y);
          sleep(random(speed / 2, speed));
        }
      } else {
        methods.mouse.move(subLoc.x + x, methods.mouse.getLocation().y, 2, 0);
      }
      sleep(random(125, 150));
      if (isOpen()) {
        y = 16 * sIdx + random(3, 12) + 21;
        methods.mouse.move(subLoc.x + x, subLoc.y + y, 0, 2);
        sleep(random(125, 150));
        if (isOpen()) {
          methods.mouse.click(true);
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Returns an array of the first parts of each item in the current menu
   * context.
   *
   * @return The first half. "Walk here", "Trade with", "Follow".
   */
  public String[] getActions() {
    return getMenuItemPart(true);
  }

  /**
   * Returns the index in the menu for a given action. Starts at 0.
   *
   * @param action The action that you want the index of.
   * @return The index of the given option in the context menu; otherwise -1.
   */
  public int getIndex(String action) {
    action = action.toLowerCase();
    final String[] items = getItems();
    for (int i = 0; i < items.length; i++) {
      if (items[i].toLowerCase().contains(action)) {
        return i;
      }
    }
    return -1;
  }

  /**
   * Returns the index in the menu for a given action with a given option.
   * Starts at 0.
   *
   * @param action The action of the menu entry of which you want the index.
   * @param option The option of the menu entry of which you want the index.
   *               If option is null, operates like getIndex(String action).
   * @return The index of the given option in the context menu; otherwise -1.
   */
  public int getIndex(String action, String option) {
    if (option == null) {
      return getIndex(action);
    }
    action = action.toLowerCase();
    option = option.toLowerCase();
    final String[] actions = getActions();
    final String[] options = getOptions();
    /* Throw exception if lengths unequal? */
    for (int i = 0; i < Math.min(actions.length, options.length); i++) {
      if (actions[i].toLowerCase().contains(action) && options[i].toLowerCase().contains(option)) {
        return i;
      }
    }
    return -1;
  }

  /**
   * Returns an array of each item in the current menu context.
   *
   * @return First half + second half. As displayed in the game.
   */
  public String[] getItems() {
    String[] options;
    String[] actions;

    synchronized (menuCacheLock) {
      options = menuOptionsCache;
      actions = menuActionsCache;
    }

    final ArrayList<String> output = new ArrayList<String>();

    final int len = Math.min(options.length, actions.length);
    for (int i = 0; i < len; i++) {
      final String option = options[i];
      final String action = actions[i];
      if (option != null && action != null) {
        final String text = action + " " + option;
        output.add(text.trim());
      }
    }

    if (output.size() > 1 && output.get(0).equals("Cancel") && !methods.menu.isCollapsed()) {
      Collections.reverse(output);
    }
    if (output.size() > 1 && output.get(output.size() - 1).equals("Cancel") && isCollapsed()) {
      Collections.reverse(output);
    }

    return output.toArray(new String[output.size()]);
  }

  /**
   * Returns the menu's location.
   *
   * @return The screen space point if the menu is open; otherwise null.
   */
  public Point getLocation() {
    if (isOpen()) {
      return new Point(methods.client.getMenuX(), methods.client.getMenuY());
    }
    return null;
  }

  private String[] getMenuItemPart(final boolean firstPart) {
    final LinkedList<String> itemsList = new LinkedList<String>();
    String action = null, lAction = null;
    if (isCollapsed()) {
      final Queue<MenuGroupNode> menu = new Queue<MenuGroupNode>(methods.client.getCollapsedMenuItems());
      for (MenuGroupNode mgn = menu.getHead(); mgn != null; mgn = menu.getNext()) {
        final Queue<MenuItemNode> submenu = new Queue<MenuItemNode>(mgn.getItems());
        for (MenuItemNode min = submenu.getHead(); min != null; min = submenu.getNext()) {
          itemsList.addLast(firstPart ? min.getAction() : min.getOption());
          lAction = min.getAction();
          if (action == null) {
            action = lAction;
          }
        }
      }
    } else {
      try {
        final Deque<MenuItemNode> menu = new Deque<MenuItemNode>(methods.client.getMenuItems());
        for (MenuItemNode min = menu.getHead(); min != null; min = menu.getNext()) {
          itemsList.addLast(firstPart ? min.getAction() : min.getOption());
          lAction = min.getAction();
          if (action == null) {
            action = lAction;
          }
        }
      } catch (final NullPointerException ignored) {
        return getMenuItemPart(firstPart);
      }
    }
    final String[] items = itemsList.toArray(new String[itemsList.size()]);
    final LinkedList<String> output = new LinkedList<String>();
    for (int i = items.length - 1; i >= 0; i--) {
      final String item = items[i];
      output.add(item == null ? "" : stripFormatting(item));
    }
    action = action == null ? "" : stripFormatting(action);
    if (output.size() > 1 && action != null && action.equals("Cancel") && !methods.menu.isCollapsed()) {
      Collections.reverse(output);
    }
    if (output.size() > 1 && lAction != null && lAction.equals("Cancel") && isCollapsed()) {
      Collections.reverse(output);
    }
    return output.toArray(new String[output.size()]);
  }

  /**
   * Returns an array of the second parts of each item in the current menu
   * context.
   *
   * @return The second half, (Use <tt>Bank</tt>).
   */
  public String[] getOptions() {
    return getMenuItemPart(false);
  }

  /**
   * Returns the menu's item count.
   *
   * @return The menu size.
   */
  public int getSize() {
    return getItems().length;
  }

  /**
   * Returns the submenu's location.
   *
   * @return The screen space point of the submenu if the menu is collapsed; otherwise null.
   */
  public Point getSubMenuLocation() {
    if (isCollapsed()) {
      return new Point(methods.client.getSubMenuX() + 4, methods.client.getSubMenuY() + 4);
    }
    return null;
  }

  /**
   * Checks whether or not the menu is collapsed.
   *
   * @return <tt>true</tt> if the menu is collapsed; otherwise <tt>false</tt>.
   */
  public boolean isCollapsed() {
    return methods.client.isMenuCollapsed();
  }

  /**
   * Checks whether or not the menu is open.
   *
   * @return <tt>true</tt> if the menu is open; otherwise <tt>false</tt>.
   */
  public boolean isOpen() {
    return methods.client.isMenuOpen();
  }

  /**
   * For internal use only: sets up the menuListener.
   */
  public void setupListener() {
    if (menuListenerStarted) {
      return;
    }
    menuListenerStarted = true;
    methods.bot.getEventManager().addListener(new PaintListener() {
      public void onRepaint(final Graphics g) {
        synchronized (menuCacheLock) {
          menuOptionsCache = getOptions();
          menuActionsCache = getActions();
        }
      }
    }, EventMulticaster.PAINT_EVENT);
  }

  /**
   * Strips HTML tags.
   *
   * @param input The string you want to parse.
   * @return The parsed {@code String}.
   */
  private String stripFormatting(final String input) {
    return HTML_TAG.matcher(input).replaceAll("");
  }
}
TOP

Related Classes of org.rsbot.script.methods.Menu

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.