Equinox

f2pMaples.java

Mar 12th, 2011
493
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 91.21 KB | None | 0 0
  1. import java.awt.Color;
  2. import java.awt.Dimension;
  3. import java.awt.Font;
  4. import java.awt.Graphics;
  5. import java.awt.Graphics2D;
  6. import java.awt.Image;
  7. import java.awt.Point;
  8. import java.awt.Polygon;
  9. import java.awt.Rectangle;
  10. import java.awt.event.MouseEvent;
  11. import java.awt.event.MouseListener;
  12. import java.awt.event.MouseMotionListener;
  13. import java.awt.font.FontRenderContext;
  14. import java.awt.geom.AffineTransform;
  15. import java.awt.geom.RoundRectangle2D;
  16. import java.awt.image.BufferedImage;
  17. import java.io.File;
  18. import java.io.IOException;
  19. import java.lang.reflect.Method;
  20. import java.net.MalformedURLException;
  21. import java.net.URL;
  22. import java.text.DecimalFormat;
  23. import java.util.ArrayList;
  24. import java.util.Arrays;
  25. import java.util.EnumSet;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.logging.Logger;
  30.  
  31. import javax.imageio.ImageIO;
  32. import javax.swing.JOptionPane;
  33.  
  34. import org.rsbot.event.listeners.PaintListener;
  35. import org.rsbot.script.Script;
  36. import org.rsbot.script.ScriptManifest;
  37. import org.rsbot.script.methods.Equipment;
  38. import org.rsbot.script.methods.Game;
  39. import org.rsbot.script.methods.GrandExchange;
  40. import org.rsbot.script.methods.GrandExchange.GEItem;
  41. import org.rsbot.script.methods.Skills;
  42. import org.rsbot.script.wrappers.RSComponent;
  43. import org.rsbot.script.wrappers.RSInterface;
  44. import org.rsbot.script.wrappers.RSModel;
  45. import org.rsbot.script.wrappers.RSNPC;
  46. import org.rsbot.script.wrappers.RSObject;
  47. import org.rsbot.script.wrappers.RSPath.TraversalOption;
  48. import org.rsbot.script.wrappers.RSTile;
  49. import org.rsbot.util.GlobalConfiguration;
  50.  
  51. @ScriptManifest(authors = "Magikarp", name = "f2pMaples", version = 1.0, description = "Chops maples in daemonhiem")
  52. public class f2pMaples extends Script implements PaintListener, MouseListener,
  53.         MouseMotionListener {
  54.  
  55.     // Item IDs
  56.     /**
  57.      * Bronze, iron, steel, black, mith, addy, rune
  58.      */
  59.     final int[] hatchetIDs = { 1351, 1349, 1353, 1361, 1355, 1357, 1359 };
  60.     final static int logID = 1517;
  61.     final int ringID = 15707;
  62.  
  63.     // Object IDs
  64.     final int treeID = 1307;
  65.     final int treeChoppedID = 7400;
  66.     final int portalInID = 52861;
  67.  
  68.     // NPC IDs
  69.     final int bankerID = 9710;
  70.  
  71.     // Animation IDs
  72.     final int idleAnim = -1;
  73.     final int[] choppingAnims = { 879, 877, 875, 873, 871, 869, 867 };
  74.     final int portalInAnim = 13288;
  75.     final int teleLeavingAnim = 13652;
  76.     final int teleArrivingAnim = 13654;
  77.  
  78.     // Paths
  79.     final RSTile[][] meshToBank = {
  80.             { new RSTile(3453, 3897), new RSTile(3447, 3897) },
  81.             { new RSTile(3448, 3702), new RSTile(3451, 3702) },
  82.             { new RSTile(3451, 3707), new RSTile(3448, 3707) },
  83.             { new RSTile(3448, 3711), new RSTile(3451, 3711) },
  84.             { new RSTile(3451, 3716), new RSTile(3448, 3716) },
  85.             { new RSTile(3448, 3719), new RSTile(3449, 3719),
  86.                     new RSTile(3449, 3718) } };
  87.     final RSTile[][] meshToTrees = {
  88.             { new RSTile(3448, 3720), new RSTile(3452, 3720) },
  89.             { new RSTile(3451, 3717), new RSTile(3448, 3717) },
  90.             { new RSTile(3448, 3711), new RSTile(3451, 3711) },
  91.             { new RSTile(3450, 3707), new RSTile(3449, 3707) },
  92.             { new RSTile(3449, 3703), new RSTile(3450, 3703) },
  93.             { new RSTile(3452, 3701), new RSTile(3449, 3696) },
  94.             { new RSTile(3456, 3692), new RSTile(3455, 3702) },
  95.             { new RSTile(3466, 3704), new RSTile(3463, 3693) },
  96.             { new RSTile(3470, 3694), new RSTile(3472, 3694) },
  97.             { new RSTile(3472, 3690), new RSTile(3470, 3690) },
  98.             { new RSTile(3473, 3684), new RSTile(3474, 3688) },
  99.             { new RSTile(3482, 3688), new RSTile(3482, 3686) },
  100.             { new RSTile(3486, 3686), new RSTile(3486, 3688) },
  101.             { new RSTile(3490, 3695), new RSTile(3492, 3689) },
  102.             { new RSTile(3494, 3693), new RSTile(3494, 3695) },
  103.             { new RSTile(3498, 3695), new RSTile(3498, 3693) },
  104.             { new RSTile(3500, 3690), new RSTile(3503, 3691) },
  105.             { new RSTile(3500, 3682), new RSTile(3496, 3683) },
  106.             { new RSTile(3491, 3677), new RSTile(3494, 3676) },
  107.             { new RSTile(3498, 3668), new RSTile(3490, 3667) },
  108.             { new RSTile(3498, 3660), new RSTile(3499, 3666) },
  109.             { new RSTile(3506, 3667), new RSTile(3505, 3659) },
  110.             { new RSTile(3513, 3665), new RSTile(3513, 3667) } };
  111.     final MeshPath pathToBank = new MeshPath(meshToBank);
  112.     final MeshPath pathToTrees = new MeshPath(meshToTrees);
  113.  
  114.     // Depricated
  115.     // Areas
  116.     // RSArea bankArea = new RSArea(3445, 3717, 3455, 3723);
  117.     // RSArea maplesArea = new RSArea(3490, 3611, 3508, 3638);
  118.     // RSArea portalArea = new RSArea(3509, 3664, 3513, 3669);
  119.  
  120.     // States
  121.     State currentState;
  122.     String status;
  123.     int mayAntiBan = 0;
  124.  
  125.     // Fixing spastic clicking
  126.     boolean clickedPortal = false;
  127.     boolean clickedTree = false;
  128.     int treeCounter = 0;
  129.     int portalCounter = 0;
  130.  
  131.     // For paint
  132.     final double version = getClass().getAnnotation(ScriptManifest.class)
  133.             .version();
  134.     final String author = PaintFormatter.formatList(getClass().getAnnotation(
  135.             ScriptManifest.class).authors());
  136.     final String name = getClass().getAnnotation(ScriptManifest.class).name();
  137.     public PaintInterface Paint;
  138.     final String baseURL = "http://equinox-scripts.web44.net/scripts/f2pMaples";
  139.  
  140.     // The main four methods
  141.     public void onRepaint(Graphics render) {
  142.         Graphics2D g = (Graphics2D) render;
  143.         try {
  144.             if (game.isLoggedIn()) {
  145.                 Paint.render(g);
  146.                 g.setColor(Color.RED);
  147.                 g.drawLine(0, (int) (mouse.getLocation().getY()), 800,
  148.                         (int) (mouse.getLocation().getY()));
  149.                 g.drawLine((int) (mouse.getLocation().getX()), 0,
  150.                         (int) (mouse.getLocation().getX()), 800);
  151.                 pathToTrees.paintMesh(g);
  152.                 if (currentState.equals(State.WalkingToBank))
  153.                     pathToBank.paintSmoothPath(g);
  154.                 if (currentState.equals(State.WalkingToTrees))
  155.                     pathToTrees.paintSmoothPath(g);
  156.             }
  157.  
  158.         } catch (Exception e) {
  159.             // log(e.getMessage());
  160.         }
  161.     }
  162.  
  163.     public boolean onStart() {
  164.         if (!game.isFixed()) {
  165.             log.severe("You must use fixed screen mode to use this script.");
  166.             return false;
  167.         }
  168.         if (game.isLoggedIn()) {
  169.             // Set up script...
  170.             log.info("Welcome to f2pMaples");
  171.             camera.setPitch(random(0, 10));
  172.             mouse.setSpeed(random(7, 9));
  173.             boolean hasHatchet = false;
  174.             boolean hasRing = false;
  175.             game.openTab(Game.TAB_EQUIPMENT);
  176.             log.info("Equipment Check: Checking for a hatchet...");
  177.             if (equipment.containsOneOf(hatchetIDs)) {
  178.                 hasHatchet = true;
  179.             }
  180.             log.info("Equipment Check: Checking for a Ring of Kinship...");
  181.             if (equipment.containsOneOf(ringID)) {
  182.                 hasRing = true;
  183.             }
  184.             game.openTab(Game.TAB_INVENTORY);
  185.             if (inventory.containsOneOf(hatchetIDs) && !hasHatchet) {
  186.                 hasHatchet = true;
  187.             }
  188.             if (!hasHatchet) {
  189.                 log.severe("You need a hatchet for this script to run!");
  190.                 log.severe("Have one in your inventory or equiped.");
  191.                 log.severe("Must be bronze, iron, steel, black, mith, addy, or rune.");
  192.                 return false;
  193.             }
  194.             if (!hasRing) {
  195.                 log.severe("You need a Ring of Kinship equiped for this script to run!");
  196.                 return false;
  197.             }
  198.  
  199.             // Start Equinox_
  200.             Paint = new PaintInterface(this, log, Skills.WOODCUTTING);
  201.             new DataLoader(this);
  202.             // End Equinox_
  203.  
  204.         } else {
  205.             log.info("Please log in before starting the script.");
  206.             return false;
  207.         }
  208.         log.info("Anitban: Antiban sleep time -.-");
  209.         sleep(2000, 5000);
  210.         log.info("Antiban: Done");
  211.         log.info("Let's get on with it ");
  212.         return true;
  213.     }
  214.  
  215.     public void onFinish() {
  216.         log.info("Thanks for using f2pMaples");
  217.         Paint.paintMenu.saveProggie();
  218.         mouse.moveOffScreen();
  219.     }
  220.  
  221.     public int loop() {
  222.         antiBan();
  223.         try {
  224.             currentState = getState();
  225.             switch (currentState) {
  226.             case Banking:
  227.                 mayAntiBan = 0;
  228.                 status = "Banking";
  229.                 if (pathToTrees.hasPath())
  230.                     pathToTrees.clearPath();
  231.                 bank();
  232.                 break;
  233.             case WalkingToTrees:
  234.                 mayAntiBan = 1;
  235.                 status = "Walking to trees";
  236.                 if (!pathToTrees.hasPath())
  237.                     pathToTrees.findPath();
  238.                 pathToTrees.traverse();
  239.                 break;
  240.             case EnteringTrees:
  241.                 mayAntiBan = 0;
  242.                 status = "Entering tree area";
  243.                 RSObject portal = objects.getNearest(portalInID);
  244.                 if (!portal.isOnScreen()) {
  245.                     walking.walkTileMM(portal.getArea().getNearestTile(
  246.                             getMyPlayer().getLocation()));
  247.                 } else {
  248.                     if (!clickedPortal) {
  249.                         clickObject(portal, "Enter", true);
  250.                         clickedPortal = true;
  251.                         portalCounter = 0;
  252.                     }
  253.                     if (clickedPortal && atPortal() && portalCounter < 5
  254.                             && getMyPlayer().getAnimation() == idleAnim) {
  255.                         portalCounter++;
  256.                     }
  257.                     if (clickedPortal && atPortal() && portalCounter >= 5) {
  258.                         clickedPortal = false;
  259.                         portalCounter = 0;
  260.                     }
  261.                 }
  262.                 break;
  263.             case Chopping:
  264.                 mayAntiBan = 2;
  265.                 status = "Chopping trees";
  266.                 if (clickedPortal)
  267.                     clickedPortal = false;
  268.                 if (pathToBank.hasPath())
  269.                     pathToBank.clearPath();
  270.                 cutTree();
  271.                 break;
  272.             case WaitingForTrees:
  273.                 mayAntiBan = 2;
  274.                 status = "Waiting for trees to respawn";
  275.                 break;
  276.             case TeleRinging:
  277.                 mayAntiBan = 0;
  278.                 status = "Using Ring of Kinship";
  279.                 sleep(1000, 2000);
  280.                 teleRing();
  281.                 break;
  282.             case WalkingToBank:
  283.                 mayAntiBan = 1;
  284.                 status = "Walking to bank";
  285.                 if (!pathToBank.hasPath())
  286.                     pathToBank.findPath();
  287.                 pathToBank.traverse();
  288.                 break;
  289.             case Lost:
  290.                 mayAntiBan = 0;
  291.                 int angle = camera.getAngle() + random(-45, 45);
  292.                 if (angle < 0)
  293.                     angle = random(0, 10);
  294.                 if (angle > 359)
  295.                     angle = random(0, 10);
  296.                 char whichDir = 37;
  297.                 if (random(0, 100) < 50)
  298.                     whichDir = 39;
  299.                 keyboard.pressKey(whichDir);
  300.                 sleep(random(98, 1302));
  301.                 keyboard.releaseKey(whichDir);
  302.                 status = "Currently lost";
  303.                 sleep(1000, 2000);
  304.             }
  305.         } catch (Exception e) {
  306.             // e.printStackTrace();
  307.         }
  308.         // log(status);
  309.         if (interfaces.canContinue())
  310.             sleep(1000, 2000);
  311.         interfaces.clickContinue();
  312.         return random(100, 125);
  313.     }
  314.  
  315.     // States 'n stuff
  316.     /**
  317.      * Represents the player's current state
  318.      *
  319.      * @author Magikarp
  320.      */
  321.     private enum State {
  322.         Banking, WalkingToTrees, EnteringTrees, Chopping, WaitingForTrees, TeleRinging, WalkingToBank, Lost
  323.     }
  324.  
  325.     /**
  326.      * Return the player's current state
  327.      *
  328.      * @author Magikarp
  329.      * @return the player's current state
  330.      */
  331.     private State getState() {
  332.         if (atBank() && inventory.contains(logID)) {
  333.             return State.Banking;
  334.         } else if (!bank.isOpen() && !inventory.contains(logID) && !atPortal()
  335.                 && !atTrees()) {
  336.             return State.WalkingToTrees;
  337.         } else if (atPortal()) {
  338.             return State.EnteringTrees;
  339.         } else if (atTrees() && !inventory.isFull()) {
  340.             return State.Chopping;
  341.         } else if (!atTrees() && nearStumps() && !inventory.isFull()) {
  342.             return State.WaitingForTrees;
  343.         } else if (atTrees() && inventory.isFull()) {
  344.             return State.TeleRinging;
  345.         } else if (!atTrees() && !atBank() && inventory.isFull()) {
  346.             return State.WalkingToBank;
  347.         } else {
  348.             return State.Lost;
  349.         }
  350.     }
  351.  
  352.     // Actually do stuff
  353.     /**
  354.      * Clicks and starts to chop a tree if the player is not already
  355.      *
  356.      * @author Magikarp
  357.      */
  358.     private void cutTree() {
  359.         RSObject tree = objects.getNearest(treeID);
  360.         if (tree != null && calc.tileOnMap(tree.getLocation())) {
  361.             if (!tree.isOnScreen()) {
  362.                 walking.walkTileMM(tree.getLocation());
  363.                 for (byte b = 0; b < 25; b++) {
  364.                     if (tree.isOnScreen())
  365.                         break;
  366.                     else
  367.                         sleep(50, 75);
  368.                 }
  369.             }
  370.             if (getMyPlayer().getAnimation() == idleAnim && !inventory.isFull()
  371.                     && tree.isOnScreen() && !clickedTree
  372.                     && !getMyPlayer().isMoving()) {
  373.                 sleep(500, 1000);
  374.                 clickObject(tree, "Chop", true);
  375.                 clickedTree = true;
  376.                 treeCounter = 0;
  377.             } else if (Arrays.asList(choppingAnims).contains(
  378.                     getMyPlayer().getAnimation())
  379.                     && clickedTree) {
  380.                 clickedTree = false;
  381.                 treeCounter = 0;
  382.             } else if (getMyPlayer().getAnimation() == idleAnim && clickedTree
  383.                     && treeCounter < 5) {
  384.                 treeCounter++;
  385.             } else if (getMyPlayer().getAnimation() == idleAnim && clickedTree
  386.                     && treeCounter >= 5) {
  387.                 treeCounter = 0;
  388.                 clickedTree = false;
  389.             }
  390.         }
  391.     }
  392.  
  393.     /**
  394.      * Activates the Daemonhiem teleport from the Ring of Kinship
  395.      *
  396.      * @author Magikarp
  397.      */
  398.     public void teleRing() /* throws Exception */{
  399.         if (getMyPlayer().getAnimation() != teleLeavingAnim) {
  400.             game.openTab(Game.TAB_EQUIPMENT, false);
  401.             if (equipment.getItem(Equipment.RING).doAction("Teleport")) {
  402.                 sleep(1000, 2000);
  403.                 while (getMyPlayer().getAnimation() != idleAnim) {
  404.                     sleep(100, 115);
  405.                 }
  406.                 game.openTab(Game.TAB_INVENTORY);
  407.             } else {
  408.                 log("Didn't use ring, teleport failed. Trying again.");
  409.             }
  410.         }
  411.     }
  412.  
  413.     // Bank bank bank...
  414.     /**
  415.      * Open bank, deposit, close bank
  416.      *
  417.      * @author Magikarp
  418.      */
  419.     private void bank() {
  420.         if (bank.open()) {
  421.             sleep(250, 500);
  422.             depositBank();
  423.             sleep(250, 500);
  424.             bank.close();
  425.         } else {
  426.             log("Didn't use bank, banking failed.  Trying again.");
  427.         }
  428.     }
  429.  
  430.     /**
  431.      * Deposit only logs
  432.      *
  433.      * @author Magikarp
  434.      */
  435.     private void depositBank() {
  436.         if (bank.isOpen() && inventory.contains(logID)) {
  437.             sleep(250, 500);
  438.             Paint.logsChopped += inventory.getCount(logID);
  439.             if (inventory.containsOneOf(hatchetIDs)) {
  440.                 bank.depositAllExcept(hatchetIDs);
  441.             } else
  442.                 bank.depositAll();
  443.         }
  444.     }
  445.  
  446.     // Where am I?
  447.     /**
  448.      * Checks if the player is at the bank
  449.      *
  450.      * @author Magikarp
  451.      * @return whether the player is at the bank
  452.      */
  453.     private boolean atBank() {
  454.         RSNPC banker = npcs.getNearest(bankerID);
  455.         return banker != null ? banker.isOnScreen() : false;
  456.     }
  457.  
  458.     /**
  459.      * Checks if the player is at the portal
  460.      *
  461.      * @author Magikarp
  462.      * @return whether the player is at the portal
  463.      */
  464.     private boolean atPortal() {
  465.         RSObject portal = objects.getNearest(portalInID);
  466.         return portal != null ? portal.isOnScreen() : false;
  467.     }
  468.  
  469.     /**
  470.      * Checks if the player is at the trees
  471.      *
  472.      * @author Magikarp
  473.      * @return whether the player is at the trees
  474.      */
  475.     private boolean atTrees() {
  476.         RSObject tree = objects.getNearest(treeID);
  477.         return tree != null ? calc.tileOnMap(tree.getLocation()) : false;
  478.     }
  479.  
  480.     /**
  481.      * Checks if the player is at the trees, but checks for stumps instead of
  482.      * trees.
  483.      *
  484.      * @author Magikarp
  485.      * @return whether the player is at the trees w/ stumps
  486.      */
  487.     private boolean nearStumps() {
  488.         RSObject stump = objects.getNearest(treeChoppedID);
  489.         return stump != null ? calc.tileOnMap(stump.getLocation()) : false;
  490.     }
  491.  
  492.     // StartEquinox_
  493.     /**
  494.      * Use these enums to define the type of path <br />
  495.      * ALL_Center: All points are near the middle of the lines <br />
  496.      * Full: Points can be anywhere on the line<br />
  497.      * WEIGHT_CENTER: Weighted to center, possibility of being on sides, but
  498.      * lower
  499.      *
  500.      * @author Equinox_
  501.      *
  502.      */
  503.     enum MeshPathType {
  504.         ALL_CENTER, FULL, WEIGHT_CENTER
  505.     }
  506.  
  507.     /**
  508.      * A class that will take a specified mesh, generate a path through it, then
  509.      * round the path off with Bezier curves.
  510.      *
  511.      * @author Equinox_
  512.      *
  513.      */
  514.     public class MeshPath {
  515.         private final Color MESH_FILL = new Color(0.5f, 0.5f, 0.5f, 0.75f);
  516.         private final Color MESH_BORDER = new Color(0.75f, 0.75f, 0.75f, 0.75f);
  517.         private final Color PATH_COLOR = new Color(0f, 1f, 0f, 1f);
  518.         private final Color SMOOTH_PATH_COLOR = new Color(0f, 0f, 1f, 1f);
  519.         private final Color SUBDIVIDED_PATH_COLOR = new Color(1f, 0f, 1f, 1f);
  520.  
  521.         private List<RSTile[]> mesh = new ArrayList<RSTile[]>();
  522.         private List<RSTile> blockPath = new ArrayList<RSTile>();
  523.         private List<RSTile> smoothPath = new ArrayList<RSTile>();
  524.         private boolean end;
  525.         private List<RSTile> subdividedPath = new ArrayList<RSTile>();
  526.  
  527.         /**
  528.          * Creates a MeshPath with a blank mesh
  529.          */
  530.         public MeshPath() {
  531.  
  532.         }
  533.  
  534.         /**
  535.          * Creates a MeshPath using the provided mesh
  536.          *
  537.          * @param mesh
  538.          *            as RSTile[][]
  539.          */
  540.         public MeshPath(RSTile[][] mesh) {
  541.             setMesh(mesh);
  542.         }
  543.  
  544.         /**
  545.          * Adds a line to the mesh with the given tiles
  546.          *
  547.          * @param tiles
  548.          *            the RSTiles making up the line
  549.          */
  550.         public void addLine(RSTile... tiles) {
  551.             mesh.add(tiles);
  552.         }
  553.  
  554.         /**
  555.          * Gets the number of lines in the mesh
  556.          *
  557.          * @return int size
  558.          */
  559.         public int meshSize() {
  560.             return mesh.size();
  561.         }
  562.  
  563.         /**
  564.          * Adds all the lines of a specified mesh to the current mesh.
  565.          *
  566.          * @param mesh
  567.          *            as RSTile[][]
  568.          */
  569.         public void addMesh(RSTile[][] mesh) {
  570.             for (RSTile[] line : mesh)
  571.                 this.mesh.add(line);
  572.         }
  573.  
  574.         /**
  575.          * Sets the current mesh to the provided mesh
  576.          *
  577.          * @param mesh
  578.          *            as RSTile[][]
  579.          */
  580.         public void setMesh(RSTile[][] mesh) {
  581.             this.mesh.clear();
  582.             addMesh(mesh);
  583.         }
  584.  
  585.         public List<RSTile> getTilesOnLine(RSTile a, RSTile b) {
  586.             List<RSTile> sublineTiles = new ArrayList<RSTile>();
  587.             int deltaX = b.getX() - a.getX();
  588.             int deltaY = b.getY() - a.getY();
  589.             double dist = calc.distanceBetween(a, b);
  590.             if (dist == 0)
  591.                 dist = 1;
  592.             double eX = deltaX / dist, eY = deltaY / dist;
  593.             for (int i = 0; i <= dist; i++)
  594.                 sublineTiles.add(new RSTile(a.getX() + (int) (eX * i), a.getY()
  595.                         + (int) (eY * i)));
  596.             return sublineTiles;
  597.         }
  598.  
  599.         /**
  600.          * Gets all the tiles on the provided line
  601.          *
  602.          * @param line
  603.          *            as RSTile...
  604.          * @return List<RSTile> tiles on line
  605.          */
  606.         public List<RSTile> getTilesOnLines(RSTile... line) {
  607.             List<RSTile> sublineTiles = new ArrayList<RSTile>();
  608.             if (line.length == 1)
  609.                 sublineTiles.add(line[0]);
  610.             else
  611.                 for (int i = 1; i < line.length; i++) {
  612.                     RSTile a = line[i - 1];
  613.                     RSTile b = line[i];
  614.                     sublineTiles.addAll(getTilesOnLine(a, b));
  615.                 }
  616.             return sublineTiles;
  617.         }
  618.  
  619.         /**
  620.          * Gets a tile on the provided line using the ALL_CENTER method
  621.          *
  622.          * @param line
  623.          *            as RSTile...
  624.          * @return RSTile tile on line
  625.          */
  626.         public RSTile getTileOnLine(RSTile... line) {
  627.             return getTileOnLine(MeshPathType.ALL_CENTER, line);
  628.         }
  629.  
  630.         /**
  631.          * Gets a tile on the provided line using the provided method
  632.          *
  633.          * @param placement
  634.          *            as MeshPathType
  635.          * @param line
  636.          *            as RSTile...
  637.          * @return RSTile tile on line
  638.          */
  639.         public RSTile getTileOnLine(MeshPathType placement, RSTile... line) {
  640.             List<RSTile> tiles = getTilesOnLines(line);
  641.             int index = 0;
  642.             switch (placement) {
  643.             case ALL_CENTER:
  644.                 index = random(tiles.size() / 4, 3 * tiles.size() / 4 + 1);
  645.                 // +1 due to exclusive upper bound
  646.                 break;
  647.             case FULL:
  648.                 index = random(0, tiles.size());
  649.                 break;
  650.             case WEIGHT_CENTER:
  651.                 index = random(tiles.size() / 4, 3 * tiles.size() / 4 + 1);
  652.                 // +1 due to exclusive upper bound
  653.  
  654.                 int rand = random(-10, tiles.size() / 4);
  655.                 index += rand > 0 ? rand : 0;
  656.                 break;
  657.             }
  658.  
  659.             if (index < 0)
  660.                 index = 0;
  661.             if (index >= tiles.size())
  662.                 index = tiles.size() - 1;
  663.  
  664.             if (tiles.size() > 0)
  665.                 return tiles.get(index);
  666.             else
  667.                 return null;
  668.         }
  669.  
  670.         /**
  671.          * Paints the mesh to the provided graphics context in the minimap
  672.          *
  673.          * @param g
  674.          *            as Graphics2D
  675.          */
  676.         public void paintMesh(Graphics2D g) {
  677.             if (mesh.size() > 1) {
  678.                 for (int i = 1; i < mesh.size(); i++) {
  679.                     RSTile[] lineA = mesh.get(i - 1).clone();
  680.                     RSTile[] lineB = mesh.get(i).clone();
  681.                     Polygon poly = new Polygon();
  682.                     RSTile a = lineA[0];
  683.                     RSTile b = lineB[0];
  684.                     RSTile c = lineA[lineA.length - 1];
  685.                     RSTile d = lineB[lineB.length - 1];
  686.                     boolean onMap = true;
  687.                     double distA = calc.distanceBetween(c, b)
  688.                             + calc.distanceBetween(a, d);
  689.                     double distB = calc.distanceBetween(a, b)
  690.                             + calc.distanceBetween(c, d);
  691.  
  692.                     if (distA > distB) {
  693.                         // Reverse lineB.
  694.                         RSTile[] newLineB = new RSTile[lineB.length];
  695.                         int start = lineB.length - 1;
  696.                         for (RSTile t : lineB) {
  697.                             if (start >= 0)
  698.                                 newLineB[start] = t;
  699.                             start--;
  700.                         }
  701.                         lineB = newLineB;
  702.                     }
  703.  
  704.                     if (lineA != null)
  705.                         for (RSTile t : lineA) {
  706.                             Point p = calc.tileToMinimap(t);
  707.                             if (p.x == -1 || p.y == -1) {
  708.                                 onMap = false;
  709.                                 break;
  710.                             }
  711.                             poly.addPoint(p.x, p.y);
  712.                         }
  713.  
  714.                     if (lineB != null)
  715.                         for (RSTile t : lineB) {
  716.                             Point p = calc.tileToMinimap(t);
  717.                             if (p.x == -1 || p.y == -1) {
  718.                                 onMap = false;
  719.                                 break;
  720.                             }
  721.                             poly.addPoint(p.x, p.y);
  722.                         }
  723.  
  724.                     if (onMap) {
  725.                         g.setColor(MESH_BORDER);
  726.                         g.draw(poly);
  727.                         g.setColor(MESH_FILL);
  728.                         g.fill(poly);
  729.                     }
  730.                 }
  731.             }
  732.         }
  733.  
  734.         public RSTile getTileOnMap(RSTile t) {
  735.             List<RSTile> tiles = getTilesOnLine(t, getMyPlayer().getLocation());
  736.             for (RSTile tt : tiles)
  737.                 if (calc.tileOnMap(tt))
  738.                     return tt;
  739.             return null;
  740.         }
  741.  
  742.         /**
  743.          * Paints the current un-smoothed path to the minimap using the provided
  744.          * graphics object
  745.          *
  746.          * @param g
  747.          *            as Graphics2D
  748.          */
  749.         public void paintPath(Graphics2D g) {
  750.             if (blockPath.size() > 1) {
  751.                 g.setColor(PATH_COLOR);
  752.                 for (int i = 1; i < blockPath.size(); i++) {
  753.                     Point a = calc.tileToMinimap(blockPath.get(i - 1));
  754.                     Point b = calc.tileToMinimap(blockPath.get(i));
  755.                     if (a.x > 0 && a.y > 0)
  756.                         g.fillOval(a.x - 2, a.y - 2, 5, 5);
  757.                     if (b.x > 0 && b.y > 0)
  758.                         g.fillOval(b.x - 2, b.y - 2, 5, 5);
  759.                     if (a.x > 0 && a.y > 0 && b.x > 0 && b.y > 0)
  760.                         g.drawLine(a.x, a.y, b.x, b.y);
  761.                 }
  762.             }
  763.         }
  764.  
  765.         /**
  766.          * Paints the smoothed version of the current path to the minimap using
  767.          * the provided graphics object
  768.          *
  769.          * @param g
  770.          *            as Graphics2D
  771.          */
  772.         public void paintSmoothPath(Graphics2D g) {
  773.             if (smoothPath.size() > 1) {
  774.                 g.setColor(SMOOTH_PATH_COLOR);
  775.                 for (int i = 1; i < smoothPath.size(); i++) {
  776.                     Point a = calc.tileToMinimap(smoothPath.get(i - 1));
  777.                     Point b = calc.tileToMinimap(smoothPath.get(i));
  778.                     if (a.x > 0 && a.y > 0)
  779.                         g.fillOval(a.x - 2, a.y - 2, 5, 5);
  780.                     if (b.x > 0 && b.y > 0)
  781.                         g.fillOval(b.x - 2, b.y - 2, 5, 5);
  782.                     if (a.x > 0 && a.y > 0 && b.x > 0 && b.y > 0)
  783.                         g.drawLine(a.x, a.y, b.x, b.y);
  784.                 }
  785.             }
  786.         }
  787.  
  788.         /**
  789.          * Paints the subdivided smoothed version of the current path to the
  790.          * minimap using the provided graphics object
  791.          *
  792.          * @param g
  793.          *            as Graphics2D
  794.          */
  795.         public void paintSubdividedPath(Graphics2D g) {
  796.             if (subdividedPath.size() > 0) {
  797.                 g.setColor(SUBDIVIDED_PATH_COLOR);
  798.                 for (RSTile t : subdividedPath) {
  799.                     Point tileLoc = calc.tileToMinimap(t);
  800.                     if (tileLoc.x > 0 && tileLoc.y > 0)
  801.                         g.fillOval(tileLoc.x, tileLoc.y, 5, 5);
  802.                 }
  803.             }
  804.         }
  805.  
  806.         /**
  807.          * Paints the mesh, and all versions of the current path to the minimap
  808.          * using the provided graphics object
  809.          *
  810.          * @param g
  811.          *            as Graphics2D
  812.          */
  813.         public void paintAll(Graphics2D g) {
  814.             paintMesh(g);
  815.             paintPath(g);
  816.             paintSmoothPath(g);
  817.             paintSubdividedPath(g);
  818.         }
  819.  
  820.         /**
  821.          * Finds a path between the start index and the end index using the
  822.          * provided placement type, then sets the current path to the found path
  823.          *
  824.          * @param placement
  825.          *            as MeshPathType
  826.          * @param start
  827.          *            index
  828.          * @param end
  829.          *            index
  830.          */
  831.         public void findPath(MeshPathType placement, int start, int end) {
  832.             blockPath.clear();
  833.             RSTile lineTile = getTileOnLine(mesh.get(start));
  834.             String s = lineTile.toString();
  835.             blockPath.add(lineTile);
  836.             for (int i = start + 1; i <= end; i++) {
  837.                 lineTile = getTileOnLine(placement, mesh.get(i));
  838.                 blockPath.add(lineTile);
  839.                 s += "," + lineTile.toString();
  840.             }
  841.             smoothPath = smoothPath(blockPath);
  842.             subdividedPath = subdividePath(smoothPath);
  843.         }
  844.  
  845.         /**
  846.          * Finds a path between the beginning and end of the mesh using the
  847.          * provided placement type, then sets the current path to the found path
  848.          *
  849.          * @param placement
  850.          *            as MeshPathType
  851.          */
  852.         public void findPath(MeshPathType placement) {
  853.             findPath(placement, 0, mesh.size() - 1);
  854.         }
  855.  
  856.         /**
  857.          * Finds a path between the beginning and end of the mesh using the
  858.          * ALL_CENTER placement type, then sets the current path to the found
  859.          * path
  860.          */
  861.         public void findPath() {
  862.             findPath(MeshPathType.ALL_CENTER);
  863.         }
  864.  
  865.         /**
  866.          * Clears the current path and all refined versions of it.
  867.          */
  868.         public void clearPath() {
  869.             blockPath.clear();
  870.             smoothPath.clear();
  871.             subdividedPath.clear();
  872.         }
  873.  
  874.         /**
  875.          * Smoothes the provided List of RSTiles using Bezier curves
  876.          *
  877.          * @param path
  878.          *            as List
  879.          * @return List<RSTile> smoothed path
  880.          */
  881.         public List<RSTile> smoothPath(List<RSTile> path) {
  882.             List<RSTile> smoothed = new ArrayList<RSTile>();
  883.             smoothed.addAll(path);
  884.             if (path.size() >= 3) {
  885.                 for (int b = 0; b < path.size(); b++) {
  886.                     if (b + 2 < path.size()) {
  887.                         double x2, y2;
  888.  
  889.                         double t = 0.5;
  890.                         // use Berstein polynomials
  891.                         x2 = (path.get(b + 0).getX() + t
  892.                                 * (-path.get(b + 0).getX() * 3 + t
  893.                                         * (3 * path.get(b + 0).getX() - path
  894.                                                 .get(b + 0).getX() * t)))
  895.                                 + t
  896.                                 * (3 * path.get(b + 1).getX() + t
  897.                                         * (-6 * path.get(b + 1).getX() + path
  898.                                                 .get(b + 1).getX() * 3 * t))
  899.                                 + t
  900.                                 * t
  901.                                 * (path.get(b + 1).getX() * 3 - path.get(b + 1)
  902.                                         .getX() * 3 * t)
  903.                                 + path.get(b + 2).getX() * t * t * t;
  904.                         y2 = (path.get(b + 0).getY() + t
  905.                                 * (-path.get(b + 0).getY() * 3 + t
  906.                                         * (3 * path.get(b + 0).getY() - path
  907.                                                 .get(b + 0).getY() * t)))
  908.                                 + t
  909.                                 * (3 * path.get(b + 1).getY() + t
  910.                                         * (-6 * path.get(b + 1).getY() + path
  911.                                                 .get(b + 1).getY() * 3 * t))
  912.                                 + t
  913.                                 * t
  914.                                 * (path.get(b + 1).getY() * 3 - path.get(b + 1)
  915.                                         .getY() * 3 * t)
  916.                                 + path.get(b + 2).getY() * t * t * t;
  917.                         RSTile loc = new RSTile((int) x2, (int) y2);
  918.                         smoothed.set(b + 1, getTileInMesh(loc));
  919.  
  920.                     }
  921.                 }
  922.             }
  923.             return smoothed;
  924.         }
  925.  
  926.         /**
  927.          * Gets the nearest tile in the mesh to the provided RSTile
  928.          *
  929.          * @param tile
  930.          *            the RSTile to use
  931.          * @return RSTile tile in mesh
  932.          */
  933.         public RSTile getTileInMesh(RSTile tile) {
  934.             if (inMesh(tile))
  935.                 return tile;
  936.             double bestDist = Double.MAX_VALUE;
  937.             RSTile nearest = null;
  938.             if (mesh.size() > 1) {
  939.                 for (int i = 1; i < mesh.size(); i++) {
  940.                     RSTile[] lineA = mesh.get(i - 1);
  941.                     RSTile[] lineB = mesh.get(i);
  942.                     if (lineA != null && lineB != null) {
  943.                         RSTile a = lineA[0];
  944.                         RSTile b = lineB[0];
  945.                         RSTile c = lineA[lineA.length - 1];
  946.                         RSTile d = lineB[lineB.length - 1];
  947.                         if (calc.distanceBetween(a, b) > calc.distanceBetween(
  948.                                 a, d)) {
  949.                             // Wrong order, switch b and d.
  950.                             RSTile clone = new RSTile(b.getX(), b.getY(),
  951.                                     b.getZ());
  952.                             b = new RSTile(d.getX(), d.getY(), d.getZ());
  953.                             d = clone;
  954.                         }
  955.                         for (RSTile t : getTilesOnLine(a, b)) {
  956.                             double dist = calc.distanceBetween(tile, t);
  957.                             if (dist < bestDist) {
  958.                                 bestDist = dist;
  959.                                 nearest = t;
  960.                             }
  961.                         }
  962.                         for (RSTile t : getTilesOnLine(c, d)) {
  963.                             double dist = calc.distanceBetween(tile, t);
  964.                             if (dist < bestDist) {
  965.                                 bestDist = dist;
  966.                                 nearest = t;
  967.                             }
  968.                         }
  969.                     }
  970.                 }
  971.             }
  972.             return nearest;
  973.         }
  974.  
  975.         /**
  976.          * Checks to see if the provided RSTile is inside the mesh
  977.          *
  978.          * @param tile
  979.          *            the RSTile to check
  980.          * @return boolean is in mesh
  981.          */
  982.         public boolean inMesh(RSTile tile) {
  983.             if (mesh.size() > 1) {
  984.                 for (int i = 1; i < mesh.size(); i++) {
  985.                     RSTile[] lineA = mesh.get(i - 1);
  986.                     RSTile[] lineB = mesh.get(i);
  987.                     Polygon poly = new Polygon();
  988.                     if (lineA != null)
  989.                         for (RSTile t : lineA)
  990.                             poly.addPoint(t.getX(), t.getY());
  991.  
  992.                     if (lineB != null)
  993.                         for (RSTile t : lineB)
  994.                             poly.addPoint(t.getX(), t.getY());
  995.  
  996.                     if (poly.npoints >= 2)
  997.                         if (poly.contains(new Point(tile.getX(), tile.getY())))
  998.                             return true;
  999.                 }
  1000.             }
  1001.             return false;
  1002.         }
  1003.  
  1004.         /**
  1005.          * Takes the provided path and subdivides it using the length provided
  1006.          * in the Options class
  1007.          *
  1008.          * @param smoothPath
  1009.          *            path to subdivide as a List<RSTile>
  1010.          * @return List<RSTile> subdivided path
  1011.          */
  1012.         public List<RSTile> subdividePath(List<RSTile> smoothPath) {
  1013.             RSTile[] smoothpathArray = new RSTile[smoothPath.size()];
  1014.             List<RSTile> path = getTilesOnLines(smoothPath
  1015.                     .toArray(smoothpathArray));
  1016.             List<RSTile> subdividedPath = new ArrayList<RSTile>();
  1017.             RSTile previous = null;
  1018.             for (RSTile next : path) {
  1019.                 if ((previous == null ? true : calc.distanceBetween(previous,
  1020.                         next) > Options.walkingDistance.random())
  1021.                         || next == path.get(path.size() - 1)) {
  1022.                     previous = new RSTile(next.getX(), next.getY());
  1023.                     subdividedPath.add(previous);
  1024.                 }
  1025.             }
  1026.             return subdividedPath;
  1027.         }
  1028.  
  1029.         /**
  1030.          * Takes a step along this path if appropriate. Specifies only
  1031.          * TraversalOption.SPACE_ACTIONS.
  1032.          *
  1033.          * @return <tt>true</tt> if this path is currently valid for the player;
  1034.          *         otherwise <tt>false</tt>.
  1035.          * @see #traverse(EnumSet)
  1036.          */
  1037.         public boolean traverse() {
  1038.             return this.traverse(EnumSet.of(TraversalOption.HANDLE_RUN,
  1039.                     TraversalOption.SPACE_ACTIONS));
  1040.         }
  1041.  
  1042.         /**
  1043.          * Takes a step along this path if appropriate. If the path cannot be
  1044.          * traversed due to the player being too far from its vertices or
  1045.          * already at the end vertex, <tt>false</tt> will be returned. In all
  1046.          * other cases, <tt>true</tt> will be returned, but an action will not
  1047.          * necessarily be performed (based on the given options).
  1048.          *
  1049.          * @param options
  1050.          *            Walking style options.
  1051.          * @return <tt>true</tt> if this path is currently valid for the player;
  1052.          *         otherwise <tt>false</tt>.
  1053.          */
  1054.         public boolean traverse(EnumSet<TraversalOption> options) {
  1055.             RSTile next = getNext();
  1056.             if (next == null)
  1057.                 return false;
  1058.             int nextIdx = getNearestIndexTo(next);
  1059.  
  1060.             if (next.equals(getEnd())) {
  1061.                 if (calc.distanceTo(next) <= 1
  1062.                         || (end && players.getMyPlayer().isMoving())
  1063.                         || next.equals(walking.getDestination())) {
  1064.                     return false;
  1065.                 }
  1066.                 end = true;
  1067.             } else {
  1068.                 end = false;
  1069.             }
  1070.             if (options.contains(TraversalOption.HANDLE_RUN)
  1071.                     && !walking.isRunEnabled() && walking.getEnergy() > 50) {
  1072.                 walking.setRun(true);
  1073.                 sleep(300);
  1074.             }
  1075.             if (walking.getDestination() != null
  1076.                     && getNearestIndexTo(walking.getDestination()) >= nextIdx)
  1077.                 return false;
  1078.             if (options.contains(TraversalOption.SPACE_ACTIONS)) {
  1079.                 RSTile dest = walking.getDestination();
  1080.                 if (dest != null && players.getMyPlayer().isMoving()
  1081.                         && calc.distanceBetween(next, dest) < 3) {
  1082.                     return true;
  1083.                 }
  1084.             }
  1085.             return walking.walkTileMM(next, 0, 0);
  1086.         }
  1087.  
  1088.         /**
  1089.          * Checks whether or not this path can be traversed by the player. This
  1090.          * will be the case provided that the player near to one of its
  1091.          * vertices, but not already standing on the end vertex.
  1092.          *
  1093.          * @return <tt>true</tt> if the player can walk along this path;
  1094.          *         otherwise <tt>false</tt>.
  1095.          */
  1096.         public boolean isValid() {
  1097.             if (!(subdividedPath.size() > 0 && !players.getMyPlayer()
  1098.                     .getLocation().equals(getEnd())))
  1099.                 return false;
  1100.             else
  1101.                 for (int i = subdividedPath.size() - 1; i >= 0; i--)
  1102.                     if (calc.tileOnMap(subdividedPath.get(i)))
  1103.                         return true;
  1104.             return false;
  1105.         }
  1106.  
  1107.         /**
  1108.          * Gets the start tile of this path.
  1109.          *
  1110.          * @return The start <code>RSTile</code>.
  1111.          */
  1112.         public RSTile getStart() {
  1113.             if (subdividedPath.size() > 0)
  1114.                 return subdividedPath.get(0);
  1115.             else
  1116.                 return null;
  1117.         }
  1118.  
  1119.         /**
  1120.          * Gets the next immediately available vertex in this path.
  1121.          *
  1122.          * @return The next walkable <code>RSTile</code>.
  1123.          */
  1124.         public RSTile getNext() {
  1125.             if (subdividedPath.size() > 0) {
  1126.                 for (int i = subdividedPath.size() - 1; i >= 0; i--)
  1127.                     if (calc.tileOnMap(subdividedPath.get(i)))
  1128.                         return subdividedPath.get(i);
  1129.                 return getTileOnMinimap(getNearest());
  1130.             } else
  1131.                 return null;
  1132.         }
  1133.  
  1134.         public RSTile getTileOnMinimap(RSTile base) {
  1135.             if (calc.tileOnMap(base))
  1136.                 return base;
  1137.             RSTile me = getMyPlayer().getLocation();
  1138.             int deltaX = base.getX() - me.getX();
  1139.             int deltaY = base.getY() - me.getY();
  1140.             double dist = calc.distanceBetween(base, me);
  1141.             double eX = deltaX / dist, eY = deltaY / dist;
  1142.             return new RSTile(me.getX() + (int) (eX * 14), me.getY()
  1143.                     + (int) (eY * 14));
  1144.         }
  1145.  
  1146.         public RSTile getNearest() {
  1147.             int len = Integer.MAX_VALUE;
  1148.             RSTile best = null;
  1149.             for (RSTile t : subdividedPath)
  1150.                 if (calc.distanceTo(t) < len) {
  1151.                     best = t;
  1152.                     len = calc.distanceTo(t);
  1153.                 }
  1154.             return best;
  1155.         }
  1156.  
  1157.         public RSTile getNearestByPath() {
  1158.             int len = Integer.MAX_VALUE;
  1159.             RSTile best = null;
  1160.             for (RSTile t : subdividedPath) {
  1161.                 int pLen = calc.pathLengthTo(t, false);
  1162.                 if (pLen < len && pLen >= 0) {
  1163.                     best = t;
  1164.                     len = pLen;
  1165.                 }
  1166.             }
  1167.             return best;
  1168.         }
  1169.  
  1170.         public int getNearestIndexTo(RSTile t) {
  1171.             int len = Integer.MAX_VALUE;
  1172.             int bestIndex = -1;
  1173.             if (walking.getDestination() != null)
  1174.                 for (int i = 0; i < subdividedPath.size(); i++)
  1175.                     if (calc.distanceBetween(t, subdividedPath.get(i)) < len) {
  1176.                         bestIndex = i;
  1177.                         len = calc.distanceTo(t);
  1178.                     }
  1179.             return bestIndex;
  1180.         }
  1181.  
  1182.         /**
  1183.          * Gets the end tile of this path.
  1184.          *
  1185.          * @return The end <code>RSTile</code>.
  1186.          */
  1187.         public RSTile getEnd() {
  1188.             if (subdividedPath.size() > 0)
  1189.                 return subdividedPath.get(subdividedPath.size() - 1);
  1190.             else
  1191.                 return null;
  1192.         }
  1193.  
  1194.         /**
  1195.          * Reverses this mesh.
  1196.          *
  1197.          * @return
  1198.          *
  1199.          * @return This path.
  1200.          */
  1201.         public MeshPath reverse() {
  1202.             MeshPath newPath = new MeshPath();
  1203.             for (int i = mesh.size() - 1; i >= 0; i--)
  1204.                 newPath.addLine(mesh.get(i));
  1205.             return newPath;
  1206.         }
  1207.  
  1208.         /**
  1209.          * Returns an array containing all of the vertices in this path.
  1210.          *
  1211.          * @return an array containing all of the vertices in this path.
  1212.          */
  1213.         public RSTile[] getTilePath() {
  1214.             RSTile[] tiles = new RSTile[subdividedPath.size()];
  1215.             for (int i = 0; i < tiles.length; i++)
  1216.                 tiles[i] = new RSTile(subdividedPath.get(i).getX(),
  1217.                         subdividedPath.get(i).getY());
  1218.             return tiles;
  1219.         }
  1220.  
  1221.         /**
  1222.          * Checks if we have a path
  1223.          *
  1224.          * @return boolean has a path
  1225.          */
  1226.         public boolean hasPath() {
  1227.             return subdividedPath.size() > 0;
  1228.         }
  1229.     }
  1230.  
  1231.     public static class Options {
  1232.         public static Range walkingDistance = new Range(4, 6);
  1233.     }
  1234.  
  1235.     /**
  1236.      * A range class for randomized items
  1237.      *
  1238.      * @author Equinox_
  1239.      *
  1240.      */
  1241.     public static class Range {
  1242.         public int MAX;
  1243.         public int MIN;
  1244.  
  1245.         public Range(int min, int max) {
  1246.             MAX = Math.max(min, max);
  1247.             MIN = Math.min(min, max);
  1248.         }
  1249.  
  1250.         public Range() {
  1251.             MAX = 1;
  1252.             MIN = -1;
  1253.         }
  1254.  
  1255.         /**
  1256.          * Get a random number in the range
  1257.          *
  1258.          * @return random int between min and max
  1259.          */
  1260.         public int random() {
  1261.             return (int) (Math.random() * (MAX - MIN)) + MIN;
  1262.         }
  1263.  
  1264.         public String toString() {
  1265.             return MIN + "-" + MAX;
  1266.         }
  1267.     }
  1268.  
  1269.     /**
  1270.      * Used to format data into more conventional formats
  1271.      *
  1272.      * @author Equinox_
  1273.      *
  1274.      */
  1275.     public static class PaintFormatter {
  1276.         /**
  1277.          * Converts the first letter of every word to uppercase, and the rest
  1278.          * lowercase.
  1279.          *
  1280.          * @param s
  1281.          *            The input String
  1282.          * @return the properly formatted string
  1283.          */
  1284.         public static String properCaseAll(String s) {
  1285.             String[] words = s.split(" ");
  1286.             String result = "";
  1287.             for (int i = 0; i < words.length; i++) {
  1288.                 String f = words[i].substring(0, 1).toUpperCase();
  1289.                 words[i] = f + words[i].substring(1).toLowerCase();
  1290.                 result += " " + words[i];
  1291.             }
  1292.             return result.substring(1);
  1293.         }
  1294.  
  1295.         /**
  1296.          * Capitalizes the first letter of every sentence, with every other
  1297.          * letter lowercase.
  1298.          *
  1299.          * @param s
  1300.          *            The input string
  1301.          * @return The properly formatted String
  1302.          */
  1303.         public static String properCaseFirst(String s) {
  1304.             String[] sentences = new String[] { s };
  1305.             if (s.contains("."))
  1306.                 sentences = s.split(".");
  1307.             String result = "";
  1308.             for (int i = 0; i < sentences.length; i++) {
  1309.                 String f = sentences[i].substring(0, 1).toUpperCase();
  1310.                 sentences[i] = f + sentences[i].substring(1).toLowerCase();
  1311.                 result += " " + sentences[i];
  1312.             }
  1313.             return result.substring(1);
  1314.         }
  1315.  
  1316.         /**
  1317.          * Formats time to DD:HH:MM:SS:MSMS with days and millis optional
  1318.          *
  1319.          * @param timeMillis
  1320.          *            long milliseconds of time
  1321.          * @param sep
  1322.          *            String seperation character
  1323.          * @param millisInc
  1324.          *            boolean include milliseconds
  1325.          * @return
  1326.          */
  1327.         public static String getFormattedTime(final long timeMillis,
  1328.                 String sep, boolean millisInc) {
  1329.             long millis = timeMillis;
  1330.             final long days = millis / (24 * 1000 * 60 * 60);
  1331.             millis -= days * (24 * 1000 * 60 * 60);
  1332.             final long hours = millis / (1000 * 60 * 60);
  1333.             millis -= hours * 1000 * 60 * 60;
  1334.             final long minutes = millis / (1000 * 60);
  1335.             millis -= minutes * 1000 * 60;
  1336.             final long _seconds = millis / 1000;
  1337.             millis -= _seconds * 1000;
  1338.             String dayString = String.valueOf(days);
  1339.             String hoursString = String.valueOf(hours);
  1340.             String minutesString = String.valueOf(minutes);
  1341.             String secondsString = String.valueOf(_seconds);
  1342.             if (hours < 10) {
  1343.                 hoursString = 0 + hoursString;
  1344.             }
  1345.             if (minutes < 10) {
  1346.                 minutesString = 0 + minutesString;
  1347.             }
  1348.             if (_seconds < 10) {
  1349.                 secondsString = 0 + secondsString;
  1350.             }
  1351.             String s = "";
  1352.             if (days > 0)
  1353.                 s = dayString + sep;
  1354.             s += hoursString + sep + minutesString + sep + secondsString;
  1355.             if (millisInc)
  1356.                 s += sep + String.valueOf(millis);
  1357.             return s;
  1358.         }
  1359.  
  1360.         /**
  1361.          * Converts the milliseconds to DD:HH:MM:SS with the days optional.
  1362.          *
  1363.          * @param timeMillis
  1364.          *            the number of milliseconds
  1365.          * @return the properly formatted time as a String
  1366.          */
  1367.         public static String getFormattedTime(final long timeMillis) {
  1368.             return getFormattedTime(timeMillis, ":", false);
  1369.         }
  1370.  
  1371.         /**
  1372.          * Formats a specified amount into thousands, millions or billions, then
  1373.          * adds the proper suffix
  1374.          *
  1375.          * @param money
  1376.          *            the amount of money
  1377.          * @return the formatted string
  1378.          */
  1379.         public static String getFormattedMoney(long money) {
  1380.             /*
  1381.              * String suffix = ""; int t = 1; if (money >= 10000) { t *= 1000;
  1382.              * suffix = "K"; } if (money / t > 10000) { t *= 1000; suffix = "M";
  1383.              * } if (money / t > 10000) { t *= 1000; suffix = "B"; } return
  1384.              * String.valueOf((money / t)) + suffix;
  1385.              */
  1386.             return new DecimalFormat("###,###,###,###,###,###").format(money);
  1387.         }
  1388.  
  1389.         /**
  1390.          * Converts an array of strings into one string, using commas and 'and' <br>
  1391.          * <br>
  1392.          * Examples: <br>
  1393.          * {"option1"} returns "option1"<br>
  1394.          * {"option1","option2"} returns "option1 and option2"<br>
  1395.          * {"op1","op2","op3"} returns "op1, op2, and op3"<br>
  1396.          * <br>
  1397.          *
  1398.          * @param list
  1399.          *            The array of strings making up the list.
  1400.          * @return The properly formatted string
  1401.          */
  1402.         public static String formatList(String[] list) {
  1403.             String s = "";
  1404.             if (list != null)
  1405.                 if (list.length == 2) {
  1406.                     s = list[0] + " and " + list[1];
  1407.                 } else if (list.length > 2) {
  1408.                     for (int i = 0; i < list.length - 1; i++)
  1409.                         s += list[i] + ", ";
  1410.                     s += "and " + list[list.length - 1];
  1411.                 } else if (list.length == 1)
  1412.                     s = list[0];
  1413.             return s;
  1414.         }
  1415.     }
  1416.    
  1417.     /**
  1418.      * A class used to represent the paint interface for this script
  1419.      *
  1420.      * @author Equinox_
  1421.      *
  1422.      */
  1423.     public class PaintInterface {
  1424.         private ModifiedDrawMouse drawMouse = new ModifiedDrawMouse();
  1425.        
  1426.         // Constant
  1427.         public final int[] SKILL_INTERFACES = { Skills.INTERFACE_ATTACK,
  1428.                 Skills.INTERFACE_DEFENSE, Skills.INTERFACE_STRENGTH,
  1429.                 Skills.INTERFACE_CONSTITUTION, Skills.INTERFACE_RANGE,
  1430.                 Skills.INTERFACE_PRAYER, Skills.INTERFACE_MAGIC,
  1431.                 Skills.INTERFACE_COOKING, Skills.INTERFACE_WOODCUTTING,
  1432.                 Skills.INTERFACE_FLETCHING, Skills.INTERFACE_FISHING,
  1433.                 Skills.INTERFACE_FIREMAKING, Skills.INTERFACE_CRAFTING,
  1434.                 Skills.INTERFACE_SMITHING, Skills.INTERFACE_MINING,
  1435.                 Skills.INTERFACE_HERBLORE, Skills.INTERFACE_AGILITY,
  1436.                 Skills.INTERFACE_THIEVING, Skills.INTERFACE_SLAYER,
  1437.                 Skills.INTERFACE_FARMING, Skills.INTERFACE_RUNECRAFTING,
  1438.                 Skills.INTERFACE_HUNTER, Skills.INTERFACE_CONSTRUCTION,
  1439.                 Skills.INTERFACE_SUMMONING, Skills.INTERFACE_DUNGEONEERING };
  1440.  
  1441.         // Start data
  1442.         public long startExp = 0;
  1443.         public long startTime = 0;
  1444.         public long startLevel = 1;
  1445.  
  1446.         // Goal data
  1447.         public int goalExp;
  1448.         public int goalLevel;
  1449.  
  1450.         // Usage data
  1451.         public int logsChopped = 0;
  1452.  
  1453.         // Price data
  1454.         public long logPrice = 1;
  1455.  
  1456.         // Result data
  1457.         public int runsMade = 0;
  1458.  
  1459.         // Images
  1460.         public Map<String, Image> icons = new HashMap<String, Image>();
  1461.  
  1462.         public void putImage(String name, Image img) {
  1463.             icons.put(name.toLowerCase(), img);
  1464.         }
  1465.  
  1466.         public Image getImage(String name) {
  1467.             if (icons.containsKey(name.toLowerCase()))
  1468.                 return icons.get(name.toLowerCase());
  1469.             return null;
  1470.         }
  1471.  
  1472.         // End Images
  1473.  
  1474.         public FontRenderContext frc = new FontRenderContext(
  1475.                 new AffineTransform(), false, false);
  1476.  
  1477.         public PaintStyle style = new PaintStyle();
  1478.         public Point mouseLoc = new Point(0, 0);
  1479.  
  1480.         final f2pMaples chopper;
  1481.         final Logger log;
  1482.         int SkillID = -1;
  1483.         public Menu paintMenu;
  1484.  
  1485.         /**
  1486.          * Constructs a PaintInterface using the provided parent and logger
  1487.          * object
  1488.          *
  1489.          * @param planker
  1490.          *            the parent Natchopper
  1491.          * @param log
  1492.          *            the Logger object
  1493.          */
  1494.         public PaintInterface(f2pMaples chopper, Logger log) {
  1495.             this(chopper, log, -1);
  1496.         }
  1497.  
  1498.         public PaintInterface(f2pMaples chopper, Logger log, int SkillID) {
  1499.             this.chopper = chopper;
  1500.             this.log = log;
  1501.             this.SkillID = SkillID;
  1502.             startTime = System.currentTimeMillis();
  1503.             if (SkillID >= 0 && SkillID < Skills.SKILL_NAMES.length) {
  1504.                 startExp = skills.getCurrentExp(SkillID);
  1505.                 startLevel = skills.getCurrentLevel(SkillID);
  1506.                 setUpGoal();
  1507.             }
  1508.             init();
  1509.         }
  1510.  
  1511.         public void init() {
  1512.             RSComponent screen = interfaces.get(548).getComponent(3);
  1513.             Point bottomRight = new Point(screen.getAbsoluteX()
  1514.                     + screen.getWidth(), screen.getAbsoluteY()
  1515.                     + screen.getHeight());
  1516.             paintMenu = new Menu(this, bottomRight, Anchor.DOWN_RIGHT);
  1517.             paintMenu.setFlowType(FlowType.HORIZONTAL);
  1518.             paintMenu.addMouseListener(new MouseListen() {
  1519.                 void MouseAction(MouseEvent e) {
  1520.                     if (e.getID() == MouseEvent.MOUSE_CLICKED)
  1521.                         paintMenu.toggleShowAll();
  1522.                 }
  1523.             });
  1524.             if (SkillID >= 0 && SkillID < Skills.SKILL_NAMES.length) {
  1525.                 MenuProgressBar progressBar = new MenuProgressBar("nextlvl",
  1526.                         paintMenu, new GetPercent() {
  1527.                             int getPercent() {
  1528.                                 return skills.getPercentToNextLevel(SkillID);
  1529.                             }
  1530.                         }, "Next Level", new GetPopup() {
  1531.                             MenuPopUp getPopUp() {
  1532.                                 long millis = Math.abs(System
  1533.                                         .currentTimeMillis() - startTime);
  1534.                                 if (millis <= 0)
  1535.                                     millis = 1;
  1536.                                 long expGained = skills.getCurrentExp(SkillID)
  1537.                                         - startExp;
  1538.                                 long expPerHour = (expGained * 3600000l)
  1539.                                         / millis;
  1540.                                 String TTL = "";
  1541.                                 int TTLunf = (int) ((expPerHour > 0) ? (((float) skills
  1542.                                         .getExpToNextLevel(SkillID))
  1543.                                         / ((float) expPerHour) * 3600000f) : 0);
  1544.                                 if (TTLunf != 0)
  1545.                                     TTL = PaintFormatter
  1546.                                             .getFormattedTime(TTLunf);
  1547.                                 else
  1548.                                     TTL = "No exp gained";
  1549.                                 String[] lines = new String[4];
  1550.                                 lines[0] = "Exp gained: "
  1551.                                         + PaintFormatter
  1552.                                                 .getFormattedMoney(expGained);
  1553.                                 lines[1] = "Exp per Hour: "
  1554.                                         + PaintFormatter
  1555.                                                 .getFormattedMoney(expPerHour);
  1556.                                 lines[2] = "Exp 'till level: "
  1557.                                         + PaintFormatter.getFormattedMoney(skills
  1558.                                                 .getExpToNextLevel(SkillID));
  1559.                                 lines[3] = "Time 'till level: " + TTL;
  1560.                                 return new MenuPopUp(lines, "nextlevel");
  1561.                             }
  1562.  
  1563.                         });
  1564.                 paintMenu.add(progressBar);
  1565.  
  1566.                 if (goalExp > skills.getCurrentExp(SkillID)) {
  1567.                     MenuProgressBar goalBar = new MenuProgressBar("goal",
  1568.                             paintMenu, new GetPercent() {
  1569.                                 int getPercent() {
  1570.                                     float expTillGoalStart = goalExp - startExp;
  1571.                                     double expGained = skills
  1572.                                             .getCurrentExp(SkillID) - startExp;
  1573.                                     double result = expGained
  1574.                                             / expTillGoalStart;
  1575.                                     if (result > 1)
  1576.                                         result = 1;
  1577.                                     if (result < 0)
  1578.                                         result = 0;
  1579.                                     return (int) (result * 100);
  1580.                                 }
  1581.                             }, "Goal", new GetPopup() {
  1582.                                 MenuPopUp getPopUp() {
  1583.                                     long millis = Math.abs(System
  1584.                                             .currentTimeMillis() - startTime);
  1585.                                     if (millis <= 0)
  1586.                                         millis = 1;
  1587.                                     long expGained = skills
  1588.                                             .getCurrentExp(SkillID) - startExp;
  1589.                                     long expPerHour = (expGained * 3600000l)
  1590.                                             / millis;
  1591.                                     int expTillGoal = goalExp
  1592.                                             - skills.getCurrentExp(SkillID);
  1593.                                     String TTG = "";
  1594.                                     int TTGunf = (int) ((expPerHour > 0) ? (((float) expTillGoal)
  1595.                                             / ((float) expPerHour) * 3600000f)
  1596.                                             : 0);
  1597.                                     if (TTGunf != 0)
  1598.                                         TTG = PaintFormatter
  1599.                                                 .getFormattedTime(TTGunf);
  1600.                                     else
  1601.                                         TTG = "No exp gained";
  1602.                                     String[] lines = new String[goalLevel > 0 ? 6
  1603.                                             : 5];
  1604.                                     int off = goalLevel > 0 ? 1 : 0;
  1605.                                     if (goalLevel > 0)
  1606.                                         lines[0] = "Goal Level: " + goalLevel;
  1607.                                     lines[0 + off] = "Goal Exp: "
  1608.                                             + PaintFormatter
  1609.                                                     .getFormattedMoney(goalExp);
  1610.                                     lines[1 + off] = "Exp gained: "
  1611.                                             + PaintFormatter
  1612.                                                     .getFormattedMoney(expGained);
  1613.                                     lines[2 + off] = "Exp per Hour: "
  1614.                                             + PaintFormatter
  1615.                                                     .getFormattedMoney(expPerHour);
  1616.                                     lines[3 + off] = "Exp 'till goal: "
  1617.                                             + PaintFormatter
  1618.                                                     .getFormattedMoney(expTillGoal);
  1619.                                     lines[4 + off] = "Time 'till goal: " + TTG;
  1620.                                     return new MenuPopUp(lines, "goalbar");
  1621.                                 }
  1622.  
  1623.                             });
  1624.                     paintMenu.add(goalBar);
  1625.                 }
  1626.             }
  1627.  
  1628.             MenuButton logging = new MenuButton("logging", paintMenu,
  1629.                     "logicon", new GetPopup() {
  1630.                         MenuPopUp getPopUp() {
  1631.                             long millis = System.currentTimeMillis()
  1632.                                     - chopper.Paint.startTime;
  1633.                             if (millis <= 0)
  1634.                                 millis = 1;
  1635.                             long logsPerHour = ((logsChopped * 3600000l) / millis);
  1636.                             long profit = (logsChopped * logPrice);
  1637.                             String[] lines = new String[4];
  1638.                             lines[0] = "Logs chopped: "
  1639.                                     + PaintFormatter
  1640.                                             .getFormattedMoney(logsChopped);
  1641.                             lines[1] = "Logs per Hour: "
  1642.                                     + PaintFormatter
  1643.                                             .getFormattedMoney(logsPerHour);
  1644.                             lines[2] = "Profit: "
  1645.                                     + PaintFormatter.getFormattedMoney(profit)
  1646.                                     + " gp";
  1647.                             lines[3] = "Profit per hour: "
  1648.                                     + PaintFormatter
  1649.                                             .getFormattedMoney((profit * 3600000)
  1650.                                                     / millis) + " gp";
  1651.                             return new MenuPopUp(lines, "logging");
  1652.                         }
  1653.                     });
  1654.             paintMenu.add(logging);
  1655.  
  1656.             MenuButton home = new MenuButton("home", paintMenu, "homeicon",
  1657.                     new GetPopup() {
  1658.                         MenuPopUp getPopUp() {
  1659.                             long millis = System.currentTimeMillis()
  1660.                                     - chopper.Paint.startTime;
  1661.                             if (millis <= 0)
  1662.                                 millis = 1;
  1663.                             String[] lines = new String[5];
  1664.                             lines[0] = chopper.name;
  1665.                             lines[1] = "By: " + chopper.author;
  1666.                             lines[2] = "Version " + chopper.version;
  1667.                             lines[3] = "Runtime: "
  1668.                                     + PaintFormatter.getFormattedTime(millis)
  1669.                                     + "\n";
  1670.                             lines[4] = PaintFormatter
  1671.                                     .properCaseAll(chopper.currentState.name()
  1672.                                             .replace("_", " "));
  1673.                             return new MenuPopUp(lines, "home");
  1674.                         }
  1675.                     });
  1676.             paintMenu.add(home);
  1677.  
  1678.             MenuButton tools = new MenuButton("tools", paintMenu, "toolsicon",
  1679.                     new GetPopup() {
  1680.                         MenuPopUp getPopUp() {
  1681.                             String[] lines = new String[2];
  1682.                             lines[0] = "Save proggie";
  1683.                             lines[1] = "Reload data";
  1684.                             MenuPopUp popUp = new MenuPopUp(lines, "tools");
  1685.                             popUp.addLineListener(new LineListener() {
  1686.                                 void fireEvent(MouseEvent e, String line) {
  1687.                                     line = line.toLowerCase().trim();
  1688.                                     if (e.getID() == MouseEvent.MOUSE_CLICKED) {
  1689.                                         if (line.contains("save proggie"))
  1690.                                             paintMenu.saveProggie();
  1691.                                         else if (line.contains("reload data"))
  1692.                                             new DataLoader(chopper);
  1693.                                     }
  1694.                                 }
  1695.  
  1696.                                 boolean hasAction(String line) {
  1697.                                     line = line.toLowerCase().trim();
  1698.                                     String[] lines = new String[2];
  1699.                                     lines[0] = "Save proggie";
  1700.                                     lines[1] = "Reload data";
  1701.                                     for (String sub : lines)
  1702.                                         if (sub.equalsIgnoreCase(line))
  1703.                                             return true;
  1704.                                     return false;
  1705.                                 }
  1706.                             });
  1707.                             return popUp;
  1708.                         }
  1709.                     });
  1710.             paintMenu.add(tools);
  1711.  
  1712.             paintMenu.compile();
  1713.         }
  1714.  
  1715.         /**
  1716.          * Gets the current Goal for the setSkill, or sets all goal variables to
  1717.          * -1 if there is no goal
  1718.          */
  1719.         public void setUpGoal() {
  1720.             try {
  1721.                 for (byte b = 0; b < 10; b++)
  1722.                     if (game.getCurrentTab() != Game.TAB_STATS) {
  1723.                         game.openTab(Game.TAB_STATS);
  1724.                         sleep(1000);
  1725.                     } else
  1726.                         break;
  1727.  
  1728.                 RSInterface stats = interfaces.get(320);
  1729.                 if (stats != null && stats.isValid()) {
  1730.                     RSComponent mage = stats
  1731.                             .getComponent(SKILL_INTERFACES[SkillID]);
  1732.                     if (mage != null && mage.isValid()
  1733.                             && mage.getArea() != null) {
  1734.                         mouse.move((int) mage.getArea().getCenterX(),
  1735.                                 (int) mage.getArea().getCenterY());
  1736.                         sleep(500, 750);
  1737.                         // Now we see what the popup is doing
  1738.                         RSComponent pop = stats.getComponent(202);
  1739.                         if (pop != null && pop.isValid()) {
  1740.                             RSComponent def = pop.getComponent(5);
  1741.                             if (def != null && def.isValid()) {
  1742.                                 if (def.getText().trim()
  1743.                                         .equalsIgnoreCase("Target XP:")) {
  1744.                                     RSComponent goalXP = pop.getComponent(6);
  1745.                                     if (goalXP != null && goalXP.isValid()) {
  1746.                                         goalExp = Integer.valueOf(goalXP
  1747.                                                 .getText().replace(",", "")
  1748.                                                 .trim());
  1749.                                         goalLevel = -1;
  1750.                                     }
  1751.                                 } else {
  1752.                                     // Proceed
  1753.                                     RSComponent currExp = pop.getComponent(4);
  1754.                                     RSComponent goalRemainder = pop
  1755.                                             .getComponent(12);
  1756.                                     RSComponent goalLvl = pop.getComponent(10);
  1757.                                     if (currExp != null && currExp.isValid()
  1758.                                             && goalRemainder != null
  1759.                                             && goalRemainder.isValid()
  1760.                                             && goalLvl != null
  1761.                                             && goalLvl.isValid()) {
  1762.                                         goalExp = Integer.valueOf(currExp
  1763.                                                 .getText().replace(",", "")
  1764.                                                 .trim())
  1765.                                                 + Integer.valueOf(goalRemainder
  1766.                                                         .getText()
  1767.                                                         .replace(",", "")
  1768.                                                         .trim());
  1769.                                         goalLevel = Integer.valueOf(goalLvl
  1770.                                                 .getText().replace(",", "")
  1771.                                                 .trim());
  1772.                                     }
  1773.                                 }
  1774.                                 log.info("Target level: "
  1775.                                         + (goalLevel > 0 ? goalLevel : "None"));
  1776.                                 log.info("Target exp: "
  1777.                                         + (goalExp > 0 ? goalExp : "None"));
  1778.                                 return;
  1779.                             }
  1780.                         }
  1781.                     }
  1782.                 }
  1783.             } catch (Exception e) {
  1784.             }
  1785.             goalExp = -1;
  1786.             goalLevel = -1;
  1787.         }
  1788.  
  1789.         /**
  1790.          * Renders the current paint to the given graphics context.
  1791.          *
  1792.          * @param g
  1793.          *            as the Graphics2D object to render to
  1794.          */
  1795.         public void render(Graphics2D g) {
  1796.             paintMenu.render(g, mouseLoc);
  1797.             int mouseX = mouseLoc.x;
  1798.             int mouseY = mouseLoc.y;
  1799.             g.setColor(Color.RED);
  1800.             g.drawLine(mouseX - 5, mouseY - 5, mouseX + 5, mouseY + 5);
  1801.             g.drawLine(mouseX - 5, mouseY + 5, mouseX + 5, mouseY - 5);
  1802.             drawMouse.onRepaint(g);
  1803.         }
  1804.  
  1805.         /**
  1806.          * Fires a MouseEvent in the paintMenu
  1807.          *
  1808.          * @param e
  1809.          *            MouseEvent
  1810.          */
  1811.         public void fireMouseEvent(MouseEvent e) {
  1812.             if (paintMenu.getBoundsFull().contains(e.getPoint()))
  1813.                 paintMenu.fireMouseEvent(e);
  1814.         }
  1815.  
  1816.         /**
  1817.          * Represents a Menu on a PaintInterface
  1818.          *
  1819.          * @author Equinox_
  1820.          *
  1821.          */
  1822.         public class Menu {
  1823.             final int padding = 1;
  1824.             Point location;
  1825.             PaintInterface parent;
  1826.             PaintStyle style;
  1827.             List<MenuItem> components = new ArrayList<MenuItem>();
  1828.             final Anchor anchor;
  1829.             boolean showAllPopups;
  1830.             MenuPopUp visiblePopup = null;
  1831.             List<MouseListen> mouseListeners;
  1832.             LineListener defaultLineListener;
  1833.             private FlowType flowType = FlowType.HORIZONTAL;
  1834.             public Dimension bounds;
  1835.  
  1836.             /**
  1837.              * Constructs a Menu using the provided PaintInterface, Location,
  1838.              * Anchor, and the GameScreen as the bounds
  1839.              *
  1840.              * @param parent
  1841.              *            PaintInterface
  1842.              * @param location
  1843.              *            Point
  1844.              * @param anchor
  1845.              *            Anchor
  1846.              */
  1847.             public Menu(PaintInterface parent, Point location, Anchor anchor) {
  1848.                 this.parent = parent;
  1849.                 this.style = parent.style;
  1850.                 this.location = location;
  1851.                 this.anchor = anchor;
  1852.  
  1853.                 // Setup dimension
  1854.                 Rectangle r = interfaces.get(548).getComponent(3).getArea();
  1855.                 bounds = new Dimension(r.width, r.height);
  1856.             }
  1857.  
  1858.             /**
  1859.              * Sets the FlowType and recompiles the menu
  1860.              *
  1861.              * @param flowType
  1862.              *            FlowType
  1863.              */
  1864.             public void setFlowType(FlowType flowType) {
  1865.                 this.flowType = flowType;
  1866.                 this.compile();
  1867.             }
  1868.  
  1869.             /**
  1870.              * Gets the FlowType
  1871.              *
  1872.              * @return FlowType
  1873.              */
  1874.             public FlowType getFlowType() {
  1875.                 return flowType;
  1876.             }
  1877.  
  1878.             /**
  1879.              * Toggles the showAllPopups state
  1880.              * */
  1881.             public void toggleShowAll() {
  1882.                 showAllPopups = !showAllPopups;
  1883.             }
  1884.  
  1885.             /**
  1886.              * Constructs a menu using the provided parent and location,
  1887.              * assuming Anchor.UP_LEFT
  1888.              *
  1889.              * @param parent
  1890.              *            PaintInterface
  1891.              * @param location
  1892.              *            Point
  1893.              */
  1894.             public Menu(PaintInterface parent, Point location) {
  1895.                 this(parent, location, Anchor.UP_LEFT);
  1896.             }
  1897.  
  1898.             /**
  1899.              * Adds the specified menu item
  1900.              *
  1901.              * @param i
  1902.              *            MenuItem
  1903.              */
  1904.             public void add(MenuItem i) {
  1905.                 i.setIndex(components.size());
  1906.                 components.add(i);
  1907.                 compile();
  1908.             }
  1909.  
  1910.             /**
  1911.              * Compiles this menu
  1912.              */
  1913.             public void compile() {
  1914.                 for (int i = 0; i < components.size(); i++)
  1915.                     components.get(i).compile();
  1916.             }
  1917.  
  1918.             /**
  1919.              * Gets position x based on the menu's anchor
  1920.              *
  1921.              * @return int
  1922.              */
  1923.             public int getAbsX() {
  1924.                 if (anchor.name().contains("LEFT"))
  1925.                     return location.x;
  1926.                 else
  1927.                     return location.x - getWidth();
  1928.             }
  1929.  
  1930.             /**
  1931.              * Gets position y based on the menu's anchor
  1932.              *
  1933.              * @return int
  1934.              */
  1935.             public int getAbsY() {
  1936.                 if (anchor.name().contains("UP"))
  1937.                     return location.y;
  1938.                 else
  1939.                     return location.y - getHeight();
  1940.             }
  1941.  
  1942.             /**
  1943.              * Gets the maximum width of this menu using the menu's FlowType
  1944.              *
  1945.              * @return int
  1946.              */
  1947.             public int getWidth() {
  1948.                 if (flowType.equals(FlowType.HORIZONTAL)) {
  1949.                     int width = padding * components.size();
  1950.                     for (MenuItem m : components)
  1951.                         if (m.bounds != null)
  1952.                             width += m.bounds.width;
  1953.                     return width + padding;
  1954.                 } else {
  1955.                     int max = Integer.MIN_VALUE;
  1956.                     for (MenuItem m : components)
  1957.                         if (m.bounds != null)
  1958.                             if (max < m.bounds.width)
  1959.                                 max = (int) m.bounds.width;
  1960.                     return max + (2 * padding);
  1961.                 }
  1962.             }
  1963.  
  1964.             /**
  1965.              * Gets the maximum height of this menu based of FlowType
  1966.              *
  1967.              * @return int
  1968.              */
  1969.             public int getHeight() {
  1970.                 if (flowType.equals(FlowType.HORIZONTAL)) {
  1971.                     int max = Integer.MIN_VALUE;
  1972.                     for (MenuItem m : components)
  1973.                         if (m.bounds != null)
  1974.                             if (max < m.bounds.height)
  1975.                                 max = (int) m.bounds.height;
  1976.                     return max + (2 * padding);
  1977.                 } else {
  1978.                     int height = padding * components.size();
  1979.                     for (MenuItem m : components)
  1980.                         if (m.bounds != null)
  1981.                             height += m.bounds.height;
  1982.                     return height + padding;
  1983.                 }
  1984.             }
  1985.  
  1986.             /**
  1987.              * Gets the current bounds of this menu, with rounded corners if
  1988.              * specified
  1989.              *
  1990.              * @param rounded
  1991.              *            boolean
  1992.              * @return RoundRectangle2D.Float
  1993.              */
  1994.             public RoundRectangle2D.Float getArea(boolean rounded) {
  1995.                 float round = rounded ? style.roundCorner : 0;
  1996.                 return new RoundRectangle2D.Float(getAbsX(), getAbsY(),
  1997.                         getWidth(), getHeight(), round, round);
  1998.             }
  1999.  
  2000.             public Rectangle getBoundsFull() {
  2001.                 RoundRectangle2D r1 = getArea(false);
  2002.                 RoundRectangle2D r2 = visiblePopup != null ? visiblePopup.bkg
  2003.                         : getArea(false);
  2004.                 int x = (int) Math.min(r1.getX(), r2.getX());
  2005.                 int y = (int) Math.min(r1.getY(), r2.getY());
  2006.                 int width = (int) Math.max(r1.getX() + r1.getWidth(), r2.getX()
  2007.                         + r2.getWidth())
  2008.                         - x;
  2009.                 int height = (int) Math.max(r1.getX() + r1.getHeight(),
  2010.                         r2.getX() + r2.getHeight())
  2011.                         - y;
  2012.                 return new Rectangle(x, y, width, height);
  2013.             }
  2014.  
  2015.             /**
  2016.              * Renders the menu to the specified Graphics object using the
  2017.              * provided mouse location for any popups
  2018.              *
  2019.              * @param g
  2020.              *            Graphics2D
  2021.              * @param mouseLoc
  2022.              *            Point
  2023.              */
  2024.             public void render(Graphics2D g, Point mouseLoc) {
  2025.                 g.setColor(style.bgColor);
  2026.                 g.fill(getArea(true));
  2027.                 MenuPopUp overPopup = null;
  2028.                 for (MenuItem m : components) {
  2029.                     m.render(g);
  2030.                     MenuPopUp p = m.getPopUp();
  2031.                     if (p != null) {
  2032.                         if (m.bounds.contains(mouseLoc)
  2033.                                 || (m.getPopUp().name
  2034.                                         .equalsIgnoreCase(visiblePopup != null ? visiblePopup.name
  2035.                                                 : "") && rectangleContainsApprox(
  2036.                                         visiblePopup.bkg, mouseLoc)))
  2037.                             overPopup = m.getPopUp();
  2038.                     }
  2039.                 }
  2040.                 if (showAllPopups)
  2041.                     getAllPopups(true, "tools").render(g);
  2042.                 else if (overPopup != null) {
  2043.                     overPopup.render(g);
  2044.                 }
  2045.                 visiblePopup = overPopup;
  2046.             }
  2047.  
  2048.             /**
  2049.              * Check if the specified point is within sqrt(2) of the Rectangle
  2050.              *
  2051.              * @param r
  2052.              *            RoundRectangle2D
  2053.              * @param p
  2054.              *            Point
  2055.              * @return boolean contains
  2056.              */
  2057.             public boolean rectangleContainsApprox(RoundRectangle2D r, Point p) {
  2058.                 for (int oX = -1; oX <= 1; oX++)
  2059.                     for (int oY = -1; oY <= 1; oY++)
  2060.                         if (r.contains(new Point(p.x + oX, p.y + oY)))
  2061.                             return true;
  2062.                 return false;
  2063.             }
  2064.  
  2065.             /**
  2066.              * Gets all popups in frontToBack or backToFront order and excluding
  2067.              * specified names
  2068.              *
  2069.              * @param rightToLeft
  2070.              *            boolean
  2071.              * @param excludeItems
  2072.              *            String...
  2073.              * @return MenuPopUp
  2074.              */
  2075.             public MenuPopUp getAllPopups(boolean backToFront,
  2076.                     String... excludeItems) {
  2077.                 List<String> lines = new ArrayList<String>();
  2078.                 if (components.size() > 0)
  2079.                     if (backToFront)
  2080.                         for (int i = components.size() - 1; i >= 0; i--) {
  2081.                             boolean ignored = false;
  2082.                             for (String subS : excludeItems)
  2083.                                 if (components.get(i).name
  2084.                                         .equalsIgnoreCase(subS))
  2085.                                     ignored = true;
  2086.                             if (!ignored) {
  2087.                                 MenuPopUp sub = components.get(i).getPopUp();
  2088.                                 if (sub != null)
  2089.                                     for (String line : sub.lines)
  2090.                                         if (!containsLine(lines, line))
  2091.                                             lines.add(line);
  2092.                             }
  2093.                         }
  2094.                     else
  2095.                         for (int i = 0; i < components.size(); i++) {
  2096.                             boolean ignored = false;
  2097.                             for (String subS : excludeItems)
  2098.                                 if (components.get(i).name
  2099.                                         .equalsIgnoreCase(subS))
  2100.                                     ignored = true;
  2101.                             if (!ignored) {
  2102.                                 MenuPopUp sub = components.get(i).getPopUp();
  2103.                                 if (sub != null)
  2104.                                     for (String line : sub.lines)
  2105.                                         if (!containsLine(lines, line))
  2106.                                             lines.add(line);
  2107.                             }
  2108.                         }
  2109.  
  2110.                 String[] linesArr = new String[lines.size()];
  2111.                 for (int i = 0; i < lines.size(); i++)
  2112.                     linesArr[i] = lines.get(i);
  2113.                 MenuPopUp p = new MenuPopUp(linesArr, "allpopups");
  2114.                 p.setParent(components.get(components.size() - 1));
  2115.                 return p;
  2116.             }
  2117.  
  2118.             /**
  2119.              * Checks if the specified array contains the specified line, just
  2120.              * the tag, not the data if possible
  2121.              *
  2122.              * @param lines
  2123.              *            List of Strings
  2124.              * @param line
  2125.              *            String
  2126.              * @return boolean contains
  2127.              */
  2128.             public boolean containsLine(List<String> lines, String line) {
  2129.                 for (String s : lines)
  2130.                     if (s.contains(":") && line.contains(":")) {
  2131.                         if (s.split(":")[0]
  2132.                                 .equalsIgnoreCase(line.split(":")[0]))
  2133.                             return true;
  2134.                     } else if (s.equalsIgnoreCase(line))
  2135.                         return true;
  2136.                 return false;
  2137.             }
  2138.  
  2139.             /**
  2140.              * Gets a proggie as a BufferedImage
  2141.              *
  2142.              * @return BufferedImage proggie
  2143.              */
  2144.             public BufferedImage getProggie() {
  2145.                 String[] lines = getAllPopups(true, "tools").lines;
  2146.                 Color color = style.FONT_COLOR;
  2147.                 Font font = style.FONT;
  2148.                 float line_height = font.getLineMetrics(lines[0], Paint.frc)
  2149.                         .getHeight();
  2150.                 int width = 0;
  2151.                 for (String line : lines)
  2152.                     if (font.getStringBounds(line, Paint.frc).getWidth() > width)
  2153.                         width = (int) font.getStringBounds(line, Paint.frc)
  2154.                                 .getWidth();
  2155.  
  2156.                 int height = (int) (lines.length * line_height);
  2157.  
  2158.                 width += style.roundCorner + 2;
  2159.                 height += style.roundCorner + 2;
  2160.  
  2161.                 RoundRectangle2D.Float bkg = new RoundRectangle2D.Float(0, 0,
  2162.                         width, height,
  2163.                         style.roundCorner > 0 ? style.roundCorner + 1 : 0,
  2164.                         style.roundCorner > 0 ? style.roundCorner + 1 : 0);
  2165.                 RoundRectangle2D.Float fg = new RoundRectangle2D.Float(
  2166.                         (float) bkg.getX() + 1, (float) bkg.getY() + 1,
  2167.                         width - 2, height - 2, style.roundCorner,
  2168.                         style.roundCorner);
  2169.                 Rectangle txtBounds = new Rectangle(
  2170.                         (int) (fg.getX() + (style.roundCorner / 2)),
  2171.                         (int) (fg.getY() + (style.roundCorner / 2)),
  2172.                         (int) (width - style.roundCorner - 2), (int) (height
  2173.                                 - style.roundCorner - 2));
  2174.                 BufferedImage bImg = new BufferedImage(width, height,
  2175.                         BufferedImage.TYPE_INT_ARGB);
  2176.                 Graphics2D g = (Graphics2D) bImg.getGraphics();
  2177.                 g.setColor(style.bgColor);
  2178.                 g.fill(bkg);
  2179.                 g.setColor(style.fgColor);
  2180.                 g.fill(fg);
  2181.                 g.setFont(font);
  2182.                 g.setColor(color);
  2183.                 for (int i = 0; i < lines.length; i++)
  2184.                     g.drawString(lines[i], txtBounds.x,
  2185.                             ((i + 1) * (line_height)) + txtBounds.y);
  2186.                 return bImg;
  2187.             }
  2188.  
  2189.             /**
  2190.              * Saves a progress report to the Screenshots directory
  2191.              */
  2192.             public void saveProggie() {
  2193.                 String name = chopper.name
  2194.                         + "_"
  2195.                         + PaintFormatter.getFormattedTime(
  2196.                                 System.currentTimeMillis() - Paint.startTime,
  2197.                                 "-", true);
  2198.                 final File dir = new File(
  2199.                         GlobalConfiguration.Paths.getScreenshotsDirectory());
  2200.                 if (dir.isDirectory() || dir.mkdirs()) {
  2201.                     try {
  2202.                         int ext = 0;
  2203.                         while (new File(dir, name
  2204.                                 + (ext > 0 ? ("(" + ext + ")") : "") + ".png")
  2205.                                 .exists())
  2206.                             ext++;
  2207.  
  2208.                         ImageIO.write(Paint.paintMenu.getProggie(), "png",
  2209.                                 new File(dir, name
  2210.                                         + (ext > 0 ? ("(" + ext + ")") : "")));
  2211.                         log.info("Saved proggie!");
  2212.                         log.info(new File(dir, name
  2213.                                 + (ext > 0 ? ("(" + ext + ")") : "") + ".png")
  2214.                                 .getAbsolutePath());
  2215.                     } catch (IOException e) {
  2216.                         log.severe("Failed to save proggie!");
  2217.                     }
  2218.                 }
  2219.             }
  2220.  
  2221.             /**
  2222.              * Adds the specified mouse listener
  2223.              *
  2224.              * @param listen
  2225.              *            MouseListen
  2226.              */
  2227.             public void addMouseListener(MouseListen listen) {
  2228.                 if (mouseListeners == null)
  2229.                     mouseListeners = new ArrayList<MouseListen>();
  2230.                 mouseListeners.add(listen);
  2231.             }
  2232.  
  2233.             /**
  2234.              * Sets the default line listener
  2235.              *
  2236.              * @param listen
  2237.              *            LineListener
  2238.              */
  2239.             public void setDefaultLineListener(LineListener listen) {
  2240.                 defaultLineListener = listen;
  2241.             }
  2242.  
  2243.             /**
  2244.              * Fires the MouseEvent in all containing children and this
  2245.              *
  2246.              * @param e
  2247.              *            MouseEvent
  2248.              */
  2249.             public void fireMouseEvent(MouseEvent e) {
  2250.                 if (getArea(true).contains(e.getPoint()))
  2251.                     if (mouseListeners != null)
  2252.                         for (MouseListen m : mouseListeners)
  2253.                             m.MouseAction(e);
  2254.                 for (MenuItem m : components)
  2255.                     if (m.bounds != null)
  2256.                         if (m.bounds.contains(e.getPoint()))
  2257.                             m.fireMouseEvent(e);
  2258.                 if (visiblePopup != null)
  2259.                     visiblePopup.fireMouseEvent(e);
  2260.  
  2261.             }
  2262.         }
  2263.  
  2264.         /**
  2265.          * Represents a class containing the method for getting the popup
  2266.          *
  2267.          * @author Equinox_
  2268.          *
  2269.          */
  2270.         public abstract class GetPopup {
  2271.             abstract MenuPopUp getPopUp();
  2272.         }
  2273.  
  2274.         /**
  2275.          * Represents a modified MouseListener used in MenuEvents
  2276.          *
  2277.          * @author Equinox_
  2278.          *
  2279.          */
  2280.         public abstract class MouseListen {
  2281.             abstract void MouseAction(MouseEvent e);
  2282.         }
  2283.  
  2284.         /**
  2285.          * An abstract class representing MenuItems
  2286.          *
  2287.          * @author Equinox_
  2288.          *
  2289.          */
  2290.         public abstract class MenuItem {
  2291.             final GetPopup getPopup;
  2292.             Menu parent;
  2293.             RoundRectangle2D.Float bounds;
  2294.             int index;
  2295.             final int width;
  2296.             final int height;
  2297.             List<MouseListen> mouseListeners;
  2298.             final String name;
  2299.  
  2300.             /**
  2301.              * Constructs a MenuItem with the given name, parent, getPopup
  2302.              * method, width and height
  2303.              *
  2304.              * @param name
  2305.              *            String
  2306.              * @param parent
  2307.              *            Menu
  2308.              * @param getPopup
  2309.              *            GetPopup
  2310.              * @param width
  2311.              *            int
  2312.              * @param height
  2313.              *            int
  2314.              */
  2315.             public MenuItem(String name, Menu parent, GetPopup getPopup,
  2316.                     int width, int height) {
  2317.                 this.name = name;
  2318.                 this.height = height;
  2319.                 this.width = width;
  2320.                 this.getPopup = getPopup;
  2321.                 this.parent = parent;
  2322.                 this.bounds = new RoundRectangle2D.Float(0, 0, width, height,
  2323.                         parent.style.roundCorner, parent.style.roundCorner);
  2324.             }
  2325.  
  2326.             /**
  2327.              * Constructs a MenuItem with the given name, parent, width and
  2328.              * height
  2329.              *
  2330.              * @param name
  2331.              *            String
  2332.              * @param parent
  2333.              *            Menu
  2334.              * @param width
  2335.              *            int
  2336.              * @param height
  2337.              *            int
  2338.              */
  2339.             public MenuItem(String name, Menu parent, int width, int height) {
  2340.                 this(name, parent, null, width, height);
  2341.             }
  2342.  
  2343.             /**
  2344.              * sets this item's index
  2345.              *
  2346.              * @param idx
  2347.              *            int
  2348.              */
  2349.             public void setIndex(int idx) {
  2350.                 this.index = idx;
  2351.             }
  2352.  
  2353.             /**
  2354.              * renders this item to the given Graphics2D
  2355.              *
  2356.              * @param g
  2357.              *            Graphics2D
  2358.              */
  2359.             abstract void render(Graphics2D g);
  2360.  
  2361.             /**
  2362.              * Compiles this item
  2363.              */
  2364.             public void compile() {
  2365.                 this.bounds = new RoundRectangle2D.Float(0, 0, width, height,
  2366.                         parent.style.roundCorner, parent.style.roundCorner);
  2367.                 bounds.x = getX();
  2368.                 bounds.y = getY();
  2369.             }
  2370.  
  2371.             /**
  2372.              * Gets the offset from upper left of parent depending on parent's
  2373.              * FlowType
  2374.              *
  2375.              * @return int offsetY
  2376.              */
  2377.             public int getOffX() {
  2378.                 if (parent.getFlowType().equals(FlowType.HORIZONTAL)) {
  2379.                     int x = 1;
  2380.                     for (int i = 0; i < index; i++)
  2381.                         x += 1 + parent.components.get(i).bounds.width;
  2382.  
  2383.                     return x;
  2384.                 }
  2385.                 if (parent.getWidth() > bounds.width)
  2386.                     return (int) (parent.getWidth() / 2 - bounds.width / 2);
  2387.                 return 1;
  2388.             }
  2389.  
  2390.             /**
  2391.              * Gets the offset from upper left of parent depending on parent's
  2392.              * FlowType
  2393.              *
  2394.              * @return int offsetX
  2395.              */
  2396.             public int getOffY() {
  2397.                 if (parent.getFlowType().equals(FlowType.VERTICAL)) {
  2398.                     int y = 1;
  2399.                     for (int i = 0; i < index; i++)
  2400.                         y += 1 + parent.components.get(i).bounds.height;
  2401.  
  2402.                     return y;
  2403.                 }
  2404.                 return 1;
  2405.             }
  2406.  
  2407.             /**
  2408.              * Gets the absolute x
  2409.              *
  2410.              * @return int absolute x
  2411.              */
  2412.             public int getX() {
  2413.                 int x = getOffX() + parent.getAbsX();
  2414.                 return x;
  2415.             }
  2416.  
  2417.             /**
  2418.              * Gets the absolute y
  2419.              *
  2420.              * @return int absolute y
  2421.              */
  2422.             public int getY() {
  2423.                 int y = getOffY() + parent.getAbsY();
  2424.                 return y;
  2425.             }
  2426.  
  2427.             /**
  2428.              * Gets this item's popup
  2429.              *
  2430.              * @return MenuPopUp
  2431.              */
  2432.             public MenuPopUp getPopUp() {
  2433.                 if (getPopup != null) {
  2434.                     MenuPopUp m = getPopup.getPopUp();
  2435.                     m.setParent(this);
  2436.                     if (parent.defaultLineListener != null)
  2437.                         m.addLineListener(parent.defaultLineListener);
  2438.                     return m;
  2439.                 }
  2440.                 return null;
  2441.             }
  2442.  
  2443.             /**
  2444.              * Adds a mouselistener
  2445.              *
  2446.              * @param listen
  2447.              *            MouseListen
  2448.              */
  2449.             public void addMouseListener(MouseListen listen) {
  2450.                 if (mouseListeners == null)
  2451.                     mouseListeners = new ArrayList<MouseListen>();
  2452.                 mouseListeners.add(listen);
  2453.             }
  2454.  
  2455.             /**
  2456.              * Sends the mouse event to all of this item's listeners
  2457.              *
  2458.              * @param e
  2459.              *            MouseEvent
  2460.              */
  2461.             public void fireMouseEvent(MouseEvent e) {
  2462.                 if (mouseListeners != null && mouseListeners.size() > 0)
  2463.                     for (MouseListen m : mouseListeners)
  2464.                         m.MouseAction(e);
  2465.             }
  2466.         }
  2467.  
  2468.         /**
  2469.          * A class representing a mouse over button on the parent menu
  2470.          *
  2471.          * @author Equinox_
  2472.          *
  2473.          */
  2474.         public class MenuButton extends MenuItem {
  2475.             final static int width = 30;
  2476.             final static int height = 30;
  2477.  
  2478.             String imageIcon;
  2479.  
  2480.             /**
  2481.              * Constructs a button using the specified name, parent, imageIcon,
  2482.              * and getPopup method.
  2483.              *
  2484.              * @param name
  2485.              *            String
  2486.              * @param parent
  2487.              *            Menu
  2488.              * @param imageIcon
  2489.              *            String
  2490.              * @param getPopUp
  2491.              *            GetPopup
  2492.              */
  2493.             public MenuButton(String name, Menu parent, String imageIcon,
  2494.                     GetPopup getPopUp) {
  2495.                 super(name, parent, getPopUp, width, height);
  2496.                 this.imageIcon = imageIcon.toLowerCase();
  2497.             }
  2498.  
  2499.             /**
  2500.              * Constructs a button using the specified name, parent, and
  2501.              * imageIcon
  2502.              *
  2503.              * @param name
  2504.              *            String
  2505.              * @param parent
  2506.              *            Menu
  2507.              * @param imageIcon
  2508.              *            String
  2509.              */
  2510.             public MenuButton(String name, Menu parent, String imageIcon) {
  2511.                 this(name, parent, imageIcon, null);
  2512.             }
  2513.  
  2514.             /**
  2515.              * Constructs a button using the specified name and parent
  2516.              *
  2517.              * @param name
  2518.              *            String
  2519.              * @param parent
  2520.              *            Menu
  2521.              */
  2522.             public MenuButton(String name, Menu parent) {
  2523.                 this(name, parent, "", null);
  2524.             }
  2525.  
  2526.             /**
  2527.              * Renders this MenuButton to the given Graphics2D context
  2528.              */
  2529.             public void render(Graphics2D g) {
  2530.                 // Compiling
  2531.                 if (parent.parent.icons.containsKey(imageIcon))
  2532.                     if (parent.parent.icons.get(imageIcon) != null)
  2533.                         if (!parent.parent.icons.containsKey("Button-"
  2534.                                 + imageIcon)) {
  2535.                             // Scale the image
  2536.                             int width = (int) (bounds.width - (parent.style.roundCorner));
  2537.                             int height = (int) (bounds.height - (parent.style.roundCorner));
  2538.                             int hints = Image.SCALE_FAST;
  2539.                             parent.parent.icons.put(
  2540.                                     "Button-" + imageIcon,
  2541.                                     parent.parent.icons.get(imageIcon)
  2542.                                             .getScaledInstance(width, height,
  2543.                                                     hints));
  2544.                         }
  2545.  
  2546.                 g.setColor(parent.style.fgColor);
  2547.                 g.fill(bounds);
  2548.                 if (parent.parent.icons.containsKey("Button-" + imageIcon))
  2549.                     if (parent.parent.icons.get("Button-" + imageIcon) != null)
  2550.                         g.drawImage(
  2551.                                 parent.parent.icons.get("Button-" + imageIcon),
  2552.                                 (int) (bounds.x + (parent.style.roundCorner / 2)),
  2553.                                 (int) (bounds.y + (parent.style.roundCorner / 2)),
  2554.                                 null);
  2555.             }
  2556.         }
  2557.  
  2558.         /**
  2559.          * A class representing a progress bar in a menu
  2560.          *
  2561.          * @author Equinox_
  2562.          *
  2563.          */
  2564.         public class MenuProgressBar extends MenuItem {
  2565.             final static int width = 100;
  2566.             final static int height = 30;
  2567.  
  2568.             final GetPercent getPercent;
  2569.             RoundRectangle2D.Float percent;
  2570.             Point textLoc;
  2571.             String prefix;
  2572.  
  2573.             /**
  2574.              * Constructs a MenuProgress bar using the specified name, parent,
  2575.              * getPercent method, text prefix, and getPopup method
  2576.              *
  2577.              * @param name
  2578.              *            String
  2579.              * @param parent
  2580.              *            Menu
  2581.              * @param getPercent
  2582.              *            GetPercent
  2583.              * @param prefix
  2584.              *            String
  2585.              * @param getPopup
  2586.              *            GetPopup
  2587.              */
  2588.             public MenuProgressBar(String name, Menu parent,
  2589.                     GetPercent getPercent, String prefix, GetPopup getPopup) {
  2590.                 super(name, parent, getPopup, width, height);
  2591.                 this.getPercent = getPercent;
  2592.                 this.prefix = prefix;
  2593.             }
  2594.  
  2595.             /**
  2596.              * Renders this progress bar to the given Graphics context
  2597.              */
  2598.             public void render(Graphics2D g) {
  2599.                 percent.width = getPercent.getPercent();
  2600.                 g.setColor(parent.style.progressBarBG);
  2601.                 g.fill(bounds);
  2602.                 g.setColor(parent.style.progressBarFG);
  2603.                 g.fill(percent);
  2604.                 String perct = String.valueOf(getPercent.getPercent());
  2605.                 if (perct.length() < 2)
  2606.                     perct = "0" + perct;
  2607.                 g.setFont(style.FONT);
  2608.                 g.setColor(style.FONT_COLOR);
  2609.                 g.drawString(prefix + ": " + perct + "%", textLoc.x, textLoc.y);
  2610.             }
  2611.  
  2612.             /**
  2613.              * Compiles this progress bar
  2614.              */
  2615.             public void compile() {
  2616.                 super.compile();
  2617.                 percent = new RoundRectangle2D.Float(bounds.x, bounds.y,
  2618.                         getPercent.getPercent(), bounds.height,
  2619.                         bounds.arcwidth, bounds.archeight);
  2620.                 textLoc = new Point();
  2621.                 textLoc.x = (int) bounds.getCenterX();
  2622.                 textLoc.y = (int) bounds.getCenterY();
  2623.                 textLoc.y += parent.style.FONT.getLineMetrics(prefix + ": 00%",
  2624.                         parent.parent.frc).getHeight() / 2f;
  2625.                 textLoc.x -= parent.style.FONT.getStringBounds(
  2626.                         prefix + ": 00%", parent.parent.frc).getWidth() / 2f;
  2627.             }
  2628.         }
  2629.  
  2630.         /**
  2631.          * Class representing the method for getting the current percentile for
  2632.          * a progress bar
  2633.          *
  2634.          * @author Equinox_
  2635.          *
  2636.          */
  2637.         public abstract class GetPercent {
  2638.             abstract int getPercent();
  2639.         }
  2640.  
  2641.         /**
  2642.          * Class representing the LineListeners in popups
  2643.          *
  2644.          * @author Equinox_
  2645.          *
  2646.          */
  2647.         public abstract class LineListener {
  2648.             abstract void fireEvent(MouseEvent e, String line);
  2649.  
  2650.             abstract boolean hasAction(String line);
  2651.         }
  2652.  
  2653.         /**
  2654.          * A class representing the popups in the paint interface
  2655.          *
  2656.          * @author Equinox_
  2657.          *
  2658.          */
  2659.         public class MenuPopUp {
  2660.             private Font font;
  2661.             private Color color;
  2662.             private PaintStyle style;
  2663.             private RoundRectangle2D bkg;
  2664.             public RoundRectangle2D fg;
  2665.             public Rectangle txtBounds;
  2666.             public MenuItem parent;
  2667.             public final String name;
  2668.             public String[] lines;
  2669.             int width;
  2670.             int height;
  2671.             List<LineListener> lineListeners;
  2672.  
  2673.             /**
  2674.              * Creates a popup using the provided array of strings making up the
  2675.              * lines and name
  2676.              *
  2677.              * @param lines
  2678.              *            as String[]
  2679.              * @param name
  2680.              *            as String
  2681.              */
  2682.             public MenuPopUp(String[] lines, String name) {
  2683.                 this.name = name;
  2684.                 this.lines = lines;
  2685.             }
  2686.  
  2687.             /**
  2688.              * Set this popup's parent and compiles locations
  2689.              *
  2690.              * @param parent
  2691.              *            MenuItem
  2692.              */
  2693.             public void setParent(MenuItem parent) {
  2694.                 this.parent = parent;
  2695.                 this.style = parent.parent.style;
  2696.                 // Calc dimensions
  2697.                 color = name.equals("tools") ? style.TOOLS_FONT_COLOR
  2698.                         : style.FONT_COLOR;
  2699.                 font = name.equals("tools") ? style.TOOLS_FONT : style.FONT;
  2700.                 float line_height = font.getLineMetrics(lines[0], Paint.frc)
  2701.                         .getHeight();
  2702.                 width = 0;
  2703.                 for (String line : lines)
  2704.                     if (font.getStringBounds(line, Paint.frc).getWidth() > width)
  2705.                         width = (int) font.getStringBounds(line, Paint.frc)
  2706.                                 .getWidth();
  2707.  
  2708.                 height = (int) (lines.length * line_height);
  2709.  
  2710.                 width += style.roundCorner + 2;
  2711.                 height += style.roundCorner + 2;
  2712.  
  2713.                 int halfPadding = (parent.parent.padding / 2);
  2714.                 if (halfPadding < 1 && halfPadding != 0)
  2715.                     halfPadding = 1;
  2716.                 int x = 0;
  2717.                 int y = 0;
  2718.                 if (parent.parent.getFlowType().equals(FlowType.HORIZONTAL)) {
  2719.                     if (parent.bounds.y - height - parent.parent.padding > 0) {
  2720.                         // Above
  2721.                         x = (int) (parent.bounds.x - width
  2722.                                 + parent.bounds.width + halfPadding);
  2723.                         if (x < 0)
  2724.                             x = (int) (parent.bounds.x - halfPadding);
  2725.                         y = (int) (parent.parent.getAbsY() - height);
  2726.                     } else {
  2727.                         // Below
  2728.                         x = (int) (parent.bounds.x - halfPadding);
  2729.                         if (x + width > parent.parent.bounds.width)
  2730.                             x = (int) (parent.bounds.x - halfPadding - width);
  2731.                         y = (int) (parent.parent.getAbsY() + parent.parent
  2732.                                 .getHeight());
  2733.                     }
  2734.                 } else {
  2735.                     // Vertical
  2736.                     if (parent.bounds.x - width - parent.parent.padding > 0) {
  2737.                         // Left
  2738.                         x = (int) (parent.parent.getAbsX() - width);
  2739.                         if (parent.bounds.y - height + halfPadding
  2740.                                 + parent.bounds.height > 0)
  2741.                             y = (int) (parent.bounds.y - height + halfPadding + parent.bounds.height);
  2742.                         else
  2743.                             y = (int) (parent.bounds.y - halfPadding);
  2744.                     } else {
  2745.                         // Right
  2746.                         x = (int) (parent.parent.getAbsX() + parent.parent
  2747.                                 .getWidth());
  2748.                         if (parent.bounds.y - height + halfPadding
  2749.                                 + parent.bounds.height > 0)
  2750.                             y = (int) (parent.bounds.y - height + halfPadding + parent.bounds.height);
  2751.                         else
  2752.                             y = (int) (parent.bounds.y - halfPadding);
  2753.                     }
  2754.                 }
  2755.                 bkg = new RoundRectangle2D.Float(x, y, width, height,
  2756.                         style.roundCorner > 0 ? style.roundCorner + 1 : 0,
  2757.                         style.roundCorner > 0 ? style.roundCorner + 1 : 0);
  2758.                 fg = new RoundRectangle2D.Float((float) bkg.getX() + 1,
  2759.                         (float) bkg.getY() + 1, width - 2, height - 2,
  2760.                         style.roundCorner, style.roundCorner);
  2761.                 txtBounds = new Rectangle(
  2762.                         (int) (fg.getX() + (style.roundCorner / 2)),
  2763.                         (int) (fg.getY() + (style.roundCorner / 2)),
  2764.                         (int) (width - style.roundCorner - 2), (int) (height
  2765.                                 - style.roundCorner - 2));
  2766.             }
  2767.  
  2768.             /**
  2769.              * Paints this popup to using the provided Graphics2D in relation to
  2770.              * it's parent PaintInterface
  2771.              *
  2772.              * @param g
  2773.              *            as Graphics2D
  2774.              */
  2775.             public void render(Graphics2D g) {
  2776.                 g.setColor(style.bgColor);
  2777.                 g.fill(bkg);
  2778.                 g.setColor(style.fgColor);
  2779.                 g.fill(fg);
  2780.  
  2781.                 float line_height = (txtBounds.height - 4) / lines.length;
  2782.  
  2783.                 g.setFont(font);
  2784.                 g.setColor(color);
  2785.                 for (int i = 0; i < lines.length; i++) {
  2786.                     if (new Rectangle(txtBounds.x,
  2787.                             (int) ((i * (line_height)) + txtBounds.y),
  2788.                             txtBounds.width, (int) line_height)
  2789.                             .contains(parent.parent.parent.mouseLoc)
  2790.                             && hasAction(lines[i])) {
  2791.                         g.setColor(style.highlightColor);
  2792.                         g.fill(new Rectangle(txtBounds.x,
  2793.                                 (int) ((i * (line_height)) + 2 + txtBounds.y),
  2794.                                 txtBounds.width, (int) line_height));
  2795.                     }
  2796.                     g.setColor(color);
  2797.                     g.drawString(lines[i], txtBounds.x,
  2798.                             ((i + 1) * (line_height)) + txtBounds.y);
  2799.                 }
  2800.             }
  2801.  
  2802.             boolean hasAction(String line) {
  2803.                 if (lineListeners != null)
  2804.                     for (LineListener l : lineListeners)
  2805.                         if (l.hasAction(line))
  2806.                             return true;
  2807.                 return false;
  2808.             }
  2809.  
  2810.             /**
  2811.              * Adds the specified line listener
  2812.              *
  2813.              * @param l
  2814.              *            LineListener
  2815.              */
  2816.             public void addLineListener(LineListener l) {
  2817.                 if (lineListeners == null)
  2818.                     lineListeners = new ArrayList<LineListener>();
  2819.                 this.lineListeners.add(l);
  2820.             }
  2821.  
  2822.             /**
  2823.              * fires the specified mouse event using this popup's line listeners
  2824.              *
  2825.              * @param e
  2826.              *            MouseEvent
  2827.              */
  2828.             public void fireMouseEvent(MouseEvent e) {
  2829.                 if (!bkg.contains(e.getPoint()) || lineListeners == null
  2830.                         || lineListeners.size() == 0)
  2831.                     return;
  2832.  
  2833.                 int line_height = (txtBounds.height - 4) / lines.length;
  2834.  
  2835.                 for (int i = 0; i < lines.length; i++) {
  2836.                     Rectangle stringRect = new Rectangle(txtBounds.x,
  2837.                             (i * (line_height)) + txtBounds.y, txtBounds.width,
  2838.                             line_height);
  2839.                     if (stringRect.contains(e.getPoint())) {
  2840.                         for (LineListener lineListener : lineListeners)
  2841.                             lineListener.fireEvent(e, lines[i]);
  2842.                         return;
  2843.                     }
  2844.                 }
  2845.             }
  2846.         }
  2847.  
  2848.     }
  2849.  
  2850.     /**
  2851.      * Used for specifing the way a menu is layed out.
  2852.      *
  2853.      * @author Equinox_
  2854.      *
  2855.      */
  2856.     private enum FlowType {
  2857.         VERTICAL, HORIZONTAL
  2858.     }
  2859.  
  2860.     /**
  2861.      * Used for anchoring the menu bar
  2862.      *
  2863.      * @author Equinox_
  2864.      *
  2865.      */
  2866.     private enum Anchor {
  2867.         UP_LEFT, UP_RIGHT, DOWN_RIGHT, DOWN_LEFT
  2868.     }
  2869.  
  2870.     /**
  2871.      * Used to style the paint
  2872.      *
  2873.      * @author Equinox_
  2874.      *
  2875.      */
  2876.     public static class PaintStyle {
  2877.         public final Color FONT_COLOR = Color.BLACK;
  2878.         public final Font FONT = new Font("Arial", 1, 10)
  2879.                 .deriveFont(Font.PLAIN);
  2880.  
  2881.         public final Font TOOLS_FONT = new Font("Arial", 1, 14)
  2882.                 .deriveFont(Font.PLAIN);
  2883.         public final Color TOOLS_FONT_COLOR = Color.BLACK;
  2884.  
  2885.         public final float roundCorner = 10f;
  2886.         public final Color progressBarFG = new Color(0f, 1f, 0f, 1f);
  2887.         public final Color progressBarBG = new Color(.3f, .3f, .3f, 1f);
  2888.         public final Color bgColor = new Color(0f, 0f, 0f, 0.75f);
  2889.         final Color fgColor = new Color(.3f, .3f, .3f, 1f);
  2890.         final Color highlightColor = new Color(1f, 0f, 0f, 0.05f);
  2891.     }
  2892.  
  2893.     /**
  2894.      * Loads script data as the actual script runs. Useful for images that are
  2895.      * non-essential.
  2896.      *
  2897.      * @author Equinox_
  2898.      *
  2899.      */
  2900.     public static class DataLoader extends Thread {
  2901.         f2pMaples chopper;
  2902.  
  2903.         public DataLoader(f2pMaples chopper) {
  2904.             super("Data Loader");
  2905.             this.chopper = chopper;
  2906.             this.start();
  2907.         }
  2908.  
  2909.         // Item Info
  2910.         public void checkGE() {
  2911.             long before = System.currentTimeMillis();
  2912.             GEItem item = chopper.getGE().lookup(logID);
  2913.             if (item != null) {
  2914.                 chopper.Paint.logPrice = getItemPrice(item);
  2915.                 chopper.log("Price of " + item.getName() + ": "
  2916.                         + getItemPrice(item));
  2917.                 chopper.log("Loaded log information in "
  2918.                         + PaintFormatter.getFormattedTime(System
  2919.                                 .currentTimeMillis() - before));
  2920.             }
  2921.         }
  2922.  
  2923.         /**
  2924.          * Gets the icon for a specified image in the runescape online database.
  2925.          *
  2926.          * @param id
  2927.          *            as int
  2928.          * @return Image
  2929.          * @throws MalformedURLException
  2930.          * @throws IOException
  2931.          */
  2932.         public Image getItemImage(int id) throws MalformedURLException,
  2933.                 IOException {
  2934.             return ImageIO.read(new URL(
  2935.                     "http://services.runescape.com/m=itemdb_rs/3290_obj_sprite.gif?id="
  2936.                             + id));
  2937.         }
  2938.        
  2939.         public void run() {
  2940.             checkGE();
  2941.             try {
  2942.                 if (JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(
  2943.                         null, "Would you like to load some images?",
  2944.                         "Equinox_ Data Loader", JOptionPane.YES_NO_OPTION))
  2945.                     throw new Exception();
  2946.  
  2947.                 long before = System.currentTimeMillis();
  2948.                 chopper.Paint.putImage(
  2949.                         "homeicon",
  2950.                         ImageIO.read(new URL(chopper.baseURL
  2951.                                 + "/images/houseIcon.png")));
  2952.                 chopper.log("Loaded home image in "
  2953.                         + PaintFormatter.getFormattedTime(System
  2954.                                 .currentTimeMillis() - before));
  2955.  
  2956.                 before = System.currentTimeMillis();
  2957.                 chopper.Paint
  2958.                         .putImage(
  2959.                                 "logicon",
  2960.                                 getItemImage(logID));
  2961.                 chopper.log("Loaded runecrafting image in "
  2962.                         + PaintFormatter.getFormattedTime(System
  2963.                                 .currentTimeMillis() - before));
  2964.  
  2965.                 before = System.currentTimeMillis();
  2966.                 chopper.Paint.putImage(
  2967.                         "toolsicon",
  2968.                         ImageIO.read(new URL(chopper.baseURL
  2969.                                 + "/images/tools.png")));
  2970.                 chopper.log("Loaded tools icon in "
  2971.                         + PaintFormatter.getFormattedTime(System
  2972.                                 .currentTimeMillis() - before));
  2973.             } catch (Exception e) {
  2974.                 chopper.log("Failed to load images");
  2975.             }
  2976.         }
  2977.     }
  2978.  
  2979.     /**
  2980.      * Gets the grandExchange singleton for reference by other classes msg
  2981.      *
  2982.      * @return GrandExchange reference
  2983.      */
  2984.     public GrandExchange getGE() {
  2985.         return grandExchange;
  2986.     }
  2987.  
  2988.     /**
  2989.      * gets the item price based on class. Works with all versions of
  2990.      * grandExchange.class
  2991.      *
  2992.      * @param item
  2993.      *            the GEItem to get the price from
  2994.      * @return int the price
  2995.      *
  2996.      * @author Equinox_
  2997.      */
  2998.     public static int getItemPrice(GEItem item) {
  2999.         for (Method m : item.getClass().getMethods())
  3000.             if (m.getName().equals("getGuidePrice")
  3001.                     || m.getName().equals("getMinPrice"))
  3002.                 try {
  3003.                     return (Integer) (m.invoke(item));
  3004.                 } catch (Exception e) {
  3005.                 }
  3006.         return 0;
  3007.     }
  3008.  
  3009.     /**
  3010.      * Modified Copy of DrawMouse
  3011.      */
  3012.     public class ModifiedDrawMouse {
  3013.         private MouseTrailing mouseTrailing = new MouseTrailing();
  3014.         private ArrayList<Mouses> Click = new ArrayList<Mouses>();
  3015.         private long clickLifeTime = 1500;
  3016.  
  3017.         public void onRepaint(final Graphics render) {
  3018.             if (mouse != null) {
  3019.                 Point Location = mouse.getLocation();
  3020.                 if (mouse.isPressed())
  3021.                     if (Click.size() <= 5)
  3022.                         Click.add(new Mouses(System.currentTimeMillis(),
  3023.                                 Location));
  3024.                 mouseTrailing.draw((Graphics2D) render, Color.WHITE);
  3025.                 render.setColor(Color.GREEN);
  3026.                 render.drawLine(Location.x - 5, Location.y, Location.x + 5,
  3027.                         Location.y);
  3028.                 render.drawLine(Location.x, Location.y - 5, Location.x,
  3029.                         Location.y + 5);
  3030.                 if (Click.size() > 1)
  3031.                     for (Mouses click : Click) {
  3032.                         if (mouse.isPressed())
  3033.                             if (Click.size() <= 10)
  3034.                                 Click.add(new Mouses(
  3035.                                         System.currentTimeMillis(), Location));
  3036.                         float i = ((float) (click.getTime() + clickLifeTime - System
  3037.                                 .currentTimeMillis()) / (float) clickLifeTime) + 0.25f;
  3038.                         if (i > 0) {
  3039.                             render.setColor(new Color(1, 0, 0, i > 1 ? 1 : i));
  3040.                             render.drawLine(click.getLocation().x - 5,
  3041.                                     click.getLocation().y,
  3042.                                     click.getLocation().x + 5,
  3043.                                     click.getLocation().y);
  3044.                             render.drawLine(click.getLocation().x,
  3045.                                     click.getLocation().y - 5,
  3046.                                     click.getLocation().x,
  3047.                                     click.getLocation().y + 5);
  3048.                         } else if (System.currentTimeMillis() - click.getTime() >= 1000) {
  3049.                             Click.remove(click);
  3050.                         }
  3051.                     }
  3052.  
  3053.             }
  3054.         }
  3055.  
  3056.         /**
  3057.          * @author Baheer (Doout).
  3058.          */
  3059.         public class MouseTrailing {
  3060.             private int LifeTime = 1500;
  3061.             private ArrayList<Mouses> Info = new ArrayList<Mouses>();
  3062.  
  3063.             private void getLocation() {
  3064.                 Point m = mouse.getLocation();
  3065.                 if (Add(m)) {
  3066.                     Info.add(new Mouses(System.currentTimeMillis(), m));
  3067.                 }
  3068.             }
  3069.  
  3070.             public boolean Add(Point p) {
  3071.                 for (Mouses Trailing : Info)
  3072.                     if (Trailing.getLocation().equals(p))
  3073.                         return false;
  3074.                 return true;
  3075.             }
  3076.  
  3077.             public void draw(Graphics2D g, Color c) {
  3078.                 getLocation();
  3079.                 if (Info.size() > 1)
  3080.                     for (int t = 1; t < Info.size(); t++) {
  3081.                         Mouses Trailing1 = Info.get(t);
  3082.                         Mouses Trailing2 = Info.get(t - 1);
  3083.                         float i = (float) (Trailing1.getTime() + LifeTime - System
  3084.                                 .currentTimeMillis()) / (float) LifeTime;
  3085.                         if (i > 0) {
  3086.                             g.setColor(new Color(c.getRed() / 255f, c
  3087.                                     .getGreen() / 255f, c.getBlue() / 255f, (c
  3088.                                     .getAlpha() / 255f) * i));
  3089.                             g.drawLine(Trailing1.getLocation().x,
  3090.                                     Trailing1.getLocation().y,
  3091.                                     Trailing2.getLocation().x,
  3092.                                     Trailing2.getLocation().y);
  3093.                         }
  3094.                     }
  3095.                 if (Info.size() > 1) {
  3096.                     if (System.currentTimeMillis() > Info.get(0).getTime()
  3097.                             + LifeTime) {
  3098.                         Info.remove(0);
  3099.                     }
  3100.                 }
  3101.             }
  3102.  
  3103.         }
  3104.  
  3105.         private class Mouses {
  3106.             private long Time;
  3107.             private Point Location;
  3108.  
  3109.             public Mouses(long time, Point loc) {
  3110.                 Time = time;
  3111.                 Location = loc;
  3112.             }
  3113.  
  3114.             public long getTime() {
  3115.                 return Time;
  3116.             }
  3117.  
  3118.             public Point getLocation() {
  3119.                 return Location;
  3120.             }
  3121.         }
  3122.     }
  3123.  
  3124.     public void mouseDragged(MouseEvent arg0) {
  3125.         Paint.mouseLoc = arg0.getPoint();
  3126.     }
  3127.  
  3128.     public void mouseMoved(MouseEvent arg0) {
  3129.         Paint.mouseLoc = arg0.getPoint();
  3130.     }
  3131.  
  3132.     public void mouseClicked(MouseEvent arg0) {
  3133.         Paint.mouseLoc = arg0.getPoint();
  3134.         Paint.fireMouseEvent(arg0);
  3135.     }
  3136.  
  3137.     public void mouseEntered(MouseEvent arg0) {
  3138.         Paint.mouseLoc = arg0.getPoint();
  3139.     }
  3140.  
  3141.     public void mouseExited(MouseEvent arg0) {
  3142.         Paint.mouseLoc = arg0.getPoint();
  3143.     }
  3144.  
  3145.     public void mousePressed(MouseEvent arg0) {
  3146.         Paint.mouseLoc = arg0.getPoint();
  3147.     }
  3148.  
  3149.     public void mouseReleased(MouseEvent arg0) {
  3150.         Paint.mouseLoc = arg0.getPoint();
  3151.     }
  3152.     // EndEquinox_
  3153.  
  3154.     // Start !@!@!
  3155.     private boolean clickObject(RSObject object, String action,
  3156.             boolean useCentralClicking) {
  3157.         Point p;
  3158.         int def = mouse.getSpeed();
  3159.         for (int i = 0; i < 4; i++) {
  3160.             p = useCentralClicking ? getCentralPoint(object.getModel())
  3161.                     : getPointOnScreen(object.getModel(), true);
  3162.             do {
  3163.                 p = useCentralClicking ? getCentralPoint(object.getModel())
  3164.                         : getPointOnScreen(object.getModel(), false);
  3165.                 mouse.move(p, 0, 0);
  3166.             } while (isPartiallyOnScreen(object.getModel()) && p.x != -1
  3167.                     && p.y != -1 && !bank.isOpen()
  3168.                     && !mouse.getLocation().equals(p) && !menu.contains(action));
  3169.             String[] items = menu.getItems();
  3170.             if (items.length > 0
  3171.                     && items[0].toLowerCase().startsWith(action.toLowerCase())) {
  3172.                 mouse.click(true);
  3173.                 return true;
  3174.             } else if (menu.contains(action)) {
  3175.                 mouse.setSpeed(random(5, 8));
  3176.                 mouse.click(false);
  3177.                 sleep(random(100, 200));
  3178.                 for (int x = 0; x < 4; x++) {
  3179.                     if (menu.doAction(action)) {
  3180.                         mouse.setSpeed(def);
  3181.                         return true;
  3182.                     }
  3183.                 }
  3184.             }
  3185.             if (!menu.contains(action) && menu.isOpen()) {
  3186.                 do {
  3187.                     mouse.moveRandomly(random(180, 422));
  3188.                 } while (menu.isOpen());
  3189.                 sleep(random(75, 220));
  3190.                 return false;
  3191.             }
  3192.         }
  3193.         return false;
  3194.     }
  3195.  
  3196.     private boolean isPartiallyOnScreen(RSModel m) {
  3197.         return getPointOnScreen(m, true) != null;
  3198.     }
  3199.  
  3200.     private Point getPointOnScreen(RSModel m, boolean first) {
  3201.         if (m == null) {
  3202.             return null;
  3203.         }
  3204.         ArrayList<Point> list = new ArrayList<Point>();
  3205.         try {
  3206.             Polygon[] tris = m.getTriangles();
  3207.             for (int i = 0; i < tris.length; i++) {
  3208.                 Polygon p = tris[i];
  3209.                 for (int j = 0; j < p.xpoints.length; j++) {
  3210.                     Point pt = new Point(p.xpoints[j], p.ypoints[j]);
  3211.                     if (calc.pointOnScreen(pt)) {
  3212.                         if (first) {
  3213.                             return pt;
  3214.                         }
  3215.                         list.add(pt);
  3216.                     }
  3217.                 }
  3218.             }
  3219.         } catch (Exception e) {
  3220.         }
  3221.         return list.size() > 0 ? list.get(random(0, list.size())) : null;
  3222.     }
  3223.  
  3224.     private Point getCentralPoint(RSModel m) {
  3225.         if (m == null) {
  3226.             return null;
  3227.         }
  3228.         try {
  3229.             int x = 0, y = 0, total = 0;
  3230.             for (Polygon poly : m.getTriangles()) {
  3231.                 for (int i = 0; i < poly.npoints; i++) {
  3232.                     x += poly.xpoints[i];
  3233.                     y += poly.ypoints[i];
  3234.                     total++;
  3235.                 }
  3236.             }
  3237.             Point central = new Point(x / total, y / total);
  3238.             Point curCentral = null;
  3239.             double dist = 20000;
  3240.             for (Polygon poly : m.getTriangles()) {
  3241.                 for (int i = 0; i < poly.npoints; i++) {
  3242.                     Point p = new Point(poly.xpoints[i], poly.ypoints[i]);
  3243.                     if (!calc.pointOnScreen(p)) {
  3244.                         continue;
  3245.                     }
  3246.                     double dist2 = distanceBetween(central, p);
  3247.                     if (curCentral == null || dist2 < dist) {
  3248.                         curCentral = p;
  3249.                         dist = dist2;
  3250.                     }
  3251.                 }
  3252.             }
  3253.             return curCentral;
  3254.         } catch (Exception e) {
  3255.         }
  3256.         return null;
  3257.     }
  3258.  
  3259.     private double distanceBetween(Point p1, Point p2) {
  3260.         return Math.sqrt(((p1.x - p2.x) * (p1.x - p2.x))
  3261.                 + ((p1.y - p2.y) * (p1.y - p2.y)));
  3262.     }
  3263.  
  3264.     // End!@!@!
  3265.  
  3266.     // StartUbuntu4life
  3267.     private void antiBan() {
  3268.         int random = random(1, 5);
  3269.         switch (random) {
  3270.         case 1:
  3271.             if (random(1, 21) != 12)
  3272.                 return;
  3273.             if (mayAntiBan == 2)
  3274.                 mouse.move(random(10, 750), random(10, 495));
  3275.             if (random(1, 7) == 1) {
  3276.                 if (mayAntiBan == 2)
  3277.                     mouse.move(random(10, 750), random(10, 495));
  3278.             }
  3279.             return;
  3280.         case 3:
  3281.             if (random(1, 13) != 8)
  3282.                 return;
  3283.             if (mayAntiBan == 2)
  3284.                 mouse.moveSlightly();
  3285.             return;
  3286.         case 2:
  3287.             if (random(1, 29) != 3)
  3288.                 return;
  3289.             if (random(1, 17) == 1)
  3290.                 camera.setPitch(true);
  3291.             if (mayAntiBan >= 1) {
  3292.                 int angle = camera.getAngle() + random(-45, 45);
  3293.                 if (angle < 0)
  3294.                     angle = random(0, 10);
  3295.                 if (angle > 359)
  3296.                     angle = random(0, 10);
  3297.                 char whichDir = 37;
  3298.                 if (random(0, 100) < 50)
  3299.                     whichDir = 39;
  3300.                 keyboard.pressKey(whichDir);
  3301.                 sleep(random(98, 1302));
  3302.                 keyboard.releaseKey(whichDir);
  3303.             }
  3304.             return;
  3305.         default:
  3306.             return;
  3307.         }
  3308.     }
  3309.     // EndUbuntu4life
  3310. }
Advertisement
Add Comment
Please, Sign In to add comment