import java.util.Map;
import java.util.TreeMap;
/**
* Kills the King Black Dragon.
*
* Instructions:
* Start script at Edgeville Bank with an empty inventory.
*
* Banked (multiple):
* dmed, dsquare, dsword, runepl8, runelegs, antidshield, charged dstone amulet, cape of legends,
* sharks, regular/super set pots, cure/anti poison pots
*
* Optional Parameter:
* name of player running AA_KBDMule script
*
* Notes:
* Modify the Equipment enum directly to change item ids.
*
*
* @Author Chomp
*/
public class AA_KBDMaster extends AA_Script {
private static final Coordinate[] PATH_TO_KBD = new Coordinate[]{
new Coordinate(239, 432),
new Coordinate(285, 384),
new Coordinate(285, 336),
new Coordinate(284, 288),
new Coordinate(286, 240),
new Coordinate(285, 192),
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_KBD_RESPAWN = new Coordinate(567, 3321),
COORDINATE_TRADE_SPOT = new Coordinate(569, 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[] ITEM_IDS_STACKABLE = new int[]{11, 31, 33, 38, 40, 42, 517, 518, 520, 619, 638, 711};
private static final int[] COMBAT_STYLE_BREAKPOINTS = new int[]{102, 106, 111, 115};
private static final int
NPC_ID_KING_BLACK_DRAGON = 477,
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_ATK = 104,
MINIMUM_STR = 104,
MINIMUM_DEF = 104,
MINIMUM_HITS = 49,
MINIMUM_HITS_KBD = 60,
MINIMUM_SHARKS = 10,
PAINT_OFFSET_X_ALT = 185;
private final Map notableLoot = new TreeMap<>();
private final int[] loot = new int[3];
private String mule;
private State state;
private PathWalker pathWalker;
private long startTime;
private long
actionTimeout,
optionMenuTimeout,
depositTimeout,
withdrawTimeout,
tradeRequestTimeout,
privateMessageTimeout;
private int
playerX,
playerY,
previousY,
eatAt,
superStrsUsed,
superAtksUsed,
superDefsUsed,
sharksEaten,
deaths;
private boolean
abort,
poisoned,
flee,
died,
idle,
wieldShield;
public AA_KBDMaster(final Extension extension) {
super(extension);
combatStyle = CombatStyle.ATTACK;
}
@Override
public void init(final String parameters) {
if (!parameters.isEmpty()) {
mule = parameters.replace('_', ' ');
}
final State initialState;
if (Area.BANK.contains(getX(), getY())) {
initialState = State.BANK;
} else if (Area.DRAGON.contains(getX(), getY())) {
initialState = State.KILL;
} else if (hasInventoryItem(Food.SHARK.getId())) {
initialState = State.WALK_TO_DRAGON;
} else {
initialState = State.WALK_TO_BANK;
}
setCombatStyle(combatStyle.getIndex());
eatAt = getBaseHits() - Food.SHARK.getHealAmount();
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();
switch (state) {
case BANK:
return bank();
case WALK_TO_DRAGON:
return walkToDragon();
case KILL:
return kill();
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")) {
sharksEaten++;
actionTimeout = System.currentTimeMillis() + TIMEOUT_ONE_TICK;
} else if (message.endsWith("flames")) {
wieldShield = true;
} else if (message.endsWith("successfully") || message.startsWith("declined", 17)) {
resetTradeTimeouts();
} else if (message.endsWith("poison potion") || message.endsWith("antidote potion")) {
poisoned = false;
} else if (message.endsWith("attack potion")) {
superAtksUsed++;
} else if (message.endsWith("defense potion")) {
superDefsUsed++;
} else if (message.endsWith("strength potion")) {
superStrsUsed++;
} 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.endsWith("area")) {
idle = true;
previousY = getY();
} 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;
flee = false;
wieldShield = false;
}
private void abort(final String reason) {
if (mule != null) {
sendPrivateMessage("abort", mule);
}
exit(reason);
}
private void resetTradeTimeouts() {
tradeRequestTimeout = 0L;
privateMessageTimeout = 0L;
}
private void setState(final State state) {
this.state = state;
switch (this.state) {
case BANK:
if (abort) {
exit("Trip aborted.");
return;
}
updateNotableLoot();
break;
case TRADE:
updateNotableLoot();
break;
}
}
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);
}
for (final Equipment equipment : Equipment.VALUES) {
if (inArray(ITEM_IDS_LOOT_NOTABLE, equipment.id) && getInventoryCount(equipment.id) > 1) {
notableLoot.merge(equipment.id, -1, 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 Map.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 Used",
PAINT_OFFSET_X_ALT, y += PAINT_OFFSET_Y_INCREMENT, 1, 0);
drawString(String.format("@or1@Strs: @whi@%s @cya@(@whi@%s p@cya@/@whi@hr@cya@)",
superStrsUsed, toUnitsPerHour(superStrsUsed, startTime)),
PAINT_OFFSET_X_ALT, y += PAINT_OFFSET_Y_INCREMENT, 1, 0);
drawString(String.format("@ora@Atks: @whi@%s @cya@(@whi@%s p@cya@/@whi@hr@cya@)",
superAtksUsed, toUnitsPerHour(superAtksUsed, startTime)),
PAINT_OFFSET_X_ALT, y += PAINT_OFFSET_Y_INCREMENT, 1, 0);
drawString(String.format("@or2@Defs: @whi@%s @cya@(@whi@%s p@cya@/@whi@hr@cya@)",
superDefsUsed, toUnitsPerHour(superDefsUsed, startTime)),
PAINT_OFFSET_X_ALT, y += PAINT_OFFSET_Y_INCREMENT, 1, 0);
drawString(String.format("@or3@Sharks: @whi@%s @cya@(@whi@%s p@cya@/@whi@hr@cya@)",
sharksEaten, toUnitsPerHour(sharksEaten, startTime)),
PAINT_OFFSET_X_ALT, y + PAINT_OFFSET_Y_INCREMENT, 1, 0);
}
@Override
public void onPrivateMessage(final String message, final String playerName, final boolean moderator,
final boolean administrator) {
if (playerName.equalsIgnoreCase(mule) && message.equalsIgnoreCase("abort")) {
mule = null;
abort = true;
}
}
@Override
public void onPlayerDamaged(final java.lang.Object player) {
if (!inCombat() || player != bot.getPlayer()) {
return;
}
if (flee) {
walkTo(playerX, playerY);
return;
}
flee = getCurrentHits() < MINIMUM_HITS ||
(poisoned && hasInventoryItem(Potion.ANTIDOTE.ids));
final int combatStyle = getCombatStyle();
if (bot.getCombatStyle() != combatStyle) setCombatStyle(combatStyle);
}
@Override
public void onNpcDamaged(final java.lang.Object npc) {
if (!inCombat() ||
getWaypointX(npc) != getWaypointX(bot.getPlayer()) ||
getWaypointY(npc) != getWaypointY(bot.getPlayer())) {
return;
}
if (flee) {
walkTo(playerX, playerY);
return;
}
if (getCombatStyle() != CombatStyle.DEFENSE.getIndex()) setCombatStyle(CombatStyle.DEFENSE.getIndex());
}
private int getCombatStyle() {
return inArray(COMBAT_STYLE_BREAKPOINTS, getCurrentLevel(Skill.ATTACK.getIndex())) ?
CombatStyle.STRENGTH.getIndex() : CombatStyle.ATTACK.getIndex();
}
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 (Equipment.isEquipment(itemId)) {
final int invCount = getInventoryCount(itemId);
if (invCount == 1) {
continue;
}
if (System.currentTimeMillis() <= depositTimeout) {
return 0;
}
deposit(itemId, invCount - 1);
depositTimeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS;
return 0;
}
if (!inArray(ITEM_IDS_LOOT, itemId) &&
itemId != ITEM_ID_DRAGONSTONE_AMULET &&
itemId != ITEM_ID_EMPTY_VIAL) {
continue;
}
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) {
if (hasInventoryItem(potion.ids)) {
continue;
}
if (System.currentTimeMillis() <= potion.timeout) {
return 0;
}
for (final int id : potion.ids) {
if (!hasBankItem(id)) {
continue;
}
withdraw(id, 1);
potion.timeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS;
return 0;
}
}
if (!isInventoryFull()) {
if (System.currentTimeMillis() <= withdrawTimeout) {
return 0;
}
if (!hasBankItem(Food.SHARK.getId())) {
abort(String.format("Out of item: %s.", Food.SHARK));
}
withdraw(Food.SHARK.getId(), getInventoryEmptyCount());
withdrawTimeout = System.currentTimeMillis() + TIMEOUT_THREE_SECONDS;
return 0;
}
setState(State.WALK_TO_DRAGON);
return 0;
}
private int walkToDragon() {
if (Area.DRAGON.contains(playerX, playerY)) {
setState(State.KILL);
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) {
if (equipment == Equipment.ANTI_SHIELD) {
continue;
}
final int equipmentIndex = getInventoryIndex(equipment.id);
if (equipmentIndex != -1 && !isItemEquipped(equipmentIndex)) {
wearItem(equipmentIndex);
return true;
}
}
return false;
}
private int kill() {
if (inCombat()) {
if (wieldShield) {
final int shieldIndex = getInventoryIndex(Equipment.SHIELD.id);
if (!isItemEquipped(shieldIndex)) {
wearItem(shieldIndex);
return SLEEP_ONE_TICK;
}
wieldShield = false;
}
return 0;
}
if (flee) {
flee = false;
}
final int antiShieldIndex = getInventoryIndex(Equipment.ANTI_SHIELD.id);
if (antiShieldIndex == -1) {
setState(State.TELEPORT_TO_BANK);
return 0;
}
if (!isItemEquipped(antiShieldIndex)) {
wearItem(antiShieldIndex);
return SLEEP_ONE_TICK;
}
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) {
setState(mule != null ? State.TRADE : State.TELEPORT_TO_BANK);
return 0;
}
return consume(sharkIndex);
}
final int vialIndex = getInventoryIndex(ITEM_ID_EMPTY_VIAL);
if (vialIndex != -1) {
return dropVial(vialIndex);
}
updateLoot();
if (loot[0] != -1 && (loot[0] != Food.SHARK.getId() || !isInventoryFull())) {
if (!isInventoryFull() ||
(inArray(ITEM_IDS_STACKABLE, loot[0]) && hasInventoryItem(loot[0]))) {
pickupItem(loot[0], loot[1], loot[2]);
return SLEEP_ONE_TICK;
}
final int sharkIndex = getInventoryIndex(Food.SHARK.getId());
if (sharkIndex != -1) {
return consume(sharkIndex);
}
}
final int[] dragon = getAllNpcById(NPC_ID_KING_BLACK_DRAGON);
if (dragon[0] == -1) {
if (mule != null && isMissingSupplies()) {
setState(State.TRADE);
return 0;
}
if (playerX != COORDINATE_KBD_RESPAWN.getX() || playerY != COORDINATE_KBD_RESPAWN.getY()) {
walkTo(COORDINATE_KBD_RESPAWN.getX(), COORDINATE_KBD_RESPAWN.getY());
return SLEEP_ONE_TICK;
}
return 0;
}
if (isNpcInCombat(dragon[0])) {
if (distanceTo(dragon[1], dragon[2]) > 1) {
walkTo(dragon[1], dragon[2]);
return SLEEP_ONE_TICK;
}
return 0;
}
final int npcHits = getCurrentHits(bot.getNpc(dragon[0]));
if (npcHits == 0 || npcHits >= MINIMUM_HITS_KBD) {
if (canDrinkSuperAttack()) {
final int potionIndex = getInventoryIndex(Potion.SUPER_ATTACK.ids);
if (potionIndex != -1) {
return consume(potionIndex);
}
}
if (canDrinkSuperDefense()) {
final int potionIndex = getInventoryIndex(Potion.SUPER_DEFENSE.ids);
if (potionIndex != -1) {
return consume(potionIndex);
}
}
if (canDrinkSuperStrength()) {
final int potionIndex = getInventoryIndex(Potion.SUPER_STRENGTH.ids);
if (potionIndex != -1) {
return consume(potionIndex);
}
}
}
attackNpc(dragon[0]);
return SLEEP_ONE_TICK;
}
private boolean isMissingSupplies() {
if (getInventoryCount(Food.SHARK.getId()) < MINIMUM_SHARKS) {
return true;
}
if (canDrinkSuperAttack() && !hasInventoryItem(Potion.SUPER_ATTACK.ids)) {
return true;
}
if (canDrinkSuperDefense() && !hasInventoryItem(Potion.SUPER_DEFENSE.ids)) {
return true;
}
if (canDrinkSuperStrength() && !hasInventoryItem(Potion.SUPER_STRENGTH.ids)) {
return true;
}
return poisoned;
}
private int trade() {
if (inCombat()) {
walkTo(playerX, playerY);
return SLEEP_ONE_TICK;
}
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.TRADE.contains(playerX, playerY) &&
(getCurrentHits() < MINIMUM_HITS || getPlayerByName(mule)[0] == -1)) {
final int[] kbd = getAllNpcById(NPC_ID_KING_BLACK_DRAGON);
if (kbd[0] != -1 && Area.TRADE.contains(kbd[1], kbd[2])) {
setState(State.TELEPORT_TO_BANK);
return 0;
}
}
}
final int vialIndex = getInventoryIndex(ITEM_ID_EMPTY_VIAL);
if (vialIndex != -1) {
return dropVial(vialIndex);
}
if (!Area.TRADE.contains(playerX, playerY) &&
getAllNpcById(NPC_ID_KING_BLACK_DRAGON)[0] == -1) {
updateLoot();
if (loot[0] != -1 && (loot[0] != Food.SHARK.getId() || !isInventoryFull())) {
if (!isInventoryFull() ||
(inArray(ITEM_IDS_STACKABLE, loot[0]) && hasInventoryItem(loot[0]))) {
pickupItem(loot[0], loot[1], loot[2]);
return SLEEP_ONE_TICK;
}
final int sharkIndex = getInventoryIndex(Food.SHARK.getId());
if (sharkIndex != -1) {
return consume(sharkIndex);
}
}
}
if (isInTradeConfirm()) {
if (!bot.hasLocalConfirmedTrade()) {
confirmTrade();
}
return 0;
}
if (isInTradeOffer()) {
return handleAcceptTrade();
}
if (idle) {
if (playerY == previousY) {
walkTo(playerX, playerY - 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());
return SLEEP_ONE_TICK;
}
final int[] mule = getPlayerByName(this.mule);
if (isMissingSupplies() || (!isInventoryFull() && mule[0] != -1)) {
if (mule[0] == -1 || System.currentTimeMillis() <= tradeRequestTimeout) {
return 0;
}
sendTradeRequest(getPlayerPID(mule[0]));
tradeRequestTimeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS;
return 0;
}
setState(State.KILL);
return 0;
}
private int handleAcceptTrade() {
final int totalTradeSize = Math.min(getInventoryLootCount() - getEquipmentLootCount(),
MAX_TRADE_SIZE);
if (getRemoteTradeItemCount() == 0 &&
System.currentTimeMillis() > privateMessageTimeout) {
sendPrivateMessage(createSupplyRequestMessage(totalTradeSize), mule);
privateMessageTimeout = System.currentTimeMillis() + TIMEOUT_THREE_SECONDS;
return 0;
}
if (bot.getLocalTradeItemCount() == totalTradeSize) {
if (!hasLocalAcceptedTrade()) {
acceptTrade();
}
return 0;
}
for (int index = 0; index < getInventoryCount(); index++) {
final int itemId = getInventoryId(index);
if (itemId == Food.SHARK.getId()) {
continue;
}
if (Equipment.isEquipment(itemId)) {
final int invCount = getInventoryCount(itemId);
if (invCount == 1) {
continue;
}
final int tradeCount = getTradeItemIdCount(itemId);
if (tradeCount == invCount - 1) {
continue;
}
if (tradeCount == invCount) {
removeTradeItemId(itemId, 1);
} else {
offerItemTrade(index, 1);
}
continue;
}
if (inArray(Potion.ANTIDOTE.ids, itemId)) {
if (!poisoned) {
offerItemTrade(index, 1);
}
continue;
}
if (inArray(ITEM_IDS_LOOT, itemId)) {
final int tradeCount = getTradeItemIdCount(itemId);
final int invCount = getInventoryCount(itemId);
if (tradeCount == invCount) {
continue;
}
offerItemTrade(index, invCount);
}
}
return SLEEP_ONE_TICK;
}
private int getInventoryLootCount() {
int count = 0;
for (int index = 0; index < getInventoryCount(); index++) {
final int itemId = getInventoryId(index);
if (itemId == Food.SHARK.getId()) {
continue;
}
if (inArray(ITEM_IDS_LOOT, itemId) ||
(inArray(Potion.ANTIDOTE.ids, itemId) && !poisoned)) {
count++;
}
}
return count;
}
private int getEquipmentLootCount() {
int count = 0;
for (final Equipment equipment : Equipment.VALUES) {
if (inArray(ITEM_IDS_LOOT, equipment.id) &&
hasInventoryItem(equipment.id)) {
count++;
}
}
return count;
}
private String createSupplyRequestMessage(final int tradeSize) {
final int maxTradeSpace = Math.min(tradeSize + getInventoryEmptyCount(), MAX_TRADE_SIZE);
final int antidote = poisoned && !hasInventoryItem(Potion.ANTIDOTE.ids) ? 1 : 0;
final int superAtk = !hasInventoryItem(Potion.SUPER_ATTACK.ids) ? 1 : 0;
final int superDef = !hasInventoryItem(Potion.SUPER_DEFENSE.ids) ? 1 : 0;
final int superStr = !hasInventoryItem(Potion.SUPER_STRENGTH.ids) ? 1 : 0;
final int totalPotions = antidote + superAtk + superDef + superStr;
final int sharks = maxTradeSpace - totalPotions;
return String.format("%d,%d,%d,%d,%d", antidote, superAtk, superDef, superStr, sharks);
}
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 boolean canDrinkSuperAttack() {
return getCurrentLevel(Skill.ATTACK.getIndex()) <= MINIMUM_ATK;
}
private boolean canDrinkSuperDefense() {
return getCurrentLevel(Skill.DEFENSE.getIndex()) <= MINIMUM_DEF;
}
private boolean canDrinkSuperStrength() {
return getCurrentLevel(Skill.STRENGTH.getIndex()) <= MINIMUM_STR;
}
private void updateLoot() {
loot[0] = -1;
int groundItemId;
for (int index = 0; index < getGroundItemCount(); index++) {
groundItemId = getGroundItemId(index);
if (!inArray(ITEM_IDS_LOOT, groundItemId)) {
continue;
}
loot[0] = groundItemId;
loot[1] = getItemX(index);
loot[2] = getItemY(index);
break;
}
}
private int consume(final int inventoryIndex) {
if (System.currentTimeMillis() <= actionTimeout) {
return 0;
}
useItem(inventoryIndex);
actionTimeout = System.currentTimeMillis() + TIMEOUT_THREE_SECONDS;
return 0;
}
private int dropVial(final int inventoryIndex) {
if (System.currentTimeMillis() <= actionTimeout) {
return 0;
}
dropItem(inventoryIndex);
actionTimeout = System.currentTimeMillis() + TIMEOUT_TWO_SECONDS;
return 0;
}
private enum State {
BANK("Bank"),
WALK_TO_DRAGON("Walk to Dragon"),
KILL("Slay 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 {
HELMET(795),
BODY(401),
LEGS(402),
SHIELD(1278),
ANTI_SHIELD(420),
WEAPON(593),
AMULET(597),
CAPE(1288);
private static final Equipment[] VALUES = Equipment.values();
private final int id;
private long timeout;
Equipment(final int id) {
this.id = id;
}
private static boolean isEquipment(final int id) {
for (final Equipment equipment : VALUES) {
if (id == equipment.id) {
return true;
}
}
return false;
}
}
}