diff --git a/src/main/java/net/runelite/client/plugins/microbot/geflipper/FlipperPlugin.java b/src/main/java/net/runelite/client/plugins/microbot/geflipper/FlipperPlugin.java index 4c38f7b7b5..a422533ffc 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/geflipper/FlipperPlugin.java +++ b/src/main/java/net/runelite/client/plugins/microbot/geflipper/FlipperPlugin.java @@ -23,7 +23,7 @@ isExternal = PluginConstants.IS_EXTERNAL ) public class FlipperPlugin extends Plugin { - public static final String version = "1.1.0"; + public static final String version = "1.2.0"; @Inject private Client client; @Inject diff --git a/src/main/java/net/runelite/client/plugins/microbot/geflipper/FlipperScript.java b/src/main/java/net/runelite/client/plugins/microbot/geflipper/FlipperScript.java index d26398f8ea..b5e51cc3c5 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/geflipper/FlipperScript.java +++ b/src/main/java/net/runelite/client/plugins/microbot/geflipper/FlipperScript.java @@ -38,6 +38,15 @@ enum State { @Slf4j public class FlipperScript extends Script { + private static final int DEFAULT_ACTION_COOLDOWN = 1200; + private static final int ACTION_COOLDOWN_VARIANCE = 600; + private static final int DEFAULT_INTERACTION_TIMEOUT = 33000; + private static final int INTERACTION_TIMEOUT_VARIANCE = 11000; + private static final int INVENTORY_WAIT_TIMEOUT = 5000; + private static final int SCHEDULE_INTERVAL_MS = 600; + private static final int KEY_PRESS_DELAY_MIN = 250; + private static final int KEY_PRESS_DELAY_MAX = 400; + private final WorldArea grandExchangeArea = new WorldArea(3136, 3465, 61, 54, 0); State state = State.GOING_TO_GE; @@ -45,7 +54,8 @@ public class FlipperScript extends Script { private Object suggestionManager; private Object highlightController; private long lastActionTime = 0; - private long actionCooldown = 1500; // randomized cooldown between actions + private long actionCooldown = DEFAULT_ACTION_COOLDOWN; + private long interactionTimeout = DEFAULT_INTERACTION_TIMEOUT; private int[] grandExchangeSlotIds = new int[] { InterfaceID.GeOffers.INDEX_0, @@ -91,7 +101,7 @@ public boolean run() { Rs2Bank.depositAll(); sleepUntil(Rs2Inventory::isEmpty); Rs2Bank.withdrawAll(ItemID.COINS); - Rs2Inventory.waitForInventoryChanges(5000); + Rs2Inventory.waitForInventoryChanges(INVENTORY_WAIT_TIMEOUT); Rs2Bank.closeBank(); sleepUntil(() -> !Rs2Bank.isOpen()); state = State.MONITORING_COPILOT; @@ -104,20 +114,34 @@ public boolean run() { return; } + // Check interaction timeout first - reset ge window state if stuck + long currentTime = System.currentTimeMillis(); + if (Rs2GrandExchange.isOfferScreenOpen() && (currentTime - lastActionTime > interactionTimeout)) { + Rs2GrandExchange.backToOverview(); + + lastActionTime = System.currentTimeMillis(); + actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE); + interactionTimeout = Rs2Random.randomGaussian(DEFAULT_INTERACTION_TIMEOUT, INTERACTION_TIMEOUT_VARIANCE); + + log.info("interactionTimeout reached, returning to GE overview."); + return; + } + // Check for Copilot price/quantity messages in chat if (checkAndPressCopilotKeybind()) return; // Check if we need to abort any offers - if (checkAndAbortIfNeeded()) return; + if (checkAndAbortOrModifyIfNeeded()) return; // Check for highlighted widgets - checkAndClickHighlightedWidgets(); + if (checkAndClickHighlightedWidgets()) return; + break; } } catch (Exception ex) { log.error("Error in FlipperScript: {} - ", ex.getMessage(), ex); } - }, 0, 600, TimeUnit.MILLISECONDS); + }, 0, SCHEDULE_INTERVAL_MS, TimeUnit.MILLISECONDS); return true; } @@ -129,7 +153,7 @@ public void shutdown() suggestionManager = null; highlightController = null; lastActionTime = 0; - actionCooldown = 1500; + actionCooldown = DEFAULT_ACTION_COOLDOWN; super.shutdown(); } @@ -282,7 +306,7 @@ private Widget getWidgetFromOverlay(Object highlightController, String suggestio return null; } - if (Objects.equals(suggestionType, "abort")) + if (Objects.equals(suggestionType, "abort") || Objects.equals(suggestionType, "modify_buy") || Objects.equals(suggestionType, "modify_sell")) { return getHighlightWidgets(highlightController).stream() .filter(Objects::nonNull) @@ -301,10 +325,9 @@ private Widget getWidgetFromOverlay(Object highlightController, String suggestio } } - private boolean checkAndAbortIfNeeded() + private boolean checkAndAbortOrModifyIfNeeded() { - long currentTime = System.currentTimeMillis(); - if (currentTime - lastActionTime < actionCooldown) return true; + if (System.currentTimeMillis() - lastActionTime < actionCooldown) return false; if (flippingCopilot == null || highlightController == null || suggestionManager == null) return false; try @@ -314,20 +337,25 @@ private boolean checkAndAbortIfNeeded() String suggestionType = getSuggestionType(currentSuggestion); - if (!Objects.equals(suggestionType, "abort")) return false; + if (!Objects.equals(suggestionType, "abort") && !Objects.equals(suggestionType, "modify_buy") && !Objects.equals(suggestionType, "modify_sell")) return false; log.info("Found suggestion type '{}'.", suggestionType); Widget abortWidget = getWidgetFromOverlay(highlightController, suggestionType); if (abortWidget != null) - { - NewMenuEntry menuEntry = new NewMenuEntry("Abort offer", "", 2, MenuAction.CC_OP, 2, abortWidget.getId(), false); + { + NewMenuEntry menuEntry; + if (Objects.equals(suggestionType, "modify_buy") || Objects.equals(suggestionType, "modify_sell")) + menuEntry = new NewMenuEntry("Modify offer", "", 3, MenuAction.CC_OP, 2, abortWidget.getId(), false); + else + menuEntry = new NewMenuEntry("Abort offer", "", 2, MenuAction.CC_OP, 2, abortWidget.getId(), false); + Rectangle bounds = abortWidget.getBounds() != null && Rs2UiHelper.isRectangleWithinCanvas(abortWidget.getBounds()) ? abortWidget.getBounds() : Rs2UiHelper.getDefaultRectangle(); Microbot.doInvoke(menuEntry, bounds); lastActionTime = System.currentTimeMillis(); - actionCooldown = Rs2Random.randomGaussian(1200, 300); + actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE); return true; } } @@ -339,24 +367,52 @@ private boolean checkAndAbortIfNeeded() } private boolean checkAndPressCopilotKeybind() { - boolean isChatboxInputOpen = Rs2Widget.isWidgetVisible(InterfaceID.Chatbox.MES_LAYER); - if (!isChatboxInputOpen) return false; - log.info("Found chatbox input open, pressing 'e' then Enter"); - // Press 'e' to trigger FlippingCopilot's keybind - Rs2Keyboard.keyPress(KeyEvent.VK_E); - sleep(250, 400); - Rs2Keyboard.keyPress(KeyEvent.VK_ENTER); - - lastActionTime = System.currentTimeMillis(); - return true; + // 1. Search MES_LAYER_SCROLLCONTENTS for a widget containing "Copilot" (if it's time to select the item suggestion) + Widget scrollContents = Rs2Widget.getWidget(InterfaceID.Chatbox.MES_LAYER_SCROLLCONTENTS); + Widget copilotWidget = null; + + if (scrollContents != null) { + copilotWidget = Rs2Widget.findWidget("Copilot", List.of(scrollContents), false); + if (copilotWidget != null && Rs2Widget.isWidgetVisible(copilotWidget.getId())) { + log.info("Found chat widget '{}'.", copilotWidget.getId()); + // 2. Press only Enter if found in scroll contents (selecting item) + Rs2Keyboard.keyPress(KeyEvent.VK_ENTER); + + // As these widgets tend to disappear quickly sometimes, we sleep after we interact with it to select the suggested item + sleepUntil(() -> System.currentTimeMillis() - lastActionTime < actionCooldown); + lastActionTime = System.currentTimeMillis(); + actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE); + return true; + } + } + + if (System.currentTimeMillis() - lastActionTime < actionCooldown) return false; + + Widget mesLayer = Rs2Widget.getWidget(InterfaceID.Chatbox.MES_LAYER); + if (mesLayer != null) { + copilotWidget = Rs2Widget.findWidget("Copilot", List.of(mesLayer), false); + } + + if (copilotWidget != null && Rs2Widget.isWidgetVisible(copilotWidget.getId())) { + // 3. Press E then Enter (setting price/quantity) + log.info("Found chat widget '{}'.", copilotWidget.getId()); + Rs2Keyboard.keyPress(KeyEvent.VK_E); + sleep(KEY_PRESS_DELAY_MIN, KEY_PRESS_DELAY_MAX); + Rs2Keyboard.keyPress(KeyEvent.VK_ENTER); + lastActionTime = System.currentTimeMillis(); + actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE); + return true; + } + + return false; } - private void checkAndClickHighlightedWidgets() + private boolean checkAndClickHighlightedWidgets() { long currentTime = System.currentTimeMillis(); - if (currentTime - lastActionTime < actionCooldown) return; + if (currentTime - lastActionTime < actionCooldown) return false; - if (flippingCopilot == null || highlightController == null) return; + if (flippingCopilot == null || highlightController == null) return false; try { Widget highlightedWidget = getWidgetFromOverlay(highlightController, ""); @@ -364,14 +420,17 @@ private void checkAndClickHighlightedWidgets() if (isHighlightedVisible) { log.info("Clicking highlighted widget: {}", highlightedWidget.getId()); - Rs2Widget.clickWidget(highlightedWidget); + sleepUntil(() -> Rs2Widget.clickWidget(highlightedWidget)); lastActionTime = currentTime; - actionCooldown = Rs2Random.randomGaussian(1800, 300); + actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE); + return true; } } catch (Exception e) { log.error("Could not process highlight widgets: {} - ", e.getMessage(), e); } + + return false; } } \ No newline at end of file diff --git a/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansConfig.java b/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansConfig.java index 4a0dc1f15a..0d331581d0 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansConfig.java +++ b/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansConfig.java @@ -1,24 +1,57 @@ package net.runelite.client.plugins.microbot.karambwans; import net.runelite.client.config.*; +import net.runelite.client.plugins.microbot.karambwans.enums.KarambwanBankLocation; +import net.runelite.client.plugins.microbot.karambwans.enums.FairyRingAccessMethod; @ConfigGroup("GabulhasKarambwans") @ConfigInformation( + "

Setup Instructions

" + "
    " + - "
  1. Configure the fairy rings to DKP (last destination must be DKP)
  2. " + - "
  3. Make sure to have karambwan vessel and raw karambwanji in your inventory
  4. " + - "
  5. Start the script next to the karambwan fishing spot
  6. " + - "
" + "
  • Configure the fairy rings to DKP (last destination must be DKP).
  • " + + "
  • Make sure to have a karambwan vessel and raw karambwanji in your inventory.
  • " + + "
  • Start the script next to the karambwan fishing spot.
  • " + + "" + + "

    Teleports & Banking

    " + + "" + + "
    Note: The script does not automatically restock teleports. Make sure to bring enough runes, a rune pouch, or teleport tabs for your session." ) public interface GabulhasKarambwansConfig extends Config { + String startingStateSection = "startingStateSection"; + @ConfigSection( - name = "Starting State", - description = "Starting State", - position = 0, - closedByDefault = true + name = "Teleports", + description = "Teleportation methods to bank and return to DKP", + position = 1, + closedByDefault = false ) - String startingStateSection = "startingStateSection"; + String teleportsSection = "teleportsSection"; + + @ConfigItem( + keyName = "bankLocation", + name = "Bank Location", + description = "Bank location to teleport to.", + position = 1, + section = teleportsSection + ) + default KarambwanBankLocation bankLocation() { + return KarambwanBankLocation.NONE; + } + + @ConfigItem( + keyName = "fairyRingAccessMethod", + name = "Fairy Ring Access", + description = "How to access the fairy ring to return to DKP.", + position = 2, + section = teleportsSection + ) + default FairyRingAccessMethod fairyRingAccessMethod() { + return FairyRingAccessMethod.ZANARIS_WALK; + } @ConfigItem( keyName = "startingState", name = "(Debug) Starting State", diff --git a/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansPlugin.java b/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansPlugin.java index e10e93c40f..ae5ec4543a 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansPlugin.java +++ b/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansPlugin.java @@ -25,7 +25,7 @@ ) @Slf4j public class GabulhasKarambwansPlugin extends Plugin { - public static final String version = "1.1.0"; + public static final String version = "1.2.0"; @Inject private GabulhasKarambwansConfig config; diff --git a/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansScript.java b/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansScript.java index 14a88dc85c..593996a2f5 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansScript.java +++ b/src/main/java/net/runelite/client/plugins/microbot/karambwans/GabulhasKarambwansScript.java @@ -5,6 +5,7 @@ import net.runelite.api.coords.WorldPoint; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.NpcID; +import net.runelite.api.gameval.VarbitID; import net.runelite.client.plugins.microbot.Microbot; import net.runelite.client.plugins.microbot.Script; import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; @@ -12,10 +13,17 @@ import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject; import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; +import net.runelite.client.plugins.microbot.util.magic.Rs2Spells; +import net.runelite.client.plugins.microbot.util.magic.Runes; import net.runelite.client.plugins.microbot.util.math.Rs2Random; import net.runelite.client.plugins.microbot.util.npc.Rs2Npc; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; +import net.runelite.client.plugins.microbot.karambwans.enums.KarambwanBankLocation; +import net.runelite.client.plugins.microbot.karambwans.enums.FairyRingAccessMethod; +import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment; +import net.runelite.client.plugins.microbot.util.magic.Rs2Magic; +import net.runelite.client.plugins.skillcalculator.skills.MagicAction; import java.util.concurrent.TimeUnit; @@ -24,11 +32,15 @@ @Slf4j public class GabulhasKarambwansScript extends Script { + public static final int FAIRY_RING_ID = 29228; + public static final int SPIRITUAL_FAIRY_TREE_ID = 35003; private final WorldPoint zanarisRingPoint = new WorldPoint(2412, 4435, 0); - private final WorldPoint fishingPoint = new WorldPoint(2900, 3112, 0); + private final WorldPoint fishingPoint = new WorldPoint(2899, 3118, 0); private final WorldPoint bankPoint = new WorldPoint(2381, 4455, 0); + private GabulhasKarambwansConfig config; public boolean run(GabulhasKarambwansConfig config) { + this.config = config; Microbot.enableAutoRunOn = false; Rs2Antiban.setActivity(Activity.CATCHING_RAW_KARAMBWAN); mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { @@ -93,6 +105,9 @@ private void fishingLoop() { } private void walkToRingToBank() { + if (config.bankLocation() != KarambwanBankLocation.NONE) { + return; + } WorldPoint ringLocation = new WorldPoint(2900, 3111, 0); // Karamja ring GameObject fairyRing = Rs2GameObject.getGameObject(ringLocation); if (fairyRing != null) { @@ -102,11 +117,21 @@ private void walkToRingToBank() { } private void doBank() { - Rs2Walker.walkTo(bankPoint, 3); - while (!Rs2Player.isInArea(bankPoint, 4) && super.isRunning()) { - Rs2Player.waitForWalking(); + if (config.bankLocation() == KarambwanBankLocation.SEERS && + Microbot.getVarbitValue(VarbitID.KANDARIN_DIARY_HARD_COMPLETE) == 1 + && Rs2Magic.hasRequiredRunes(Rs2Spells.CAMELOT_TELEPORT)) + { + Rs2Magic.cast(Rs2Spells.CAMELOT_TELEPORT, "Seers'", 2); + sleepUntil(() -> Rs2Bank.isNearBank(net.runelite.client.plugins.microbot.util.bank.enums.BankLocation.CAMELOT, 15), 5000); + } else { + Rs2Walker.walkTo(bankPoint, 3); + while (!Rs2Player.isInArea(bankPoint, 4) && super.isRunning()) { + Rs2Player.waitForWalking(); + } + } + if (!Rs2Bank.walkToBankAndUseBank()) { + Rs2Bank.openBank(); } - Rs2Bank.openBank(); } private void useBank() { @@ -121,6 +146,11 @@ private void useBank() { Rs2Bank.emptyFishBarrel(); Rs2Inventory.waitForInventoryChanges(2000); } + + + + Rs2Bank.closeBank(); + sleepUntil(() -> !Rs2Bank.isOpen(), 3000); } private void interactWithFishingSpot() { @@ -128,17 +158,43 @@ private void interactWithFishingSpot() { } private void walkToFish() { - Rs2Walker.walkTo(zanarisRingPoint, 3); - Rs2Player.waitForWalking(); - WorldPoint ringLocation = new WorldPoint(2412, 4434, 0); // Zanaris ring - GameObject fairyRing = Rs2GameObject.getGameObject(ringLocation); - if (fairyRing != null) { - Rs2GameObject.interact(fairyRing, "Last-destination (DKP)"); - sleepUntil(() -> Rs2Player.distanceTo(fishingPoint) < 2); + if (config.fairyRingAccessMethod() == FairyRingAccessMethod.POH) { + if (hasPohCape()) { + Rs2Equipment.interact(net.runelite.api.EquipmentInventorySlot.CAPE, "Tele to POH"); + } else if (Rs2Inventory.hasItem("Teleport to house")) { + Rs2Inventory.interact("Teleport to house", "Break"); + } else { + Rs2Magic.quickCast(MagicAction.TELEPORT_TO_HOUSE); + } + sleepUntil(() -> Rs2GameObject.exists(FAIRY_RING_ID) || Rs2GameObject.exists(SPIRITUAL_FAIRY_TREE_ID), 5000); + + boolean interacted = Rs2GameObject.interact(FAIRY_RING_ID, "Last-destination (DKP)") || + Rs2GameObject.interact(SPIRITUAL_FAIRY_TREE_ID, "Last-destination (DKP)"); + + if (interacted) { + waitTillPlayerNextToFishingSpot(); + } } else { - Rs2Walker.walkTo(fishingPoint, 1); + Rs2Walker.walkTo(zanarisRingPoint, 3); Rs2Player.waitForWalking(); + + if (Rs2GameObject.interact(FAIRY_RING_ID, "Last-destination (DKP)")) { + waitTillPlayerNextToFishingSpot(); + } else { + Rs2Player.waitForWalking(); + } } } + + private boolean hasPohCape() { + return Rs2Equipment.isWearing("Construct. cape") || + Rs2Equipment.isWearing("Construct. cape(t)") || + Rs2Equipment.isWearing("Max cape") || + Rs2Equipment.isWearing("Max cape(t)"); + } + + private void waitTillPlayerNextToFishingSpot() { + sleepUntil(() -> Rs2Player.distanceTo(fishingPoint) < 2); + } } diff --git a/src/main/java/net/runelite/client/plugins/microbot/karambwans/enums/FairyRingAccessMethod.java b/src/main/java/net/runelite/client/plugins/microbot/karambwans/enums/FairyRingAccessMethod.java new file mode 100644 index 0000000000..baeb60664c --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/karambwans/enums/FairyRingAccessMethod.java @@ -0,0 +1,18 @@ +package net.runelite.client.plugins.microbot.karambwans.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum FairyRingAccessMethod { + ZANARIS_WALK("Zanaris (Walk)"), + POH("POH (Teleport)"); + + private final String name; + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/karambwans/enums/KarambwanBankLocation.java b/src/main/java/net/runelite/client/plugins/microbot/karambwans/enums/KarambwanBankLocation.java new file mode 100644 index 0000000000..2448e22f08 --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/karambwans/enums/KarambwanBankLocation.java @@ -0,0 +1,18 @@ +package net.runelite.client.plugins.microbot.karambwans.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum KarambwanBankLocation { + NONE("None (Walk to Zanaris)"), + SEERS("Seers Village"); + + private final String name; + + @Override + public String toString() { + return name; + } +}