import java.util.*; /** * Kills Druids at the Druidic Circle and banks at Falador West Bank. *

* Required: * Start script at Druids or Falador West Bank and have sleeping bag in inventory. *

* Optional Parameters: * -a,--alt * -f,--fightmode (default strength) *

* Notes: * Specifying names of alts will enable spawn synchronization between accounts via PM. * Alt accounts need to have each other added as friends. * Replace any spaces in an rsn with an underscore _. * e.g. -f attack -a bot02 -a bot03 *

* * @Author Chomp */ public class AA_DruidsCircle extends AA_Script { private static final Coordinate COORDINATE_LOAD_SOUTH_MEMBERS_GATE = new Coordinate(346, 479); private static final Coordinate COORDINATE_LOAD_NORTH_MEMBERS_GATE = new Coordinate(326, 544); private static final Coordinate COORDINATE_LOAD_FALADOR = new Coordinate(324, 512); private static final int[] ITEM_IDS_LOOT = new int[]{10, 31, 32, 34, 41, 42, 220, 165, 435, 436, 437, 438, 439, 440, 441, 442, 443, 566}; private static final int[] ITEM_IDS_PREMIUM_LOOT = new int[]{41, 42, 220, 438, 439, 440, 441, 442, 443, 566}; private static final int NPC_ID_DRUID = 200; private static final int NPC_XP_DRUID = 78; private static final int MAXIMUM_FATIGUE = 99; private static final int MAXIMUM_DISTANCE_FROM_OBJECT = 18; private final int[] loot = new int[3]; private final Map spawnMap = new HashMap<>(); private final Map premiumLoot = new TreeMap<>(); private String[] alts; private Spawn nextSpawn; private Iterator> syncDataIterator; private String syncPlayerName; private long startTime; private double initialCombatXp; private long gateTimeout; private long syncRequestTimeout; private int playerX; private int playerY; private boolean syncWithAlt; public AA_DruidsCircle(final Extension extension) { super(extension); } @Override public void init(final String parameters) { if (!hasInventoryItem(ITEM_ID_SLEEPING_BAG)) { throw new IllegalStateException("Sleeping bag missing from inventory."); } if (!parameters.isEmpty()) { List alts = null; final String[] args = parameters.split(" "); for (int i = 0; i < args.length; i++) { switch (args[i].toLowerCase()) { case "-a": case "--alt": if (alts == null) { alts = new ArrayList<>(); } final String altName = args[++i].replace('_', ' '); if (!isFriend(altName)) { addFriend(altName); } alts.add(altName); break; case "-f": case "--fightmode": combatStyle = CombatStyle.valueOf(args[++i].toUpperCase()); break; default: throw new IllegalArgumentException("Error: malformed parameters. Try again ..."); } } if (alts != null) { this.alts = alts.toArray(new String[0]); } } setCombatStyle(combatStyle.getIndex()); initialCombatXp = getTotalCombatXp(); startTime = System.currentTimeMillis(); } @Override public int main() { playerX = getX(); playerY = getY(); if (bot.getCombatStyle() != combatStyle.getIndex()) setCombatStyle(combatStyle.getIndex()); return getInventoryCount() == MAX_INV_SIZE || isBanking() ? bank() : kill(); } @Override public void onServerMessage(final String message) { if (message.endsWith("gate") || message.endsWith("shut") || message.endsWith("open")) { gateTimeout = 0L; } else { super.onServerMessage(message); } } private int bank() { if (Area.BANK.contains(playerX, playerY)) { if (!isBanking()) { return openBank(); } for (int index = 0; index < getInventoryCount(); index++) { final int itemId = getInventoryId(index); if (!inArray(ITEM_IDS_LOOT, itemId)) { continue; } deposit(itemId, getInventoryCount(itemId)); return SLEEP_ONE_TICK; } updateBankLoot(); closeBank(); return SLEEP_ONE_SECOND; } if (playerX <= Object.MEMBERS_GATE.coordinate.getX()) { if (playerY >= COORDINATE_LOAD_FALADOR.getY()) { if (distanceTo(Object.BANK_DOORS.coordinate.getX(), Object.BANK_DOORS.coordinate.getY()) <= MAXIMUM_DISTANCE_FROM_OBJECT && getObjectIdFromCoords(Object.BANK_DOORS.coordinate.getX(), Object.BANK_DOORS.coordinate.getY()) == Object.BANK_DOORS.id) { atObject(Object.BANK_DOORS.coordinate.getX(), Object.BANK_DOORS.coordinate.getY()); return SLEEP_ONE_SECOND; } walkTo(Object.BANK_DOORS.coordinate.getX() + 1, Object.BANK_DOORS.coordinate.getY()); return SLEEP_ONE_TICK; } walkTo(COORDINATE_LOAD_FALADOR.getX(), COORDINATE_LOAD_FALADOR.getY()); return SLEEP_ONE_TICK; } if (playerY >= COORDINATE_LOAD_SOUTH_MEMBERS_GATE.getY()) { if (System.currentTimeMillis() <= gateTimeout) { return 0; } atObject(Object.MEMBERS_GATE.coordinate.getX(), Object.MEMBERS_GATE.coordinate.getY()); gateTimeout = System.currentTimeMillis() + TIMEOUT_FIVE_SECONDS; return 0; } walkTo(COORDINATE_LOAD_SOUTH_MEMBERS_GATE.getX(), COORDINATE_LOAD_SOUTH_MEMBERS_GATE.getY()); return SLEEP_ONE_TICK; } private int kill() { if (Area.DRUIDS.contains(playerX, playerY)) { return combatCycle(); } if (playerX > Object.MEMBERS_GATE.coordinate.getX()) { if (!spawnMap.isEmpty()) { resetSpawns(); if (alts != null) { resetSync(); } } walkTo(Area.DRUIDS.lowerBoundingCoordinate.getX(), Area.DRUIDS.lowerBoundingCoordinate.getY()); return SLEEP_ONE_TICK; } if (playerY <= COORDINATE_LOAD_NORTH_MEMBERS_GATE.getY()) { if (distanceTo(Object.MEMBERS_GATE.coordinate.getX(), Object.MEMBERS_GATE.coordinate.getY()) <= MAXIMUM_DISTANCE_FROM_OBJECT) { if (System.currentTimeMillis() <= gateTimeout) { return 0; } atObject(Object.MEMBERS_GATE.coordinate.getX(), Object.MEMBERS_GATE.coordinate.getY()); gateTimeout = System.currentTimeMillis() + TIMEOUT_FIVE_SECONDS; return 0; } walkTo(Object.MEMBERS_GATE.coordinate.getX(), Object.MEMBERS_GATE.coordinate.getY()); return SLEEP_ONE_TICK; } if (Area.BANK.contains(playerX, playerY) && getObjectIdFromCoords(Object.BANK_DOORS.coordinate.getX(), Object.BANK_DOORS.coordinate.getY()) == Object.BANK_DOORS.id) { atObject(Object.BANK_DOORS.coordinate.getX(), Object.BANK_DOORS.coordinate.getY()); return SLEEP_ONE_SECOND; } walkTo(COORDINATE_LOAD_NORTH_MEMBERS_GATE.getX(), COORDINATE_LOAD_NORTH_MEMBERS_GATE.getY()); return SLEEP_ONE_TICK; } private void updateBankLoot() { for (final int itemId : ITEM_IDS_PREMIUM_LOOT) { final int bankCount = bankCount(itemId); if (bankCount == 0) { continue; } premiumLoot.put(itemId, bankCount); } } private int combatCycle() { if (inCombat()) { if (syncWithAlt) { return syncWithAlt(); } return 0; } if (getFatigue() >= MAXIMUM_FATIGUE) { return sleep(); } final int[] druid = getNpcById(NPC_ID_DRUID); if (druid[0] != -1) { attackNpc(druid[0]); return SLEEP_ONE_TICK; } updateLoot(); if (loot[0] != -1) { pickupItem(loot[0], loot[1], loot[2]); return SLEEP_ONE_TICK; } if (nextSpawn == null) { return 0; } final Coordinate spawnCoordinate = nextSpawn.getCoordinate(); if (playerX != spawnCoordinate.getX() || playerY != spawnCoordinate.getY()) { if (alts != null && isSpawnCoordinateOccupied(spawnCoordinate)) { nextSpawn.setTimestamp(System.currentTimeMillis()); nextSpawn = getOldestSpawn(); return 0; } walkTo(spawnCoordinate.getX(), spawnCoordinate.getY()); return SLEEP_ONE_TICK; } if (syncWithAlt) { return syncWithAlt(); } return 0; } private void resetSpawns() { spawnMap.clear(); nextSpawn = null; } private void resetSync() { syncWithAlt = false; syncPlayerName = null; syncDataIterator = null; } private int syncWithAlt() { if (syncDataIterator.hasNext()) { final Map.Entry entry = syncDataIterator.next(); final int serverIndex = entry.getKey(); final Spawn spawn = entry.getValue(); final Coordinate coordinate = spawn.getCoordinate(); final long timestamp = spawn.getTimestamp(); sendPrivateMessage(String.format("%d,%d,%d,%d", serverIndex, coordinate.getX(), coordinate.getY(), timestamp), syncPlayerName); return SLEEP_ONE_TICK; } resetSync(); return 0; } private void updateLoot() { loot[0] = -1; int currentDistance = Integer.MAX_VALUE; for (int index = 0; index < getGroundItemCount(); index++) { final int groundItemId = getGroundItemId(index); if (!inArray(ITEM_IDS_LOOT, groundItemId)) { continue; } final int groundItemX = getItemX(index); final int groundItemY = getItemY(index); if (!Area.DRUIDS.contains(groundItemX, groundItemY)) { continue; } final int distance = distanceTo(groundItemX, groundItemY); if (distance < currentDistance) { loot[0] = groundItemId; loot[1] = groundItemX; loot[2] = groundItemY; currentDistance = distance; } } } private boolean isSpawnCoordinateOccupied(final Coordinate spawnCoordinate) { for (int index = 0; index < bot.getPlayerCount(); index++) { final String playerName = getPlayerName(index); if (isAnAlt(playerName) && getPlayerX(index) == spawnCoordinate.getX() && getPlayerY(index) == spawnCoordinate.getY()) { return true; } } return false; } private Spawn getOldestSpawn() { if (spawnMap.isEmpty()) { return null; } return spawnMap.values().stream().sorted().findFirst().get(); } private boolean isAnAlt(final String playerName) { for (final String alt : alts) { if (alt.equalsIgnoreCase(playerName)) { return true; } } return false; } @Override public void paint() { int y = PAINT_OFFSET_Y; drawString("@yel@Druids Circle", PAINT_OFFSET_X, y, 1, 0); drawString(String.format("@yel@Runtime: @whi@%s", toDuration(startTime)), PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); final double xpGained = getTotalCombatXp() - initialCombatXp; drawString(String.format("@yel@Xp: @whi@%s @cya@(@whi@%s xp@cya@/@whi@hr@cya@)", DECIMAL_FORMAT.format(xpGained), toUnitsPerHour((int) xpGained, startTime)), PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT * 2, 1, 0); final int kills = (int) xpGained / NPC_XP_DRUID; drawString(String.format("@yel@Kills: @whi@%d @cya@(@whi@%s per@cya@/@whi@hr@cya@)", kills, toUnitsPerHour(kills, startTime)), PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); if (premiumLoot.isEmpty()) return; drawString("", PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); for (final Map.Entry entry : premiumLoot.entrySet()) { drawString(String.format("@gre@%s: @whi@%d", getItemNameId(entry.getKey()), entry.getValue()), PAINT_OFFSET_X, y += PAINT_OFFSET_Y_INCREMENT, 1, 0); } } @Override public void onPrivateMessage(final String message, final String playerName, final boolean moderator, final boolean administrator) { if (alts == null || !isAnAlt(playerName)) { return; } if (message.equalsIgnoreCase("sync")) { if (syncWithAlt || spawnMap.isEmpty()) { return; } syncWithAlt = true; syncPlayerName = playerName; syncDataIterator = new HashMap<>(spawnMap).entrySet().iterator(); } else { final String[] syncData = message.split(","); final int serverIndex = Integer.parseInt(syncData[0]); if (spawnMap.containsKey(serverIndex)) { return; } final Coordinate coordinate = new Coordinate(Integer.parseInt(syncData[1]), Integer.parseInt(syncData[2])); final Spawn spawn = new Spawn(coordinate, Long.parseLong(syncData[3])); spawnMap.put(serverIndex, spawn); nextSpawn = getOldestSpawn(); } } @Override public void onNpcSpawned(final java.lang.Object npc) { final int npcId = bot.getNpcId(npc); if (npcId != NPC_ID_DRUID) { return; } if (spawnMap.isEmpty() && alts != null) { requestSyncWithAlt(); } final int npcX = bot.getMobLocalX(npc) + bot.getAreaX(); final int npcY = bot.getMobLocalY(npc) + bot.getAreaY(); if (!Area.DRUIDS.contains(npcX, npcY)) { return; } final int serverIndex = bot.getMobServerIndex(npc); final Spawn spawn = spawnMap.get(serverIndex); if (spawn != null) { spawn.getCoordinate().set(npcX, npcY); spawn.setTimestamp(System.currentTimeMillis()); } else { spawnMap.put(serverIndex, new Spawn(new Coordinate(npcX, npcY), System.currentTimeMillis())); } nextSpawn = getOldestSpawn(); } private void requestSyncWithAlt() { if (System.currentTimeMillis() <= syncRequestTimeout) { return; } for (final String alt : alts) { sendPrivateMessage("sync", alt); } syncRequestTimeout = System.currentTimeMillis() + (TIMEOUT_TEN_SECONDS * 6); } private enum Area implements RSArea { DRUIDS(new Coordinate(350, 451), new Coordinate(375, 472)), BANK(new Coordinate(328, 549), new Coordinate(334, 557)); 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 { MEMBERS_GATE(137, new Coordinate(341, 487)), BANK_DOORS(64, new Coordinate(327, 552)); 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; } } }