Equinox

Equinox Paint System and Mesh Walking

Mar 12th, 2011
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 69.19 KB | None | 0 0
  1.     /**
  2.      * Used to format data into more conventional formats
  3.      *
  4.      * @author Equinox_
  5.      *
  6.      */
  7.     public static class PaintFormatter {
  8.         /**
  9.          * Converts the first letter of every word to uppercase, and the rest
  10.          * lowercase.
  11.          *
  12.          * @param s
  13.          *            The input String
  14.          * @return the properly formatted string
  15.          */
  16.         public static String properCaseAll(String s) {
  17.             String[] words = s.split(" ");
  18.             String result = "";
  19.             for (int i = 0; i < words.length; i++) {
  20.                 String f = words[i].substring(0, 1).toUpperCase();
  21.                 words[i] = f + words[i].substring(1).toLowerCase();
  22.                 result += " " + words[i];
  23.             }
  24.             return result.substring(1);
  25.         }
  26.  
  27.         /**
  28.          * Capitalizes the first letter of every sentence, with every other
  29.          * letter lowercase.
  30.          *
  31.          * @param s
  32.          *            The input string
  33.          * @return The properly formatted String
  34.          */
  35.         public static String properCaseFirst(String s) {
  36.             String[] sentences = new String[] { s };
  37.             if (s.contains("."))
  38.                 sentences = s.split(".");
  39.             String result = "";
  40.             for (int i = 0; i < sentences.length; i++) {
  41.                 String f = sentences[i].substring(0, 1).toUpperCase();
  42.                 sentences[i] = f + sentences[i].substring(1).toLowerCase();
  43.                 result += " " + sentences[i];
  44.             }
  45.             return result.substring(1);
  46.         }
  47.  
  48.         /**
  49.          * Formats time to DD:HH:MM:SS:MSMS with days and millis optional
  50.          *
  51.          * @param timeMillis
  52.          *            long milliseconds of time
  53.          * @param sep
  54.          *            String seperation character
  55.          * @param millisInc
  56.          *            boolean include milliseconds
  57.          * @return
  58.          */
  59.         public static String getFormattedTime(final long timeMillis,
  60.                 String sep, boolean millisInc) {
  61.             long millis = timeMillis;
  62.             final long days = millis / (24 * 1000 * 60 * 60);
  63.             millis -= days * (24 * 1000 * 60 * 60);
  64.             final long hours = millis / (1000 * 60 * 60);
  65.             millis -= hours * 1000 * 60 * 60;
  66.             final long minutes = millis / (1000 * 60);
  67.             millis -= minutes * 1000 * 60;
  68.             final long _seconds = millis / 1000;
  69.             millis -= _seconds * 1000;
  70.             String dayString = String.valueOf(days);
  71.             String hoursString = String.valueOf(hours);
  72.             String minutesString = String.valueOf(minutes);
  73.             String secondsString = String.valueOf(_seconds);
  74.             if (hours < 10) {
  75.                 hoursString = 0 + hoursString;
  76.             }
  77.             if (minutes < 10) {
  78.                 minutesString = 0 + minutesString;
  79.             }
  80.             if (_seconds < 10) {
  81.                 secondsString = 0 + secondsString;
  82.             }
  83.             String s = "";
  84.             if (days > 0)
  85.                 s = dayString + sep;
  86.             s += hoursString + sep + minutesString + sep + secondsString;
  87.             if (millisInc)
  88.                 s += sep + String.valueOf(millis);
  89.             return s;
  90.         }
  91.  
  92.         /**
  93.          * Converts the milliseconds to DD:HH:MM:SS with the days optional.
  94.          *
  95.          * @param timeMillis
  96.          *            the number of milliseconds
  97.          * @return the properly formatted time as a String
  98.          */
  99.         public static String getFormattedTime(final long timeMillis) {
  100.             return getFormattedTime(timeMillis, ":", false);
  101.         }
  102.  
  103.         /**
  104.          * Formats a specified amount into thousands, millions or billions, then
  105.          * adds the proper suffix
  106.          *
  107.          * @param money
  108.          *            the amount of money
  109.          * @return the formatted string
  110.          */
  111.         public static String getFormattedMoney(long money) {
  112.             /*
  113.              * String suffix = ""; int t = 1; if (money >= 10000) { t *= 1000;
  114.              * suffix = "K"; } if (money / t > 10000) { t *= 1000; suffix = "M";
  115.              * } if (money / t > 10000) { t *= 1000; suffix = "B"; } return
  116.              * String.valueOf((money / t)) + suffix;
  117.              */
  118.             return new DecimalFormat("###,###,###,###,###,###").format(money);
  119.         }
  120.  
  121.         /**
  122.          * Converts an array of strings into one string, using commas and 'and' <br>
  123.          * <br>
  124.          * Examples: <br>
  125.          * {"option1"} returns "option1"<br>
  126.          * {"option1","option2"} returns "option1 and option2"<br>
  127.          * {"op1","op2","op3"} returns "op1, op2, and op3"<br>
  128.          * <br>
  129.          *
  130.          * @param list
  131.          *            The array of strings making up the list.
  132.          * @return The properly formatted string
  133.          */
  134.         public static String formatList(String[] list) {
  135.             String s = "";
  136.             if (list != null)
  137.                 if (list.length == 2) {
  138.                     s = list[0] + " and " + list[1];
  139.                 } else if (list.length > 2) {
  140.                     for (int i = 0; i < list.length - 1; i++)
  141.                         s += list[i] + ", ";
  142.                     s += "and " + list[list.length - 1];
  143.                 } else if (list.length == 1)
  144.                     s = list[0];
  145.             return s;
  146.         }
  147.     }
  148.  
  149.     /**
  150.      * A class used to represent the paint interface for this script
  151.      *
  152.      * @author Equinox_
  153.      *
  154.      */
  155.     public class PaintInterface {
  156.         // Constant
  157.         public final int[] SKILL_INTERFACES = { Skills.INTERFACE_ATTACK,
  158.                 Skills.INTERFACE_DEFENSE, Skills.INTERFACE_STRENGTH,
  159.                 Skills.INTERFACE_CONSTITUTION, Skills.INTERFACE_RANGE,
  160.                 Skills.INTERFACE_PRAYER, Skills.INTERFACE_MAGIC,
  161.                 Skills.INTERFACE_COOKING, Skills.INTERFACE_WOODCUTTING,
  162.                 Skills.INTERFACE_FLETCHING, Skills.INTERFACE_FISHING,
  163.                 Skills.INTERFACE_FIREMAKING, Skills.INTERFACE_CRAFTING,
  164.                 Skills.INTERFACE_SMITHING, Skills.INTERFACE_MINING,
  165.                 Skills.INTERFACE_HERBLORE, Skills.INTERFACE_AGILITY,
  166.                 Skills.INTERFACE_THIEVING, Skills.INTERFACE_SLAYER,
  167.                 Skills.INTERFACE_FARMING, Skills.INTERFACE_RUNECRAFTING,
  168.                 Skills.INTERFACE_HUNTER, Skills.INTERFACE_CONSTRUCTION,
  169.                 Skills.INTERFACE_SUMMONING, Skills.INTERFACE_DUNGEONEERING };
  170.  
  171.         // Start data
  172.         public long startExp = 0;
  173.         public long startTime = 0;
  174.         public long startLevel = 1;
  175.  
  176.         // Goal data
  177.         public int goalExp;
  178.         public int goalLevel;
  179.  
  180.         // Usage data
  181.         public int runesMade = 0;
  182.         public int essUsed = 0;
  183.  
  184.         // Price data
  185.         public long essPrice = 1;
  186.  
  187.         // Result data
  188.         public int runsMade = 0;
  189.  
  190.         // Images
  191.         public Map<String, Image> icons = new HashMap<String, Image>();
  192.  
  193.         public void putImage(String name, Image img) {
  194.             icons.put(name.toLowerCase(), img);
  195.         }
  196.  
  197.         public Image getImage(String name) {
  198.             if (icons.containsKey(name.toLowerCase()))
  199.                 return icons.get(name.toLowerCase());
  200.             return null;
  201.         }
  202.  
  203.         // End Images
  204.  
  205.         public FontRenderContext frc = new FontRenderContext(
  206.                 new AffineTransform(), false, false);
  207.  
  208.         public PaintStyle style = new PaintStyle();
  209.         public Point mouseLoc = new Point(0, 0);
  210.  
  211.         final EquinoxZMICrafter crafter;
  212.         final Logger log;
  213.         int SkillID = -1;
  214.         public Menu paintMenu;
  215.  
  216.         /**
  217.          * Constructs a PaintInterface using the provided parent and logger
  218.          * object
  219.          *
  220.          * @param planker
  221.          *            the parent NatCrafter
  222.          * @param log
  223.          *            the Logger object
  224.          */
  225.         public PaintInterface(EquinoxZMICrafter crafter, Logger log) {
  226.             this(crafter, log, -1);
  227.         }
  228.  
  229.         public PaintInterface(EquinoxZMICrafter crafter, Logger log, int SkillID) {
  230.             this.crafter = crafter;
  231.             this.log = log;
  232.             this.SkillID = SkillID;
  233.             startTime = System.currentTimeMillis();
  234.             if (SkillID >= 0 && SkillID < Skills.SKILL_NAMES.length) {
  235.                 startExp = skills.getCurrentExp(SkillID);
  236.                 startLevel = skills.getCurrentLevel(SkillID);
  237.                 setUpGoal();
  238.             }
  239.             init();
  240.         }
  241.  
  242.         public void init() {
  243.             RSComponent screen = interfaces.get(548).getComponent(3);
  244.             Point bottomRight = new Point(screen.getAbsoluteX()
  245.                     + screen.getWidth(), screen.getAbsoluteY()
  246.                     + screen.getHeight());
  247.             paintMenu = new Menu(this, bottomRight, Anchor.DOWN_RIGHT);
  248.             paintMenu.setFlowType(FlowType.HORIZONTAL);
  249.             paintMenu.addMouseListener(new MouseListen() {
  250.                 void MouseAction(MouseEvent e) {
  251.                     if (e.getID() == MouseEvent.MOUSE_CLICKED)
  252.                         paintMenu.toggleShowAll();
  253.                 }
  254.             });
  255.             if (SkillID >= 0 && SkillID < Skills.SKILL_NAMES.length) {
  256.                 MenuProgressBar progressBar = new MenuProgressBar("nextlvl",
  257.                         paintMenu, new GetPercent() {
  258.                             int getPercent() {
  259.                                 return skills.getPercentToNextLevel(SkillID);
  260.                             }
  261.                         }, "Next Level", new GetPopup() {
  262.                             MenuPopUp getPopUp() {
  263.                                 long millis = Math.abs(System
  264.                                         .currentTimeMillis() - startTime);
  265.                                 if (millis <= 0)
  266.                                     millis = 1;
  267.                                 long expGained = skills.getCurrentExp(SkillID)
  268.                                         - startExp;
  269.                                 long expPerHour = (expGained * 3600000l)
  270.                                         / millis;
  271.                                 String TTL = "";
  272.                                 int TTLunf = (int) ((expPerHour > 0) ? (((float) skills
  273.                                         .getExpToNextLevel(SkillID))
  274.                                         / ((float) expPerHour) * 3600000f) : 0);
  275.                                 if (TTLunf != 0)
  276.                                     TTL = PaintFormatter
  277.                                             .getFormattedTime(TTLunf);
  278.                                 else
  279.                                     TTL = "No exp gained";
  280.                                 String[] lines = new String[4];
  281.                                 lines[0] = "Exp gained: "
  282.                                         + PaintFormatter
  283.                                                 .getFormattedMoney(expGained);
  284.                                 lines[1] = "Exp per Hour: "
  285.                                         + PaintFormatter
  286.                                                 .getFormattedMoney(expPerHour);
  287.                                 lines[2] = "Exp 'till level: "
  288.                                         + PaintFormatter.getFormattedMoney(skills
  289.                                                 .getExpToNextLevel(SkillID));
  290.                                 lines[3] = "Time 'till level: " + TTL;
  291.                                 return new MenuPopUp(lines, "nextlevel");
  292.                             }
  293.  
  294.                         });
  295.                 paintMenu.add(progressBar);
  296.  
  297.                 if (goalExp > skills.getCurrentExp(SkillID)) {
  298.                     MenuProgressBar goalBar = new MenuProgressBar("goal",
  299.                             paintMenu, new GetPercent() {
  300.                                 int getPercent() {
  301.                                     float expTillGoalStart = goalExp - startExp;
  302.                                     double expGained = skills
  303.                                             .getCurrentExp(SkillID) - startExp;
  304.                                     double result = expGained
  305.                                             / expTillGoalStart;
  306.                                     if (result > 1)
  307.                                         result = 1;
  308.                                     if (result < 0)
  309.                                         result = 0;
  310.                                     return (int) (result * 100);
  311.                                 }
  312.                             }, "Goal", new GetPopup() {
  313.                                 MenuPopUp getPopUp() {
  314.                                     long millis = Math.abs(System
  315.                                             .currentTimeMillis() - startTime);
  316.                                     if (millis <= 0)
  317.                                         millis = 1;
  318.                                     long expGained = skills
  319.                                             .getCurrentExp(SkillID) - startExp;
  320.                                     long expPerHour = (expGained * 3600000l)
  321.                                             / millis;
  322.                                     int expTillGoal = goalExp
  323.                                             - skills.getCurrentExp(SkillID);
  324.                                     String TTG = "";
  325.                                     int TTGunf = (int) ((expPerHour > 0) ? (((float) expTillGoal)
  326.                                             / ((float) expPerHour) * 3600000f)
  327.                                             : 0);
  328.                                     if (TTGunf != 0)
  329.                                         TTG = PaintFormatter
  330.                                                 .getFormattedTime(TTGunf);
  331.                                     else
  332.                                         TTG = "No exp gained";
  333.                                     String[] lines = new String[goalLevel > 0 ? 6
  334.                                             : 5];
  335.                                     int off = goalLevel > 0 ? 1 : 0;
  336.                                     if (goalLevel > 0)
  337.                                         lines[0] = "Goal Level: " + goalLevel;
  338.                                     lines[0 + off] = "Goal Exp: "
  339.                                             + PaintFormatter
  340.                                                     .getFormattedMoney(goalExp);
  341.                                     lines[1 + off] = "Exp gained: "
  342.                                             + PaintFormatter
  343.                                                     .getFormattedMoney(expGained);
  344.                                     lines[2 + off] = "Exp per Hour: "
  345.                                             + PaintFormatter
  346.                                                     .getFormattedMoney(expPerHour);
  347.                                     lines[3 + off] = "Exp 'till goal: "
  348.                                             + PaintFormatter
  349.                                                     .getFormattedMoney(expTillGoal);
  350.                                     lines[4 + off] = "Time 'till goal: " + TTG;
  351.                                     return new MenuPopUp(lines, "goalbar");
  352.                                 }
  353.  
  354.                             });
  355.                     paintMenu.add(goalBar);
  356.                 }
  357.             }
  358.  
  359.             MenuButton rcing = new MenuButton("rcing", paintMenu, "rcicon",
  360.                     new GetPopup() {
  361.                         MenuPopUp getPopUp() {
  362.                             long millis = System.currentTimeMillis()
  363.                                     - crafter.Paint.startTime;
  364.                             if (millis <= 0)
  365.                                 millis = 1;
  366.                             String runesPerEssence = "Runes per Ess: "
  367.                                     + ((essUsed > 0) ? (new DecimalFormat(
  368.                                             "#.##").format(((double) runesMade)
  369.                                             / ((double) essUsed)))
  370.                                             : "No essence used");
  371.                             long runesPerHour = ((runesMade * 3600000l) / millis);
  372.                             /*
  373.                              * long profit = (runesMade * natPrice) - (essUsed *
  374.                              * essPrice) - (graahksUsed * graahkPrice);
  375.                              */
  376.                             String[] lines = new String[7];
  377.                             lines[0] = "Essence Used: "
  378.                                     + PaintFormatter.getFormattedMoney(essUsed);
  379.                             lines[1] = "Runes Crafted: "
  380.                                     + PaintFormatter
  381.                                             .getFormattedMoney(runesMade);
  382.                             lines[2] = "Runes/Hour: "
  383.                                     + PaintFormatter
  384.                                             .getFormattedMoney(runesPerHour);
  385.                             /*
  386.                              * lines[4] = "Profit: " +
  387.                              * PaintFormatter.getFormattedMoney(profit) + " gp";
  388.                              * lines[5] = "Profit per hour: " + PaintFormatter
  389.                              * .getFormattedMoney((profit * 3600000) / millis) +
  390.                              * " gp";
  391.                              */
  392.                             lines[3] = runesPerEssence;
  393.                             lines[4] = "Runs made: " + runsMade;
  394.                             lines[5] = "Runes per run: "
  395.                                     + (runsMade > 0 ? (int) (runesMade / runsMade)
  396.                                             : "No runs made");
  397.                             lines[6] = "Runes in inventory: "
  398.                                     + crafter.getRuneCount(true);
  399.                             return new MenuPopUp(lines, "runes");
  400.                         }
  401.                     });
  402.             paintMenu.add(rcing);
  403.  
  404.             MenuButton home = new MenuButton("home", paintMenu, "homeicon",
  405.                     new GetPopup() {
  406.                         MenuPopUp getPopUp() {
  407.                             long millis = System.currentTimeMillis()
  408.                                     - crafter.Paint.startTime;
  409.                             if (millis <= 0)
  410.                                 millis = 1;
  411.                             String[] lines = new String[5];
  412.                             lines[0] = crafter.name;
  413.                             lines[1] = "By: " + crafter.author;
  414.                             lines[2] = "Version " + crafter.VERSION;
  415.                             lines[3] = "Runtime: "
  416.                                     + PaintFormatter.getFormattedTime(millis)
  417.                                     + "\n";
  418.                             lines[4] = PaintFormatter
  419.                                     .properCaseAll(crafter.currentState.name()
  420.                                             .replace("_", " "));
  421.                             if (crafter.currentState.equals(State.NPC_CONTACT))
  422.                                 lines[4] += " - "
  423.                                         + PaintFormatter
  424.                                                 .properCaseAll(npcContact.currentState
  425.                                                         .name().replace("_",
  426.                                                                 " "));
  427.                             return new MenuPopUp(lines, "home");
  428.                         }
  429.                     });
  430.             paintMenu.add(home);
  431.  
  432.             MenuButton tools = new MenuButton("tools", paintMenu, "toolsicon",
  433.                     new GetPopup() {
  434.                         MenuPopUp getPopUp() {
  435.                             String[] lines = new String[5];
  436.                             lines[0] = "Save proggie";
  437.                             lines[1] = "Reload data";
  438.                             if (crafter.pathTypeCurrent.equals(Path.Danger))
  439.                                 lines[2] = "Set to safe path";
  440.                             else
  441.                                 lines[2] = "Set to dangerous path";
  442.                             if (Options.chargeEnergy)
  443.                                 lines[3] = "Do not recharge energy";
  444.                             else
  445.                                 lines[3] = "Recharge energy";
  446.                             if (Options.tryOuraniaTeleport)
  447.                                 lines[4] = "Do not try Ourania Teleport";
  448.                             else
  449.                                 lines[4] = "Try Ourania Teleport";
  450.                             MenuPopUp popUp = new MenuPopUp(lines, "tools");
  451.                             popUp.addLineListener(new LineListener() {
  452.                                 void fireEvent(MouseEvent e, String line) {
  453.                                     line = line.toLowerCase().trim();
  454.                                     if (e.getID() == MouseEvent.MOUSE_CLICKED) {
  455.                                         if (line.contains("save proggie"))
  456.                                             paintMenu.saveProggie();
  457.                                         else if (line.contains("reload data"))
  458.                                             new DataLoader(crafter);
  459.                                         else if (line.contains("safe path"))
  460.                                             Options.pathType = Path.Safe;
  461.                                         else if (line
  462.                                                 .contains("dangerous path"))
  463.                                             Options.pathType = Path.Danger;
  464.                                         else if (line
  465.                                                 .contains("do not recharge"))
  466.                                             Options.chargeEnergy = false;
  467.                                         else if (line.contains("recharge"))
  468.                                             Options.chargeEnergy = true;
  469.                                         else if (line
  470.                                                 .contains("do not try ourania teleport"))
  471.                                             Options.tryOuraniaTeleport = false;
  472.                                         else if (line
  473.                                                 .contains("try ourania teleport")) {
  474.                                             if (skills
  475.                                                     .getCurrentLevel(Skills.MAGIC) < 17) {
  476.                                                 log.severe("You must have 71 magic to use this feature!");
  477.                                                 return;
  478.                                             }
  479.                                             if (!Options.onLunars) {
  480.                                                 log.severe("You must be on the Lunar spellbook to use this feature!");
  481.                                                 return;
  482.                                             }
  483.                                             Options.tryOuraniaTeleport = true;
  484.                                         }
  485.                                     }
  486.                                 }
  487.  
  488.                                 boolean hasAction(String line) {
  489.                                     line = line.toLowerCase().trim();
  490.                                     String[] lines = new String[5];
  491.                                     lines[0] = "Save proggie";
  492.                                     lines[1] = "Reload data";
  493.                                     if (crafter.pathTypeCurrent
  494.                                             .equals(Path.Danger))
  495.                                         lines[2] = "Set to safe path";
  496.                                     else
  497.                                         lines[2] = "Set to dangerous path";
  498.                                     if (Options.chargeEnergy)
  499.                                         lines[3] = "Do not recharge energy";
  500.                                     else
  501.                                         lines[3] = "Recharge energy";
  502.                                     if (Options.tryOuraniaTeleport)
  503.                                         lines[4] = "Do not try Ourania Teleport";
  504.                                     else
  505.                                         lines[4] = "Try Ourania Teleport";
  506.                                     for (String sub : lines)
  507.                                         if (sub.equalsIgnoreCase(line))
  508.                                             return true;
  509.                                     return false;
  510.                                 }
  511.                             });
  512.                             return popUp;
  513.                         }
  514.                     });
  515.             paintMenu.add(tools);
  516.  
  517.             paintMenu.compile();
  518.         }
  519.  
  520.         /**
  521.          * Gets the current Goal for the setSkill, or sets all goal variables to
  522.          * -1 if there is no goal
  523.          */
  524.         public void setUpGoal() {
  525.             try {
  526.                 for (byte b = 0; b < 10; b++)
  527.                     if (game.getCurrentTab() != Game.TAB_STATS) {
  528.                         game.openTab(Game.TAB_STATS);
  529.                         sleep(1000);
  530.                     } else
  531.                         break;
  532.  
  533.                 RSInterface stats = interfaces.get(320);
  534.                 if (stats != null && stats.isValid()) {
  535.                     RSComponent mage = stats
  536.                             .getComponent(SKILL_INTERFACES[SkillID]);
  537.                     if (mage != null && mage.isValid()
  538.                             && mage.getArea() != null) {
  539.                         mouse.move((int) mage.getArea().getCenterX(),
  540.                                 (int) mage.getArea().getCenterY());
  541.                         sleep(500, 750);
  542.                         // Now we see what the popup is doing
  543.                         RSComponent pop = stats.getComponent(202);
  544.                         if (pop != null && pop.isValid()) {
  545.                             RSComponent def = pop.getComponent(5);
  546.                             if (def != null && def.isValid()) {
  547.                                 if (def.getText().trim()
  548.                                         .equalsIgnoreCase("Target XP:")) {
  549.                                     RSComponent goalXP = pop.getComponent(6);
  550.                                     if (goalXP != null && goalXP.isValid()) {
  551.                                         goalExp = Integer.valueOf(goalXP
  552.                                                 .getText().replace(",", "")
  553.                                                 .trim());
  554.                                         goalLevel = -1;
  555.                                     }
  556.                                 } else {
  557.                                     // Proceed
  558.                                     RSComponent currExp = pop.getComponent(4);
  559.                                     RSComponent goalRemainder = pop
  560.                                             .getComponent(12);
  561.                                     RSComponent goalLvl = pop.getComponent(10);
  562.                                     if (currExp != null && currExp.isValid()
  563.                                             && goalRemainder != null
  564.                                             && goalRemainder.isValid()
  565.                                             && goalLvl != null
  566.                                             && goalLvl.isValid()) {
  567.                                         goalExp = Integer.valueOf(currExp
  568.                                                 .getText().replace(",", "")
  569.                                                 .trim())
  570.                                                 + Integer.valueOf(goalRemainder
  571.                                                         .getText()
  572.                                                         .replace(",", "")
  573.                                                         .trim());
  574.                                         goalLevel = Integer.valueOf(goalLvl
  575.                                                 .getText().replace(",", "")
  576.                                                 .trim());
  577.                                     }
  578.                                 }
  579.                                 log.info("Target level: "
  580.                                         + (goalLevel > 0 ? goalLevel : "None"));
  581.                                 log.info("Target exp: "
  582.                                         + (goalExp > 0 ? goalExp : "None"));
  583.                                 return;
  584.                             }
  585.                         }
  586.                     }
  587.                 }
  588.             } catch (Exception e) {
  589.             }
  590.             goalExp = -1;
  591.             goalLevel = -1;
  592.         }
  593.  
  594.         /**
  595.          * Renders the current paint to the given graphics context.
  596.          *
  597.          * @param g
  598.          *            as the Graphics2D object to render to
  599.          */
  600.         public void render(Graphics2D g) {
  601.             paintPouches(g);
  602.             paintMenu.render(g, mouseLoc);
  603.             int mouseX = mouseLoc.x;
  604.             int mouseY = mouseLoc.y;
  605.             g.setColor(Color.RED);
  606.             g.drawLine(mouseX - 5, mouseY - 5, mouseX + 5, mouseY + 5);
  607.             g.drawLine(mouseX - 5, mouseY + 5, mouseX + 5, mouseY - 5);
  608.         }
  609.  
  610.         /**
  611.          * Paints the pouches loaded into the list using red for empty and green
  612.          * for full. Only paints if inventory is visible.
  613.          *
  614.          * @param g
  615.          *            as Graphics
  616.          */
  617.         public void paintPouches(Graphics g) {
  618.             // Loop through pouches
  619.             for (PouchType pouch : crafter.pouches.keySet()) {
  620.                 if (game.getCurrentTab() == Game.TAB_INVENTORY) {
  621.                     RSItem item = inventory.getItem(pouch.ids);
  622.                     if (item != null) {
  623.                         if (crafter.pouches.get(pouch).equals(PouchState.Empty))
  624.                             g.setColor(new Color(1f, 0f, 0f, 0.5f));
  625.                         else
  626.                             g.setColor(new Color(0f, 1f, 0f, 0.5f));
  627.  
  628.                         RSComponent c = item.getComponent();
  629.                         g.fillRect(c.getAbsoluteX(), c.getAbsoluteY(),
  630.                                 c.getWidth(), c.getHeight());
  631.                         // Decay:
  632.                         for (int id : Pouch.ALL_DEGRADED)
  633.                             if (item.getID() == id) {
  634.                                 g.setColor(Color.WHITE);
  635.                                 g.setFont(style.FONT.deriveFont(4));
  636.                                 g.drawString("Degraded", c.getAbsoluteX(),
  637.                                         c.getAbsoluteY() + c.getHeight());
  638.                                 break;
  639.                             }
  640.                     }
  641.                 }
  642.             }
  643.         }
  644.  
  645.         /**
  646.          * Fires a MouseEvent in the paintMenu
  647.          *
  648.          * @param e
  649.          *            MouseEvent
  650.          */
  651.         public void fireMouseEvent(MouseEvent e) {
  652.             if (paintMenu.getBoundsFull().contains(e.getPoint()))
  653.                 paintMenu.fireMouseEvent(e);
  654.         }
  655.  
  656.         /**
  657.          * Represents a Menu on a PaintInterface
  658.          *
  659.          * @author Equinox_
  660.          *
  661.          */
  662.         public class Menu {
  663.             final int padding = 1;
  664.             Point location;
  665.             PaintInterface parent;
  666.             PaintStyle style;
  667.             List<MenuItem> components = new ArrayList<MenuItem>();
  668.             final Anchor anchor;
  669.             boolean showAllPopups;
  670.             MenuPopUp visiblePopup = null;
  671.             List<MouseListen> mouseListeners;
  672.             LineListener defaultLineListener;
  673.             private FlowType flowType = FlowType.HORIZONTAL;
  674.             public Dimension bounds;
  675.  
  676.             /**
  677.              * Constructs a Menu using the provided PaintInterface, Location,
  678.              * Anchor, and the GameScreen as the bounds
  679.              *
  680.              * @param parent
  681.              *            PaintInterface
  682.              * @param location
  683.              *            Point
  684.              * @param anchor
  685.              *            Anchor
  686.              */
  687.             public Menu(PaintInterface parent, Point location, Anchor anchor) {
  688.                 this.parent = parent;
  689.                 this.style = parent.style;
  690.                 this.location = location;
  691.                 this.anchor = anchor;
  692.  
  693.                 // Setup dimension
  694.                 Rectangle r = interfaces.get(548).getComponent(3).getArea();
  695.                 bounds = new Dimension(r.width, r.height);
  696.             }
  697.  
  698.             /**
  699.              * Sets the FlowType and recompiles the menu
  700.              *
  701.              * @param flowType
  702.              *            FlowType
  703.              */
  704.             public void setFlowType(FlowType flowType) {
  705.                 this.flowType = flowType;
  706.                 this.compile();
  707.             }
  708.  
  709.             /**
  710.              * Gets the FlowType
  711.              *
  712.              * @return FlowType
  713.              */
  714.             public FlowType getFlowType() {
  715.                 return flowType;
  716.             }
  717.  
  718.             /**
  719.              * Toggles the showAllPopups state
  720.              * */
  721.             public void toggleShowAll() {
  722.                 showAllPopups = !showAllPopups;
  723.             }
  724.  
  725.             /**
  726.              * Constructs a menu using the provided parent and location,
  727.              * assuming Anchor.UP_LEFT
  728.              *
  729.              * @param parent
  730.              *            PaintInterface
  731.              * @param location
  732.              *            Point
  733.              */
  734.             public Menu(PaintInterface parent, Point location) {
  735.                 this(parent, location, Anchor.UP_LEFT);
  736.             }
  737.  
  738.             /**
  739.              * Adds the specified menu item
  740.              *
  741.              * @param i
  742.              *            MenuItem
  743.              */
  744.             public void add(MenuItem i) {
  745.                 i.setIndex(components.size());
  746.                 components.add(i);
  747.                 compile();
  748.             }
  749.  
  750.             /**
  751.              * Compiles this menu
  752.              */
  753.             public void compile() {
  754.                 for (int i = 0; i < components.size(); i++)
  755.                     components.get(i).compile();
  756.             }
  757.  
  758.             /**
  759.              * Gets position x based on the menu's anchor
  760.              *
  761.              * @return int
  762.              */
  763.             public int getAbsX() {
  764.                 if (anchor.name().contains("LEFT"))
  765.                     return location.x;
  766.                 else
  767.                     return location.x - getWidth();
  768.             }
  769.  
  770.             /**
  771.              * Gets position y based on the menu's anchor
  772.              *
  773.              * @return int
  774.              */
  775.             public int getAbsY() {
  776.                 if (anchor.name().contains("UP"))
  777.                     return location.y;
  778.                 else
  779.                     return location.y - getHeight();
  780.             }
  781.  
  782.             /**
  783.              * Gets the maximum width of this menu using the menu's FlowType
  784.              *
  785.              * @return int
  786.              */
  787.             public int getWidth() {
  788.                 if (flowType.equals(FlowType.HORIZONTAL)) {
  789.                     int width = padding * components.size();
  790.                     for (MenuItem m : components)
  791.                         if (m.bounds != null)
  792.                             width += m.bounds.width;
  793.                     return width + padding;
  794.                 } else {
  795.                     int max = Integer.MIN_VALUE;
  796.                     for (MenuItem m : components)
  797.                         if (m.bounds != null)
  798.                             if (max < m.bounds.width)
  799.                                 max = (int) m.bounds.width;
  800.                     return max + (2 * padding);
  801.                 }
  802.             }
  803.  
  804.             /**
  805.              * Gets the maximum height of this menu based of FlowType
  806.              *
  807.              * @return int
  808.              */
  809.             public int getHeight() {
  810.                 if (flowType.equals(FlowType.HORIZONTAL)) {
  811.                     int max = Integer.MIN_VALUE;
  812.                     for (MenuItem m : components)
  813.                         if (m.bounds != null)
  814.                             if (max < m.bounds.height)
  815.                                 max = (int) m.bounds.height;
  816.                     return max + (2 * padding);
  817.                 } else {
  818.                     int height = padding * components.size();
  819.                     for (MenuItem m : components)
  820.                         if (m.bounds != null)
  821.                             height += m.bounds.height;
  822.                     return height + padding;
  823.                 }
  824.             }
  825.  
  826.             /**
  827.              * Gets the current bounds of this menu, with rounded corners if
  828.              * specified
  829.              *
  830.              * @param rounded
  831.              *            boolean
  832.              * @return RoundRectangle2D.Float
  833.              */
  834.             public RoundRectangle2D.Float getArea(boolean rounded) {
  835.                 float round = rounded ? style.roundCorner : 0;
  836.                 return new RoundRectangle2D.Float(getAbsX(), getAbsY(),
  837.                         getWidth(), getHeight(), round, round);
  838.             }
  839.  
  840.             public Rectangle getBoundsFull() {
  841.                 RoundRectangle2D r1 = getArea(false);
  842.                 RoundRectangle2D r2 = visiblePopup != null ? visiblePopup.bkg
  843.                         : getArea(false);
  844.                 int x = (int) Math.min(r1.getX(), r2.getX());
  845.                 int y = (int) Math.min(r1.getY(), r2.getY());
  846.                 int width = (int) Math.max(r1.getX() + r1.getWidth(), r2.getX()
  847.                         + r2.getWidth())
  848.                         - x;
  849.                 int height = (int) Math.max(r1.getX() + r1.getHeight(),
  850.                         r2.getX() + r2.getHeight())
  851.                         - y;
  852.                 return new Rectangle(x, y, width, height);
  853.             }
  854.  
  855.             /**
  856.              * Renders the menu to the specified Graphics object using the
  857.              * provided mouse location for any popups
  858.              *
  859.              * @param g
  860.              *            Graphics2D
  861.              * @param mouseLoc
  862.              *            Point
  863.              */
  864.             public void render(Graphics2D g, Point mouseLoc) {
  865.                 g.setColor(style.bgColor);
  866.                 g.fill(getArea(true));
  867.                 MenuPopUp overPopup = null;
  868.                 for (MenuItem m : components) {
  869.                     m.render(g);
  870.                     MenuPopUp p = m.getPopUp();
  871.                     if (p != null) {
  872.                         if (m.bounds.contains(mouseLoc)
  873.                                 || (m.getPopUp().name
  874.                                         .equalsIgnoreCase(visiblePopup != null ? visiblePopup.name
  875.                                                 : "") && rectangleContainsApprox(
  876.                                         visiblePopup.bkg, mouseLoc)))
  877.                             overPopup = m.getPopUp();
  878.                     }
  879.                 }
  880.                 if (showAllPopups)
  881.                     getAllPopups(true, "tools").render(g);
  882.                 else if (overPopup != null) {
  883.                     overPopup.render(g);
  884.                 }
  885.                 visiblePopup = overPopup;
  886.             }
  887.  
  888.             /**
  889.              * Check if the specified point is within sqrt(2) of the Rectangle
  890.              *
  891.              * @param r
  892.              *            RoundRectangle2D
  893.              * @param p
  894.              *            Point
  895.              * @return boolean contains
  896.              */
  897.             public boolean rectangleContainsApprox(RoundRectangle2D r, Point p) {
  898.                 for (int oX = -1; oX <= 1; oX++)
  899.                     for (int oY = -1; oY <= 1; oY++)
  900.                         if (r.contains(new Point(p.x + oX, p.y + oY)))
  901.                             return true;
  902.                 return false;
  903.             }
  904.  
  905.             /**
  906.              * Gets all popups in frontToBack or backToFront order and excluding
  907.              * specified names
  908.              *
  909.              * @param rightToLeft
  910.              *            boolean
  911.              * @param excludeItems
  912.              *            String...
  913.              * @return MenuPopUp
  914.              */
  915.             public MenuPopUp getAllPopups(boolean backToFront,
  916.                     String... excludeItems) {
  917.                 List<String> lines = new ArrayList<String>();
  918.                 if (components.size() > 0)
  919.                     if (backToFront)
  920.                         for (int i = components.size() - 1; i >= 0; i--) {
  921.                             boolean ignored = false;
  922.                             for (String subS : excludeItems)
  923.                                 if (components.get(i).name
  924.                                         .equalsIgnoreCase(subS))
  925.                                     ignored = true;
  926.                             if (!ignored) {
  927.                                 MenuPopUp sub = components.get(i).getPopUp();
  928.                                 if (sub != null)
  929.                                     for (String line : sub.lines)
  930.                                         if (!containsLine(lines, line))
  931.                                             lines.add(line);
  932.                             }
  933.                         }
  934.                     else
  935.                         for (int i = 0; i < components.size(); i++) {
  936.                             boolean ignored = false;
  937.                             for (String subS : excludeItems)
  938.                                 if (components.get(i).name
  939.                                         .equalsIgnoreCase(subS))
  940.                                     ignored = true;
  941.                             if (!ignored) {
  942.                                 MenuPopUp sub = components.get(i).getPopUp();
  943.                                 if (sub != null)
  944.                                     for (String line : sub.lines)
  945.                                         if (!containsLine(lines, line))
  946.                                             lines.add(line);
  947.                             }
  948.                         }
  949.  
  950.                 String[] linesArr = new String[lines.size()];
  951.                 for (int i = 0; i < lines.size(); i++)
  952.                     linesArr[i] = lines.get(i);
  953.                 MenuPopUp p = new MenuPopUp(linesArr, "allpopups");
  954.                 p.setParent(components.get(components.size() - 1));
  955.                 return p;
  956.             }
  957.  
  958.             /**
  959.              * Checks if the specified array contains the specified line, just
  960.              * the tag, not the data if possible
  961.              *
  962.              * @param lines
  963.              *            List of Strings
  964.              * @param line
  965.              *            String
  966.              * @return boolean contains
  967.              */
  968.             public boolean containsLine(List<String> lines, String line) {
  969.                 for (String s : lines)
  970.                     if (s.contains(":") && line.contains(":")) {
  971.                         if (s.split(":")[0]
  972.                                 .equalsIgnoreCase(line.split(":")[0]))
  973.                             return true;
  974.                     } else if (s.equalsIgnoreCase(line))
  975.                         return true;
  976.                 return false;
  977.             }
  978.  
  979.             /**
  980.              * Gets a proggie as a BufferedImage
  981.              *
  982.              * @return BufferedImage proggie
  983.              */
  984.             public BufferedImage getProggie() {
  985.                 String[] lines = getAllPopups(true, "tools").lines;
  986.                 Color color = style.FONT_COLOR;
  987.                 Font font = style.FONT;
  988.                 float line_height = font.getLineMetrics(lines[0], Paint.frc)
  989.                         .getHeight();
  990.                 int width = 0;
  991.                 for (String line : lines)
  992.                     if (font.getStringBounds(line, Paint.frc).getWidth() > width)
  993.                         width = (int) font.getStringBounds(line, Paint.frc)
  994.                                 .getWidth();
  995.  
  996.                 int height = (int) (lines.length * line_height);
  997.  
  998.                 width += style.roundCorner + 2;
  999.                 height += style.roundCorner + 2;
  1000.  
  1001.                 RoundRectangle2D.Float bkg = new RoundRectangle2D.Float(0, 0,
  1002.                         width, height,
  1003.                         style.roundCorner > 0 ? style.roundCorner + 1 : 0,
  1004.                         style.roundCorner > 0 ? style.roundCorner + 1 : 0);
  1005.                 RoundRectangle2D.Float fg = new RoundRectangle2D.Float(
  1006.                         (float) bkg.getX() + 1, (float) bkg.getY() + 1,
  1007.                         width - 2, height - 2, style.roundCorner,
  1008.                         style.roundCorner);
  1009.                 Rectangle txtBounds = new Rectangle(
  1010.                         (int) (fg.getX() + (style.roundCorner / 2)),
  1011.                         (int) (fg.getY() + (style.roundCorner / 2)),
  1012.                         (int) (width - style.roundCorner - 2), (int) (height
  1013.                                 - style.roundCorner - 2));
  1014.                 BufferedImage bImg = new BufferedImage(width, height,
  1015.                         BufferedImage.TYPE_INT_ARGB);
  1016.                 Graphics2D g = (Graphics2D) bImg.getGraphics();
  1017.                 g.setColor(style.bgColor);
  1018.                 g.fill(bkg);
  1019.                 g.setColor(style.fgColor);
  1020.                 g.fill(fg);
  1021.                 g.setFont(font);
  1022.                 g.setColor(color);
  1023.                 for (int i = 0; i < lines.length; i++)
  1024.                     g.drawString(lines[i], txtBounds.x,
  1025.                             ((i + 1) * (line_height)) + txtBounds.y);
  1026.                 return bImg;
  1027.             }
  1028.  
  1029.             /**
  1030.              * Saves a progress report to the Screenshots directory
  1031.              */
  1032.             public void saveProggie() {
  1033.                 String name = crafter.name
  1034.                         + "_"
  1035.                         + PaintFormatter.getFormattedTime(
  1036.                                 System.currentTimeMillis() - Paint.startTime,
  1037.                                 "-", true);
  1038.                 final File dir = new File(
  1039.                         GlobalConfiguration.Paths.getScreenshotsDirectory());
  1040.                 if (dir.isDirectory() || dir.mkdirs()) {
  1041.                     try {
  1042.                         int ext = 0;
  1043.                         while (new File(dir, name
  1044.                                 + (ext > 0 ? ("(" + ext + ")") : "") + ".png")
  1045.                                 .exists())
  1046.                             ext++;
  1047.  
  1048.                         ImageIO.write(Paint.paintMenu.getProggie(), "png",
  1049.                                 new File(dir, name
  1050.                                         + (ext > 0 ? ("(" + ext + ")") : "")));
  1051.                         log.info("Saved proggie!");
  1052.                         log.info(new File(dir, name
  1053.                                 + (ext > 0 ? ("(" + ext + ")") : "") + ".png")
  1054.                                 .getAbsolutePath());
  1055.                     } catch (IOException e) {
  1056.                         log.severe("Failed to save proggie!");
  1057.                     }
  1058.                 }
  1059.             }
  1060.  
  1061.             /**
  1062.              * Adds the specified mouse listener
  1063.              *
  1064.              * @param listen
  1065.              *            MouseListen
  1066.              */
  1067.             public void addMouseListener(MouseListen listen) {
  1068.                 if (mouseListeners == null)
  1069.                     mouseListeners = new ArrayList<MouseListen>();
  1070.                 mouseListeners.add(listen);
  1071.             }
  1072.  
  1073.             /**
  1074.              * Sets the default line listener
  1075.              *
  1076.              * @param listen
  1077.              *            LineListener
  1078.              */
  1079.             public void setDefaultLineListener(LineListener listen) {
  1080.                 defaultLineListener = listen;
  1081.             }
  1082.  
  1083.             /**
  1084.              * Fires the MouseEvent in all containing children and this
  1085.              *
  1086.              * @param e
  1087.              *            MouseEvent
  1088.              */
  1089.             public void fireMouseEvent(MouseEvent e) {
  1090.                 if (getArea(true).contains(e.getPoint()))
  1091.                     if (mouseListeners != null)
  1092.                         for (MouseListen m : mouseListeners)
  1093.                             m.MouseAction(e);
  1094.                 for (MenuItem m : components)
  1095.                     if (m.bounds != null)
  1096.                         if (m.bounds.contains(e.getPoint()))
  1097.                             m.fireMouseEvent(e);
  1098.                 if (visiblePopup != null)
  1099.                     visiblePopup.fireMouseEvent(e);
  1100.  
  1101.             }
  1102.         }
  1103.  
  1104.         /**
  1105.          * Represents a class containing the method for getting the popup
  1106.          *
  1107.          * @author Equinox_
  1108.          *
  1109.          */
  1110.         public abstract class GetPopup {
  1111.             abstract MenuPopUp getPopUp();
  1112.         }
  1113.  
  1114.         /**
  1115.          * Represents a modified MouseListener used in MenuEvents
  1116.          *
  1117.          * @author Equinox_
  1118.          *
  1119.          */
  1120.         public abstract class MouseListen {
  1121.             abstract void MouseAction(MouseEvent e);
  1122.         }
  1123.  
  1124.         /**
  1125.          * An abstract class representing MenuItems
  1126.          *
  1127.          * @author Equinox_
  1128.          *
  1129.          */
  1130.         public abstract class MenuItem {
  1131.             final GetPopup getPopup;
  1132.             Menu parent;
  1133.             RoundRectangle2D.Float bounds;
  1134.             int index;
  1135.             final int width;
  1136.             final int height;
  1137.             List<MouseListen> mouseListeners;
  1138.             final String name;
  1139.  
  1140.             /**
  1141.              * Constructs a MenuItem with the given name, parent, getPopup
  1142.              * method, width and height
  1143.              *
  1144.              * @param name
  1145.              *            String
  1146.              * @param parent
  1147.              *            Menu
  1148.              * @param getPopup
  1149.              *            GetPopup
  1150.              * @param width
  1151.              *            int
  1152.              * @param height
  1153.              *            int
  1154.              */
  1155.             public MenuItem(String name, Menu parent, GetPopup getPopup,
  1156.                     int width, int height) {
  1157.                 this.name = name;
  1158.                 this.height = height;
  1159.                 this.width = width;
  1160.                 this.getPopup = getPopup;
  1161.                 this.parent = parent;
  1162.                 this.bounds = new RoundRectangle2D.Float(0, 0, width, height,
  1163.                         parent.style.roundCorner, parent.style.roundCorner);
  1164.             }
  1165.  
  1166.             /**
  1167.              * Constructs a MenuItem with the given name, parent, width and
  1168.              * height
  1169.              *
  1170.              * @param name
  1171.              *            String
  1172.              * @param parent
  1173.              *            Menu
  1174.              * @param width
  1175.              *            int
  1176.              * @param height
  1177.              *            int
  1178.              */
  1179.             public MenuItem(String name, Menu parent, int width, int height) {
  1180.                 this(name, parent, null, width, height);
  1181.             }
  1182.  
  1183.             /**
  1184.              * sets this item's index
  1185.              *
  1186.              * @param idx
  1187.              *            int
  1188.              */
  1189.             public void setIndex(int idx) {
  1190.                 this.index = idx;
  1191.             }
  1192.  
  1193.             /**
  1194.              * renders this item to the given Graphics2D
  1195.              *
  1196.              * @param g
  1197.              *            Graphics2D
  1198.              */
  1199.             abstract void render(Graphics2D g);
  1200.  
  1201.             /**
  1202.              * Compiles this item
  1203.              */
  1204.             public void compile() {
  1205.                 this.bounds = new RoundRectangle2D.Float(0, 0, width, height,
  1206.                         parent.style.roundCorner, parent.style.roundCorner);
  1207.                 bounds.x = getX();
  1208.                 bounds.y = getY();
  1209.             }
  1210.  
  1211.             /**
  1212.              * Gets the offset from upper left of parent depending on parent's
  1213.              * FlowType
  1214.              *
  1215.              * @return int offsetY
  1216.              */
  1217.             public int getOffX() {
  1218.                 if (parent.getFlowType().equals(FlowType.HORIZONTAL)) {
  1219.                     int x = 1;
  1220.                     for (int i = 0; i < index; i++)
  1221.                         x += 1 + parent.components.get(i).bounds.width;
  1222.  
  1223.                     return x;
  1224.                 }
  1225.                 if (parent.getWidth() > bounds.width)
  1226.                     return (int) (parent.getWidth() / 2 - bounds.width / 2);
  1227.                 return 1;
  1228.             }
  1229.  
  1230.             /**
  1231.              * Gets the offset from upper left of parent depending on parent's
  1232.              * FlowType
  1233.              *
  1234.              * @return int offsetX
  1235.              */
  1236.             public int getOffY() {
  1237.                 if (parent.getFlowType().equals(FlowType.VERTICAL)) {
  1238.                     int y = 1;
  1239.                     for (int i = 0; i < index; i++)
  1240.                         y += 1 + parent.components.get(i).bounds.height;
  1241.  
  1242.                     return y;
  1243.                 }
  1244.                 return 1;
  1245.             }
  1246.  
  1247.             /**
  1248.              * Gets the absolute x
  1249.              *
  1250.              * @return int absolute x
  1251.              */
  1252.             public int getX() {
  1253.                 int x = getOffX() + parent.getAbsX();
  1254.                 return x;
  1255.             }
  1256.  
  1257.             /**
  1258.              * Gets the absolute y
  1259.              *
  1260.              * @return int absolute y
  1261.              */
  1262.             public int getY() {
  1263.                 int y = getOffY() + parent.getAbsY();
  1264.                 return y;
  1265.             }
  1266.  
  1267.             /**
  1268.              * Gets this item's popup
  1269.              *
  1270.              * @return MenuPopUp
  1271.              */
  1272.             public MenuPopUp getPopUp() {
  1273.                 if (getPopup != null) {
  1274.                     MenuPopUp m = getPopup.getPopUp();
  1275.                     m.setParent(this);
  1276.                     if (parent.defaultLineListener != null)
  1277.                         m.addLineListener(parent.defaultLineListener);
  1278.                     return m;
  1279.                 }
  1280.                 return null;
  1281.             }
  1282.  
  1283.             /**
  1284.              * Adds a mouselistener
  1285.              *
  1286.              * @param listen
  1287.              *            MouseListen
  1288.              */
  1289.             public void addMouseListener(MouseListen listen) {
  1290.                 if (mouseListeners == null)
  1291.                     mouseListeners = new ArrayList<MouseListen>();
  1292.                 mouseListeners.add(listen);
  1293.             }
  1294.  
  1295.             /**
  1296.              * Sends the mouse event to all of this item's listeners
  1297.              *
  1298.              * @param e
  1299.              *            MouseEvent
  1300.              */
  1301.             public void fireMouseEvent(MouseEvent e) {
  1302.                 if (mouseListeners != null && mouseListeners.size() > 0)
  1303.                     for (MouseListen m : mouseListeners)
  1304.                         m.MouseAction(e);
  1305.             }
  1306.         }
  1307.  
  1308.         /**
  1309.          * A class representing a mouse over button on the parent menu
  1310.          *
  1311.          * @author Equinox_
  1312.          *
  1313.          */
  1314.         public class MenuButton extends MenuItem {
  1315.             final static int width = 30;
  1316.             final static int height = 30;
  1317.  
  1318.             String imageIcon;
  1319.  
  1320.             /**
  1321.              * Constructs a button using the specified name, parent, imageIcon,
  1322.              * and getPopup method.
  1323.              *
  1324.              * @param name
  1325.              *            String
  1326.              * @param parent
  1327.              *            Menu
  1328.              * @param imageIcon
  1329.              *            String
  1330.              * @param getPopUp
  1331.              *            GetPopup
  1332.              */
  1333.             public MenuButton(String name, Menu parent, String imageIcon,
  1334.                     GetPopup getPopUp) {
  1335.                 super(name, parent, getPopUp, width, height);
  1336.                 this.imageIcon = imageIcon.toLowerCase();
  1337.             }
  1338.  
  1339.             /**
  1340.              * Constructs a button using the specified name, parent, and
  1341.              * imageIcon
  1342.              *
  1343.              * @param name
  1344.              *            String
  1345.              * @param parent
  1346.              *            Menu
  1347.              * @param imageIcon
  1348.              *            String
  1349.              */
  1350.             public MenuButton(String name, Menu parent, String imageIcon) {
  1351.                 this(name, parent, imageIcon, null);
  1352.             }
  1353.  
  1354.             /**
  1355.              * Constructs a button using the specified name and parent
  1356.              *
  1357.              * @param name
  1358.              *            String
  1359.              * @param parent
  1360.              *            Menu
  1361.              */
  1362.             public MenuButton(String name, Menu parent) {
  1363.                 this(name, parent, "", null);
  1364.             }
  1365.  
  1366.             /**
  1367.              * Renders this MenuButton to the given Graphics2D context
  1368.              */
  1369.             public void render(Graphics2D g) {
  1370.                 // Compiling
  1371.                 if (parent.parent.icons.containsKey(imageIcon))
  1372.                     if (parent.parent.icons.get(imageIcon) != null)
  1373.                         if (!parent.parent.icons.containsKey("Button-"
  1374.                                 + imageIcon)) {
  1375.                             // Scale the image
  1376.                             int width = (int) (bounds.width - (parent.style.roundCorner));
  1377.                             int height = (int) (bounds.height - (parent.style.roundCorner));
  1378.                             int hints = Image.SCALE_FAST;
  1379.                             parent.parent.icons.put(
  1380.                                     "Button-" + imageIcon,
  1381.                                     parent.parent.icons.get(imageIcon)
  1382.                                             .getScaledInstance(width, height,
  1383.                                                     hints));
  1384.                         }
  1385.  
  1386.                 g.setColor(parent.style.fgColor);
  1387.                 g.fill(bounds);
  1388.                 if (parent.parent.icons.containsKey("Button-" + imageIcon))
  1389.                     if (parent.parent.icons.get("Button-" + imageIcon) != null)
  1390.                         g.drawImage(
  1391.                                 parent.parent.icons.get("Button-" + imageIcon),
  1392.                                 (int) (bounds.x + (parent.style.roundCorner / 2)),
  1393.                                 (int) (bounds.y + (parent.style.roundCorner / 2)),
  1394.                                 null);
  1395.             }
  1396.         }
  1397.  
  1398.         /**
  1399.          * A class representing a progress bar in a menu
  1400.          *
  1401.          * @author Equinox_
  1402.          *
  1403.          */
  1404.         public class MenuProgressBar extends MenuItem {
  1405.             final static int width = 100;
  1406.             final static int height = 30;
  1407.  
  1408.             final GetPercent getPercent;
  1409.             RoundRectangle2D.Float percent;
  1410.             Point textLoc;
  1411.             String prefix;
  1412.  
  1413.             /**
  1414.              * Constructs a MenuProgress bar using the specified name, parent,
  1415.              * getPercent method, text prefix, and getPopup method
  1416.              *
  1417.              * @param name
  1418.              *            String
  1419.              * @param parent
  1420.              *            Menu
  1421.              * @param getPercent
  1422.              *            GetPercent
  1423.              * @param prefix
  1424.              *            String
  1425.              * @param getPopup
  1426.              *            GetPopup
  1427.              */
  1428.             public MenuProgressBar(String name, Menu parent,
  1429.                     GetPercent getPercent, String prefix, GetPopup getPopup) {
  1430.                 super(name, parent, getPopup, width, height);
  1431.                 this.getPercent = getPercent;
  1432.                 this.prefix = prefix;
  1433.             }
  1434.  
  1435.             /**
  1436.              * Renders this progress bar to the given Graphics context
  1437.              */
  1438.             public void render(Graphics2D g) {
  1439.                 percent.width = getPercent.getPercent();
  1440.                 g.setColor(parent.style.progressBarBG);
  1441.                 g.fill(bounds);
  1442.                 g.setColor(parent.style.progressBarFG);
  1443.                 g.fill(percent);
  1444.                 String perct = String.valueOf(getPercent.getPercent());
  1445.                 if (perct.length() < 2)
  1446.                     perct = "0" + perct;
  1447.                 g.setFont(style.FONT);
  1448.                 g.setColor(style.FONT_COLOR);
  1449.                 g.drawString(prefix + ": " + perct + "%", textLoc.x, textLoc.y);
  1450.             }
  1451.  
  1452.             /**
  1453.              * Compiles this progress bar
  1454.              */
  1455.             public void compile() {
  1456.                 super.compile();
  1457.                 percent = new RoundRectangle2D.Float(bounds.x, bounds.y,
  1458.                         getPercent.getPercent(), bounds.height,
  1459.                         bounds.arcwidth, bounds.archeight);
  1460.                 textLoc = new Point();
  1461.                 textLoc.x = (int) bounds.getCenterX();
  1462.                 textLoc.y = (int) bounds.getCenterY();
  1463.                 textLoc.y += parent.style.FONT.getLineMetrics(prefix + ": 00%",
  1464.                         parent.parent.frc).getHeight() / 2f;
  1465.                 textLoc.x -= parent.style.FONT.getStringBounds(
  1466.                         prefix + ": 00%", parent.parent.frc).getWidth() / 2f;
  1467.             }
  1468.         }
  1469.  
  1470.         /**
  1471.          * Class representing the method for getting the current percentile for
  1472.          * a progress bar
  1473.          *
  1474.          * @author Equinox_
  1475.          *
  1476.          */
  1477.         public abstract class GetPercent {
  1478.             abstract int getPercent();
  1479.         }
  1480.  
  1481.         /**
  1482.          * Class representing the LineListeners in popups
  1483.          *
  1484.          * @author Equinox_
  1485.          *
  1486.          */
  1487.         public abstract class LineListener {
  1488.             abstract void fireEvent(MouseEvent e, String line);
  1489.  
  1490.             abstract boolean hasAction(String line);
  1491.         }
  1492.  
  1493.         /**
  1494.          * A class representing the popups in the paint interface
  1495.          *
  1496.          * @author Equinox_
  1497.          *
  1498.          */
  1499.         public class MenuPopUp {
  1500.             private Font font;
  1501.             private Color color;
  1502.             private PaintStyle style;
  1503.             private RoundRectangle2D bkg;
  1504.             public RoundRectangle2D fg;
  1505.             public Rectangle txtBounds;
  1506.             public MenuItem parent;
  1507.             public final String name;
  1508.             public String[] lines;
  1509.             int width;
  1510.             int height;
  1511.             List<LineListener> lineListeners;
  1512.  
  1513.             /**
  1514.              * Creates a popup using the provided array of strings making up the
  1515.              * lines and name
  1516.              *
  1517.              * @param lines
  1518.              *            as String[]
  1519.              * @param name
  1520.              *            as String
  1521.              */
  1522.             public MenuPopUp(String[] lines, String name) {
  1523.                 this.name = name;
  1524.                 this.lines = lines;
  1525.             }
  1526.  
  1527.             /**
  1528.              * Set this popup's parent and compiles locations
  1529.              *
  1530.              * @param parent
  1531.              *            MenuItem
  1532.              */
  1533.             public void setParent(MenuItem parent) {
  1534.                 this.parent = parent;
  1535.                 this.style = parent.parent.style;
  1536.                 // Calc dimensions
  1537.                 color = name.equals("tools") ? style.TOOLS_FONT_COLOR
  1538.                         : style.FONT_COLOR;
  1539.                 font = name.equals("tools") ? style.TOOLS_FONT : style.FONT;
  1540.                 float line_height = font.getLineMetrics(lines[0], Paint.frc)
  1541.                         .getHeight();
  1542.                 width = 0;
  1543.                 for (String line : lines)
  1544.                     if (font.getStringBounds(line, Paint.frc).getWidth() > width)
  1545.                         width = (int) font.getStringBounds(line, Paint.frc)
  1546.                                 .getWidth();
  1547.  
  1548.                 height = (int) (lines.length * line_height);
  1549.  
  1550.                 width += style.roundCorner + 2;
  1551.                 height += style.roundCorner + 2;
  1552.  
  1553.                 int halfPadding = (parent.parent.padding / 2);
  1554.                 if (halfPadding < 1 && halfPadding != 0)
  1555.                     halfPadding = 1;
  1556.                 int x = 0;
  1557.                 int y = 0;
  1558.                 if (parent.parent.getFlowType().equals(FlowType.HORIZONTAL)) {
  1559.                     if (parent.bounds.y - height - parent.parent.padding > 0) {
  1560.                         // Above
  1561.                         x = (int) (parent.bounds.x - width
  1562.                                 + parent.bounds.width + halfPadding);
  1563.                         if (x < 0)
  1564.                             x = (int) (parent.bounds.x - halfPadding);
  1565.                         y = (int) (parent.parent.getAbsY() - height);
  1566.                     } else {
  1567.                         // Below
  1568.                         x = (int) (parent.bounds.x - halfPadding);
  1569.                         if (x + width > parent.parent.bounds.width)
  1570.                             x = (int) (parent.bounds.x - halfPadding - width);
  1571.                         y = (int) (parent.parent.getAbsY() + parent.parent
  1572.                                 .getHeight());
  1573.                     }
  1574.                 } else {
  1575.                     // Vertical
  1576.                     if (parent.bounds.x - width - parent.parent.padding > 0) {
  1577.                         // Left
  1578.                         x = (int) (parent.parent.getAbsX() - width);
  1579.                         if (parent.bounds.y - height + halfPadding
  1580.                                 + parent.bounds.height > 0)
  1581.                             y = (int) (parent.bounds.y - height + halfPadding + parent.bounds.height);
  1582.                         else
  1583.                             y = (int) (parent.bounds.y - halfPadding);
  1584.                     } else {
  1585.                         // Right
  1586.                         x = (int) (parent.parent.getAbsX() + parent.parent
  1587.                                 .getWidth());
  1588.                         if (parent.bounds.y - height + halfPadding
  1589.                                 + parent.bounds.height > 0)
  1590.                             y = (int) (parent.bounds.y - height + halfPadding + parent.bounds.height);
  1591.                         else
  1592.                             y = (int) (parent.bounds.y - halfPadding);
  1593.                     }
  1594.                 }
  1595.                 bkg = new RoundRectangle2D.Float(x, y, width, height,
  1596.                         style.roundCorner > 0 ? style.roundCorner + 1 : 0,
  1597.                         style.roundCorner > 0 ? style.roundCorner + 1 : 0);
  1598.                 fg = new RoundRectangle2D.Float((float) bkg.getX() + 1,
  1599.                         (float) bkg.getY() + 1, width - 2, height - 2,
  1600.                         style.roundCorner, style.roundCorner);
  1601.                 txtBounds = new Rectangle(
  1602.                         (int) (fg.getX() + (style.roundCorner / 2)),
  1603.                         (int) (fg.getY() + (style.roundCorner / 2)),
  1604.                         (int) (width - style.roundCorner - 2), (int) (height
  1605.                                 - style.roundCorner - 2));
  1606.             }
  1607.  
  1608.             /**
  1609.              * Paints this popup to using the provided Graphics2D in relation to
  1610.              * it's parent PaintInterface
  1611.              *
  1612.              * @param g
  1613.              *            as Graphics2D
  1614.              */
  1615.             public void render(Graphics2D g) {
  1616.                 g.setColor(style.bgColor);
  1617.                 g.fill(bkg);
  1618.                 g.setColor(style.fgColor);
  1619.                 g.fill(fg);
  1620.  
  1621.                 float line_height = (txtBounds.height - 4) / lines.length;
  1622.  
  1623.                 g.setFont(font);
  1624.                 g.setColor(color);
  1625.                 for (int i = 0; i < lines.length; i++) {
  1626.                     if (new Rectangle(txtBounds.x,
  1627.                             (int) ((i * (line_height)) + txtBounds.y),
  1628.                             txtBounds.width, (int) line_height)
  1629.                             .contains(parent.parent.parent.mouseLoc)
  1630.                             && hasAction(lines[i])) {
  1631.                         g.setColor(style.highlightColor);
  1632.                         g.fill(new Rectangle(txtBounds.x,
  1633.                                 (int) ((i * (line_height)) + 2 + txtBounds.y),
  1634.                                 txtBounds.width, (int) line_height));
  1635.                     }
  1636.                     g.setColor(color);
  1637.                     g.drawString(lines[i], txtBounds.x,
  1638.                             ((i + 1) * (line_height)) + txtBounds.y);
  1639.                 }
  1640.             }
  1641.  
  1642.             boolean hasAction(String line) {
  1643.                 if (lineListeners != null)
  1644.                     for (LineListener l : lineListeners)
  1645.                         if (l.hasAction(line))
  1646.                             return true;
  1647.                 return false;
  1648.             }
  1649.  
  1650.             /**
  1651.              * Adds the specified line listener
  1652.              *
  1653.              * @param l
  1654.              *            LineListener
  1655.              */
  1656.             public void addLineListener(LineListener l) {
  1657.                 if (lineListeners == null)
  1658.                     lineListeners = new ArrayList<LineListener>();
  1659.                 this.lineListeners.add(l);
  1660.             }
  1661.  
  1662.             /**
  1663.              * fires the specified mouse event using this popup's line listeners
  1664.              *
  1665.              * @param e
  1666.              *            MouseEvent
  1667.              */
  1668.             public void fireMouseEvent(MouseEvent e) {
  1669.                 if (!bkg.contains(e.getPoint()) || lineListeners == null
  1670.                         || lineListeners.size() == 0)
  1671.                     return;
  1672.  
  1673.                 int line_height = (txtBounds.height - 4) / lines.length;
  1674.  
  1675.                 for (int i = 0; i < lines.length; i++) {
  1676.                     Rectangle stringRect = new Rectangle(txtBounds.x,
  1677.                             (i * (line_height)) + txtBounds.y, txtBounds.width,
  1678.                             line_height);
  1679.                     if (stringRect.contains(e.getPoint())) {
  1680.                         for (LineListener lineListener : lineListeners)
  1681.                             lineListener.fireEvent(e, lines[i]);
  1682.                         return;
  1683.                     }
  1684.                 }
  1685.             }
  1686.         }
  1687.  
  1688.     }
  1689.  
  1690.     /**
  1691.      * Used for specifing the way a menu is layed out.
  1692.      *
  1693.      * @author Equinox_
  1694.      *
  1695.      */
  1696.     private enum FlowType {
  1697.         VERTICAL, HORIZONTAL
  1698.     }
  1699.  
  1700.     /**
  1701.      * Used for anchoring the menu bar
  1702.      *
  1703.      * @author Equinox_
  1704.      *
  1705.      */
  1706.     private enum Anchor {
  1707.         UP_LEFT, UP_RIGHT, DOWN_RIGHT, DOWN_LEFT
  1708.     }
  1709.  
  1710.     /**
  1711.      * Used to style the paint
  1712.      *
  1713.      * @author Equinox_
  1714.      *
  1715.      */
  1716.     public static class PaintStyle {
  1717.         public final Color FONT_COLOR = Color.BLACK;
  1718.         public final Font FONT = new Font("Arial", 1, 10)
  1719.                 .deriveFont(Font.PLAIN);
  1720.  
  1721.         public final Font TOOLS_FONT = new Font("Arial", 1, 14)
  1722.                 .deriveFont(Font.PLAIN);
  1723.         public final Color TOOLS_FONT_COLOR = Color.BLACK;
  1724.  
  1725.         public final float roundCorner = 10f;
  1726.         public final Color progressBarFG = new Color(0f, 1f, 0f, 1f);
  1727.         public final Color progressBarBG = new Color(.3f, .3f, .3f, 1f);
  1728.         public final Color bgColor = new Color(0f, 0f, 0f, 0.75f);
  1729.         final Color fgColor = new Color(.3f, .3f, .3f, 1f);
  1730.         final Color highlightColor = new Color(1f, 0f, 0f, 0.05f);
  1731.     }
  1732.  
  1733.     /**
  1734.      * Use these enums to define the type of path <br />
  1735.      * ALL_Center: All points are near the middle of the lines <br />
  1736.      * Full: Points can be anywhere on the line<br />
  1737.      * WEIGHT_CENTER: Weighted to center, possibility of being on sides, but
  1738.      * lower
  1739.      *
  1740.      * @author Equinox_
  1741.      *
  1742.      */
  1743.     enum MeshPathType {
  1744.         ALL_CENTER, FULL, WEIGHT_CENTER
  1745.     }
  1746.  
  1747.     /**
  1748.      * A class that will take a specified mesh, generate a path through it, then
  1749.      * round the path off with Bezier curves.
  1750.      *
  1751.      * @author Equinox_
  1752.      *
  1753.      */
  1754.     public class MeshPath {
  1755.         private final Color MESH_FILL = new Color(0.5f, 0.5f, 0.5f, 0.75f);
  1756.         private final Color MESH_BORDER = new Color(0.75f, 0.75f, 0.75f, 0.75f);
  1757.         private final Color PATH_COLOR = new Color(0f, 1f, 0f, 1f);
  1758.         private final Color SMOOTH_PATH_COLOR = new Color(0f, 0f, 1f, 1f);
  1759.         private final Color SUBDIVIDED_PATH_COLOR = new Color(1f, 0f, 1f, 1f);
  1760.  
  1761.         private List<RSTile[]> mesh = new ArrayList<RSTile[]>();
  1762.         private List<RSTile> blockPath = new ArrayList<RSTile>();
  1763.         private List<RSTile> smoothPath = new ArrayList<RSTile>();
  1764.         private boolean end;
  1765.         private List<RSTile> subdividedPath = new ArrayList<RSTile>();
  1766.  
  1767.         /**
  1768.          * Creates a MeshPath with a blank mesh
  1769.          */
  1770.         public MeshPath() {
  1771.  
  1772.         }
  1773.  
  1774.         /**
  1775.          * Creates a MeshPath using the provided mesh
  1776.          *
  1777.          * @param mesh
  1778.          *            as RSTile[][]
  1779.          */
  1780.         public MeshPath(RSTile[][] mesh) {
  1781.             setMesh(mesh);
  1782.         }
  1783.  
  1784.         /**
  1785.          * Adds a line to the mesh with the given tiles
  1786.          *
  1787.          * @param tiles
  1788.          *            the RSTiles making up the line
  1789.          */
  1790.         public void addLine(RSTile... tiles) {
  1791.             mesh.add(tiles);
  1792.         }
  1793.  
  1794.         /**
  1795.          * Gets the number of lines in the mesh
  1796.          *
  1797.          * @return int size
  1798.          */
  1799.         public int meshSize() {
  1800.             return mesh.size();
  1801.         }
  1802.  
  1803.         /**
  1804.          * Adds all the lines of a specified mesh to the current mesh.
  1805.          *
  1806.          * @param mesh
  1807.          *            as RSTile[][]
  1808.          */
  1809.         public void addMesh(RSTile[][] mesh) {
  1810.             for (RSTile[] line : mesh)
  1811.                 this.mesh.add(line);
  1812.         }
  1813.  
  1814.         /**
  1815.          * Sets the current mesh to the provided mesh
  1816.          *
  1817.          * @param mesh
  1818.          *            as RSTile[][]
  1819.          */
  1820.         public void setMesh(RSTile[][] mesh) {
  1821.             this.mesh.clear();
  1822.             addMesh(mesh);
  1823.         }
  1824.  
  1825.         public List<RSTile> getTilesOnLine(RSTile a, RSTile b) {
  1826.             List<RSTile> sublineTiles = new ArrayList<RSTile>();
  1827.             int deltaX = b.getX() - a.getX();
  1828.             int deltaY = b.getY() - a.getY();
  1829.             double dist = calc.distanceBetween(a, b);
  1830.             if (dist == 0)
  1831.                 dist = 1;
  1832.             double eX = deltaX / dist, eY = deltaY / dist;
  1833.             for (int i = 0; i <= dist; i++)
  1834.                 sublineTiles.add(new RSTile(a.getX() + (int) (eX * i), a.getY()
  1835.                         + (int) (eY * i)));
  1836.             return sublineTiles;
  1837.         }
  1838.  
  1839.         /**
  1840.          * Gets all the tiles on the provided line
  1841.          *
  1842.          * @param line
  1843.          *            as RSTile...
  1844.          * @return List<RSTile> tiles on line
  1845.          */
  1846.         public List<RSTile> getTilesOnLines(RSTile... line) {
  1847.             List<RSTile> sublineTiles = new ArrayList<RSTile>();
  1848.             if (line.length == 1)
  1849.                 sublineTiles.add(line[0]);
  1850.             else
  1851.                 for (int i = 1; i < line.length; i++) {
  1852.                     RSTile a = line[i - 1];
  1853.                     RSTile b = line[i];
  1854.                     sublineTiles.addAll(getTilesOnLine(a, b));
  1855.                 }
  1856.             return sublineTiles;
  1857.         }
  1858.  
  1859.         /**
  1860.          * Gets a tile on the provided line using the ALL_CENTER method
  1861.          *
  1862.          * @param line
  1863.          *            as RSTile...
  1864.          * @return RSTile tile on line
  1865.          */
  1866.         public RSTile getTileOnLine(RSTile... line) {
  1867.             return getTileOnLine(MeshPathType.ALL_CENTER, line);
  1868.         }
  1869.  
  1870.         /**
  1871.          * Gets a tile on the provided line using the provided method
  1872.          *
  1873.          * @param placement
  1874.          *            as MeshPathType
  1875.          * @param line
  1876.          *            as RSTile...
  1877.          * @return RSTile tile on line
  1878.          */
  1879.         public RSTile getTileOnLine(MeshPathType placement, RSTile... line) {
  1880.             List<RSTile> tiles = getTilesOnLines(line);
  1881.             int index = 0;
  1882.             switch (placement) {
  1883.             case ALL_CENTER:
  1884.                 index = random(tiles.size() / 4, 3 * tiles.size() / 4 + 1);
  1885.                 // +1 due to exclusive upper bound
  1886.                 break;
  1887.             case FULL:
  1888.                 index = random(0, tiles.size());
  1889.                 break;
  1890.             case WEIGHT_CENTER:
  1891.                 index = random(tiles.size() / 4, 3 * tiles.size() / 4 + 1);
  1892.                 // +1 due to exclusive upper bound
  1893.  
  1894.                 int rand = random(-10, tiles.size() / 4);
  1895.                 index += rand > 0 ? rand : 0;
  1896.                 break;
  1897.             }
  1898.  
  1899.             if (index < 0)
  1900.                 index = 0;
  1901.             if (index >= tiles.size())
  1902.                 index = tiles.size() - 1;
  1903.  
  1904.             if (tiles.size() > 0)
  1905.                 return tiles.get(index);
  1906.             else
  1907.                 return null;
  1908.         }
  1909.  
  1910.         /**
  1911.          * Paints the mesh to the provided graphics context in the minimap
  1912.          *
  1913.          * @param g
  1914.          *            as Graphics2D
  1915.          */
  1916.         public void paintMesh(Graphics2D g) {
  1917.             if (mesh.size() > 1) {
  1918.                 for (int i = 1; i < mesh.size(); i++) {
  1919.                     RSTile[] lineA = mesh.get(i - 1).clone();
  1920.                     RSTile[] lineB = mesh.get(i).clone();
  1921.                     Polygon poly = new Polygon();
  1922.                     RSTile a = lineA[0];
  1923.                     RSTile b = lineB[0];
  1924.                     RSTile c = lineA[lineA.length - 1];
  1925.                     RSTile d = lineB[lineB.length - 1];
  1926.                     boolean onMap = true;
  1927.                     double distA = calc.distanceBetween(c, b)
  1928.                             + calc.distanceBetween(a, d);
  1929.                     double distB = calc.distanceBetween(a, b)
  1930.                             + calc.distanceBetween(c, d);
  1931.  
  1932.                     if (distA > distB) {
  1933.                         // Reverse lineB.
  1934.                         RSTile[] newLineB = new RSTile[lineB.length];
  1935.                         int start = lineB.length - 1;
  1936.                         for (RSTile t : lineB) {
  1937.                             if (start >= 0)
  1938.                                 newLineB[start] = t;
  1939.                             start--;
  1940.                         }
  1941.                         lineB = newLineB;
  1942.                     }
  1943.  
  1944.                     if (lineA != null)
  1945.                         for (RSTile t : lineA) {
  1946.                             Point p = calc.tileToMinimap(t);
  1947.                             if (p.x == -1 || p.y == -1) {
  1948.                                 onMap = false;
  1949.                                 break;
  1950.                             }
  1951.                             poly.addPoint(p.x, p.y);
  1952.                         }
  1953.  
  1954.                     if (lineB != null)
  1955.                         for (RSTile t : lineB) {
  1956.                             Point p = calc.tileToMinimap(t);
  1957.                             if (p.x == -1 || p.y == -1) {
  1958.                                 onMap = false;
  1959.                                 break;
  1960.                             }
  1961.                             poly.addPoint(p.x, p.y);
  1962.                         }
  1963.  
  1964.                     if (onMap) {
  1965.                         g.setColor(MESH_BORDER);
  1966.                         g.draw(poly);
  1967.                         g.setColor(MESH_FILL);
  1968.                         g.fill(poly);
  1969.                     }
  1970.                 }
  1971.             }
  1972.         }
  1973.  
  1974.         public RSTile getTileOnMap(RSTile t) {
  1975.             List<RSTile> tiles = getTilesOnLine(t, getMyPlayer().getLocation());
  1976.             for (RSTile tt : tiles)
  1977.                 if (calc.tileOnMap(tt))
  1978.                     return tt;
  1979.             return null;
  1980.         }
  1981.  
  1982.         /**
  1983.          * Paints the current un-smoothed path to the minimap using the provided
  1984.          * graphics object
  1985.          *
  1986.          * @param g
  1987.          *            as Graphics2D
  1988.          */
  1989.         public void paintPath(Graphics2D g) {
  1990.             if (blockPath.size() > 1) {
  1991.                 g.setColor(PATH_COLOR);
  1992.                 for (int i = 1; i < blockPath.size(); i++) {
  1993.                     Point a = calc.tileToMinimap(blockPath.get(i - 1));
  1994.                     Point b = calc.tileToMinimap(blockPath.get(i));
  1995.                     if (a.x > 0 && a.y > 0)
  1996.                         g.fillOval(a.x - 2, a.y - 2, 5, 5);
  1997.                     if (b.x > 0 && b.y > 0)
  1998.                         g.fillOval(b.x - 2, b.y - 2, 5, 5);
  1999.                     if (a.x > 0 && a.y > 0 && b.x > 0 && b.y > 0)
  2000.                         g.drawLine(a.x, a.y, b.x, b.y);
  2001.                 }
  2002.             }
  2003.         }
  2004.  
  2005.         /**
  2006.          * Paints the smoothed version of the current path to the minimap using
  2007.          * the provided graphics object
  2008.          *
  2009.          * @param g
  2010.          *            as Graphics2D
  2011.          */
  2012.         public void paintSmoothPath(Graphics2D g) {
  2013.             if (smoothPath.size() > 1) {
  2014.                 g.setColor(SMOOTH_PATH_COLOR);
  2015.                 for (int i = 1; i < smoothPath.size(); i++) {
  2016.                     Point a = calc.tileToMinimap(smoothPath.get(i - 1));
  2017.                     Point b = calc.tileToMinimap(smoothPath.get(i));
  2018.                     if (a.x > 0 && a.y > 0)
  2019.                         g.fillOval(a.x - 2, a.y - 2, 5, 5);
  2020.                     if (b.x > 0 && b.y > 0)
  2021.                         g.fillOval(b.x - 2, b.y - 2, 5, 5);
  2022.                     if (a.x > 0 && a.y > 0 && b.x > 0 && b.y > 0)
  2023.                         g.drawLine(a.x, a.y, b.x, b.y);
  2024.                 }
  2025.             }
  2026.         }
  2027.  
  2028.         /**
  2029.          * Paints the subdivided smoothed version of the current path to the
  2030.          * minimap using the provided graphics object
  2031.          *
  2032.          * @param g
  2033.          *            as Graphics2D
  2034.          */
  2035.         public void paintSubdividedPath(Graphics2D g) {
  2036.             if (subdividedPath.size() > 0) {
  2037.                 g.setColor(SUBDIVIDED_PATH_COLOR);
  2038.                 for (RSTile t : subdividedPath) {
  2039.                     Point tileLoc = calc.tileToMinimap(t);
  2040.                     if (tileLoc.x > 0 && tileLoc.y > 0)
  2041.                         g.fillOval(tileLoc.x, tileLoc.y, 5, 5);
  2042.                 }
  2043.             }
  2044.         }
  2045.  
  2046.         /**
  2047.          * Paints the mesh, and all versions of the current path to the minimap
  2048.          * using the provided graphics object
  2049.          *
  2050.          * @param g
  2051.          *            as Graphics2D
  2052.          */
  2053.         public void paintAll(Graphics2D g) {
  2054.             paintMesh(g);
  2055.             paintPath(g);
  2056.             paintSmoothPath(g);
  2057.             paintSubdividedPath(g);
  2058.         }
  2059.  
  2060.         /**
  2061.          * Finds a path between the start index and the end index using the
  2062.          * provided placement type, then sets the current path to the found path
  2063.          *
  2064.          * @param placement
  2065.          *            as MeshPathType
  2066.          * @param start
  2067.          *            index
  2068.          * @param end
  2069.          *            index
  2070.          */
  2071.         public void findPath(MeshPathType placement, int start, int end) {
  2072.             blockPath.clear();
  2073.             RSTile lineTile = getTileOnLine(mesh.get(start));
  2074.             String s = lineTile.toString();
  2075.             blockPath.add(lineTile);
  2076.             for (int i = start + 1; i <= end; i++) {
  2077.                 lineTile = getTileOnLine(placement, mesh.get(i));
  2078.                 blockPath.add(lineTile);
  2079.                 s += "," + lineTile.toString();
  2080.             }
  2081.             smoothPath = smoothPath(blockPath);
  2082.             subdividedPath = subdividePath(smoothPath);
  2083.         }
  2084.  
  2085.         /**
  2086.          * Finds a path between the beginning and end of the mesh using the
  2087.          * provided placement type, then sets the current path to the found path
  2088.          *
  2089.          * @param placement
  2090.          *            as MeshPathType
  2091.          */
  2092.         public void findPath(MeshPathType placement) {
  2093.             findPath(placement, 0, mesh.size() - 1);
  2094.         }
  2095.  
  2096.         /**
  2097.          * Finds a path between the beginning and end of the mesh using the
  2098.          * ALL_CENTER placement type, then sets the current path to the found
  2099.          * path
  2100.          */
  2101.         public void findPath() {
  2102.             findPath(MeshPathType.ALL_CENTER);
  2103.         }
  2104.  
  2105.         /**
  2106.          * Clears the current path and all refined versions of it.
  2107.          */
  2108.         public void clearPath() {
  2109.             blockPath.clear();
  2110.             smoothPath.clear();
  2111.             subdividedPath.clear();
  2112.         }
  2113.  
  2114.         /**
  2115.          * Smoothes the provided List of RSTiles using Bezier curves
  2116.          *
  2117.          * @param path
  2118.          *            as List
  2119.          * @return List<RSTile> smoothed path
  2120.          */
  2121.         public List<RSTile> smoothPath(List<RSTile> path) {
  2122.             List<RSTile> smoothed = new ArrayList<RSTile>();
  2123.             smoothed.addAll(path);
  2124.             if (path.size() >= 3) {
  2125.                 for (int b = 0; b < path.size(); b++) {
  2126.                     if (b + 2 < path.size()) {
  2127.                         double x2, y2;
  2128.  
  2129.                         double t = 0.5;
  2130.                         // use Berstein polynomials
  2131.                         x2 = (path.get(b + 0).getX() + t
  2132.                                 * (-path.get(b + 0).getX() * 3 + t
  2133.                                         * (3 * path.get(b + 0).getX() - path
  2134.                                                 .get(b + 0).getX() * t)))
  2135.                                 + t
  2136.                                 * (3 * path.get(b + 1).getX() + t
  2137.                                         * (-6 * path.get(b + 1).getX() + path
  2138.                                                 .get(b + 1).getX() * 3 * t))
  2139.                                 + t
  2140.                                 * t
  2141.                                 * (path.get(b + 1).getX() * 3 - path.get(b + 1)
  2142.                                         .getX() * 3 * t)
  2143.                                 + path.get(b + 2).getX() * t * t * t;
  2144.                         y2 = (path.get(b + 0).getY() + t
  2145.                                 * (-path.get(b + 0).getY() * 3 + t
  2146.                                         * (3 * path.get(b + 0).getY() - path
  2147.                                                 .get(b + 0).getY() * t)))
  2148.                                 + t
  2149.                                 * (3 * path.get(b + 1).getY() + t
  2150.                                         * (-6 * path.get(b + 1).getY() + path
  2151.                                                 .get(b + 1).getY() * 3 * t))
  2152.                                 + t
  2153.                                 * t
  2154.                                 * (path.get(b + 1).getY() * 3 - path.get(b + 1)
  2155.                                         .getY() * 3 * t)
  2156.                                 + path.get(b + 2).getY() * t * t * t;
  2157.                         RSTile loc = new RSTile((int) x2, (int) y2);
  2158.                         smoothed.set(b + 1, getTileInMesh(loc));
  2159.  
  2160.                     }
  2161.                 }
  2162.             }
  2163.             return smoothed;
  2164.         }
  2165.  
  2166.         /**
  2167.          * Gets the nearest tile in the mesh to the provided RSTile
  2168.          *
  2169.          * @param tile
  2170.          *            the RSTile to use
  2171.          * @return RSTile tile in mesh
  2172.          */
  2173.         public RSTile getTileInMesh(RSTile tile) {
  2174.             if (inMesh(tile))
  2175.                 return tile;
  2176.             double bestDist = Double.MAX_VALUE;
  2177.             RSTile nearest = null;
  2178.             if (mesh.size() > 1) {
  2179.                 for (int i = 1; i < mesh.size(); i++) {
  2180.                     RSTile[] lineA = mesh.get(i - 1);
  2181.                     RSTile[] lineB = mesh.get(i);
  2182.                     if (lineA != null && lineB != null) {
  2183.                         RSTile a = lineA[0];
  2184.                         RSTile b = lineB[0];
  2185.                         RSTile c = lineA[lineA.length - 1];
  2186.                         RSTile d = lineB[lineB.length - 1];
  2187.                         if (calc.distanceBetween(a, b) > calc.distanceBetween(
  2188.                                 a, d)) {
  2189.                             // Wrong order, switch b and d.
  2190.                             RSTile clone = new RSTile(b.getX(), b.getY(),
  2191.                                     b.getZ());
  2192.                             b = new RSTile(d.getX(), d.getY(), d.getZ());
  2193.                             d = clone;
  2194.                         }
  2195.                         for (RSTile t : getTilesOnLine(a, b)) {
  2196.                             double dist = calc.distanceBetween(tile, t);
  2197.                             if (dist < bestDist) {
  2198.                                 bestDist = dist;
  2199.                                 nearest = t;
  2200.                             }
  2201.                         }
  2202.                         for (RSTile t : getTilesOnLine(c, d)) {
  2203.                             double dist = calc.distanceBetween(tile, t);
  2204.                             if (dist < bestDist) {
  2205.                                 bestDist = dist;
  2206.                                 nearest = t;
  2207.                             }
  2208.                         }
  2209.                     }
  2210.                 }
  2211.             }
  2212.             return nearest;
  2213.         }
  2214.  
  2215.         /**
  2216.          * Checks to see if the provided RSTile is inside the mesh
  2217.          *
  2218.          * @param tile
  2219.          *            the RSTile to check
  2220.          * @return boolean is in mesh
  2221.          */
  2222.         public boolean inMesh(RSTile tile) {
  2223.             if (mesh.size() > 1) {
  2224.                 for (int i = 1; i < mesh.size(); i++) {
  2225.                     RSTile[] lineA = mesh.get(i - 1);
  2226.                     RSTile[] lineB = mesh.get(i);
  2227.                     Polygon poly = new Polygon();
  2228.                     if (lineA != null)
  2229.                         for (RSTile t : lineA)
  2230.                             poly.addPoint(t.getX(), t.getY());
  2231.  
  2232.                     if (lineB != null)
  2233.                         for (RSTile t : lineB)
  2234.                             poly.addPoint(t.getX(), t.getY());
  2235.  
  2236.                     if (poly.npoints >= 2)
  2237.                         if (poly.contains(new Point(tile.getX(), tile.getY())))
  2238.                             return true;
  2239.                 }
  2240.             }
  2241.             return false;
  2242.         }
  2243.  
  2244.         /**
  2245.          * Takes the provided path and subdivides it using the length provided
  2246.          * in the Options class
  2247.          *
  2248.          * @param smoothPath
  2249.          *            path to subdivide as a List<RSTile>
  2250.          * @return List<RSTile> subdivided path
  2251.          */
  2252.         public List<RSTile> subdividePath(List<RSTile> smoothPath) {
  2253.             RSTile[] smoothpathArray = new RSTile[smoothPath.size()];
  2254.             List<RSTile> path = getTilesOnLines(smoothPath
  2255.                     .toArray(smoothpathArray));
  2256.             List<RSTile> subdividedPath = new ArrayList<RSTile>();
  2257.             RSTile previous = null;
  2258.             for (RSTile next : path) {
  2259.                 if ((previous == null ? true : calc.distanceBetween(previous,
  2260.                         next) > Options.walkingDistance.random())
  2261.                         || next == path.get(path.size() - 1)) {
  2262.                     previous = new RSTile(next.getX(), next.getY());
  2263.                     subdividedPath.add(previous);
  2264.                 }
  2265.             }
  2266.             return subdividedPath;
  2267.         }
  2268.  
  2269.         /**
  2270.          * Takes a step along this path if appropriate. Specifies only
  2271.          * TraversalOption.SPACE_ACTIONS.
  2272.          *
  2273.          * @return <tt>true</tt> if this path is currently valid for the player;
  2274.          *         otherwise <tt>false</tt>.
  2275.          * @see #traverse(EnumSet)
  2276.          */
  2277.         public boolean traverse() {
  2278.             return this.traverse(EnumSet.of(TraversalOption.HANDLE_RUN,
  2279.                     TraversalOption.SPACE_ACTIONS));
  2280.         }
  2281.  
  2282.         /**
  2283.          * Takes a step along this path if appropriate. If the path cannot be
  2284.          * traversed due to the player being too far from its vertices or
  2285.          * already at the end vertex, <tt>false</tt> will be returned. In all
  2286.          * other cases, <tt>true</tt> will be returned, but an action will not
  2287.          * necessarily be performed (based on the given options).
  2288.          *
  2289.          * @param options
  2290.          *            Walking style options.
  2291.          * @return <tt>true</tt> if this path is currently valid for the player;
  2292.          *         otherwise <tt>false</tt>.
  2293.          */
  2294.         public boolean traverse(EnumSet<TraversalOption> options) {
  2295.             RSTile next = getNext();
  2296.             if (next == null)
  2297.                 return false;
  2298.             int nextIdx = getNearestIndexTo(next);
  2299.  
  2300.             if (next.equals(getEnd())) {
  2301.                 if (calc.distanceTo(next) <= 1
  2302.                         || (end && players.getMyPlayer().isMoving())
  2303.                         || next.equals(walking.getDestination())) {
  2304.                     return false;
  2305.                 }
  2306.                 end = true;
  2307.             } else {
  2308.                 end = false;
  2309.             }
  2310.             if (options.contains(TraversalOption.HANDLE_RUN)
  2311.                     && !walking.isRunEnabled() && walking.getEnergy() > 50) {
  2312.                 walking.setRun(true);
  2313.                 sleep(300);
  2314.             }
  2315.             if (walking.getDestination() != null
  2316.                     && getNearestIndexTo(walking.getDestination()) >= nextIdx)
  2317.                 return false;
  2318.             if (options.contains(TraversalOption.SPACE_ACTIONS)) {
  2319.                 RSTile dest = walking.getDestination();
  2320.                 if (dest != null && players.getMyPlayer().isMoving()
  2321.                         && calc.distanceBetween(next, dest) < 3) {
  2322.                     return true;
  2323.                 }
  2324.             }
  2325.             return walking.walkTileMM(next, 0, 0);
  2326.         }
  2327.  
  2328.         /**
  2329.          * Checks whether or not this path can be traversed by the player. This
  2330.          * will be the case provided that the player near to one of its
  2331.          * vertices, but not already standing on the end vertex.
  2332.          *
  2333.          * @return <tt>true</tt> if the player can walk along this path;
  2334.          *         otherwise <tt>false</tt>.
  2335.          */
  2336.         public boolean isValid() {
  2337.             if (!(subdividedPath.size() > 0 && !players.getMyPlayer()
  2338.                     .getLocation().equals(getEnd())))
  2339.                 return false;
  2340.             else
  2341.                 for (int i = subdividedPath.size() - 1; i >= 0; i--)
  2342.                     if (calc.tileOnMap(subdividedPath.get(i)))
  2343.                         return true;
  2344.             return false;
  2345.         }
  2346.  
  2347.         /**
  2348.          * Gets the start tile of this path.
  2349.          *
  2350.          * @return The start <code>RSTile</code>.
  2351.          */
  2352.         public RSTile getStart() {
  2353.             if (subdividedPath.size() > 0)
  2354.                 return subdividedPath.get(0);
  2355.             else
  2356.                 return null;
  2357.         }
  2358.  
  2359.         /**
  2360.          * Gets the next immediately available vertex in this path.
  2361.          *
  2362.          * @return The next walkable <code>RSTile</code>.
  2363.          */
  2364.         public RSTile getNext() {
  2365.             if (subdividedPath.size() > 0) {
  2366.                 for (int i = subdividedPath.size() - 1; i >= 0; i--)
  2367.                     if (calc.tileOnMap(subdividedPath.get(i)))
  2368.                         return subdividedPath.get(i);
  2369.                 return getTileOnMinimap(getNearest());
  2370.             } else
  2371.                 return null;
  2372.         }
  2373.  
  2374.         public RSTile getTileOnMinimap(RSTile base) {
  2375.             if (calc.tileOnMap(base))
  2376.                 return base;
  2377.             RSTile me = getMyPlayer().getLocation();
  2378.             int deltaX = base.getX() - me.getX();
  2379.             int deltaY = base.getY() - me.getY();
  2380.             double dist = calc.distanceBetween(base, me);
  2381.             double eX = deltaX / dist, eY = deltaY / dist;
  2382.             return new RSTile(me.getX() + (int) (eX * 14), me.getY()
  2383.                     + (int) (eY * 14));
  2384.         }
  2385.  
  2386.         public RSTile getNearest() {
  2387.             int len = Integer.MAX_VALUE;
  2388.             RSTile best = null;
  2389.             for (RSTile t : subdividedPath)
  2390.                 if (calc.distanceTo(t) < len) {
  2391.                     best = t;
  2392.                     len = calc.distanceTo(t);
  2393.                 }
  2394.             return best;
  2395.         }
  2396.  
  2397.         public RSTile getNearestByPath() {
  2398.             int len = Integer.MAX_VALUE;
  2399.             RSTile best = null;
  2400.             for (RSTile t : subdividedPath) {
  2401.                 int pLen = calc.pathLengthTo(t, false);
  2402.                 if (pLen < len && pLen >= 0) {
  2403.                     best = t;
  2404.                     len = pLen;
  2405.                 }
  2406.             }
  2407.             return best;
  2408.         }
  2409.  
  2410.         public int getNearestIndexTo(RSTile t) {
  2411.             int len = Integer.MAX_VALUE;
  2412.             int bestIndex = -1;
  2413.             if (walking.getDestination() != null)
  2414.                 for (int i = 0; i < subdividedPath.size(); i++)
  2415.                     if (calc.distanceBetween(t, subdividedPath.get(i)) < len) {
  2416.                         bestIndex = i;
  2417.                         len = calc.distanceTo(t);
  2418.                     }
  2419.             return bestIndex;
  2420.         }
  2421.  
  2422.         /**
  2423.          * Gets the end tile of this path.
  2424.          *
  2425.          * @return The end <code>RSTile</code>.
  2426.          */
  2427.         public RSTile getEnd() {
  2428.             if (subdividedPath.size() > 0)
  2429.                 return subdividedPath.get(subdividedPath.size() - 1);
  2430.             else
  2431.                 return null;
  2432.         }
  2433.  
  2434.         /**
  2435.          * Reverses this mesh.
  2436.          *
  2437.          * @return
  2438.          *
  2439.          * @return This path.
  2440.          */
  2441.         public MeshPath reverse() {
  2442.             MeshPath newPath = new MeshPath();
  2443.             for (int i = mesh.size() - 1; i >= 0; i--)
  2444.                 newPath.addLine(mesh.get(i));
  2445.             return newPath;
  2446.         }
  2447.  
  2448.         /**
  2449.          * Returns an array containing all of the vertices in this path.
  2450.          *
  2451.          * @return an array containing all of the vertices in this path.
  2452.          */
  2453.         public RSTile[] getTilePath() {
  2454.             RSTile[] tiles = new RSTile[subdividedPath.size()];
  2455.             for (int i = 0; i < tiles.length; i++)
  2456.                 tiles[i] = new RSTile(subdividedPath.get(i).getX(),
  2457.                         subdividedPath.get(i).getY());
  2458.             return tiles;
  2459.         }
  2460.  
  2461.         /**
  2462.          * Checks if we have a path
  2463.          *
  2464.          * @return boolean has a path
  2465.          */
  2466.         public boolean hasPath() {
  2467.             return subdividedPath.size() > 0;
  2468.         }
  2469.     }
Advertisement
Add Comment
Please, Sign In to add comment