Equinox

EquinoxZMICrafter.java

Apr 12th, 2011
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 60.82 KB | None | 0 0
  1. import java.awt.Color;
  2. import java.awt.Graphics;
  3. import java.awt.Graphics2D;
  4. import java.awt.Point;
  5. import java.awt.Polygon;
  6. import java.awt.Rectangle;
  7. import java.lang.reflect.Method;
  8. import java.text.DecimalFormat;
  9. import java.util.ArrayList;
  10. import java.util.EnumSet;
  11. import java.util.HashMap;
  12. import java.util.List;
  13. import java.util.Random;
  14.  
  15. import javax.swing.JOptionPane;
  16.  
  17. import org.rsbot.event.events.MessageEvent;
  18. import org.rsbot.event.listeners.MessageListener;
  19. import org.rsbot.event.listeners.PaintListener;
  20. import org.rsbot.script.Script;
  21. import org.rsbot.script.ScriptManifest;
  22. import org.rsbot.script.methods.Calculations;
  23. import org.rsbot.script.methods.Equipment;
  24. import org.rsbot.script.methods.Game;
  25. import org.rsbot.script.methods.GrandExchange;
  26. import org.rsbot.script.methods.GrandExchange.GEItem;
  27. import org.rsbot.script.methods.Magic;
  28. import org.rsbot.script.methods.Players;
  29. import org.rsbot.script.methods.Skills;
  30. import org.rsbot.script.methods.Walking;
  31. import org.rsbot.script.wrappers.RSComponent;
  32. import org.rsbot.script.wrappers.RSInterface;
  33. import org.rsbot.script.wrappers.RSItem;
  34. import org.rsbot.script.wrappers.RSNPC;
  35. import org.rsbot.script.wrappers.RSObject;
  36. import org.rsbot.script.wrappers.RSPath.TraversalOption;
  37. import org.rsbot.script.wrappers.RSTile;
  38. import org.rsbot.script.wrappers.RSTilePath;
  39.  
  40. @ScriptManifest(authors = "Equinox_", keywords = "Runecrafting", name = "Equinox_ ZMI Crafter", version = 0.7, description = "Beta Version")
  41. /**
  42.  * @author Equinox_
  43.  */
  44. public class EquinoxZMICrafter extends Script implements MessageListener,
  45.         PaintListener {
  46.  
  47.     // Variables
  48.     final String baseURL = "http://equinox-scripts.web44.net/scripts/natcrafter";
  49.     final double VERSION = getClass().getAnnotation(ScriptManifest.class)
  50.             .version();
  51.     final String author = PaintFormatter.formatList(getClass().getAnnotation(
  52.             ScriptManifest.class).authors());
  53.     final String name = getClass().getAnnotation(ScriptManifest.class).name();
  54.     public final static int COSMIC_RUNE_ID = 564;
  55.     public final static int ASTRAL_RUNE_ID = 9075;
  56.     public static final int AIR_STAFF_ID = 1405;
  57.     public final static int PURE_ESS_ID = 7936;
  58.     public final static int ZMI_ALTAR_ID = 26847;
  59.     public final static int AIR_RUNE_ID = 556;
  60.     public final static int NPC_CONTACT_ANIM = 4413;
  61.     public final static int BANKER_ID = 6362;
  62.     public final static int CRAFT_RUNE_ANIM = 791;
  63.     public final static int FIRE_RUNE_ID = 554;
  64.     public final static int CRACK_IN = 26844;
  65.     public final static int CRACK_OUT = 26845;
  66.     public final static RSTile alterDet = new RSTile(3314, 4813, 0);
  67.     public final static int PAY_BANK_INTERFACE = 619;
  68.     public final static int LAW_RUNE = 563;
  69.     public final static int ASTRAL_RUNE = 9075;
  70.     public final static int EARTH_RUNE = 557;
  71.     public final static String[] PAY_BANKER_ORDER = { "fire", "air", "mind",
  72.             "body", "water", "earth", "cosmic", "chaos", "astral", "law",
  73.             "death", "blood", "nature", "soul" };
  74.  
  75.     public final static RSTile[][] SAFE_MESH = { { new RSTile(3273, 4856, 0) },
  76.             { new RSTile(3280, 4848, 0) }, { new RSTile(3279, 4839, 0) },
  77.             { new RSTile(3286, 4832, 0) }, { new RSTile(3297, 4834, 0) },
  78.             { new RSTile(3309, 4836, 0) }, { new RSTile(3320, 4833, 0) },
  79.             { new RSTile(3310, 4828, 0) }, { new RSTile(3301, 4828, 0) },
  80.             { new RSTile(3289, 4829, 0) }, { new RSTile(3280, 4822, 0) },
  81.             { new RSTile(3290, 4820, 0) }, { new RSTile(3301, 4820, 0) },
  82.             { new RSTile(3308, 4820, 0) } };
  83.  
  84.     public final static RSTile[][] DANGER_MESH = {
  85.             { new RSTile(3272, 4851, 0), new RSTile(3269, 4854, 0) },
  86.             { new RSTile(3272, 4844, 0), new RSTile(3268, 4846, 0) },
  87.             { new RSTile(3271, 4837, 0), new RSTile(3268, 4838, 0) },
  88.             { new RSTile(3272, 4828, 0), new RSTile(3267, 4832, 0) },
  89.             { new RSTile(3273, 4821, 0), new RSTile(3268, 4825, 0) },
  90.             { new RSTile(3270, 4814, 0), new RSTile(3268, 4819, 0) },
  91.             { new RSTile(3275, 4808, 0), new RSTile(3276, 4814, 0) },
  92.             { new RSTile(3283, 4806, 0), new RSTile(3279, 4810, 0) },
  93.             { new RSTile(3288, 4812, 0), new RSTile(3287, 4807, 0) },
  94.             { new RSTile(3295, 4813, 0), new RSTile(3293, 4814, 0) },
  95.             { new RSTile(3300, 4807, 0), new RSTile(3298, 4813, 0) },
  96.             { new RSTile(3309, 4812, 0), new RSTile(3305, 4807, 0) } };
  97.     public final RSTile[] OURANIA_PATH = { new RSTile(2469, 3245),
  98.             new RSTile(2459, 3249), new RSTile(2455, 3239),
  99.             new RSTile(2453, 3232) };
  100.     public final static int POUCH_TRIES = 20;
  101.     public final static int[] food = { 333, 329, 379, 373, 7946, 361, 1901,
  102.             1899, 1897, 1895, 1893, 1891, 2142 };
  103.     public static final int LADDER_ID = 26849;
  104.  
  105.     // Pouch IDs
  106.     public static class Pouch {
  107.         public final static int SMALL = 5509;
  108.         public final static int MEDIUM = 5510;
  109.         public final static int MEDIUM_DEGRADED = 5511;
  110.         public final static int LARGE = 5512;
  111.         public final static int LARGE_DEGRADED = 5513;
  112.         public final static int GIANT = 5514;
  113.         public final static int GIANT_DEGRADED = 5515;
  114.         public final static int[] ALL = { SMALL, MEDIUM, MEDIUM_DEGRADED,
  115.                 LARGE, LARGE_DEGRADED, GIANT, GIANT_DEGRADED };
  116.         public final static int[] ALL_REPAIRED = { SMALL, MEDIUM, LARGE, GIANT };
  117.         public final static int[] ALL_DEGRADED = { MEDIUM_DEGRADED,
  118.                 LARGE_DEGRADED, GIANT_DEGRADED };
  119.         public final static int[] ALL_DEGRADEABLE = { MEDIUM, MEDIUM_DEGRADED,
  120.                 LARGE, LARGE_DEGRADED, GIANT, GIANT_DEGRADED };
  121.     }
  122.  
  123.     public static String serverMsg = "";
  124.     public HashMap<PouchType, PouchState> pouches = new HashMap<PouchType, PouchState>();
  125.     State currentState = State.LOST;
  126.     public MeshPath alterMeshPath;
  127.     public MeshPath bankMeshPath;
  128.     public NPCContact npcContact = new NPCContact();
  129.     public OptionsClass.Path pathTypeCurrent;
  130.     public OptionsClass Options = new OptionsClass();
  131.  
  132.     // Options
  133.     public static class OptionsClass {
  134.         public pouchRepairOption pouchRepair = pouchRepairOption.ONE;
  135.         public boolean hasAirStaff = true;
  136.         public boolean hasEarthStaff = true;
  137.         public PouchCheckSystem pouchCheckSystem = PouchCheckSystem.SERVER_MSG;
  138.         public Range walkingDistance = new Range(4, 6);
  139.         public Path pathType = Path.Danger;
  140.         public boolean chargeEnergy = true;
  141.         public boolean tryOuraniaTeleport = true;
  142.         public boolean onLunars = false;
  143.  
  144.         enum Path {
  145.             Danger, Safe
  146.         }
  147.  
  148.         /**
  149.          * When to repair pouches
  150.          *
  151.          * @author Equinox_
  152.          *
  153.          */
  154.         public enum pouchRepairOption {
  155.             ONE, TWO, ALL, NEVER
  156.         }
  157.  
  158.         /**
  159.          * How to determine a pouch's state
  160.          *
  161.          * @author Equinox_
  162.          *
  163.          */
  164.         public enum PouchCheckSystem {
  165.             SERVER_MSG, INVENTORY_STATUS
  166.         }
  167.     }
  168.  
  169.     /**
  170.      * A range class for randomized items
  171.      *
  172.      * @author Equinox_
  173.      *
  174.      */
  175.     public static class Range {
  176.         public int MAX;
  177.         public int MIN;
  178.  
  179.         public Range() {
  180.             MAX = 1;
  181.             MIN = -1;
  182.         }
  183.  
  184.         /**
  185.          *
  186.          * @param min
  187.          *            The inclusive lower bound
  188.          * @param max
  189.          *            The inclusive upper bound
  190.          */
  191.         public Range(int min, int max) {
  192.             MAX = Math.max(min, max) + 1;
  193.             MIN = Math.min(min, max);
  194.         }
  195.  
  196.         /**
  197.          * Returns a linearly distributed pseudorandom integer.
  198.          *
  199.          * @return Random integer min <= n < max.
  200.          */
  201.         public int randomLinearDistribution() {
  202.             return MIN + (MAX == MIN ? 0 : new Random().nextInt(MAX - MIN));
  203.         }
  204.  
  205.         /**
  206.          * Returns a normally distributed pseudorandom integer about a mean
  207.          * centered between min and max with a calculated standard deviation.
  208.          *
  209.          * @return Random integer min <= n < max from the normal distribution
  210.          *         described by the parameters.
  211.          */
  212.         public int randomNormalDistribution() {
  213.             int mean = MIN + (MAX - MIN) / 2;
  214.             int rand;
  215.             int sd = (MAX - MIN) / 3;
  216.             do {
  217.                 rand = (int) (new Random().nextGaussian() * sd + mean);
  218.             } while (rand < MIN || rand >= MAX);
  219.             return rand;
  220.         }
  221.  
  222.         /**
  223.          * Returns a normally distributed pseudorandom integer about a mean
  224.          * centered between min and max with a provided standard deviation.
  225.          *
  226.          * @param sd
  227.          *            The standard deviation. A higher value will increase the
  228.          *            probability of numbers further from the mean being
  229.          *            returned.
  230.          * @return Random integer min <= n < max from the normal distribution
  231.          *         described by the parameters.
  232.          */
  233.         public int randomNormalDistribution(int sd) {
  234.             int mean = MIN + (MAX - MIN) / 2;
  235.             int rand;
  236.             do {
  237.                 rand = (int) (new Random().nextGaussian() * sd + mean);
  238.             } while (rand < MIN || rand >= MAX);
  239.             return rand;
  240.         }
  241.  
  242.         public String toString() {
  243.             return MIN + "-" + MAX;
  244.         }
  245.     }
  246.  
  247.     public static int[] mergeArrays(int[] a1, int... a2) {
  248.         int[] newArr = new int[a1.length + a2.length];
  249.         for (int i = 0; i < a1.length; i++)
  250.             newArr[i] = a1[i];
  251.         for (int i = 0; i < a2.length; i++)
  252.             newArr[a1.length + i] = a2[i];
  253.         return newArr;
  254.     }
  255.  
  256.     /**
  257.      * Possible states in the process of nature runecrafting
  258.      *
  259.      * @author Equinox_
  260.      *
  261.      */
  262.     public enum State {
  263.         NEAR_BANK, NPC_CONTACT, BANK_WITHDRAW, BANK_DEPOSIT, FILL_POUCHES, TRAVERSE_ALTER, CRAFT_RUNES, EMPTY_POUCHES, TRAVERSE_BANK, LOST, EAT_FOOD, CHARGE_ENERGY, OURANIA_TELEPORT, LADDER_DOWN, TRAVERSE_OURANIA
  264.     }
  265.  
  266.     /**
  267.      * Possible states of pouches, Empty or Full
  268.      *
  269.      * @author Equinox_
  270.      *
  271.      */
  272.     public enum PouchState {
  273.         Empty, Full
  274.     }
  275.  
  276.     /**
  277.      * Different pouches and their possible IDs
  278.      *
  279.      * @author Equinox_
  280.      *
  281.      */
  282.     public enum PouchType {
  283.         Small(Pouch.SMALL), Medium(Pouch.MEDIUM, Pouch.MEDIUM_DEGRADED), Large(
  284.                 Pouch.LARGE, Pouch.LARGE_DEGRADED), Giant(Pouch.GIANT,
  285.                 Pouch.GIANT_DEGRADED);
  286.         public int[] ids;
  287.  
  288.         private PouchType(int... ids) {
  289.             this.ids = ids;
  290.         }
  291.     }
  292.  
  293.     /**
  294.      * Gets the current state
  295.      *
  296.      * @return State the current state
  297.      * @throws Exception
  298.      *             so we can pipe errors back to the recorder
  299.      */
  300.     public State getState() throws Exception {
  301.         if (objects.getNearest(LADDER_ID) != null
  302.                 && objects.getNearest(LADDER_ID).isOnScreen())
  303.             return State.LADDER_DOWN;
  304.         if (objects.getNearest(ZMI_ALTAR_ID) != null
  305.                 && objects.getNearest(ZMI_ALTAR_ID).getLocation() != null)
  306.             if (calc.tileOnMap(objects.getNearest(ZMI_ALTAR_ID).getLocation())
  307.                     && (Options.pathType.equals(OptionsClass.Path.Danger) || calc
  308.                             .pathLengthTo(alterDet, true) <= 15)) {
  309.                 if ((inventory.isFull() || !pouches
  310.                         .containsValue(PouchState.Full))
  311.                         && inventory.contains(PURE_ESS_ID))
  312.                     return State.CRAFT_RUNES;
  313.                 else if (pouches.containsValue(PouchState.Full))
  314.                     return State.EMPTY_POUCHES;
  315.                 // Check path type change
  316.                 if (!pathTypeCurrent.equals(Options.pathType)) {
  317.                     pathTypeCurrent = Options.pathType;
  318.                     // Set up path:
  319.                     if (Options.pathType.equals(OptionsClass.Path.Danger))
  320.                         alterMeshPath = new MeshPath(walking, calc, players,
  321.                                 DANGER_MESH);
  322.                     else
  323.                         alterMeshPath = new MeshPath(walking, calc, players,
  324.                                 SAFE_MESH);
  325.                     bankMeshPath = alterMeshPath.reverse();
  326.                 }
  327.             }
  328.  
  329.         // Banking
  330.         if (npcs.getNearest(BANKER_ID) != null) {
  331.             if (npcs.getNearest(BANKER_ID).isOnScreen() || bank.isOpen()) {
  332.                 // Check path type change
  333.                 if (!pathTypeCurrent.equals(Options.pathType)) {
  334.                     pathTypeCurrent = Options.pathType;
  335.                     // Set up path:
  336.                     if (Options.pathType.equals(OptionsClass.Path.Danger))
  337.                         alterMeshPath = new MeshPath(walking, calc, players,
  338.                                 DANGER_MESH);
  339.                     else
  340.                         alterMeshPath = new MeshPath(walking, calc, players,
  341.                                 SAFE_MESH);
  342.                     bankMeshPath = alterMeshPath.reverse();
  343.                 }
  344.                 if (!bank.isOpen() && walking.getEnergy() < 10
  345.                         && Options.chargeEnergy)
  346.                     return State.CHARGE_ENERGY;
  347.                 // Pouch Repair
  348.                 if (shouldRepairPouches())
  349.                     return State.NPC_CONTACT;
  350.                 if ((combat.getLifePoints() + 200 < skills
  351.                         .getCurrentLevel(Skills.CONSTITUTION) * 10)
  352.                         || combat.getHealth() < 50)
  353.                     return State.EAT_FOOD;
  354.                 if (inventory.getCount(Pouch.ALL)
  355.                         + inventory.getCount(PURE_ESS_ID)
  356.                         + inventory.getCount(FIRE_RUNE_ID) != inventory
  357.                         .getCount())
  358.                     return State.BANK_DEPOSIT;
  359.  
  360.                 if (inventory.contains(PURE_ESS_ID)
  361.                         && pouches.containsValue(PouchState.Empty))
  362.                     return State.FILL_POUCHES;
  363.  
  364.                 if (!inventory.isFull())
  365.                     return State.BANK_WITHDRAW;
  366.             } else if (!inventory.contains(PURE_ESS_ID))
  367.                 return State.NEAR_BANK;
  368.  
  369.         }
  370.  
  371.         if (inventory.contains(PURE_ESS_ID) && !shouldRepairPouches())
  372.             return State.TRAVERSE_ALTER;
  373.         else {
  374.             if (objects.getNearest(LADDER_ID) != null)
  375.                 return State.TRAVERSE_OURANIA;
  376.             if (Options.tryOuraniaTeleport
  377.                     && skills.getCurrentLevel(Skills.MAGIC) >= 71
  378.                     && inventory.contains(LAW_RUNE)
  379.                     && inventory.getCount(true, ASTRAL_RUNE) >= 2
  380.                     && (inventory.getCount(true, EARTH_RUNE) >= 6 || Options.hasEarthStaff))
  381.                 return State.OURANIA_TELEPORT;
  382.             return State.TRAVERSE_BANK;
  383.         }
  384.         // return State.LOST;
  385.     }
  386.  
  387.     /**
  388.      * Internal use only. When the client receives a message this method is
  389.      * invoked, saving the message for later use.
  390.      */
  391.     public void messageReceived(MessageEvent msg) {
  392.         if (msg.getID() == MessageEvent.MESSAGE_ACTION
  393.                 || msg.getID() == MessageEvent.MESSAGE_SERVER) {
  394.             serverMsg = msg.getMessage().toLowerCase();
  395.         }
  396.     }
  397.  
  398.     /**
  399.      * Determines if pouches need repairing by using the method defined in the
  400.      * Options class
  401.      *
  402.      * @return boolean should repair pouches
  403.      */
  404.     public boolean shouldRepairPouches() {
  405.         int degradeable = inventory.getCount(Pouch.ALL_DEGRADEABLE);
  406.         int degraded = inventory.getCount(Pouch.ALL_DEGRADED);
  407.         switch (Options.pouchRepair) {
  408.         case ONE:
  409.             return degraded > 0;
  410.         case TWO:
  411.             return degraded > 1 || degradeable < 2;
  412.         case ALL:
  413.             return degradeable == degraded;
  414.         case NEVER:
  415.             return false;
  416.         default:
  417.             return degraded > 1 || degradeable < 2;
  418.         }
  419.     }
  420.  
  421.     /**
  422.      * Tries to open the bank
  423.      *
  424.      * @return boolean did bank open
  425.      */
  426.     public boolean openBank() {
  427.         if (!alterMeshPath.hasPath())
  428.             alterMeshPath.findPath();
  429.         if (bankMeshPath.hasPath())
  430.             bankMeshPath.clearPath();
  431.  
  432.         for (byte b = 0; b < 10; b++) {
  433.             if (interfaces.get(PAY_BANK_INTERFACE) != null
  434.                     && interfaces.get(PAY_BANK_INTERFACE).isValid())
  435.                 payBankCharge();
  436.             if (npcs.getNearest(BANKER_ID) != null) {
  437.                 if (bank.isOpen())
  438.                     return true;
  439.                 npcs.getNearest(BANKER_ID).doAction("Bank");
  440.                 sleep(100, 250);
  441.             }
  442.             sleep(1000);
  443.         }
  444.         return false;
  445.     }
  446.  
  447.     public void payBankCharge() {
  448.         RSInterface pay = interfaces.get(PAY_BANK_INTERFACE);
  449.         if (pay != null && pay.isValid())
  450.             for (String rune : PAY_BANKER_ORDER)
  451.                 for (RSComponent c : pay.getComponents())
  452.                     if (c != null
  453.                             && c.isValid()
  454.                             && c.getTooltip() != null
  455.                             && c.getTooltip().toLowerCase()
  456.                                     .contains(rune.toLowerCase()))
  457.                         if (inventoryCount(rune) >= 20)
  458.                             if (c.doClick()) {
  459.                                 sleep(1500);
  460.                                 return;
  461.                             }
  462.         log.severe("Unable to pay banker!");
  463.     }
  464.  
  465.     public int inventoryCount(String name) {
  466.         for (RSItem i : inventory.getCachedItems())
  467.             if (i != null
  468.                     && i.getName().toLowerCase().contains(name.toLowerCase()))
  469.                 return i.getStackSize();
  470.         return 0;
  471.     }
  472.  
  473.     /**
  474.      * Deposit all non necessary items.
  475.      */
  476.     public void deposit() {
  477.         if (!openBank())
  478.             return;
  479.         int invBefore = inventory.getCount();
  480.         int pouchesBefore = inventory.getCount(Pouch.ALL);
  481.         bank.depositAll();
  482.         for (byte b = 0; b < 15 && invBefore >= inventory.getCount(); b++)
  483.             sleep(100, 125);
  484.         for (byte b = 0; b < 5 && !inventory.contains(FIRE_RUNE_ID); b++) {
  485.             bank.withdraw(FIRE_RUNE_ID, 0);
  486.             sleep(250, 300);
  487.         }
  488.         int[] pouchIds = {};
  489.         for (PouchType p : pouches.keySet())
  490.             pouchIds = mergeArrays(pouchIds, p.ids);
  491.         for (byte b = 0; b < 5 && inventory.getCount(Pouch.ALL) < pouchesBefore; b++) {
  492.             for (RSItem item : bank.getItems())
  493.                 if (item != null)
  494.                     for (int id : pouchIds)
  495.                         if (item.getID() == id)
  496.                             if (bank.withdraw(item.getID(), 1))
  497.                                 sleep(250, 300);
  498.         }
  499.  
  500.         // Paint.runsMade++; TODO
  501.     }
  502.  
  503.     /**
  504.      * Tries to open the bank if the bank is not open, then tries to withdraw
  505.      * the item
  506.      *
  507.      * @param id
  508.      *            the item to withdraw
  509.      * @param amount
  510.      *            the amount to withdraw, 0 for all
  511.      * @return boolean successfully withdraw
  512.      */
  513.     public boolean withdrawItem(int id, int amount) {
  514.         if (!openBank())
  515.             return false;
  516.         boolean returns = bank.withdraw(id, amount);
  517.         sleep(250, 500);
  518.         return returns;
  519.     }
  520.  
  521.     /**
  522.      * Withdraws pure essence
  523.      *
  524.      * @return boolean did withdraw item
  525.      */
  526.     public boolean withdrawEss() {
  527.         return withdrawItem(PURE_ESS_ID, 0);
  528.     }
  529.  
  530.     /**
  531.      * Gets the count of items by the provided id(s) in both the bank and
  532.      * inventory. Includes stack sizes
  533.      *
  534.      * @param id
  535.      *            item ids to search
  536.      * @return int number of items in bank and inventory
  537.      */
  538.     public int getCountBankInv(int... id) {
  539.         int count = 0;
  540.         if (bank.isOpen())
  541.             count += bank.getCount(id);
  542.         count += inventory.getCount(true, id);
  543.         return count;
  544.     }
  545.  
  546.     /**
  547.      * Emptys pouches using the method set in the Options class
  548.      */
  549.     public void emptyPouches() {
  550.         if (game.getCurrentTab() == Game.TAB_INVENTORY)
  551.             updatePouches();
  552.         for (PouchType pType : pouches.keySet()) {
  553.             if (inventory.isFull())
  554.                 break;
  555.             if (inventory.containsOneOf(pType.ids)) {
  556.                 if (pouches.get(pType).equals(PouchState.Full)) {
  557.                     RSItem item = inventory.getItem(pType.ids);
  558.                     if (item != null) {
  559.                         int invCount = inventory.getCount();
  560.                         if (item.doAction("Empty"))
  561.                             switch (Options.pouchCheckSystem) {
  562.                             case SERVER_MSG:
  563.                                 for (int i = 0; i < POUCH_TRIES; i++) {
  564.                                     if (serverMsg != null)
  565.                                         if (serverMsg
  566.                                                 .contains("pouch has no ess")
  567.                                                 || serverMsg
  568.                                                         .contains("are no essences in your pouch")) {
  569.                                             pouches.put(pType, PouchState.Empty);
  570.                                             serverMsg = "";
  571.                                             break;
  572.                                         }
  573.                                     sleep(80, 120);
  574.                                 }
  575.                                 break;
  576.                             case INVENTORY_STATUS:
  577.                                 for (int i = 1; i <= POUCH_TRIES; i++)
  578.                                     if (inventory.getCount() == invCount
  579.                                             && i != POUCH_TRIES)
  580.                                         sleep(100, 150);
  581.                                     else {
  582.                                         if (!inventory.isFull())
  583.                                             pouches.put(pType, PouchState.Empty);
  584.                                         break;
  585.                                     }
  586.  
  587.                                 break;
  588.                             }
  589.                     }
  590.                 }
  591.             }
  592.         }
  593.     }
  594.  
  595.     /**
  596.      * Fills pouches using the method set in the Options class
  597.      */
  598.     public void fillPouches() {
  599.         if (game.getCurrentTab() == Game.TAB_INVENTORY)
  600.             updatePouches();
  601.         for (PouchType pType : pouches.keySet()) {
  602.             if (!inventory.contains(PURE_ESS_ID))
  603.                 break;
  604.             if (inventory.containsOneOf(pType.ids)) {
  605.                 if (pouches.get(pType).equals(PouchState.Empty)) {
  606.                     RSItem item = inventory.getItem(pType.ids);
  607.                     if (item != null) {
  608.                         int invCount = inventory.getCount();
  609.                         if (item.doAction("Fill"))
  610.                             switch (Options.pouchCheckSystem) {
  611.                             case SERVER_MSG:
  612.                                 for (int i = 0; i < POUCH_TRIES; i++) {
  613.                                     if (serverMsg != null)
  614.                                         if (serverMsg.contains("pouch is ful")) {
  615.                                             pouches.put(pType, PouchState.Full);
  616.                                             serverMsg = "";
  617.                                             break;
  618.                                         }
  619.                                     sleep(80, 120);
  620.                                 }
  621.                                 break;
  622.                             case INVENTORY_STATUS:
  623.                                 for (int i = 1; i <= POUCH_TRIES; i++)
  624.                                     if (inventory.getCount() == invCount
  625.                                             && i != POUCH_TRIES)
  626.                                         sleep(100, 150);
  627.                                     else {
  628.                                         if (inventory.contains(PURE_ESS_ID))
  629.                                             pouches.put(pType, PouchState.Full);
  630.                                         break;
  631.                                     }
  632.  
  633.                                 break;
  634.                             }
  635.                     }
  636.                 }
  637.             }
  638.         }
  639.     }
  640.  
  641.     /**
  642.      * Rechecks pouches with the inventory's current contents. If a pouch in the
  643.      * list no longer exists it removes it, if there's a pouch in the inventory
  644.      * not in the list it adds it as an empty pouch
  645.      */
  646.     public void updatePouches() {
  647.         for (PouchType pouch : PouchType.values())
  648.             if (inventory.containsOneOf(pouch.ids)) {
  649.                 if (!pouches.containsKey(pouch))
  650.                     pouches.put(pouch, PouchState.Empty);
  651.             } else if (pouches.containsKey(pouch))
  652.                 pouches.remove(pouch);
  653.     }
  654.  
  655.     public int getRuneCount(boolean cache) {
  656.         int count = 0;
  657.         for (RSItem i : cache ? inventory.getCachedItems() : inventory
  658.                 .getItems())
  659.             if (i.getName() != null
  660.                     && i.getName().toLowerCase().contains("rune"))
  661.                 count += i.getStackSize();
  662.         return count;
  663.     }
  664.  
  665.     /**
  666.      * Crafts essence at the alter
  667.      */
  668.     public void craftEssence() {
  669.         if (alterMeshPath.hasPath())
  670.             alterMeshPath.clearPath();
  671.         if (!bankMeshPath.hasPath())
  672.             bankMeshPath.findPath();
  673.  
  674.         RSObject alter = objects.getNearest(ZMI_ALTAR_ID);
  675.         if (!alter.isOnScreen()
  676.                 && (!getMyPlayer().isMoving()
  677.                         || walking.getDestination() == null || calc
  678.                         .distanceBetween(
  679.                                 alter.getArea().getNearestTile(
  680.                                         getMyPlayer().getLocation()),
  681.                                 walking.getDestination()) > 2))
  682.             walking.walkTileMM(alter.getArea().getNearestTile(
  683.                     getMyPlayer().getLocation()));
  684.  
  685.         // int invBefore = inventory.getCount(PURE_ESS_ID);
  686.         // int runesBefore = getRuneCount(false);
  687.         alter.doAction("Craft-rune");
  688.         sleep(1000);
  689.         for (byte b = 0; b < 50
  690.                 && (getMyPlayer().getAnimation() == CRAFT_RUNE_ANIM
  691.                         || getMyPlayer().isMoving() || walking.getDestination() != null); b++)
  692.             sleep(100, 125);
  693.  
  694.         // Paint.essUsed += invBefore - inventory.getCount(PURE_ESS_ID); TODO
  695.         // Paint.runesMade += getRuneCount(false) - runesBefore;
  696.     }
  697.  
  698.     public boolean onStart() {
  699.         if (game.getCurrentTab() != Game.TAB_MAGIC)
  700.             game.openTab(Game.TAB_MAGIC);
  701.         Options.onLunars = magic.getInterface() != null
  702.                 && magic.getInterface().getIndex() == Magic.Book.LUNAR
  703.                         .getInterfaceID();
  704.         Options.tryOuraniaTeleport = (skills.getCurrentLevel(Skills.MAGIC) >= 71 && Options.onLunars);
  705.  
  706.         pathTypeCurrent = Options.pathType;
  707.         // Set up path:
  708.         if (Options.pathType.equals(OptionsClass.Path.Danger))
  709.             alterMeshPath = new MeshPath(walking, calc, players, DANGER_MESH);
  710.         else
  711.             alterMeshPath = new MeshPath(walking, calc, players, SAFE_MESH);
  712.         bankMeshPath = alterMeshPath.reverse();
  713.  
  714.         // Set up the pouches:
  715.         updatePouches();
  716.  
  717.         RSItem wep = equipment.getItem(Equipment.WEAPON);
  718.         if (wep != null) {
  719.             Options.hasAirStaff = (wep.getName().toLowerCase()
  720.                     .contains("staff") && wep.getName().toLowerCase()
  721.                     .contains("air"));
  722.             Options.hasEarthStaff = (wep.getName().toLowerCase()
  723.                     .contains("staff") && (wep.getName().toLowerCase()
  724.                     .contains("earth")
  725.                     || wep.getName().toLowerCase().contains("mud") || wep
  726.                     .getName().toLowerCase().contains("lava")));
  727.         }
  728.  
  729.         new DataLoader(this);
  730.  
  731.         // optimal alt
  732.         camera.setPitch(random(0, 10));
  733.  
  734.         log.info("Script initiation successful!");
  735.         log.info("--Setup--");
  736.         log.info("Air staff: " + (Options.hasAirStaff ? "yes" : "no"));
  737.         log.info("Earth staff: " + (Options.hasEarthStaff ? "yes" : "no"));
  738.         log.info("Walking range: " + Options.walkingDistance.toString());
  739.         log.info("Pouch method: "
  740.                 + PaintFormatter.properCaseAll(Options.pouchCheckSystem.name()
  741.                         .replaceAll("_", " ")));
  742.         log.info("Pouch repair system: "
  743.                 + PaintFormatter.properCaseAll(Options.pouchRepair.name()
  744.                         .replaceAll("_", " ")));
  745.         log.info("Walking style: "
  746.                 + PaintFormatter.properCaseAll(Options.pathType.name()));
  747.         log.info("Recharge Energy: "
  748.                 + (Options.chargeEnergy ? "True" : "False"));
  749.         log.info("Try Ourania Teleport: "
  750.                 + (Options.tryOuraniaTeleport ? "True" : "False"));
  751.         return true;
  752.     }
  753.  
  754.     public boolean isResting() {
  755.         int anim = getMyPlayer().getAnimation();
  756.         return (anim == 12108 || anim == 2033 || anim == 2716 || anim == 11786 || anim == 5713);
  757.     }
  758.  
  759.     public void rest() {
  760.         for (int d = 0; d < 5; d++) {
  761.             interfaces.getComponent(walking.INTERFACE_RUN_ORB, 1).doAction(
  762.                     "Rest");
  763.             mouse.moveSlightly();
  764.             sleep(random(400, 600));
  765.             int anim = players.getMyPlayer().getAnimation();
  766.             if (anim == 12108 || anim == 2033 || anim == 2716 || anim == 11786
  767.                     || anim == 5713) {
  768.                 break;
  769.             }
  770.         }
  771.     }
  772.  
  773.     public int loop() {
  774.         mouse.setSpeed(random(4, 6));
  775.         if (!walking.isRunEnabled() && walking.getEnergy() > 50 && !isResting())
  776.             walking.setRun(true);
  777.         try {
  778.             currentState = getState();
  779.             switch (currentState) {
  780.             case LADDER_DOWN:
  781.                 if (objects.getNearest(LADDER_ID).isOnScreen())
  782.                     if (objects.getNearest(LADDER_ID).doAction("Climb"))
  783.                         sleep(500, 750);
  784.                 break;
  785.             case OURANIA_TELEPORT:
  786.                 if (magic.castSpell(Magic.SPELL_OURANIA_TELEPORT))
  787.                     for (byte b = 0; b < 30 && !calc.tileOnMap(OURANIA_PATH[0]); b++)
  788.                         sleep(100, 125);
  789.                 sleep(500, 750);
  790.                 break;
  791.             case TRAVERSE_OURANIA:
  792.                 RSTilePath tPath = walking.newTilePath(OURANIA_PATH).randomize(
  793.                         2, 2);
  794.                 for (byte b = 0; b < 300 && tPath.isValid()
  795.                         && (objects.getNearest(LADDER_ID) != null) ? !objects
  796.                         .getNearest(LADDER_ID).isOnScreen() : true; b++) {
  797.                     tPath.traverse();
  798.                     sleep(95, 105);
  799.                 }
  800.                 break;
  801.             case CHARGE_ENERGY:
  802.                 if (!isResting())
  803.                     rest();
  804.                 if (isResting())
  805.                     while (walking.getEnergy() < 100 && isResting()
  806.                             && isActive())
  807.                         sleep(200);
  808.                 break;
  809.             case NEAR_BANK:
  810.                 RSNPC banker = npcs.getNearest(BANKER_ID);
  811.                 if (banker != null)
  812.                     if (!banker.isOnScreen()) {
  813.                         RSTile loc = banker.getLocation();
  814.                         if (calc.tileOnMap(loc)) {
  815.                             walking.walkTileMM(loc);
  816.                             for (byte b = 0; b < 22 && !banker.isOnScreen(); b++)
  817.                                 sleep(100, 115);
  818.                         }
  819.                     }
  820.                 break;
  821.             case BANK_DEPOSIT:
  822.                 deposit();
  823.                 break;
  824.             case BANK_WITHDRAW:
  825.                 withdrawEss();
  826.                 break;
  827.             case CRAFT_RUNES:
  828.                 craftEssence();
  829.                 break;
  830.             case EMPTY_POUCHES:
  831.                 emptyPouches();
  832.                 break;
  833.             case EAT_FOOD:
  834.                 if (!inventory.containsOneOf(food)) {
  835.                     openBank();
  836.                     for (int id : food)
  837.                         if (bank.getCount(id) > 0)
  838.                             if (bank.withdraw(id, 1))
  839.                                 break;
  840.                 }
  841.                 if (bank.isOpen())
  842.                     bank.close();
  843.                 if (inventory.containsOneOf(food)) {
  844.                     RSItem foodI = inventory.getItem(food);
  845.                     if (foodI != null)
  846.                         foodI.doAction("Eat");
  847.                 }
  848.                 break;
  849.             case FILL_POUCHES:
  850.                 fillPouches();
  851.                 break;
  852.             case NPC_CONTACT:
  853.                 npcContact.main();
  854.                 break;
  855.             case TRAVERSE_BANK:
  856.                 if (!bankMeshPath.hasPath())
  857.                     bankMeshPath.findPath(MeshPath.MeshPathType.FULL);
  858.                 if (Options.pathType.equals(OptionsClass.Path.Safe)
  859.                         && (bankMeshPath.getNearestByPath() == null || !bankMeshPath
  860.                                 .getNearestByPath().equals(
  861.                                         bankMeshPath.getEnd())))
  862.                     if (objects.getNearest(CRACK_OUT) != null
  863.                             && objects.getNearest(CRACK_OUT).isOnScreen()
  864.                             && objects.getNearest(CRACK_OUT).doAction(
  865.                                     "Squeeze-through")) {
  866.                         sleep(500);
  867.                         for (byte b = 0; b < 20
  868.                                 && getMyPlayer().getAnimation() != -1; b++)
  869.                             sleep(100, 110);
  870.                         break;
  871.                     }
  872.                 bankMeshPath.traverse();
  873.                 break;
  874.             case TRAVERSE_ALTER:
  875.                 if (!alterMeshPath.hasPath())
  876.                     alterMeshPath.findPath(MeshPath.MeshPathType.ALL_CENTER);
  877.                 if ((calc.pathLengthTo(alterDet, true) > 25 || calc
  878.                         .pathLengthTo(alterDet, true) < 0)
  879.                         && Options.pathType.equals(OptionsClass.Path.Safe))
  880.                     if (objects.getNearest(CRACK_IN) != null)
  881.                         if (objects.getNearest(CRACK_IN).isOnScreen()
  882.                                 && objects.getNearest(CRACK_IN).doAction(
  883.                                         "Squeeze-through")) {
  884.                             sleep(500);
  885.                             for (byte b = 0; b < 20
  886.                                     && getMyPlayer().getAnimation() != -1; b++)
  887.                                 sleep(100, 110);
  888.                             break;
  889.                         }
  890.                 alterMeshPath.traverse();
  891.                 break;
  892.             }
  893.         } catch (Exception e) {
  894.             logError(e);
  895.         }
  896.         return random(50, 100);
  897.     }
  898.  
  899.     public void onFinish() {
  900.         FailSafe();
  901.         // Paint.paintMenu.saveProggie();
  902.     }
  903.  
  904.     /**
  905.      * Logs an exception to the Logger and to the error cache
  906.      *
  907.      * @param e
  908.      *            as the Exception to log
  909.      */
  910.     public void logError(Exception e) {
  911.         String s = e.getMessage();
  912.         log.severe(s);
  913.         for (StackTraceElement ele : e.getStackTrace()) {
  914.             s += "\n" + ele.toString();
  915.             log.severe(ele.toString());
  916.         }
  917.     }
  918.  
  919.     /**
  920.      * {@inheritDoc}
  921.      */
  922.     public void onRepaint(Graphics g1) {
  923.         Graphics2D g = (Graphics2D) g1;
  924.         try {
  925.             // MeshPaths
  926.             alterMeshPath.paintAll(g);
  927.             if (bankMeshPath.hasPath()) {
  928.                 bankMeshPath.paintBlockPath(g);
  929.                 bankMeshPath.paintSmoothPath(g);
  930.             }
  931.         } catch (NullPointerException e) {
  932.             logError(e);
  933.         }
  934.     }
  935.  
  936.     /**
  937.      * The different states the NPC contact process can be in
  938.      *
  939.      * @author Equinox_
  940.      *
  941.      */
  942.     enum npcContactState {
  943.         CAST, SCROLL, SELECT, WAIT, CONTINUE, MENU, WITHDRAW_ASTRAL, WITHDRAW_COSMIC, WITHDRAW_AIR, OUT_OF_RUNES
  944.     }
  945.  
  946.     /**
  947.      * A class to contact people using NPC contact
  948.      *
  949.      * @author Equinox_
  950.      *
  951.      */
  952.     class NPCContact {
  953.         public npcContactState currentState = npcContactState.WAIT;
  954.         private final int MAIN_FRAME = 88;
  955.         private final int SCROLL_BAR = 20;
  956.         private final int SCROLL_BAR_DOWN = 0;
  957.         private final int VISIBLE_NPCS_CONTAINER = 21;
  958.         private final int NPCS_CONTAINER = 22;
  959.         private final int NPC_CONTACT_ANIM = 4413;
  960.  
  961.         private final int NPC_TO_SELECT = 14;
  962.         private final String[] MENU_ITEM = { "repair", "pouch" };
  963.  
  964.         /**
  965.          * Gets the current npcContactState
  966.          *
  967.          * @return the current npcContactState
  968.          */
  969.         private npcContactState getState() {
  970.             if (interfaces.get(MAIN_FRAME).isValid()) {
  971.                 if (interfaces.get(MAIN_FRAME).getComponent(NPCS_CONTAINER)
  972.                         .isValid()) {
  973.                     Point npcPoint = interfaces.get(MAIN_FRAME)
  974.                             .getComponent(NPCS_CONTAINER)
  975.                             .getComponent(NPC_TO_SELECT).getCenter();
  976.                     Rectangle visible = interfaces.get(MAIN_FRAME)
  977.                             .getComponent(VISIBLE_NPCS_CONTAINER).getArea();
  978.                     if (!visible.contains(npcPoint))
  979.                         return npcContactState.SCROLL;
  980.                     else
  981.                         return npcContactState.SELECT;
  982.                 }
  983.             }
  984.  
  985.             if (interfaces.canContinue())
  986.                 return npcContactState.CONTINUE;
  987.  
  988.             if (getComponent(MENU_ITEM) != null)
  989.                 return npcContactState.MENU;
  990.  
  991.             if (!interfaces.canContinue()
  992.                     && getMyPlayer().getAnimation() != NPC_CONTACT_ANIM
  993.                     && getComponent(MENU_ITEM) == null
  994.                     && getComponent("lease wai") == null) {
  995.                 if (!inventory.contains(ASTRAL_RUNE_ID))
  996.                     return npcContactState.WITHDRAW_ASTRAL;
  997.                 if (!inventory.contains(COSMIC_RUNE_ID))
  998.                     return npcContactState.WITHDRAW_COSMIC;
  999.                 if (inventory.getCount(true, AIR_RUNE_ID) < 2
  1000.                         && !Options.hasAirStaff)
  1001.                     return npcContactState.WITHDRAW_AIR;
  1002.                 return npcContactState.CAST;
  1003.             }
  1004.             return npcContactState.WAIT;
  1005.         }
  1006.  
  1007.         /**
  1008.          * Finds a RSComponent with the specified string
  1009.          *
  1010.          * @param s
  1011.          *            The String to search
  1012.          * @return RSComponent with string, otherwise null
  1013.          */
  1014.         private RSComponent getComponent(String... s) {
  1015.             RSInterface[] valid = interfaces.getAll();
  1016.             for (RSInterface iface : valid) {
  1017.                 if (iface.getIndex() != 137) {
  1018.                     int len = iface.getChildCount();
  1019.                     for (int i = 0; i < len; i++) {
  1020.                         RSComponent child = iface.getComponent(i);
  1021.                         boolean b = (child.isValid()
  1022.                                 && child.getAbsoluteX() > 10 && child
  1023.                                 .getAbsoluteY() > 300);
  1024.                         for (String sub : s)
  1025.                             if (!child.getText().toLowerCase()
  1026.                                     .contains(sub.toLowerCase()))
  1027.                                 b = false;
  1028.                         if (b)
  1029.                             return child;
  1030.                     }
  1031.                 }
  1032.             }
  1033.             return null;
  1034.         }
  1035.  
  1036.         /**
  1037.          * Checks if the inventory or bank contains the specified item
  1038.          *
  1039.          * @param id
  1040.          *            the item id
  1041.          * @return <tt>true</tt> if the bank or inventory contains the item,
  1042.          *         otherwise, <tt>false</tt>
  1043.          */
  1044.         boolean invBank(int id) {
  1045.             return bank.getCount(id) > 0 || inventory.containsOneOf(id);
  1046.         }
  1047.  
  1048.         /**
  1049.          * Gets the count of a specified item in the inventory and bank
  1050.          *
  1051.          * @param int itemId
  1052.          * @return the item count
  1053.          */
  1054.         int invBankCount(int id) {
  1055.             return bank.getCount(id) + inventory.getCount(true, id);
  1056.         }
  1057.  
  1058.         /**
  1059.          * The main loop. Call this to do the next action for the contact
  1060.          * process.
  1061.          */
  1062.         public void main() {
  1063.             switch (currentState = getState()) {
  1064.             case WITHDRAW_ASTRAL:
  1065.                 withdrawItem(ASTRAL_RUNE_ID, 1);
  1066.                 if (!invBank(ASTRAL_RUNE_ID))
  1067.                     removePouches();
  1068.                 break;
  1069.             case WITHDRAW_COSMIC:
  1070.                 withdrawItem(COSMIC_RUNE_ID, 1);
  1071.                 if (!invBank(COSMIC_RUNE_ID))
  1072.                     removePouches();
  1073.                 break;
  1074.             case WITHDRAW_AIR:
  1075.                 if (!inventory.contains(AIR_RUNE_ID)) {
  1076.                     if (inventory.isFull())
  1077.                         bank.deposit(PURE_ESS_ID, 1);
  1078.                     withdrawItem(AIR_RUNE_ID, 1);
  1079.                 }
  1080.                 withdrawItem(AIR_RUNE_ID, 1);
  1081.                 if (invBankCount(AIR_RUNE_ID) < 2)
  1082.                     removePouches();
  1083.                 break;
  1084.             case CAST:
  1085.                 for (byte b = 0; b < 5; b++)
  1086.                     if (bank.isOpen()) {
  1087.                         bank.close();
  1088.                         for (byte b2 = 0; b2 < 25; b2++)
  1089.                             if (bank.isOpen())
  1090.                                 break;
  1091.                             else
  1092.                                 sleep(95, 115);
  1093.                     }
  1094.                 if (game.getCurrentTab() != Game.TAB_MAGIC)
  1095.                     game.openTab(Game.TAB_MAGIC);
  1096.  
  1097.                 sleep(500, 1250);
  1098.                 magic.castSpell(Magic.SPELL_NPC_CONTACT);
  1099.                 sleep(750, 1250);
  1100.                 break;
  1101.             case SCROLL:
  1102.                 // Scroll
  1103.                 RSComponent bar = interfaces.get(MAIN_FRAME)
  1104.                         .getComponent(SCROLL_BAR).getComponent(SCROLL_BAR_DOWN);
  1105.                 Point p = bar.getCenter();
  1106.                 p.y = bar.getAbsoluteY() + bar.getHeight() - 5;
  1107.                 mouse.click(p, true);
  1108.                 break;
  1109.             case SELECT:
  1110.                 interfaces.get(MAIN_FRAME).getComponent(NPCS_CONTAINER)
  1111.                         .getComponent(NPC_TO_SELECT).doClick();
  1112.                 break;
  1113.             case WAIT:
  1114.                 break;
  1115.             case CONTINUE:
  1116.                 if (interfaces.canContinue())
  1117.                     interfaces.clickContinue();
  1118.                 break;
  1119.             case MENU:
  1120.                 if (getComponent(MENU_ITEM) != null)
  1121.                     getComponent(MENU_ITEM).doClick();
  1122.                 break;
  1123.             }
  1124.             sleep(900, 1200);
  1125.         }
  1126.  
  1127.         public void removePouches() {
  1128.             if (!openBank())
  1129.                 return;
  1130.             // not enough runes, bank pouches:
  1131.             for (int id : Pouch.ALL_DEGRADED)
  1132.                 if (inventory.contains(id)) {
  1133.                     if (bank.deposit(id, 1))
  1134.                         sleep(500, 600);
  1135.                 }
  1136.             updatePouches();
  1137.         }
  1138.     }
  1139.  
  1140.     /**
  1141.      * Loads script data as the actual script runs. Useful for images that are
  1142.      * non-essential.
  1143.      *
  1144.      * @author Equinox_
  1145.      *
  1146.      */
  1147.     public static class DataLoader extends Thread {
  1148.         EquinoxZMICrafter crafter;
  1149.  
  1150.         public DataLoader(EquinoxZMICrafter crafter) {
  1151.             super("Data Loader");
  1152.             this.crafter = crafter;
  1153.             this.start();
  1154.         }
  1155.  
  1156.         // Item Info
  1157.         public void checkGE() {
  1158.             long before = System.currentTimeMillis();
  1159.             GEItem item = crafter.getGE().lookup(PURE_ESS_ID);
  1160.             if (item != null) {
  1161.                 // crafter.Paint.essPrice = getItemPrice(item);
  1162.                 crafter.log("Price of " + item.getName() + ": "
  1163.                         + getItemPrice(item));
  1164.                 crafter.log("Loaded essence information in "
  1165.                         + PaintFormatter.getFormattedTime(System
  1166.                                 .currentTimeMillis() - before));
  1167.             }
  1168.         }
  1169.  
  1170.         public void run() {
  1171.             checkGE();
  1172.             try {
  1173.                 if (JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(
  1174.                         null, "Would you like to load some images?",
  1175.                         "Equinox_ Data Loader", JOptionPane.YES_NO_OPTION))
  1176.                     throw new Exception();
  1177.  
  1178.                 /*
  1179.                  * long before = System.currentTimeMillis();
  1180.                  * crafter.Paint.putImage( "homeicon", ImageIO.read(new
  1181.                  * URL(crafter.baseURL + "/images/houseIcon.png")));
  1182.                  * crafter.log("Loaded home image in " +
  1183.                  * PaintFormatter.getFormattedTime(System .currentTimeMillis() -
  1184.                  * before));
  1185.                  *
  1186.                  * before = System.currentTimeMillis(); crafter.Paint .putImage(
  1187.                  * "rcicon", ImageIO.read(new URL(
  1188.                  * "http://www.runescape.com/img/hiscores/skill_icon_Runecrafting1.gif"
  1189.                  * ))); crafter.log("Loaded runecrafting image in " +
  1190.                  * PaintFormatter.getFormattedTime(System .currentTimeMillis() -
  1191.                  * before));
  1192.                  *
  1193.                  * before = System.currentTimeMillis(); crafter.Paint.putImage(
  1194.                  * "toolsicon", ImageIO.read(new URL(crafter.baseURL +
  1195.                  * "/images/tools.png"))); crafter.log("Loaded tools icon in " +
  1196.                  * PaintFormatter.getFormattedTime(System .currentTimeMillis() -
  1197.                  * before));
  1198.                  */
  1199.             } catch (Exception e) {
  1200.                 crafter.log("Failed to load images");
  1201.             }
  1202.         }
  1203.     }
  1204.  
  1205.     /**
  1206.      * Gets the grandExchange singleton for reference by other classes msg
  1207.      *
  1208.      * @return GrandExchange reference
  1209.      */
  1210.     public GrandExchange getGE() {
  1211.         return grandExchange;
  1212.     }
  1213.  
  1214.     /**
  1215.      * gets the item price based on class. Works with all versions of
  1216.      * grandExchange.class
  1217.      *
  1218.      * @param item
  1219.      *            the GEItem to get the price from
  1220.      * @return int the price
  1221.      *
  1222.      * @author Equinox_
  1223.      */
  1224.     public static int getItemPrice(GEItem item) {
  1225.         for (Method m : item.getClass().getMethods())
  1226.             if (m.getName().equals("getGuidePrice")
  1227.                     || m.getName().equals("getMinPrice"))
  1228.                 try {
  1229.                     return (Integer) (m.invoke(item));
  1230.                 } catch (Exception e) {
  1231.                 }
  1232.         return 0;
  1233.     }
  1234.  
  1235.     public void FailSafe() {
  1236.         log.info("FailSafe Activated!");
  1237.  
  1238.         // Set up path:
  1239.         if (pathTypeCurrent.equals(OptionsClass.Path.Danger))
  1240.             alterMeshPath = new MeshPath(walking, calc, players, DANGER_MESH);
  1241.         else
  1242.             alterMeshPath = new MeshPath(walking, calc, players, SAFE_MESH);
  1243.         bankMeshPath = alterMeshPath.reverse();
  1244.         if (!bankMeshPath.hasPath())
  1245.             bankMeshPath.findPath(MeshPath.MeshPathType.WEIGHT_CENTER);
  1246.         while (bankMeshPath.isValid()
  1247.                 && calc.distanceTo(bankMeshPath.getEnd()) >= 2) {
  1248.             if (Options.pathType.equals(OptionsClass.Path.Safe)
  1249.                     && (bankMeshPath.getNearestByPath() == null || !bankMeshPath
  1250.                             .getNearestByPath().equals(bankMeshPath.getEnd())))
  1251.                 if (objects.getNearest(CRACK_OUT) != null
  1252.                         && objects.getNearest(CRACK_OUT).isOnScreen()
  1253.                         && objects.getNearest(CRACK_OUT).doAction(
  1254.                                 "Squeeze-through")) {
  1255.                     sleep(500);
  1256.                     for (byte b = 0; b < 20
  1257.                             && getMyPlayer().getAnimation() != -1; b++)
  1258.                         sleep(100);
  1259.                     continue;
  1260.                 }
  1261.  
  1262.             bankMeshPath.traverse();
  1263.  
  1264.         }
  1265.         log.info("Failsafe Complete");
  1266.     }
  1267.  
  1268.     /**
  1269.      * A class that will take a specified mesh, generate a path through it, then
  1270.      * round the path off with Bezier curves.
  1271.      *
  1272.      * @author Equinox_
  1273.      *
  1274.      */
  1275.     static class MeshPath {
  1276.         public static final Color BLOCK_PATH_COLOR = new Color(0f, 1f, 0f, 1f);
  1277.         public static final Color MESH_BORDER = new Color(0.75f, 0.75f, 0.75f,
  1278.                 0.75f);
  1279.         public static final Color MESH_FILL = new Color(0.5f, 0.5f, 0.5f, 0.75f);
  1280.         public static final Color SMOOTH_PATH_COLOR = new Color(0f, 0f, 1f, 1f);
  1281.         private List<RSTile> blockPath = new ArrayList<RSTile>();
  1282.         private final Calculations calc;
  1283.         private boolean end;
  1284.         private List<RSTile[]> mesh = new ArrayList<RSTile[]>();
  1285.         private final Players players;
  1286.         private List<RSTile> smoothPath = new ArrayList<RSTile>();
  1287.         private final Walking walking;
  1288.         private final Range walkingDistance;
  1289.  
  1290.         /**
  1291.          * Creates a mesh path with the provided walking methods, calculation
  1292.          * methods, player methods, and walking range.
  1293.          *
  1294.          * @param walking
  1295.          * @param calc
  1296.          * @param players
  1297.          */
  1298.         public MeshPath(Walking walking, Calculations calc, Players players) {
  1299.             this(walking, calc, players, new Range(7, 9));
  1300.         }
  1301.  
  1302.         /**
  1303.          * Creates a mesh path with the provided walking methods, calculation
  1304.          * methods, player methods, and walking range.
  1305.          *
  1306.          * @param walking
  1307.          * @param calc
  1308.          * @param players
  1309.          * @param walkingDistance
  1310.          */
  1311.         public MeshPath(Walking walking, Calculations calc, Players players,
  1312.                 Range walkingDistance) {
  1313.             this.walking = walking;
  1314.             this.calc = calc;
  1315.             this.players = players;
  1316.             this.walkingDistance = walkingDistance;
  1317.         }
  1318.  
  1319.         /**
  1320.          * Creates a mesh path with the provided walking methods, calculation
  1321.          * methods, player methods, and mesh.
  1322.          *
  1323.          * @param walking
  1324.          * @param calc
  1325.          * @param players
  1326.          * @param mesh
  1327.          */
  1328.         public MeshPath(Walking walking, Calculations calc, Players players,
  1329.                 RSTile[][] mesh) {
  1330.             this(walking, calc, players);
  1331.             setMesh(mesh);
  1332.         }
  1333.  
  1334.         /**
  1335.          * Creates a mesh path with the provided walking methods, calculation
  1336.          * methods, player methods, walking range, and mesh.
  1337.          *
  1338.          * @param walking
  1339.          * @param calc
  1340.          * @param players
  1341.          * @param walkingDistance
  1342.          * @param mesh
  1343.          */
  1344.         public MeshPath(Walking walking, Calculations calc, Players players,
  1345.                 RSTile[][] mesh, Range walkingDistance) {
  1346.             this(walking, calc, players, walkingDistance);
  1347.             setMesh(mesh);
  1348.         }
  1349.  
  1350.         /**
  1351.          * Adds a line to the mesh with the given tiles
  1352.          *
  1353.          * @param tiles
  1354.          *            the RSTiles making up the line
  1355.          */
  1356.         public void addLine(RSTile... tiles) {
  1357.             if (mesh.size() == 0) {
  1358.                 mesh.add(tiles);
  1359.                 return;
  1360.             }
  1361.             RSTile first = tiles[0];
  1362.             RSTile last = tiles[tiles.length - 1];
  1363.             RSTile[] oLine = mesh.get(mesh.size() - 1);
  1364.             RSTile oFirst = oLine[0];
  1365.             RSTile oLast = oLine[oLine.length - 1];
  1366.             double straight = calc.distanceBetween(first, oFirst)
  1367.                     + calc.distanceBetween(last, oLast);
  1368.             double crossed = calc.distanceBetween(first, oLast)
  1369.                     + calc.distanceBetween(last, oFirst);
  1370.             if (straight > crossed) {
  1371.                 mesh.add(tiles);
  1372.                 return;
  1373.             } else {
  1374.                 RSTile[] reversed = new RSTile[tiles.length];
  1375.                 for (int i = 0; i < tiles.length; i++)
  1376.                     reversed[i] = tiles[tiles.length - 1 - i];
  1377.                 mesh.add(reversed);
  1378.                 return;
  1379.             }
  1380.         }
  1381.  
  1382.         /**
  1383.          * Adds all the lines of a specified mesh to the current mesh.
  1384.          *
  1385.          * @param mesh
  1386.          *            as RSTile[][]
  1387.          */
  1388.         public void addMesh(RSTile[][] mesh) {
  1389.             for (RSTile[] line : mesh)
  1390.                 addLine(line);
  1391.         }
  1392.  
  1393.         /**
  1394.          * Clears the current path and all refined versions of it.
  1395.          */
  1396.         public void clearPath() {
  1397.             blockPath.clear();
  1398.             smoothPath.clear();
  1399.         }
  1400.  
  1401.         /**
  1402.          * Finds a path between the beginning and end of the mesh using the
  1403.          * WEIGHT_CENTER placement type, then sets the current path to the found
  1404.          * path
  1405.          */
  1406.         public void findPath() {
  1407.             findPath(MeshPathType.WEIGHT_CENTER);
  1408.         }
  1409.  
  1410.         /**
  1411.          * Finds a path between the beginning and end of the mesh using the
  1412.          * provided placement type, then sets the current path to the found path
  1413.          *
  1414.          * @param placement
  1415.          *            as MeshPathType
  1416.          */
  1417.         public void findPath(MeshPathType placement) {
  1418.             findPath(placement, 0, mesh.size() - 1);
  1419.         }
  1420.  
  1421.         /**
  1422.          * Finds a path between the start index and the end index using the
  1423.          * provided placement type, then sets the current path to the found path
  1424.          *
  1425.          * @param placement
  1426.          *            as MeshPathType
  1427.          * @param start
  1428.          *            index
  1429.          * @param end
  1430.          *            index
  1431.          */
  1432.         public void findPath(MeshPathType placement, int start, int end) {
  1433.             blockPath.clear();
  1434.             for (int i = start; i <= end; i++)
  1435.                 blockPath.add(getTileOnLine(placement, mesh.get(i)));
  1436.             smoothPath = smoothPath(blockPath);
  1437.         }
  1438.  
  1439.         /**
  1440.          * Gets the end tile of this path.
  1441.          *
  1442.          * @return The end <code>RSTile</code>.
  1443.          */
  1444.         public RSTile getEnd() {
  1445.             if (smoothPath.size() > 0)
  1446.                 return smoothPath.get(smoothPath.size() - 1);
  1447.             else
  1448.                 return null;
  1449.         }
  1450.  
  1451.         /**
  1452.          * Gets the next immediately available vertex in this path.
  1453.          *
  1454.          * @return The next walkable <code>RSTile</code>.
  1455.          */
  1456.         public RSTile getNext() {
  1457.             if (smoothPath.size() > 0)
  1458.                 for (int i = smoothPath.size() - 1; i >= 0; i--)
  1459.                     if (calc.tileOnMap(smoothPath.get(i)))
  1460.                         return smoothPath.get(i);
  1461.  
  1462.             return null;
  1463.         }
  1464.  
  1465.         /**
  1466.          * Gets the start tile of this path.
  1467.          *
  1468.          * @return The start <code>RSTile</code>.
  1469.          */
  1470.         public RSTile getStart() {
  1471.             if (smoothPath.size() > 0)
  1472.                 return smoothPath.get(0);
  1473.             else
  1474.                 return null;
  1475.         }
  1476.  
  1477.         /**
  1478.          * Gets the nearest tile in the mesh to the provided RSTile
  1479.          *
  1480.          * @param tile
  1481.          *            the RSTile to use
  1482.          * @return RSTile tile in mesh
  1483.          */
  1484.         public RSTile getTileInMesh(RSTile tile) {
  1485.             if (inMesh(tile))
  1486.                 return tile;
  1487.             double bestDist = Double.MAX_VALUE;
  1488.             RSTile nearest = null;
  1489.             if (mesh.size() > 1) {
  1490.                 for (int i = 1; i < mesh.size(); i++) {
  1491.                     RSTile[] lineA = mesh.get(i - 1);
  1492.                     RSTile[] lineB = mesh.get(i);
  1493.                     if (lineA != null)
  1494.                         for (RSTile t : lineA) {
  1495.                             double dist = calc.distanceBetween(t, tile);
  1496.                             if (dist < bestDist) {
  1497.                                 nearest = new RSTile(t.getX(), t.getY());
  1498.                                 bestDist = Double.valueOf(dist);
  1499.                             }
  1500.                         }
  1501.                     if (lineB != null)
  1502.                         for (RSTile t : lineB) {
  1503.                             double dist = calc.distanceBetween(t, tile);
  1504.                             if (dist < bestDist) {
  1505.                                 nearest = new RSTile(t.getX(), t.getY());
  1506.                                 bestDist = Double.valueOf(dist);
  1507.                             }
  1508.                         }
  1509.                 }
  1510.             }
  1511.             return nearest;
  1512.         }
  1513.  
  1514.         /**
  1515.          * Gets a tile on the provided line using the provided method
  1516.          *
  1517.          * @param placement
  1518.          *            as MeshPathType
  1519.          * @param line
  1520.          *            as RSTile...
  1521.          * @return RSTile tile on line
  1522.          */
  1523.         public RSTile getTileOnLine(MeshPathType placement, RSTile... line) {
  1524.             List<RSTile> tiles = getTilesOnLines(line);
  1525.             int index = 0;
  1526.             switch (placement) {
  1527.             case ALL_CENTER:
  1528.                 index = new Range((int) (tiles.size() * .25d),
  1529.                         (int) (tiles.size() * 0.75d))
  1530.                         .randomLinearDistribution();
  1531.                 break;
  1532.             case FULL:
  1533.                 index = new Range(0, tiles.size()).randomLinearDistribution();
  1534.                 break;
  1535.             case WEIGHT_CENTER:
  1536.                 index = new Range(0, tiles.size()).randomNormalDistribution();
  1537.                 break;
  1538.             }
  1539.  
  1540.             if (index < 0)
  1541.                 index = 0;
  1542.             if (index >= tiles.size())
  1543.                 index = tiles.size() - 1;
  1544.  
  1545.             if (tiles.size() > 0)
  1546.                 return tiles.get(index);
  1547.             else
  1548.                 return null;
  1549.         }
  1550.  
  1551.         /**
  1552.          * Gets a tile on the provided line using the ALL_CENTER method
  1553.          *
  1554.          * @param line
  1555.          *            as RSTile...
  1556.          * @return RSTile tile on line
  1557.          */
  1558.         public RSTile getTileOnLine(RSTile... line) {
  1559.             return getTileOnLine(MeshPathType.WEIGHT_CENTER, line);
  1560.         }
  1561.  
  1562.         /**
  1563.          * Returns an array containing all of the vertices in this path.
  1564.          *
  1565.          * @return an array containing all of the vertices in this path.
  1566.          */
  1567.         public RSTile[] getTilePath() {
  1568.             RSTile[] tiles = new RSTile[smoothPath.size()];
  1569.             for (int i = 0; i < tiles.length; i++)
  1570.                 tiles[i] = new RSTile(smoothPath.get(i).getX(), smoothPath.get(
  1571.                         i).getY());
  1572.             return tiles;
  1573.         }
  1574.  
  1575.         public List<RSTile> getTilesOnLine(RSTile a, RSTile b) {
  1576.             List<RSTile> sublineTiles = new ArrayList<RSTile>();
  1577.             int deltaX = b.getX() - a.getX();
  1578.             int deltaY = b.getY() - a.getY();
  1579.             double dist = calc.distanceBetween(a, b);
  1580.             if (dist == 0)
  1581.                 dist = 1;
  1582.             double eX = deltaX / dist, eY = deltaY / dist;
  1583.             for (int i = 0; i <= dist; i++)
  1584.                 sublineTiles.add(new RSTile(a.getX() + (int) (eX * i), a.getY()
  1585.                         + (int) (eY * i)));
  1586.             return sublineTiles;
  1587.         }
  1588.  
  1589.         /**
  1590.          * Gets all the tiles on the provided line
  1591.          *
  1592.          * @param line
  1593.          *            as RSTile...
  1594.          * @return List<RSTile> tiles on line
  1595.          */
  1596.         public List<RSTile> getTilesOnLines(RSTile... line) {
  1597.             List<RSTile> sublineTiles = new ArrayList<RSTile>();
  1598.             if (line.length == 1)
  1599.                 sublineTiles.add(line[0]);
  1600.             else
  1601.                 for (int i = 1; i < line.length; i++) {
  1602.                     RSTile a = line[i - 1];
  1603.                     RSTile b = line[i];
  1604.                     sublineTiles.addAll(getTilesOnLine(a, b));
  1605.                 }
  1606.             return sublineTiles;
  1607.         }
  1608.  
  1609.         /**
  1610.          * Checks if we have a path
  1611.          *
  1612.          * @return boolean has path
  1613.          */
  1614.         public boolean hasPath() {
  1615.             return smoothPath.size() > 0;
  1616.         }
  1617.  
  1618.         /**
  1619.          * Checks to see if the provided RSTile is inside the mesh
  1620.          *
  1621.          * @param tile
  1622.          *            the RSTile to check
  1623.          * @return boolean is in mesh
  1624.          */
  1625.         public boolean inMesh(RSTile tile) {
  1626.             if (mesh.size() > 1) {
  1627.                 for (int i = 1; i < mesh.size(); i++) {
  1628.                     RSTile[] lineA = mesh.get(i - 1);
  1629.                     RSTile[] lineB = mesh.get(i);
  1630.                     Polygon poly = new Polygon();
  1631.                     if (lineA != null)
  1632.                         for (RSTile t : lineA)
  1633.                             poly.addPoint(t.getX(), t.getY());
  1634.                     if (lineB != null)
  1635.                         for (RSTile t : lineB)
  1636.                             poly.addPoint(t.getX(), t.getY());
  1637.  
  1638.                     if (poly.npoints >= 2)
  1639.                         if (poly.contains(new Point(tile.getX(), tile.getY())))
  1640.                             return true;
  1641.                 }
  1642.             }
  1643.             return false;
  1644.         }
  1645.  
  1646.         /**
  1647.          * Checks whether or not this path can be traversed by the player. This
  1648.          * will be the case provided that the player near to one of its
  1649.          * vertices, but not already standing on the end vertex.
  1650.          *
  1651.          * @return <tt>true</tt> if the player can walk along this path;
  1652.          *         otherwise <tt>false</tt>.
  1653.          */
  1654.         public boolean isValid() {
  1655.             return smoothPath.size() > 0 && getNext() != null
  1656.                     && !players.getMyPlayer().getLocation().equals(getEnd());
  1657.         }
  1658.  
  1659.         /**
  1660.          * Gets the number of lines in the mesh
  1661.          *
  1662.          * @return int size
  1663.          */
  1664.         public int meshSize() {
  1665.             return mesh.size();
  1666.         }
  1667.  
  1668.         /**
  1669.          * Paints the mesh, and all versions of the current path to the minimap
  1670.          * using the provided graphics object
  1671.          *
  1672.          * @param g
  1673.          *            as Graphics2D
  1674.          */
  1675.         public void paintAll(Graphics2D g) {
  1676.             paintMesh(g);
  1677.             paintBlockPath(g);
  1678.             paintSmoothPath(g);
  1679.         }
  1680.  
  1681.         /**
  1682.          * Paints the current un-smoothed path to the minimap using the provided
  1683.          * graphics object
  1684.          *
  1685.          * @param g
  1686.          *            as Graphics2D
  1687.          */
  1688.         public void paintBlockPath(Graphics2D g) {
  1689.             if (blockPath.size() > 1) {
  1690.                 g.setColor(BLOCK_PATH_COLOR);
  1691.                 Point a = null;
  1692.                 for (RSTile t : blockPath) {
  1693.                     Point b = calc.tileToMinimap(t);
  1694.                     if (b.x > 0 && b.y > 0)
  1695.                         g.fillOval(b.x - 2, b.y - 2, 5, 5);
  1696.                     if (a != null && a.x > 0 && a.y > 0 && b.x > 0 && b.y > 0)
  1697.                         g.drawLine(a.x, a.y, b.x, b.y);
  1698.                     a = b;
  1699.                 }
  1700.             }
  1701.         }
  1702.  
  1703.         /**
  1704.          * Paints the mesh to the provided graphics context in the minimap
  1705.          *
  1706.          * @param g
  1707.          *            as Graphics2D
  1708.          */
  1709.         public void paintMesh(Graphics2D g) {
  1710.             if (mesh.size() > 1) {
  1711.                 Point[] oldLine = null;
  1712.                 for (int i = 0; i < mesh.size(); i++) {
  1713.                     RSTile[] lineB = mesh.get(i);
  1714.                     Point[] thisLine = new Point[lineB.length];
  1715.                     Polygon poly = new Polygon();
  1716.                     boolean onMap = true;
  1717.                     for (int tile = 0; tile < thisLine.length; tile++) {
  1718.                         Point p = calc.tileToMinimap(lineB[tile]);
  1719.                         thisLine[tile] = p;
  1720.                         poly.addPoint(p.x, p.y);
  1721.                         if (p.x == -1 || p.y == -1)
  1722.                             onMap = false;
  1723.                     }
  1724.                     if (oldLine != null) {
  1725.                         for (Point p : oldLine) {
  1726.                             poly.addPoint(p.x, p.y);
  1727.                             if (p.x == -1 || p.y == -1)
  1728.                                 onMap = false;
  1729.                         }
  1730.                         if (poly.npoints >= 2 && onMap) {
  1731.                             g.setColor(MESH_BORDER);
  1732.                             g.draw(poly);
  1733.                             g.setColor(MESH_FILL);
  1734.                             g.fill(poly);
  1735.                         }
  1736.                     }
  1737.                     oldLine = thisLine;
  1738.                 }
  1739.             }
  1740.         }
  1741.  
  1742.         /**
  1743.          * Paints the smoothed version of the current path to the minimap using
  1744.          * the provided graphics object
  1745.          *
  1746.          * @param g
  1747.          *            as Graphics2D
  1748.          */
  1749.         public void paintSmoothPath(Graphics2D g) {
  1750.             if (smoothPath.size() > 1) {
  1751.                 g.setColor(SMOOTH_PATH_COLOR);
  1752.                 Point a = null;
  1753.                 for (RSTile t : smoothPath) {
  1754.                     Point b = calc.tileToMinimap(t);
  1755.                     if (b.x > 0 && b.y > 0)
  1756.                         g.fillOval(b.x - 2, b.y - 2, 5, 5);
  1757.                     if (a != null && a.x > 0 && a.y > 0 && b.x > 0 && b.y > 0)
  1758.                         g.drawLine(a.x, a.y, b.x, b.y);
  1759.                     a = b;
  1760.                 }
  1761.             }
  1762.         }
  1763.  
  1764.         /**
  1765.          * Reverses this path.
  1766.          *
  1767.          * @return This path.
  1768.          */
  1769.         public MeshPath reverse() {
  1770.             MeshPath m = new MeshPath(walking, calc, players);
  1771.             for (int i = mesh.size() - 1; i >= 0; i--) {
  1772.                 m.addLine(blockPath.get(i));
  1773.             }
  1774.             return m;
  1775.         }
  1776.  
  1777.         /**
  1778.          * Sets the current mesh to the provided mesh
  1779.          *
  1780.          * @param mesh
  1781.          *            as RSTile[][]
  1782.          */
  1783.         public void setMesh(RSTile[][] mesh) {
  1784.             this.mesh.clear();
  1785.             addMesh(mesh);
  1786.         }
  1787.  
  1788.         /**
  1789.          * Smoothes the provided List of RSTiles using Bezier curves. Will
  1790.          * return a path with 4 times as many vertices
  1791.          *
  1792.          * @param path
  1793.          *            as List
  1794.          * @return List<RSTile> smoothed path
  1795.          */
  1796.         public List<RSTile> smoothPath(List<RSTile> path) {
  1797.             List<RSTile> smoothed = new ArrayList<RSTile>();
  1798.             if (path.size() >= 3) {
  1799.                 for (int i = 0; i < path.size(); i++) {
  1800.                     if (i + 2 < path.size()) {
  1801.                         RSTile tile1 = path.get(i);
  1802.                         RSTile tile2 = path.get(i + 1);
  1803.                         RSTile tile3 = path.get(i + 2);
  1804.                         if (i == 0)
  1805.                             smoothed.add(tile1);
  1806.                         double x2, y2;
  1807.                         double t = 0.5d;
  1808.                         // use Berstein polynomials
  1809.                         x2 = (tile1.getX() + t
  1810.                                 * (-tile1.getX() * 3 + t
  1811.                                         * (3 * tile1.getX() - tile1.getX() * t)))
  1812.                                 + t
  1813.                                 * (3 * tile2.getX() + t
  1814.                                         * (-6 * tile2.getX() + tile2.getX() * 3
  1815.                                                 * t))
  1816.                                 + t
  1817.                                 * t
  1818.                                 * (tile2.getX() * 3 - tile2.getX() * 3 * t)
  1819.                                 + tile3.getX() * t * t * t;
  1820.                         y2 = (tile1.getY() + t
  1821.                                 * (-tile1.getY() * 3 + t
  1822.                                         * (3 * tile1.getY() - tile1.getY() * t)))
  1823.                                 + t
  1824.                                 * (3 * tile2.getY() + t
  1825.                                         * (-6 * tile2.getY() + tile2.getY() * 3
  1826.                                                 * t))
  1827.                                 + t
  1828.                                 * t
  1829.                                 * (tile2.getY() * 3 - tile2.getY() * 3 * t)
  1830.                                 + tile3.getY() * t * t * t;
  1831.                         smoothed.add(getTileInMesh(new RSTile((int) x2,
  1832.                                 (int) y2)));
  1833.                     } else {
  1834.                         // Just add the vert.
  1835.                         smoothed.add(path.get(i));
  1836.                     }
  1837.                 }
  1838.             }
  1839.             return smoothed;
  1840.         }
  1841.  
  1842.         /**
  1843.          * Returns a string representation of this Mesh Path.
  1844.          *
  1845.          * @return String
  1846.          */
  1847.         public String toString() {
  1848.             return "{ Line count: " + mesh.size() + ", Path size: "
  1849.                     + (hasPath() ? smoothPath.size() : "No path") + " }";
  1850.         }
  1851.  
  1852.         /**
  1853.          * Takes a step along this path if appropriate. Specifies only
  1854.          * TraversalOption.SPACE_ACTIONS.
  1855.          *
  1856.          * @return <tt>true</tt> if this path is currently valid for the player;
  1857.          *         otherwise <tt>false</tt>.
  1858.          * @see #traverse(EnumSet)
  1859.          */
  1860.         public boolean traverse() {
  1861.             return this.traverse(EnumSet.of(TraversalOption.HANDLE_RUN,
  1862.                     TraversalOption.SPACE_ACTIONS));
  1863.         }
  1864.  
  1865.         /**
  1866.          * Takes a step along this path if appropriate. If the path cannot be
  1867.          * traversed due to the player being too far from its vertices or
  1868.          * already at the end vertex, <tt>false</tt> will be returned. In all
  1869.          * other cases, <tt>true</tt> will be returned, but an action will not
  1870.          * necessarily be performed (based on the given options).
  1871.          *
  1872.          * @param options
  1873.          *            Walking style options.
  1874.          * @return <tt>true</tt> if this path is currently valid for the player;
  1875.          *         otherwise <tt>false</tt>.
  1876.          */
  1877.         public boolean traverse(EnumSet<TraversalOption> options) {
  1878.             RSTile next = getNext();
  1879.             if (next == null) {
  1880.                 return false;
  1881.             }
  1882.             if (next.equals(getEnd())) {
  1883.                 if (calc.distanceTo(next) <= 1
  1884.                         || (end && players.getMyPlayer().isMoving())
  1885.                         || next.equals(walking.getDestination())) {
  1886.                     return false;
  1887.                 }
  1888.                 end = true;
  1889.             } else {
  1890.                 end = false;
  1891.             }
  1892.             if (options.contains(TraversalOption.HANDLE_RUN)
  1893.                     && !walking.isRunEnabled() && walking.getEnergy() > 50) {
  1894.                 walking.setRun(true);
  1895.             }
  1896.             if (options.contains(TraversalOption.SPACE_ACTIONS)) {
  1897.                 RSTile dest = walking.getDestination();
  1898.                 if (dest != null
  1899.                         && players.getMyPlayer().isMoving()
  1900.                         && calc.distanceTo(dest) > 5
  1901.                         && calc.distanceBetween(next, dest) < walkingDistance
  1902.                                 .randomLinearDistribution()) {
  1903.                     return true;
  1904.                 }
  1905.             }
  1906.             return walking.walkTileMM(next, 0, 0);
  1907.         }
  1908.  
  1909.         /**
  1910.          * Gets the nearest tile on the path by distance alone
  1911.          *
  1912.          * @return RSTile
  1913.          */
  1914.         public RSTile getNearest() {
  1915.             int len = Integer.MAX_VALUE;
  1916.             RSTile best = null;
  1917.             if (hasPath())
  1918.                 for (RSTile t : smoothPath)
  1919.                     if (calc.distanceTo(t) < len) {
  1920.                         best = t;
  1921.                         len = calc.distanceTo(t);
  1922.                     }
  1923.             return best;
  1924.         }
  1925.  
  1926.         /**
  1927.          * Gets the nearest tile on the path by the length of a path to it.
  1928.          *
  1929.          * @return RSTile
  1930.          */
  1931.         public RSTile getNearestByPath() {
  1932.             int len = Integer.MAX_VALUE;
  1933.             RSTile best = null;
  1934.             if (hasPath())
  1935.                 for (RSTile t : smoothPath) {
  1936.                     int pLen = calc.pathLengthTo(t, false);
  1937.                     if (pLen < len && pLen >= 0) {
  1938.                         best = t;
  1939.                         len = pLen;
  1940.                     }
  1941.                 }
  1942.             return best;
  1943.         }
  1944.  
  1945.         /**
  1946.          * Gets the nearest index on the path to the given tile
  1947.          *
  1948.          * @param t
  1949.          *            RSTile
  1950.          * @return int
  1951.          */
  1952.         public int getNearestIndexTo(RSTile t) {
  1953.             int len = Integer.MAX_VALUE;
  1954.             int bestIndex = -1;
  1955.             if (hasPath())
  1956.                 for (int i = 0; i < smoothPath.size(); i++)
  1957.                     if (calc.distanceBetween(t, smoothPath.get(i)) < len) {
  1958.                         bestIndex = i;
  1959.                         len = calc.distanceTo(t);
  1960.                     }
  1961.             return bestIndex;
  1962.         }
  1963.  
  1964.         /**
  1965.          * Use this enum to define the type of path <br />
  1966.          * ALL_Center: All points are near the middle of the lines <br />
  1967.          * Full: Points can be anywhere on the line<br />
  1968.          * WEIGHT_CENTER: Weighted to center, possibility of being on sides, but
  1969.          * lower
  1970.          *
  1971.          * @author Equinox_
  1972.          *
  1973.          */
  1974.         public enum MeshPathType {
  1975.             ALL_CENTER, FULL, WEIGHT_CENTER
  1976.         }
  1977.     }
  1978.  
  1979.     /**
  1980.      * Used to format data into more conventional formats
  1981.      *
  1982.      * @author Equinox_
  1983.      *
  1984.      */
  1985.     static class PaintFormatter {
  1986.         /**
  1987.          * Converts an array of strings into one string, using commas and 'and' <br>
  1988.          * <br>
  1989.          * Examples: <br>
  1990.          * {"option1"} returns "option1"<br>
  1991.          * {"option1","option2"} returns "option1 and option2"<br>
  1992.          * {"op1","op2","op3"} returns "op1, op2, and op3"<br>
  1993.          * <br>
  1994.          *
  1995.          * @param list
  1996.          *            The array of strings making up the list.
  1997.          * @return The properly formatted string
  1998.          */
  1999.         public static String formatList(String[] list) {
  2000.             String s = "";
  2001.             if (list != null)
  2002.                 if (list.length == 2) {
  2003.                     s = list[0] + " and " + list[1];
  2004.                 } else if (list.length > 2) {
  2005.                     for (int i = 0; i < list.length - 1; i++)
  2006.                         s += list[i] + ", ";
  2007.                     s += "and " + list[list.length - 1];
  2008.                 } else if (list.length == 1)
  2009.                     s = list[0];
  2010.             return s;
  2011.         }
  2012.  
  2013.         /**
  2014.          * Formats a specified amount into thousands, millions or billions, then
  2015.          * adds the proper suffix
  2016.          *
  2017.          * @param money
  2018.          *            the amount of money
  2019.          * @return the formatted string
  2020.          */
  2021.         public static String getFormattedMoney(long money) {
  2022.             /*
  2023.              * String suffix = ""; int t = 1; if (money >= 10000) { t *= 1000;
  2024.              * suffix = "K"; } if (money / t > 10000) { t *= 1000; suffix = "M";
  2025.              * } if (money / t > 10000) { t *= 1000; suffix = "B"; } return
  2026.              * String.valueOf((money / t)) + suffix;
  2027.              */
  2028.             return new DecimalFormat("###,###,###,###,###,###").format(money);
  2029.         }
  2030.  
  2031.         /**
  2032.          * Converts the milliseconds to DD:HH:MM:SS with the days optional.
  2033.          *
  2034.          * @param timeMillis
  2035.          *            the number of milliseconds
  2036.          * @return the properly formatted time as a String
  2037.          */
  2038.         public static String getFormattedTime(final long timeMillis) {
  2039.             return getFormattedTime(timeMillis, ":", false);
  2040.         }
  2041.  
  2042.         /**
  2043.          * Formats time to DD:HH:MM:SS:MSMS with days and millis optional
  2044.          *
  2045.          * @param timeMillis
  2046.          *            long milliseconds of time
  2047.          * @param sep
  2048.          *            String seperation character
  2049.          * @param millisInc
  2050.          *            boolean include milliseconds
  2051.          * @return
  2052.          */
  2053.         public static String getFormattedTime(final long timeMillis,
  2054.                 String sep, boolean millisInc) {
  2055.             long millis = timeMillis;
  2056.             final long days = millis / (24 * 1000 * 60 * 60);
  2057.             millis -= days * (24 * 1000 * 60 * 60);
  2058.             final long hours = millis / (1000 * 60 * 60);
  2059.             millis -= hours * 1000 * 60 * 60;
  2060.             final long minutes = millis / (1000 * 60);
  2061.             millis -= minutes * 1000 * 60;
  2062.             final long _seconds = millis / 1000;
  2063.             millis -= _seconds * 1000;
  2064.             String dayString = String.valueOf(days);
  2065.             String hoursString = String.valueOf(hours);
  2066.             String minutesString = String.valueOf(minutes);
  2067.             String secondsString = String.valueOf(_seconds);
  2068.             if (hours < 10) {
  2069.                 hoursString = 0 + hoursString;
  2070.             }
  2071.             if (minutes < 10) {
  2072.                 minutesString = 0 + minutesString;
  2073.             }
  2074.             if (_seconds < 10) {
  2075.                 secondsString = 0 + secondsString;
  2076.             }
  2077.             String s = "";
  2078.             if (days > 0)
  2079.                 s = dayString + sep;
  2080.             s += hoursString + sep + minutesString + sep + secondsString;
  2081.             if (millisInc)
  2082.                 s += sep + String.valueOf(millis);
  2083.             return s;
  2084.         }
  2085.  
  2086.         /**
  2087.          * Converts the first letter of every word to uppercase, and the rest
  2088.          * lowercase.
  2089.          *
  2090.          * @param s
  2091.          *            The input String
  2092.          * @return the properly formatted string
  2093.          */
  2094.         public static String properCaseAll(String s) {
  2095.             String[] words = s.split(" ");
  2096.             String result = "";
  2097.             for (int i = 0; i < words.length; i++) {
  2098.                 String f = words[i].substring(0, 1).toUpperCase();
  2099.                 words[i] = f + words[i].substring(1).toLowerCase();
  2100.                 result += " " + words[i];
  2101.             }
  2102.             return result.substring(1);
  2103.         }
  2104.  
  2105.         /**
  2106.          * Capitalizes the first letter of every sentence, with every other
  2107.          * letter lowercase.
  2108.          *
  2109.          * @param s
  2110.          *            The input string
  2111.          * @return The properly formatted String
  2112.          */
  2113.         public static String properCaseFirst(String s) {
  2114.             String[] sentences = new String[] { s };
  2115.             if (s.contains("."))
  2116.                 sentences = s.split(".");
  2117.             String result = "";
  2118.             for (int i = 0; i < sentences.length; i++) {
  2119.                 String f = sentences[i].substring(0, 1).toUpperCase();
  2120.                 sentences[i] = f + sentences[i].substring(1).toLowerCase();
  2121.                 result += " " + sentences[i];
  2122.             }
  2123.             return result.substring(1);
  2124.         }
  2125.     }
  2126. }
Advertisement
Add Comment
Please, Sign In to add comment