From 2239281943273591fa45dda21bd337a23fbc22af Mon Sep 17 00:00:00 2001 From: chsami Date: Wed, 3 Sep 2025 19:50:42 +0200 Subject: [PATCH 1/6] Update README.md --- README.md | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/README.md b/README.md index 0756c9fd358..ed3a98ea704 100644 --- a/README.md +++ b/README.md @@ -20,32 +20,6 @@ If you have any questions, please join our [Discord](https://discord.gg/zaGrfqFE If you enjoy my open source work and would like to support me, consider buying me a coffee! Your support helps me stay caffeinated and motivated to keep improving and creating awesome projects. -## Quest Helper Integration - -The integrated Quest Helper works together with other plugins to give a nice unified experience while questing. - -### Not Enough Runes - -If you have the [Not Enough Runes](https://runelite.net/plugin-hub/show/not-enough-runes) plugin installed, you can -right-click item requirements and click `Go to NER...` to look that item up in Not Enough Runes. - -![Not Enough Runes context menu](./images/not-enough-runes-01.png) - -### Shortest Path - -If you have the [Shortest Path](https://runelite.net/plugin-hub/show/shortest-path) plugin installed, you can enable the -the "Use 'Shortest Path' plugin" in the Quest Helper config. - -![](./images/shortest-path-01.png) - -Next time you start a quest, the Shortest Path plugin will help you take the shortest path to the destination. - -![Shortest Path path overlay example](./images/shortest-path-02.png) - -You can configure what teleportation methods, or the aesthetic of the path in the Shortest Path config. - -## Help and discussion - [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-donate-yellow)](https://www.paypal.com/paypalme/MicrobotBE?country.x=BE) From 5ddaf5ab18e9d7cd5a03ac0e24642fce9aa143e0 Mon Sep 17 00:00:00 2001 From: heap-overfl0w Date: Sat, 6 Sep 2025 15:10:23 -0500 Subject: [PATCH 2/6] - Added world hopping logic to Fortis Gem Stall due to long stall respawn times. - Added fuzzy gem bag support because I don't have an account to test this with. My implementation passes the eye test but will need actual testing. --- .../model/FortisGemStallThievingSpot.java | 68 ++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java index 4f5d98b3794..9e84a0de9bb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java @@ -3,11 +3,17 @@ import net.runelite.api.GameObject; import net.runelite.api.Skill; import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; +import net.runelite.api.gameval.ItemID; import net.runelite.client.plugins.microbot.util.Global; +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.Rs2Gembag; +import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; +import net.runelite.client.plugins.microbot.util.inventory.Rs2ItemModel; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.util.security.Login; import javax.inject.Inject; @@ -30,19 +36,59 @@ public void thieve() { } } + if (Rs2Player.hopIfPlayerDetected(1, 0, 2)) { + return; + } + final GameObject stall = Rs2GameObject.getGameObject(STALL_ID, SAFESPOT, 2); if (stall == null) { + boolean started = Microbot.hopToWorld(Login.getRandomWorld(Rs2Player.isMember())); + if (started) { + Global.sleepUntil(Microbot::isLoggedIn, 15000); + } + return; + } + + if (!Rs2GameObject.hasAction(Rs2GameObject.convertToObjectComposition(stall), "Steal-from")) { + boolean started = Microbot.hopToWorld(Login.getRandomWorld(Rs2Player.isMember())); + if (started) { + Global.sleepUntil(Microbot::isLoggedIn, 15000); + } return; } Rs2GameObject.interact(stall, "Steal-from"); Rs2Player.waitForXpDrop(Skill.THIEVING); + + if (Rs2Gembag.hasGemBag()) { + if (Rs2Gembag.isUnknown()) { + Rs2Gembag.checkGemBag(); + } + if (!isGemBagCompletelyFull()) { + if (Rs2Inventory.hasItem(ItemID.GEM_BAG)) { + Rs2Inventory.interact(ItemID.GEM_BAG, "Open"); + Global.sleepUntil(Rs2Gembag::isGemBagOpen, 2000); + } + if (Rs2Gembag.isGemBagOpen() && hasAnyUncutGemInInventory()) { + Rs2Inventory.interact(ItemID.GEM_BAG_OPEN, "Fill"); + } + } + } } @Override public void bank() { Rs2Bank.walkToBankAndUseBank(); - Rs2Bank.depositAll(); + if (!Rs2Bank.isOpen()) return; + + Rs2Bank.depositAll(ItemID.UNCUT_SAPPHIRE); + Rs2Bank.depositAll(ItemID.UNCUT_EMERALD); + Rs2Bank.depositAll(ItemID.UNCUT_RUBY); + Rs2Bank.depositAll(ItemID.UNCUT_DIAMOND); + + Rs2Bank.emptyGemBag(); + + Rs2Bank.depositAllExcept(ItemID.GEM_BAG, ItemID.GEM_BAG_OPEN); Rs2Bank.closeBank(); } @@ -50,4 +96,22 @@ public void bank() { public Integer[] getItemIdsToDrop() { return new Integer[0]; } + + private boolean hasAnyUncutGemInInventory() { + return Rs2Inventory.items(this::isUncutGem).findAny().isPresent(); + } + + private boolean isUncutGem(Rs2ItemModel item) { + String n = item.getName().toLowerCase(); + return n.equals("uncut sapphire") || + n.equals("uncut emerald") || + n.equals("uncut ruby") || + n.equals("uncut diamond"); + } + + private boolean isGemBagCompletelyFull() { + if (Rs2Gembag.isUnknown()) return false; + return Rs2Gembag.getGemBagContents().size() == 5 && + Rs2Gembag.getGemBagContents().stream().allMatch(g -> g.getQuantity() >= 60); + } } From 41bcd2e375667cb6ae76bce9d54f9e3f130b3245 Mon Sep 17 00:00:00 2001 From: heap-overfl0w Date: Sat, 6 Sep 2025 15:25:29 -0500 Subject: [PATCH 3/6] Coderabbit made a good point... Because this stall doesn't give you dragonstones, our gem bag will never be "completely full" (consisting of >= 60 gems of all 5 types) and could cause unnecessary fill attempts. Let's check the 4 types individually. --- .../thieving/stalls/model/FortisGemStallThievingSpot.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java index 9e84a0de9bb..8ac4a12b4e3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java @@ -111,7 +111,10 @@ private boolean isUncutGem(Rs2ItemModel item) { private boolean isGemBagCompletelyFull() { if (Rs2Gembag.isUnknown()) return false; - return Rs2Gembag.getGemBagContents().size() == 5 && - Rs2Gembag.getGemBagContents().stream().allMatch(g -> g.getQuantity() >= 60); + int sapphire = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getName().equalsIgnoreCase("uncut sapphire")).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); + int emerald = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getName().equalsIgnoreCase("uncut emerald")).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); + int ruby = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getName().equalsIgnoreCase("uncut ruby")).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); + int diamond = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getName().equalsIgnoreCase("uncut diamond")).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); + return sapphire >= 60 && emerald >= 60 && ruby >= 60 && diamond >= 60; } } From cf098c7171d41bb2a0d488bde90af8aef15fca78 Mon Sep 17 00:00:00 2001 From: heap-overfl0w Date: Sat, 6 Sep 2025 15:48:31 -0500 Subject: [PATCH 4/6] Stick with ItemID. usage --- .../model/FortisGemStallThievingSpot.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java index 8ac4a12b4e3..e63cd50eee3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/thieving/stalls/model/FortisGemStallThievingSpot.java @@ -102,19 +102,19 @@ private boolean hasAnyUncutGemInInventory() { } private boolean isUncutGem(Rs2ItemModel item) { - String n = item.getName().toLowerCase(); - return n.equals("uncut sapphire") || - n.equals("uncut emerald") || - n.equals("uncut ruby") || - n.equals("uncut diamond"); + int id = item.getId(); + return id == ItemID.UNCUT_SAPPHIRE || + id == ItemID.UNCUT_EMERALD || + id == ItemID.UNCUT_RUBY || + id == ItemID.UNCUT_DIAMOND; } private boolean isGemBagCompletelyFull() { if (Rs2Gembag.isUnknown()) return false; - int sapphire = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getName().equalsIgnoreCase("uncut sapphire")).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); - int emerald = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getName().equalsIgnoreCase("uncut emerald")).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); - int ruby = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getName().equalsIgnoreCase("uncut ruby")).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); - int diamond = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getName().equalsIgnoreCase("uncut diamond")).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); + int sapphire = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getId() == ItemID.UNCUT_SAPPHIRE).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); + int emerald = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getId() == ItemID.UNCUT_EMERALD).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); + int ruby = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getId() == ItemID.UNCUT_RUBY).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); + int diamond = Rs2Gembag.getGemBagContents().stream().filter(i -> i.getId() == ItemID.UNCUT_DIAMOND).findFirst().map(Rs2ItemModel::getQuantity).orElse(0); return sapphire >= 60 && emerald >= 60 && ruby >= 60 && diamond >= 60; } } From 5f18953d158383ac56df24c3c140446a27d2d650 Mon Sep 17 00:00:00 2001 From: heap-overfl0w Date: Sun, 7 Sep 2025 09:53:42 -0500 Subject: [PATCH 5/6] - All routing decisions outside BANKING state now use inventory-only checks, so starting with the bank open no longer tricks the script into WALKING/COOKING states without raw food to cook in the inventory. - BANKING state specifically checks the bank for raw food and handles withdrawals, then closes the bank. - Null check on Rogue's Den banker --- .../cooking/scripts/AutoCookingScript.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/cooking/scripts/AutoCookingScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/cooking/scripts/AutoCookingScript.java index d92b2c26de5..f4384d370cd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/cooking/scripts/AutoCookingScript.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/cooking/scripts/AutoCookingScript.java @@ -74,6 +74,12 @@ public boolean run(AutoCookingConfig config) { } } + if (location == null) { + Microbot.showMessage("No suitable cooking location found"); + shutdown(); + return; + } + getState(config, location); } @@ -81,6 +87,10 @@ public boolean run(AutoCookingConfig config) { switch (state) { case COOKING: + if (Rs2Bank.isOpen()) { + Rs2Bank.closeBank(); + return; + } if (!cookingItem.hasRequirements()) { Microbot.showMessage("You do not meet the requirements to cook this item"); shutdown(); @@ -119,6 +129,8 @@ public boolean run(AutoCookingConfig config) { state = CookingState.BANKING; break; } + state = CookingState.WALKING; + break; case DROPPING: Microbot.status = "Dropping " + cookingItem.getBurntItemName(); Rs2Inventory.dropAll(item -> item.getName().equalsIgnoreCase(cookingItem.getBurntItemName()), config.getDropOrder()); @@ -128,6 +140,7 @@ public boolean run(AutoCookingConfig config) { case BANKING: if (location == CookingLocation.ROUGES_DEN) { NPC npc = Rs2Npc.getBankerNPC(); + if (npc == null) return; boolean isNPCBankOpen = Rs2Bank.openBank(npc); if (!isNPCBankOpen) return; } else { @@ -138,7 +151,7 @@ public boolean run(AutoCookingConfig config) { Rs2Bank.depositAll(); Rs2Inventory.waitForInventoryChanges(1800); - if (!hasRawItem(cookingItem)) { + if (!hasRawItemInBank(cookingItem)) { Microbot.showMessage("No Raw Food Item found in Bank"); shutdown(); return; @@ -210,12 +223,13 @@ private boolean isNearCookingLocation(CookingLocation location, int distance) { } private boolean hasRawItem(CookingItem cookingItem) { - if (Rs2Bank.isOpen()) { - return Rs2Bank.hasBankItem(cookingItem.getRawItemName(), true); - } return Rs2Inventory.hasItem(cookingItem.getRawItemName(), true); } + private boolean hasRawItemInBank(CookingItem cookingItem) { + return Rs2Bank.hasBankItem(cookingItem.getRawItemName(), true); + } + private boolean hasCookedItem(CookingItem cookingItem) { return Rs2Inventory.hasItem(cookingItem.getCookedItemName(), true); } From 2676be8b795dd08888753bc8047d1ad0de730bd4 Mon Sep 17 00:00:00 2001 From: heap-overfl0w Date: Sun, 7 Sep 2025 14:39:50 -0500 Subject: [PATCH 6/6] Currently Rs2Bank.setWithdrawAs(boolean) always clicks the Note button (786458), even when switching to Item (786456), so setWithdrawAsItem() can never flip the mode, therefore never select Item mode. --- .../client/plugins/microbot/util/bank/Rs2Bank.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java index 3d846567084..907c08d0b65 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/Rs2Bank.java @@ -23,6 +23,7 @@ import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.gameval.ItemID; import net.runelite.api.gameval.VarbitID; +import net.runelite.api.gameval.InterfaceID; import net.runelite.api.widgets.ComponentID; import net.runelite.api.widgets.Widget; import net.runelite.client.config.RuneScapeProfileType; @@ -2635,11 +2636,11 @@ public static boolean hasWithdrawAsItem() { return isWithdrawAs(false); } - private static final int NOTED_TOGGLE_WIDGET = 786458; - public static boolean setWithdrawAs(boolean noted) { if (isWithdrawAs(noted)) return true; - Rs2Widget.clickWidget(NOTED_TOGGLE_WIDGET); + int target = noted ? InterfaceID.Bankmain.NOTE : InterfaceID.Bankmain.ITEM; + boolean clicked = Rs2Widget.clickWidget(target); + if (!clicked) return false; return sleepUntil(() -> isWithdrawAs(noted)); }