Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package net.runelite.client.plugins.microbot.shortestpath;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.runelite.api.TileObject;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.plugins.microbot.util.player.Rs2Player;
import net.runelite.client.plugins.microbot.util.widget.Rs2Widget;

import static net.runelite.client.plugins.microbot.util.Global.sleepUntil;

/**
* Handles the Magic Mushtree (Mycelium Transportation System) on Fossil Island.
* The mushtree network connects four locations:
* - House on the Hill
* - Verdant Valley
* - Sticky Swamp
* - Mushroom Meadow
*/
@Getter
@RequiredArgsConstructor
public enum MagicMushtree {
HOUSE_ON_THE_HILL("House on the Hill", new WorldPoint(3764, 3879, 1)),
VERDANT_VALLEY("Verdant Valley", new WorldPoint(3760, 3758, 0)),
STICKY_SWAMP("Sticky Swamp", new WorldPoint(3676, 3755, 0)),
MUSHROOM_MEADOW("Mushroom Meadow", new WorldPoint(3676, 3871, 0));

private final String destinationName;
private final WorldPoint destination;

// Object IDs for the Magic Mushtrees
public static final int MUSHTREE_HOUSE_ON_HILL = 30920;
public static final int MUSHTREE_OTHER = 30924;

private static final int OFFSET = 10;

/**
* Checks if the given object ID is a Magic Mushtree.
*/
public static boolean isMagicMushtree(int objectId) {
return objectId == MUSHTREE_HOUSE_ON_HILL || objectId == MUSHTREE_OTHER;
}

/**
* Checks if the given TileObject is a Magic Mushtree.
*/
public static boolean isMagicMushtree(TileObject tileObject) {
return tileObject != null && isMagicMushtree(tileObject.getId());
}

/**
* Handles the Magic Mushtree transport after the initial "Use" interaction.
* Waits for the menu to appear, then clicks the appropriate destination.
*
* @param transport The transport containing the destination
* @return true if the transport was handled successfully
*/
public static boolean handleTransport(Transport transport) {
WorldPoint dest = transport.getDestination();
MagicMushtree destination = getByDestination(dest);

if (destination == null) {
return false;
}

// Wait for the mushtree menu widget to appear
if (!sleepUntil(() -> Rs2Widget.hasWidget("Mycelium"), 5000)) {
return false;
}

// Click the destination option
if (!Rs2Widget.clickWidget(destination.getDestinationName())) {
return false;
}

// Wait until we arrive at destination
sleepUntil(() -> Rs2Player.getWorldLocation().distanceTo(dest) < OFFSET, 10000);
return true;
Comment on lines +76 to +78
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Return failure if arrival wait times out.

sleepUntil is ignored, so handleTransport can return success even when the teleport fails or times out. Return the boolean result instead.

Proposed fix
-		// Wait until we arrive at destination
-		sleepUntil(() -> Rs2Player.getWorldLocation().distanceTo(dest) < OFFSET, 10000);
-		return true;
+		// Wait until we arrive at destination
+		return sleepUntil(() -> Rs2Player.getWorldLocation().distanceTo(dest) < OFFSET, 10000);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Wait until we arrive at destination
sleepUntil(() -> Rs2Player.getWorldLocation().distanceTo(dest) < OFFSET, 10000);
return true;
// Wait until we arrive at destination
return sleepUntil(() -> Rs2Player.getWorldLocation().distanceTo(dest) < OFFSET, 10000);
🤖 Prompt for AI Agents
In
`@runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/MagicMushtree.java`
around lines 76 - 78, The code is ignoring sleepUntil's result so
handleTransport (in MagicMushtree.java) can return true even if the teleport
timed out; capture the boolean returned by sleepUntil(...) that uses
Rs2Player.getWorldLocation().distanceTo(dest) < OFFSET and return that boolean
instead of unconditionally returning true so callers get failure on timeout.

}

/**
* Gets the MagicMushtree enum by destination WorldPoint.
*/
public static MagicMushtree getByDestination(WorldPoint destination) {
if (destination == null) return null;

for (MagicMushtree mushtree : values()) {
WorldPoint dest = mushtree.getDestination();
if (dest.equals(destination)) {
return mushtree;
}
// Also match by X and Y only (ignore plane differences in destination matching)
if (dest.getX() == destination.getX() && dest.getY() == destination.getY()) {
return mushtree;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import net.runelite.api.gameval.VarbitID;
import net.runelite.client.plugins.microbot.Microbot;
import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment;
import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory;
import net.runelite.client.plugins.microbot.util.player.Rs2Player;

@Getter
Expand Down Expand Up @@ -128,7 +129,9 @@ public boolean hasRequirements() {
boolean isWearingCraftingGuild = (Rs2Equipment.isWearing("brown apron") || Rs2Equipment.isWearing("golden apron")) ||
(Rs2Equipment.isWearing("max cape") || Rs2Equipment.isWearing("max hood")) ||
(Rs2Equipment.isWearing("crafting cape") || Rs2Equipment.isWearing("crafting hood"));
return isWearingCraftingGuild && (hasMaxedCrafting || hasFaladorHardDiary);
// Also check if crafting cape is in inventory (can equip it to teleport and enter)
boolean hasCraftingCapeInInventory = Rs2Inventory.contains("crafting cape") || Rs2Inventory.contains("crafting cape(t)");
return (isWearingCraftingGuild || hasCraftingCapeInInventory) && (hasMaxedCrafting || hasFaladorHardDiary);
Comment on lines 129 to +134
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent handling of trimmed crafting cape between equipment and inventory checks.

The new inventory check on line 133 correctly handles both "crafting cape" and "crafting cape(t)", but the equipment check on line 131 only checks for "crafting cape". This means a player wearing "crafting cape(t)" would fail the equipment check but pass if they put the same cape in their inventory.

🔧 Proposed fix for consistency
                boolean isWearingCraftingGuild = (Rs2Equipment.isWearing("brown apron") || Rs2Equipment.isWearing("golden apron")) ||
                        (Rs2Equipment.isWearing("max cape") || Rs2Equipment.isWearing("max hood")) ||
-                       (Rs2Equipment.isWearing("crafting cape") || Rs2Equipment.isWearing("crafting hood"));
+                       (Rs2Equipment.isWearing("crafting cape") || Rs2Equipment.isWearing("crafting cape(t)") || Rs2Equipment.isWearing("crafting hood"));
🤖 Prompt for AI Agents
In
`@runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/bank/enums/BankLocation.java`
around lines 129 - 134, The equipment check in BankLocation (variable
isWearingCraftingGuild) only calls Rs2Equipment.isWearing("crafting cape") while
the inventory check handles both "crafting cape" and "crafting cape(t)"; update
the equipment condition to also check Rs2Equipment.isWearing("crafting cape(t)")
(or extract a helper like isWearingOrInInventoryCraftingCape) so both equipment
and inventory checks treat trimmed capes consistently; modify the expression in
isWearingCraftingGuild to include the additional
Rs2Equipment.isWearing("crafting cape(t)") check.

case LUMBRIDGE_BASEMENT:
return Rs2Player.getQuestState(Quest.RECIPE_FOR_DISASTER__ANOTHER_COOKS_QUEST) == QuestState.FINISHED;
case COOKS_GUILD:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public boolean execute() {
return false;
}
if (pendant.getId() == objectId) {
//The correct id for the object means it has the right left click option, so we can just use that.
// The correct id for the object means it has the right left click option, so we can just use that.
return Rs2GameObject.interact(pendant, destinationName);
}
Widget widget = getWidget();
Expand All @@ -49,6 +49,10 @@ public boolean execute() {
return Rs2Widget.clickWidget(destinationName);
}

private static Widget getWidget() {
return Rs2Widget.getWidget(InterfaceID.MENU, 3);
}

public static final Integer[] IDS = {ObjectID.POH_AMULET_DIGSITE, ObjectID.POH_AMULET_DIG_LITHKREN, ObjectID.POH_AMULET_DIG_FOSSIL, ObjectID.POH_AMULET_DIG_DIGSITE};

public static DecorativeObject getObject() {
Expand All @@ -63,10 +67,6 @@ public static boolean isMountedDigsite(DecorativeObject go) {
return false;
}

private static Widget getWidget() {
return Rs2Widget.getWidget(InterfaceID.MENU, 3);
}

@Override
public String displayInfo() {
return "MountedDigsite -> " + destinationName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1605,9 +1605,8 @@ private static boolean handleTransports(List<WorldPoint> path, int indexOfStartP
}

if (object != null) {
System.out.println("Object Type: " + Rs2GameObject.getObjectType(object));

if (!(object instanceof GroundObject)) {
// Skip reachability check for GroundObjects and Magic Mushtrees
if (!(object instanceof GroundObject) && !MagicMushtree.isMagicMushtree(transport.getObjectId())) {
if (!Rs2Tile.isTileReachable(transport.getOrigin())) {
break;
}
Expand Down Expand Up @@ -1811,6 +1810,11 @@ private static boolean handleObjectExceptions(Transport transport, TileObject ti
sleepUntil(() -> Rs2Player.getWorldLocation().distanceTo2D(transport.getDestination()) < OFFSET, 10000);
return true;
}

// Handle Magic Mushtree (Fossil Island Mycelium Transportation System)
if (MagicMushtree.isMagicMushtree(tileObject)) {
return MagicMushtree.handleTransport(transport);
}
return false;
}

Expand Down Expand Up @@ -1925,6 +1929,18 @@ private static boolean handleInventoryTeleports(Transport transport, int itemId)

if (itemAction.equalsIgnoreCase("open") && itemId == ItemID.BOOKOFSCROLLS_CHARGED) {
return handleMasterScrollBook(destination);
} else if (isDialogueBasedTeleportItem(transport.getDisplayInfo())) {
// Multi-destination teleport items: wait for destination selection dialogue
Rs2Dialogue.sleepUntilSelectAnOption();
Rs2Dialogue.clickOption(destination);
log.info("Traveling to {} - ({})", transport.getDisplayInfo(), transport.getDestination());
return true;
} else if (transport.getDisplayInfo().toLowerCase().contains("burning amulet")) {
// Burning amulet in inventory: confirm wilderness teleport
Rs2Dialogue.sleepUntilInDialogue();
Rs2Dialogue.clickOption("Okay, teleport to level");
log.info("Traveling to {} - ({})", transport.getDisplayInfo(), transport.getDestination());
return true;
} else if (wildernessTransport) {
Rs2Dialogue.sleepUntilInDialogue();
return Rs2Dialogue.clickOption("Yes", "Okay");
Expand Down Expand Up @@ -1960,6 +1976,28 @@ private static boolean handleWearableTeleports(Transport transport, int itemId)
return false;
}

/**
* Checks if the teleport item requires dialogue-based destination selection.
* These are items that, when rubbed/activated, show a dialogue menu to choose destination.
*
* @param displayInfo the displayInfo from the transport
* @return true if the item requires dialogue handling
*/
private static boolean isDialogueBasedTeleportItem(String displayInfo) {
if (displayInfo == null) return false;
String lowerDisplayInfo = displayInfo.toLowerCase();
return lowerDisplayInfo.contains("slayer ring")
|| lowerDisplayInfo.contains("games necklace")
|| lowerDisplayInfo.contains("skills necklace")
|| lowerDisplayInfo.contains("ring of dueling")
|| lowerDisplayInfo.contains("ring of wealth")
|| lowerDisplayInfo.contains("amulet of glory")
|| lowerDisplayInfo.contains("combat bracelet")
|| lowerDisplayInfo.contains("digsite pendant")
|| lowerDisplayInfo.contains("necklace of passage")
|| lowerDisplayInfo.contains("giantsoul amulet");
}

/**
* Checks if the player's current location is within the specified area defined by the given world points.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,24 @@
3666 3809 0 3685 3756 0 Jump on;Rubber cap mushroom;30606
3663 3808 0 3685 3756 0 Jump on;Rubber cap mushroom;30606
3664 3808 0 3685 3756 0 Jump on;Rubber cap mushroom;30606
3665 3808 0 3685 3756 0 Jump on;Rubber cap mushroom;30606
3665 3808 0 3685 3756 0 Jump on;Rubber cap mushroom;30606
# Magic Mushtree - Fossil Island Mycelium Transportation System
# House on the Hill mushtree (ID 30920)
3764 3880 1 3760 3758 0 Use;Magic Mushtree;30920
3764 3880 1 3676 3755 0 Use;Magic Mushtree;30920
3764 3880 1 3676 3871 0 Use;Magic Mushtree;30920
# Verdant Valley mushtree (ID 30924)
3758 3756 0 3764 3879 1 Use;Magic Mushtree;30924
3758 3756 0 3676 3755 0 Use;Magic Mushtree;30924
3758 3756 0 3676 3871 0 Use;Magic Mushtree;30924
# Sticky Swamp mushtree (ID 30924)
3677 3755 0 3764 3879 1 Use;Magic Mushtree;30924
3677 3755 0 3760 3758 0 Use;Magic Mushtree;30924
3677 3755 0 3676 3871 0 Use;Magic Mushtree;30924
# Mushroom Meadow mushtree (ID 30924)
3674 3871 0 3764 3879 1 Use;Magic Mushtree;30924
3674 3871 0 3760 3758 0 Use;Magic Mushtree;30924
3674 3871 0 3676 3755 0 Use;Magic Mushtree;30924
3768 3868 1 3768 3868 0 Climb-down;Trapdoor;30725
3768 3868 0 3768 3868 1 Climb-up;Ladder;30727
3767 3868 1 3768 3868 0 Climb-down;Trapdoor;30725
Expand Down Expand Up @@ -1544,33 +1561,62 @@
2775 3234 1 2776 3235 0 Climb-down;Ship's ladder;9745
2808 3162 0 2808 3162 1 Climb-up;Ladder;16683 3
2808 3162 1 2808 3162 0 Climb-down;Ladder;16679 3
2743 3153 0 2713 9564 0 Enter;Dungeon entrance;34713 875 Coins
2714 9564 0 2743 3153 0 Leave;Exit;20878
2691 9564 0 2689 9564 0 Chop-down;Vines;21731 1351;1349;1361;1353;1355;1357;1359
2689 9564 0 2691 9564 0 Chop-down;Vines;21731 1351;1349;1361;1353;1355;1357;1359
2683 9568 0 2683 9570 0 Chop-down;Vines;21732 1351;1349;1361;1353;1355;1357;1359
2683 9570 0 2683 9568 0 Chop-down;Vines;21732 1351;1349;1361;1353;1355;1357;1359
2674 9479 0 2676 9479 0 Chop-down;Vines;21734 1351;1349;1361;1353;1355;1357;1359
2676 9479 0 2674 9479 0 Chop-down;Vines;21734 1351;1349;1361;1353;1355;1357;1359
2693 9482 0 2695 9482 0 Chop-down;Vines;21735 1351;1349;1361;1353;1355;1357;1359
2695 9482 0 2693 9482 0 Chop-down;Vines;21735 1351;1349;1361;1353;1355;1357;1359
2649 9591 0 2643 9595 2 Walk-up;Stairs;21722
2650 9591 0 2643 9595 2 Walk-up;Stairs;21722
2643 9595 2 2649 9591 0 Walk-down;Stairs;21724
2647 9557 0 2649 9562 0 Jump-from;Stepping Stone;21739 3
2649 9562 0 2647 9557 0 Jump-from;Stepping Stone;21738 3
2636 9517 0 2636 9510 2 Walk-up;Stairs;21725
2637 9517 0 2636 9510 2 Walk-up;Stairs;21725
2636 9510 2 2636 9517 0 Walk-down;Stairs;21726
2682 9506 0 2687 9506 0 Walk-across;Log balance;20882 3
2687 9506 0 2682 9506 0 Walk-across;Log balance;20884 3
2698 9500 0 2698 9492 0 Squeeze-through;Pipe;21727
2698 9492 0 2698 9500 0 Squeeze-through;Pipe;21727
2697 9436 0 2684 9436 0 Enter;Crevice;30198
# Main Entrance - ID 20877
# With coin requirement (875 coins for entry)
2744 3154 0 2713 9564 0 Enter;Dungeon entrance;20877 875 Coins
2744 3153 0 2713 9564 0 Enter;Dungeon entrance;20877 875 Coins
2745 3154 0 2713 9564 0 Enter;Dungeon entrance;20877 875 Coins
2743 3154 0 2713 9564 0 Enter;Dungeon entrance;20877 875 Coins
# Permanent access (after paying 1.5m one-time fee)
2744 3154 0 2713 9564 0 Enter;Dungeon entrance;20877
2744 3153 0 2713 9564 0 Enter;Dungeon entrance;20877
2745 3154 0 2713 9564 0 Enter;Dungeon entrance;20877
2743 3154 0 2713 9564 0 Enter;Dungeon entrance;20877
# Exit from inside
2713 9564 0 2744 3153 0 Leave;Exit;20878
# Vines (axe IDs: bronze, iron, steel, black, mithril, adamant, rune, dragon, 3rd age, infernal, crystal)
2689 9564 0 2691 9564 0 Chop-down;Vines;21731 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2691 9564 0 2689 9564 0 Chop-down;Vines;21731 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2683 9568 0 2683 9570 0 Chop-down;Vines;21732 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2683 9570 0 2683 9568 0 Chop-down;Vines;21732 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2674 9499 0 2672 9499 0 Chop-down;Vines;21733 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2672 9499 0 2674 9499 0 Chop-down;Vines;21733 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2676 9479 0 2674 9479 0 Chop-down;Vines;21734 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2674 9479 0 2676 9479 0 Chop-down;Vines;21734 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2693 9482 0 2695 9482 0 Chop-down;Vines;21735 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
2695 9482 0 2693 9482 0 Chop-down;Vines;21735 1351;1349;1353;1361;1355;1357;1359;6739;20011;13241;23673;25066;28222
# 87 Agility Vine Shortcut
2673 9583 0 2670 9583 2 Climb;Vine;26880
2670 9583 2 2673 9583 0 Climb;Vine;26882
# Stairs
2649 9591 0 2643 9595 2 Walk-up;Stairs;21722
2643 9595 2 2649 9591 0 Walk-down;Stairs;21724
2636 9517 0 2636 9510 2 Walk-up;Stairs;21725
2636 9510 2 2636 9517 0 Walk-down;Stairs;21726
# Stepping Stones
2647 9557 0 2649 9562 0 Jump-from;Stepping stone;21739
2649 9562 0 2647 9557 0 Jump-from;Stepping stone;21738
2695 9533 0 2697 9525 0 Cross;Stepping stone;19040
2697 9525 0 2695 9533 0 Cross;Stepping stone;19040
2690 9547 0 2682 9548 0 Cross;Stepping stone;19040
2682 9548 0 2690 9547 0 Cross;Stepping stone;19040
# Log Balance
2682 9506 0 2687 9506 0 Walk-across;Log balance;20882
2687 9506 0 2682 9506 0 Walk-across;Log balance;20884
# Pipes
2698 9500 0 2698 9492 0 Squeeze-through;Pipe;21727
2698 9492 0 2698 9500 0 Squeeze-through;Pipe;21727
2655 9573 0 2655 9566 0 Squeeze-through;Pipe;21728
2655 9566 0 2655 9573 0 Squeeze-through;Pipe;21728
# Crevice
2684 9436 0 2697 9436 0 Enter;Crevice;30198
2697 9436 0 2684 9436 0 Enter;Crevice;30198
# Brimhaven Dungeon - CKR Fairy Ring Alternate Entrance
2759 3062 0 2734 9478 0 Climb-down;Rope;30200
2734 9477 0 2761 3062 0 Enter;Crevice;30201
2761 3062 0 2734 9478 0 Climb;Rope;66
2761 3063 0 2734 9478 0 Climb;Rope;66
2760 3064 0 2734 9478 0 Climb;Rope;66
2760 3061 0 2734 9478 0 Climb;Rope;66
2734 9478 0 2760 3061 0 Use;Crevice;30201

# Karamja Volcano
2855 3169 0 2855 9569 0 Climb-down;Rocks;11441
Expand Down Expand Up @@ -5195,7 +5241,6 @@
3066 3741 0 3187 10127 0 Jump-Down;Crevice;40386
3066 3740 0 3187 10127 0 Jump-Down;Crevice;40386
3066 3739 0 3187 10127 0 Jump-Down;Crevice;40386

# CRASH SITE
2026 5611 0 2128 5647 0 Enter;Cavern Entrance;28686
2128 5647 0 2026 5611 0 Climb-up;Rope;28687
Expand All @@ -5205,11 +5250,9 @@
2167 9308 0 2310 2919 0 Exit;Opening;40737
2763 2951 0 2763 2951 1 Climb-up;Ladder;16683
2763 2952 1 2763 2951 0 Climb-down;Ladder;16679

# woodcutting guild
1574 3483 1 1575 3483 0 Climb-down;Rope ladder;28858
1575 3483 0 1574 3483 1 Climb-up;Rope ladder;28857

#Grimstone Dungeon
2902 10454 0 2902 10456 0 Climb;Uneven stone ledges;60120
2902 10456 0 2902 10454 0 Climb;Uneven stone ledges;60120
2902 10456 0 2902 10454 0 Climb;Uneven stone ledges;60120