import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; /** * Trades supplies and banks loot. *

* Instructions: * Start script at Edgeville Bank with an empty inventory. *

* Banked (multiple): * runechain, runelegs, antidshield, charged dstone amulet, * sharks, regular/super set pots, cure/anti poison pots *

* Required Parameter: * name of player running AA_KBDMaster script *

* Notes: * Modify the Equipment enum directly to change item ids. *

* * @Author Chomp */ public class AA_KBDMule extends AA_Script { private static final Coordinate[] PATH_TO_KBD = new Coordinate[]{ new Coordinate(239, 432), new Coordinate(240, 396), new Coordinate(266, 363), new Coordinate(279, 336), new Coordinate(299, 288), new Coordinate(296, 241), new Coordinate(285, 193), new Coordinate(285, 185) }; private static final Coordinate[] PATH_TO_EDGEVILLE = new Coordinate[]{ new Coordinate(285, 234), new Coordinate(284, 283), new Coordinate(277, 332), new Coordinate(272, 381), new Coordinate(240, 422), new Coordinate(217, 447) }; private static final Coordinate COORDINATE_DEATH_WALK_LUMBRIDGE = new Coordinate(120, 648), COORDINATE_DEATH_WALK_EDGEVILLE = new Coordinate(220, 446), COORDINATE_TRADE_SPOT = new Coordinate(565, 3331); /** * Excluded drops: * 10 (coins) * 91 (Mithril battle Axe) * 157, 158, 159, 160 (gems) * 204 (Adamantite Axe) **/ private static final int[] ITEM_IDS_LOOT = new int[]{ 11, 31, 33, 38, 40, 42, 75, 81, 93, 120, 174, 316, 403, 404, 405, 408, 517, 518, 520, 523, 526, 527, 546, 619, 638, 711, 793, 795, 814, 1092, 1277 }; private static final int[] ITEM_IDS_LOOT_NOTABLE = new int[]{ 38, 75, 81, 93, 403, 404, 405, 408, 523, 526, 527, 619, 711, 795, 814, 1092, 1277 }; private static final int NPC_ID_POISON_SPIDER = 292, NPC_ID_LESSER_DEMON = 22, ITEM_ID_CHARGED_DRAGONSTONE_AMULET = 597, ITEM_ID_DRAGONSTONE_AMULET = 522, ITEM_ID_EMPTY_VIAL = 465, MINIMUM_SHARKS = 10, PAINT_OFFSET_X_ALT = 185; private final Map notableLoot = new TreeMap<>(); private String master; private State state; private SupplyRequest supplyRequest; private PathWalker pathWalker; private long startTime; private long actionTimeout, withdrawFoodTimeout, optionMenuTimeout, tradeOfferTimeout; private int playerX, playerY, eatAt, deaths; private String sharksRemaining = "n/a", amuletsRemaining = "n/a", antidotesRemaining = "n/a", superSetsRemaining = "n/a"; private boolean poisoned, died, idle, abort; public AA_KBDMule(final Extension extension) { super(extension); combatStyle = CombatStyle.DEFENSE; } @Override public void init(final String parameters) { if (parameters.isEmpty()) printInstructions(); master = parameters.replace('_', ' '); final State initialState; if (Area.BANK.contains(getX(), getY())) { initialState = State.BANK; } else if (Area.DRAGON.contains(getX(), getY())) { initialState = State.TRADE; } else { initialState = State.WALK_TO_DRAGON; } setCombatStyle(combatStyle.getIndex()); eatAt = getBaseHits() / 2; startTime = System.currentTimeMillis(); setState(initialState); } @Override public int main() { if (died) { if (isDead() || (pathWalker != null && pathWalker.walkPath())) { return 0; } pathWalker = null; died = false; } playerX = getX(); playerY = getY(); if (bot.getCombatStyle() != combatStyle.getIndex()) setCombatStyle(combatStyle.getIndex()); switch (state) { case BANK: return bank(); case WALK_TO_DRAGON: return walkToDragon(); case TRADE: return trade(); case TELEPORT_TO_BANK: return teleportToBank(); case WALK_TO_BANK: return walkToBank(); default: return exit("Invalid script state."); } } @Override public void onServerMessage(final String message) { if (message.endsWith("shark")) { actionTimeout = System.currentTimeMillis() + TIMEOUT_ONE_TICK; } else if (message.endsWith("poison potion") || message.endsWith("antidote potion")) { poisoned = false; } else if (message.endsWith("left") || message.startsWith("finished", 9) || message.endsWith("Vial")) { actionTimeout = System.currentTimeMillis() + TIMEOUT_ONE_TICK; } else if (message.startsWith("poisioned", 23)) { poisoned = true; } else if (message.startsWith("declined", 17) || message.endsWith("successfully")) { supplyRequest = null; } else if (message.endsWith("area")) { idle = true; } else { super.onServerMessage(message); } } @Override public void onDeath() { if (pathWalker == null) { pathWalker = new PathWalker(bot); pathWalker.init(null); } final PathWalker.Path path = pathWalker.calcPath(COORDINATE_DEATH_WALK_LUMBRIDGE.getX(), COORDINATE_DEATH_WALK_LUMBRIDGE.getY(), COORDINATE_DEATH_WALK_EDGEVILLE.getX(), COORDINATE_DEATH_WALK_EDGEVILLE.getY()); if (path == null) { abort("Failed to calculate path from Lumbridge to Edgeville."); } pathWalker.setPath(path); setState(State.BANK); died = true; deaths++; idle = false; poisoned = false; } private void abort(final String reason) { sendPrivateMessage("abort", master); exit(reason); } private void setState(final State state) { this.state = state; if (this.state == State.BANK) { if (abort) { exit("Trip aborted."); return; } updateNotableLoot(); } } private void updateNotableLoot() { for (int index = 0; index < getInventoryCount(); index++) { final int itemId = getInventoryId(index); if (!inArray(ITEM_IDS_LOOT_NOTABLE, itemId)) { continue; } notableLoot.merge(itemId, getInventoryStack(index), Integer::sum); } } @Override public void paint() { int y = PAINT_OFFSET_Y; drawString("@yel@King Black Dragon", PAINT_OFFSET_X, y, 1, 0); drawString(String.format("@yel@State: @cya@%s", state), PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); drawString(String.format("@yel@Runtime: @whi@%s", toDuration(startTime)), PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); if (!notableLoot.isEmpty()) { drawString("", PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); for (final Entry entry : notableLoot.entrySet()) { drawString(String.format("@gr1@%s: @whi@%d", getItemNameId(entry.getKey()), entry.getValue()), PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); } } y = 0; drawString("@yel@Supplies Remaining", PAINT_OFFSET_X_ALT, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); drawString(String.format("@or1@Sharks: @whi@%s", sharksRemaining), PAINT_OFFSET_X_ALT, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); drawString(String.format("@ora@Amulets: @whi@%s", amuletsRemaining), PAINT_OFFSET_X_ALT, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); drawString(String.format("@or2@Antidotes: @whi@%s", antidotesRemaining), PAINT_OFFSET_X_ALT, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); drawString(String.format("@or3@Super sets: @whi@%s", superSetsRemaining), PAINT_OFFSET_X_ALT, y + PAINT_OFFSET_Y_INCREMENT, 1, 0); } @Override public void onTradeRequest(final String playerName) { if (state != State.TRADE || !playerName.equalsIgnoreCase(master)) { return; } final int[] master = getPlayerByName(this.master); if (master[0] == -1) { return; } supplyRequest = null; sendTradeRequest(getPlayerPID(master[0])); } @Override public void onPrivateMessage(final String message, final String playerName, final boolean moderator, final boolean administrator) { if (!playerName.equalsIgnoreCase(master)) { return; } if (message.equalsIgnoreCase("abort")) { abort = true; return; } try { supplyRequest = SupplyRequest.from(message); } catch (final IllegalArgumentException e) { System.err.println(e.getMessage()); } } private int bank() { if (getCurrentHits() != getBaseHits()) { final int sharkIndex = getInventoryIndex(Food.SHARK.getId()); if (sharkIndex != -1) { return consume(sharkIndex); } } if (poisoned) { final int potionIndex = getInventoryIndex(Potion.ANTIDOTE.ids); if (potionIndex != -1) { return consume(potionIndex); } } if (!isBanking()) { return openBank(); } for (int index = 0; index < getInventoryCount(); index++) { final int itemId = getInventoryId(index); if (itemId == Food.SHARK.getId()) { continue; } if (inArray(ITEM_IDS_LOOT, itemId) || itemId == ITEM_ID_DRAGONSTONE_AMULET || itemId == ITEM_ID_EMPTY_VIAL) { deposit(itemId, getInventoryCount(itemId)); return SLEEP_ONE_TICK; } } for (final Equipment equipment : Equipment.VALUES) { if (hasInventoryItem(equipment.id)) { continue; } if (System.currentTimeMillis() <= equipment.timeout) { return 0; } if (!hasBankItem(equipment.id)) { abort(String.format("Out of item: %s.", getItemNameId(equipment.id))); } withdraw(equipment.id, 1); equipment.timeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS; return 0; } for (final Potion potion : Potion.VALUES) { final int potionCount = getInventoryCount(potion.ids); if (potionCount == 1) { continue; } if (System.currentTimeMillis() <= potion.timeout) { return 0; } if (potionCount == 0) { for (final int id : potion.ids) { if (!hasBankItem(id)) { continue; } withdraw(id, 1); potion.timeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS; return 0; } } else { for (final int id : potion.ids) { if (!hasInventoryItem(id)) { continue; } deposit(id, 1); potion.timeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS; return 0; } } } if (!isInventoryFull()) { if (System.currentTimeMillis() <= withdrawFoodTimeout) { return 0; } if (!hasBankItem(Food.SHARK.getId())) { abort(String.format("Out of item: %s.", Food.SHARK)); } withdraw(Food.SHARK.getId(), getInventoryEmptyCount()); withdrawFoodTimeout = System.currentTimeMillis() + TIMEOUT_THREE_SECONDS; return 0; } updateSuppliesRemaining(); setState(State.WALK_TO_DRAGON); return 0; } private int walkToDragon() { if (Area.DRAGON.contains(playerX, playerY)) { setState(State.TRADE); return 0; } if (!inCombat()) { if (poisoned) { final int potionIndex = getInventoryIndex(Potion.ANTIDOTE.ids); if (potionIndex != -1) { return consume(potionIndex); } } if (getCurrentHits() <= eatAt) { final int sharkIndex = getInventoryIndex(Food.SHARK.getId()); if (sharkIndex != -1) { return consume(sharkIndex); } } } if (Area.SPIDERS.contains(playerX, playerY)) { if (distanceTo(Object.LEVER_SPIDER.coordinate.getX(), Object.LEVER_SPIDER.coordinate.getY()) <= 1) { if (inCombat()) { walkTo(playerX, playerY); return SLEEP_ONE_TICK; } useObject1(Object.LEVER_SPIDER.coordinate.getX(), Object.LEVER_SPIDER.coordinate.getY()); return SLEEP_ONE_SECOND; } if (!inCombat()) { final int poisonSpider = getBlockingPoisonSpider(); if (poisonSpider != -1) { attackNpc(poisonSpider); return SLEEP_ONE_TICK; } } walkTo(Object.LEVER_SPIDER.coordinate.getX(), Object.LEVER_SPIDER.coordinate.getY()); return SLEEP_ONE_TICK; } if (Area.LESSERS.contains(playerX, playerY)) { if (distanceTo(Object.LADDER_DOWN.coordinate.getX(), Object.LADDER_DOWN.coordinate.getY()) <= 1) { if (inCombat()) { walkTo(playerX, playerY); return SLEEP_ONE_TICK; } useObject1(Object.LADDER_DOWN.coordinate.getX(), Object.LADDER_DOWN.coordinate.getY()); return SLEEP_ONE_SECOND; } if (!inCombat()) { final int lesserDemon = getBlockingLesserDemon(); if (lesserDemon != -1) { attackNpc(lesserDemon); return SLEEP_ONE_TICK; } } walkTo(Object.LADDER_DOWN.coordinate.getX() + 1, Object.LADDER_DOWN.coordinate.getY()); return SLEEP_ONE_TICK; } if (distanceTo(Object.GATE.coordinate.getX(), Object.GATE.coordinate.getY()) <= 1) { if (inCombat()) { walkTo(playerX, playerY); return SLEEP_ONE_TICK; } useObject1(Object.GATE.coordinate.getX(), Object.GATE.coordinate.getY()); return SLEEP_ONE_SECOND; } if (Area.BANK.contains(playerX, playerY)) { if (wieldEquipment()) { return SLEEP_ONE_TICK; } if (getObjectIdFromCoords(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()) == Object.DOORS.id) { atObject(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()); return SLEEP_ONE_SECOND; } } for (final Coordinate coordinate : PATH_TO_KBD) { if (playerY > coordinate.getY()) { walkTo(coordinate.getX(), coordinate.getY()); break; } } return SLEEP_ONE_TICK; } private boolean wieldEquipment() { for (final Equipment equipment : Equipment.VALUES) { final int equipmentIndex = getInventoryIndex(equipment.id); if (equipmentIndex != -1 && !isItemEquipped(equipmentIndex)) { wearItem(equipmentIndex); return true; } } return false; } private int trade() { final int sharkCount = getInventoryCount(Food.SHARK.getId()); if (sharkCount == 0) { setState(State.TELEPORT_TO_BANK); return 0; } final boolean lowOnSupplies = sharkCount < MINIMUM_SHARKS || !hasInventoryItem(Potion.SUPER_ATTACK.ids) || !hasInventoryItem(Potion.SUPER_DEFENSE.ids) || !hasInventoryItem(Potion.SUPER_STRENGTH.ids); if (lowOnSupplies) { final int[] master = getPlayerByName(this.master); if (master[0] == -1 || !Area.TRADE.contains(master[1], master[2])) { setState(State.TELEPORT_TO_BANK); return 0; } } if (inCombat()) { walkTo(playerX, playerY); return 0; } if (poisoned) { final int potionIndex = getInventoryIndex(Potion.ANTIDOTE.ids); if (potionIndex != -1) { return consume(potionIndex); } } if (getCurrentHits() <= eatAt) { final int sharkIndex = getInventoryIndex(Food.SHARK.getId()); if (sharkIndex != -1) { return consume(sharkIndex); } } final int vialIndex = getInventoryIndex(ITEM_ID_EMPTY_VIAL); if (vialIndex != -1) { if (System.currentTimeMillis() <= actionTimeout) { return 0; } dropItem(vialIndex); actionTimeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS; return 0; } if (isInTradeConfirm()) { if (!bot.hasLocalConfirmedTrade()) { confirmTrade(); } return 0; } if (isInTradeOffer()) { return handleAcceptTrade(); } if (idle) { if (playerY == COORDINATE_TRADE_SPOT.getY()) { walkTo(COORDINATE_TRADE_SPOT.getX(), COORDINATE_TRADE_SPOT.getY() - 1); return SLEEP_ONE_TICK; } idle = false; } if (playerX != COORDINATE_TRADE_SPOT.getX() || playerY != COORDINATE_TRADE_SPOT.getY()) { walkTo(COORDINATE_TRADE_SPOT.getX(), COORDINATE_TRADE_SPOT.getY()); } if (abort) { setState(State.TELEPORT_TO_BANK); } return SLEEP_ONE_TICK; } private int handleAcceptTrade() { if (hasLocalAcceptedTrade() || supplyRequest == null) { return 0; } for (final Potion potion : Potion.values()) { if (!supplyRequest.isPotionRequested(potion) || !hasInventoryItem(potion.ids)) { continue; } if (hasTradeItem(potion.ids)) { continue; } if (System.currentTimeMillis() <= potion.timeout) { return 0; } offerItemTrade(getInventoryIndex(potion.ids), 1); potion.timeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS; return 0; } final int sharkTradeCount = getTradeItemIdCount(Food.SHARK.getId()); final int sharkInvCount = getInventoryCount(Food.SHARK.getId()); final int requiredCount = Math.min(sharkInvCount, supplyRequest.sharks); if (sharkTradeCount == requiredCount) { acceptTrade(); return 0; } if (System.currentTimeMillis() <= tradeOfferTimeout) { return 0; } if (sharkTradeCount > requiredCount) { removeTradeItemId(Food.SHARK.getId(), sharkTradeCount - requiredCount); } else { offerTradeItemId(Food.SHARK.getId(), requiredCount - sharkTradeCount); } tradeOfferTimeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS; return 0; } private int teleportToBank() { if (Area.BANK.contains(playerX, playerY)) { setState(State.BANK); return 0; } if (Area.DRAGON.contains(playerX, playerY)) { if (isQuestMenu()) { answer(0); optionMenuTimeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS; return 0; } if (inCombat()) { walkTo(playerX, playerY); return SLEEP_ONE_TICK; } if (getCurrentHits() <= eatAt) { final int sharkIndex = getInventoryIndex(Food.SHARK.getId()); if (sharkIndex != -1) { return consume(sharkIndex); } } if (System.currentTimeMillis() <= optionMenuTimeout) { return 0; } final int amuletIndex = getInventoryIndex(ITEM_ID_CHARGED_DRAGONSTONE_AMULET); if (amuletIndex == -1) { setState(State.WALK_TO_BANK); return 0; } useItem(amuletIndex); optionMenuTimeout = System.currentTimeMillis() + TIMEOUT_THREE_SECONDS; return 0; } if (distanceTo(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()) <= 1) { if (getObjectIdFromCoords(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()) == Object.DOORS.id) { useObject1(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()); return SLEEP_ONE_SECOND; } walkTo(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY() + 1); return SLEEP_ONE_TICK; } walkTo(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()); return SLEEP_ONE_TICK; } private int walkToBank() { if (Area.BANK.contains(playerX, playerY)) { setState(State.BANK); return 0; } if (distanceTo(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()) <= 1) { if (getObjectIdFromCoords(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()) == Object.DOORS.id) { useObject1(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY()); return SLEEP_ONE_SECOND; } walkTo(Object.DOORS.coordinate.getX(), Object.DOORS.coordinate.getY() + 1); return SLEEP_ONE_TICK; } if (!inCombat()) { if (poisoned) { final int potionIndex = getInventoryIndex(Potion.ANTIDOTE.ids); if (potionIndex != -1) { return consume(potionIndex); } } if (getCurrentHits() <= eatAt) { final int sharkIndex = getInventoryIndex(Food.SHARK.getId()); if (sharkIndex != -1) { return consume(sharkIndex); } } } if (Area.LESSERS.contains(playerX, playerY)) { if (distanceTo(Object.GATE.coordinate.getX(), Object.GATE.coordinate.getY()) <= 1) { if (inCombat()) { walkTo(playerX, playerY); return SLEEP_ONE_TICK; } useObject1(Object.GATE.coordinate.getX(), Object.GATE.coordinate.getY()); return SLEEP_ONE_SECOND; } if (!inCombat()) { final int lesserDemon = getBlockingLesserDemon(); if (lesserDemon != -1) { attackNpc(lesserDemon); return SLEEP_ONE_TICK; } } walkTo(Object.GATE.coordinate.getX() - 1, Object.GATE.coordinate.getY() + 1); return SLEEP_ONE_TICK; } if (Area.SPIDERS.contains(playerX, playerY)) { if (distanceTo(Object.LADDER_UP.coordinate.getX(), Object.LADDER_UP.coordinate.getY()) <= 1) { if (inCombat()) { walkTo(playerX, playerY); return SLEEP_ONE_TICK; } useObject1(Object.LADDER_UP.coordinate.getX(), Object.LADDER_UP.coordinate.getY()); return SLEEP_ONE_SECOND; } if (!inCombat()) { final int poisonSpider = getBlockingPoisonSpider(); if (poisonSpider != -1) { attackNpc(poisonSpider); return SLEEP_ONE_TICK; } } walkTo(Object.LADDER_UP.coordinate.getX(), Object.LADDER_UP.coordinate.getY() + 1); return SLEEP_ONE_TICK; } if (Area.DRAGON.contains(playerX, playerY)) { if (distanceTo(Object.LEVER_DRAGON.coordinate.getX(), Object.LEVER_DRAGON.coordinate.getY()) <= 1) { if (inCombat()) { walkTo(playerX, playerY); return SLEEP_ONE_TICK; } useObject1(Object.LEVER_DRAGON.coordinate.getX(), Object.LEVER_DRAGON.coordinate.getY()); return SLEEP_ONE_SECOND; } walkTo(Object.LEVER_DRAGON.coordinate.getX(), Object.LEVER_DRAGON.coordinate.getY()); return SLEEP_ONE_TICK; } for (final Coordinate coordinate : PATH_TO_EDGEVILLE) { if (playerY < coordinate.getY()) { walkTo(coordinate.getX(), coordinate.getY()); break; } } return SLEEP_ONE_TICK; } private int getBlockingPoisonSpider() { for (int index = 0; index < bot.getNpcCount(); index++) { final java.lang.Object npc = bot.getNpc(index); if (bot.getNpcId(npc) != NPC_ID_POISON_SPIDER || bot.isMobInCombat(npc)) { continue; } final int npcX = getNpcX(index); final int npcY = getNpcY(index); if (npcX != playerX) { continue; } if (npcY == playerY + (state == State.WALK_TO_DRAGON ? 1 : -1)) { return index; } } return -1; } private int getBlockingLesserDemon() { for (int index = 0; index < bot.getNpcCount(); index++) { final java.lang.Object npc = bot.getNpc(index); if (bot.getNpcId(npc) != NPC_ID_LESSER_DEMON || bot.isMobInCombat(npc)) { continue; } final int npcX = getNpcX(index); final int npcY = getNpcY(index); if (npcY != playerY) { continue; } if (npcX == playerX + (state == State.WALK_TO_DRAGON ? -1 : 1)) { return index; } } return -1; } private int consume(final int inventoryIndex) { if (System.currentTimeMillis() <= actionTimeout) { return 0; } useItem(inventoryIndex); actionTimeout = System.currentTimeMillis() + TIMEOUT_THREE_SECONDS; return 0; } private void updateSuppliesRemaining() { int antidoteCount = 0, supAtkCount = 0, supStrCount = 0, supDefCount = 0; int itemId; for (int index = 0; index < getBankSize(); index++) { itemId = getBankId(index); if (itemId == Food.SHARK.getId()) { sharksRemaining = DECIMAL_FORMAT.format(getBankStack(index)); } else if (itemId == Equipment.AMULET.id) { amuletsRemaining = DECIMAL_FORMAT.format(getBankStack(index)); } else if (inArray(Potion.ANTIDOTE.ids, itemId)) { antidoteCount += getBankStack(index); } else if (inArray(Potion.SUPER_ATTACK.ids, itemId)) { supAtkCount += getBankStack(index); } else if (inArray(Potion.SUPER_DEFENSE.ids, itemId)) { supDefCount += getBankStack(index); } else if (inArray(Potion.SUPER_STRENGTH.ids, itemId)) { supStrCount += getBankStack(index); } } antidotesRemaining = DECIMAL_FORMAT.format(antidoteCount); superSetsRemaining = DECIMAL_FORMAT.format(Math.min(supAtkCount, Math.min(supDefCount, supStrCount))); } private enum State { BANK("Bank"), WALK_TO_DRAGON("Walk to Dragon"), TRADE("Trade"), TELEPORT_TO_BANK("Teleport to Bank"), WALK_TO_BANK("Walk to Bank"); private final String description; State(final String description) { this.description = description; } @Override public String toString() { return description; } } private enum Area implements RSArea { BANK(new Coordinate(212, 448), new Coordinate(220, 453)), LESSERS(new Coordinate(278, 181), new Coordinate(284, 187)) { @Override public boolean contains(final int x, final int y) { return super.contains(x, y) || (x >= 280 && x <= 283 && y >= 188 && y <= 189); } }, SPIDERS(new Coordinate(279, 3014), new Coordinate(283, 3020)), TRADE(new Coordinate(565, 3329), new Coordinate(569, 3331)), DRAGON(new Coordinate(563, 3315), new Coordinate(571, 3331)); private final Coordinate lowerBoundingCoordinate; private final Coordinate upperBoundingCoordinate; Area(final Coordinate lowerBoundingCoordinate, final Coordinate upperBoundingCoordinate) { this.lowerBoundingCoordinate = lowerBoundingCoordinate; this.upperBoundingCoordinate = upperBoundingCoordinate; } public Coordinate getLowerBoundingCoordinate() { return lowerBoundingCoordinate; } public Coordinate getUpperBoundingCoordinate() { return upperBoundingCoordinate; } } private enum Object implements RSObject { DOORS(64, new Coordinate(217, 447)), GATE(508, new Coordinate(285, 185)), LADDER_DOWN(6, new Coordinate(282, 185)), LADDER_UP(5, new Coordinate(282, 3017)), LEVER_SPIDER(487, new Coordinate(282, 3020)), LEVER_DRAGON(488, new Coordinate(567, 3331)); private final int id; private final Coordinate coordinate; Object(final int id, final Coordinate coordinate) { this.id = id; this.coordinate = coordinate; } public int getId() { return id; } public Coordinate getCoordinate() { return coordinate; } } private enum Potion { ANTIDOTE(new int[]{568, 571, 567, 570, 566, 569}), SUPER_ATTACK(new int[]{486, 487, 488, 474, 475, 476}), SUPER_DEFENSE(new int[]{495, 496, 497, 480, 481, 482}), SUPER_STRENGTH(new int[]{492, 493, 494, 221, 222, 223, 224}); private static final Potion[] VALUES = Potion.values(); private final int[] ids; private long timeout; Potion(final int[] ids) { this.ids = ids; } } private enum Equipment { BODY(400), LEGS(402), SHIELD(420), AMULET(597); private static final Equipment[] VALUES = Equipment.values(); private final int id; private long timeout; Equipment(final int id) { this.id = id; } } private static final class SupplyRequest { private static final int NUMBER_OF_ARGUMENTS = 5; private final boolean antidote; private final boolean superAtk; private final boolean superDef; private final boolean superStr; private final int sharks; private SupplyRequest(final boolean antidote, final boolean superAtk, final boolean superDef, final boolean superStr, final int sharks) { this.antidote = antidote; this.superAtk = superAtk; this.superDef = superDef; this.superStr = superStr; this.sharks = sharks; } private static SupplyRequest from(final String request) throws IllegalArgumentException { final String[] data = request.split(","); if (data.length != NUMBER_OF_ARGUMENTS) { throw new IllegalArgumentException(String.format("Invalid supply request: %s", request)); } final SupplyRequest supplyRequest; try { supplyRequest = new SupplyRequest(SupplyRequest.parse(data[0]), SupplyRequest.parse(data[1]), SupplyRequest.parse(data[2]), SupplyRequest.parse(data[3]), Integer.parseInt(data[4])); } catch (final NumberFormatException e) { throw new IllegalArgumentException(String.format("Malformed supply request: %s", request), e); } return supplyRequest; } private static boolean parse(final String str) { return Integer.parseInt(str) == 1; } private boolean isPotionRequested(final Potion potion) { switch (potion) { case ANTIDOTE: return antidote; case SUPER_ATTACK: return superAtk; case SUPER_DEFENSE: return superDef; case SUPER_STRENGTH: return superStr; default: return false; } } } }