Skip to content
Merged
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
Expand Up @@ -16,6 +16,9 @@
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.npc.Rs2Npc;
import net.runelite.client.plugins.microbot.util.npc.Rs2NpcModel;
import net.runelite.client.plugins.microbot.util.magic.Rs2Magic;
import net.runelite.client.plugins.skillcalculator.skills.MagicAction;
import net.runelite.client.plugins.microbot.util.player.Rs2Player;
import net.runelite.client.plugins.microbot.util.walker.Rs2Walker;
import net.runelite.client.plugins.microbot.agility.courses.PyramidObstacleData.ObstacleArea;
Expand Down Expand Up @@ -1157,7 +1160,7 @@ private boolean handlePyramidTurnIn() {
}
} else {
// Not in dialogue, use pyramid top on Simon
boolean used = Rs2Inventory.useItemOnNpc(ItemID.PYRAMID_TOP, simon);
boolean used = Rs2Inventory.useItemOnNpc(ItemID.PYRAMID_TOP, new Rs2NpcModel(simon));
if (used) {
log.debug("Successfully used pyramid top on Simon");
Global.sleepUntil(() -> Rs2Dialogue.isInDialogue(), 3000);
Expand Down Expand Up @@ -1197,19 +1200,35 @@ private boolean handlePyramidTurnIn() {
return false;
}
}

/**
* Checks for empty waterskins in inventory and drops them
* @return true if waterskins were dropped, false otherwise
*/


private boolean handleEmptyWaterskins() {
if (Rs2Inventory.contains(ItemID.WATERSKIN0)) {
log.debug("Found empty waterskin(s), dropping them");
Rs2Inventory.drop(ItemID.WATERSKIN0);
Global.sleep(300, 500);
final boolean hasEmpty = Rs2Inventory.contains(ItemID.WATERSKIN0);
if (!hasEmpty) return false;

final boolean hasFilled = Rs2Inventory.contains(
ItemID.WATERSKIN1, ItemID.WATERSKIN2, ItemID.WATERSKIN3, ItemID.WATERSKIN4
);

if (!hasFilled && Rs2Magic.canCast(MagicAction.HUMIDIFY)) {
log.debug("All waterskins are empty; casting Humidify");
if (Rs2Magic.cast(MagicAction.HUMIDIFY)) {
Global.sleepUntil(Rs2Player::isAnimating, 1500);
Global.sleepUntil(() -> !Rs2Player.isAnimating() && !Rs2Inventory.contains(ItemID.WATERSKIN0), 3500);
Global.sleep(200, 400);
}
return true;
}
return false;

if (hasFilled && Rs2Magic.canCast(MagicAction.HUMIDIFY)) {
log.debug("Have filled waterskin(s); not casting Humidify because not all Waterskins are empty");
return false;
}

log.debug("Cannot cast Humidify; dropping empty waterskin(s)");
Rs2Inventory.drop(ItemID.WATERSKIN0);
Global.sleep(300, 500);
return true;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public boolean run() {
Rs2Inventory.waitForInventoryChanges(1800);
}

if (plugin.getJewelry().getGem() != null) {
if (plugin.getJewelry().getGem() != Gem.NONE) {
Rs2Bank.withdrawX(plugin.getJewelry().getGem().getCutItemID(), withdrawAmount);
Rs2Inventory.waitForInventoryChanges(1800);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public enum Jewelry {
GOLD_NECKLACE("gold necklace", ItemID.GOLD_NECKLACE, Gem.NONE, ItemID.NECKLACE_MOULD, JewelryType.GOLD, null, 6),
GOLD_BRACELET("gold bracelet", ItemID.GOLD_BRACELET, Gem.NONE, ItemID.BRACELET_MOULD, JewelryType.GOLD, null, 7),
GOLD_AMULET("gold amulet", ItemID.GOLD_AMULET_U, Gem.NONE, ItemID.AMULET_MOULD, JewelryType.GOLD, null, 8),
TIARA("tiara", ItemID.TIARA, Gem.NONE, ItemID.TIARA_MOULD, JewelryType.SILVER, null, 23),
UNSTRUNG_SYMBOL("holy symbol", ItemID.UNSTRUNG_SYMBOL, Gem.NONE, ItemID.HOLY_MOULD, JewelryType.SILVER, null, 16),
OPAL_RING("opal ring", ItemID.OPAL_RING, Gem.OPAL, ItemID.RING_MOULD, JewelryType.SILVER, EnchantSpell.LEVEL_1, 1),
Comment on lines +18 to 20
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

Wrong display name for UNSTRUNG_SYMBOL breaks widget clicks.

Crafting widget button is “unstrung symbol”; using “holy symbol” will likely fail selection.

-    UNSTRUNG_SYMBOL("holy symbol", ItemID.UNSTRUNG_SYMBOL, Gem.NONE, ItemID.HOLY_MOULD, JewelryType.SILVER, null, 16),
+    UNSTRUNG_SYMBOL("unstrung symbol", ItemID.UNSTRUNG_SYMBOL, Gem.NONE, ItemID.HOLY_MOULD, JewelryType.SILVER, null, 16),
📝 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
TIARA("tiara", ItemID.TIARA, Gem.NONE, ItemID.TIARA_MOULD, JewelryType.SILVER, null, 23),
UNSTRUNG_SYMBOL("holy symbol", ItemID.UNSTRUNG_SYMBOL, Gem.NONE, ItemID.HOLY_MOULD, JewelryType.SILVER, null, 16),
OPAL_RING("opal ring", ItemID.OPAL_RING, Gem.OPAL, ItemID.RING_MOULD, JewelryType.SILVER, EnchantSpell.LEVEL_1, 1),
TIARA("tiara", ItemID.TIARA, Gem.NONE, ItemID.TIARA_MOULD, JewelryType.SILVER, null, 23),
UNSTRUNG_SYMBOL("unstrung symbol", ItemID.UNSTRUNG_SYMBOL, Gem.NONE, ItemID.HOLY_MOULD, JewelryType.SILVER, null, 16),
OPAL_RING("opal ring", ItemID.OPAL_RING, Gem.OPAL, ItemID.RING_MOULD, JewelryType.SILVER, EnchantSpell.LEVEL_1, 1),
🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/crafting/jewelry/enums/Jewelry.java
around lines 18 to 20, the UNSTRUNG_SYMBOL enum uses the display name "holy
symbol" which doesn't match the crafting widget text "unstrung symbol" and
prevents correct widget clicks; update the enum entry to use the exact display
name "unstrung symbol" (replace "holy symbol") so selection matches the UI, and
run a quick search for any other references expecting the old display name to
update them accordingly.

OPAL_NECKLACE("opal necklace", ItemID.OPAL_NECKLACE, Gem.OPAL, ItemID.NECKLACE_MOULD, JewelryType.SILVER, EnchantSpell.LEVEL_1, 16),
OPAL_BRACELET("opal bracelet", ItemID.OPAL_BRACELET, Gem.OPAL, ItemID.BRACELET_MOULD, JewelryType.SILVER, EnchantSpell.LEVEL_1, 22),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,19 @@ AIOMagicConfig provideConfig(ConfigManager configManager) {
private SuperHeatScript superHeatScript;

@Inject
private TeleportScript teleportScript;
private TeleportScript teleportScript;

@Inject
private TeleAlchScript teleAlchScript;
private TeleAlchScript teleAlchScript;

@Inject
private StunAlchScript stunAlchScript;
private StunAlchScript stunAlchScript;

@Inject
private StunTeleAlchScript stunTeleAlchScript; // NEW
private StunTeleAlchScript stunTeleAlchScript; // NEW

@Inject
private SpinFlaxScript spinFlaxScript;

public static String version = "1.2.0"; // bumped

Expand Down Expand Up @@ -108,41 +111,45 @@ protected void startUp() throws AWTException {
overlayManager.add(aioMagicOverlay);
}

switch (config.magicActivity()) {
case SPLASHING:
splashScript.run();
break;
case ALCHING:
alchScript.run();
break;
case SUPERHEAT:
superHeatScript.run();
break;
case TELEPORT:
teleportScript.run();
break;
case TELEALCH:
teleAlchScript.run();
break;
case STUNALCH:
stunAlchScript.run();
break;
case STUNTELEALCH: // NEW
stunTeleAlchScript.run();
break;
}
}

protected void shutDown() {
splashScript.shutdown();
alchScript.shutdown();
superHeatScript.shutdown();
teleportScript.shutdown();
teleAlchScript.shutdown();
stunAlchScript.shutdown();
if (stunTeleAlchScript != null) stunTeleAlchScript.shutdown(); // NEW
overlayManager.remove(aioMagicOverlay);
}
switch (config.magicActivity()) {
case SPLASHING:
splashScript.run();
break;
case ALCHING:
alchScript.run();
break;
case SUPERHEAT:
superHeatScript.run();
break;
case TELEPORT:
teleportScript.run();
break;
case TELEALCH:
teleAlchScript.run();
break;
case STUNALCH:
stunAlchScript.run();
break;
case STUNTELEALCH: // NEW
stunTeleAlchScript.run();
break;
case SPINFLAX:
spinFlaxScript.run();
break;
}
}

protected void shutDown() {
splashScript.shutdown();
alchScript.shutdown();
superHeatScript.shutdown();
teleportScript.shutdown();
teleAlchScript.shutdown();
stunAlchScript.shutdown();
if (stunTeleAlchScript != null) stunTeleAlchScript.shutdown(); // NEW
if (spinFlaxScript != null) spinFlaxScript.shutdown();
overlayManager.remove(aioMagicOverlay);
}

@Subscribe
public void onConfigChanged(ConfigChanged event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public enum MagicActivity {
TELEALCH,
STUNALCH,
STUNTELEALCH, // NEW
SPINFLAX,
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public boolean run() {
}

if (!Rs2Magic.hasRequiredRunes(plugin.getAlchSpell())) {
Microbot.log("Unable to cast alchemy spell");
Microbot.showMessage("Out of runes for alchemy");
shutdown();
return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package net.runelite.client.plugins.microbot.magic.aiomagic.scripts;

import net.runelite.api.Skill;
import net.runelite.api.gameval.ItemID;
import net.runelite.client.plugins.microbot.Microbot;
import net.runelite.client.plugins.microbot.Script;
import net.runelite.client.plugins.microbot.magic.aiomagic.AIOMagicPlugin;
import net.runelite.client.plugins.microbot.magic.aiomagic.enums.MagicState;
import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban;
import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings;
import net.runelite.client.plugins.microbot.util.antiban.enums.Activity;
import net.runelite.client.plugins.microbot.util.bank.Rs2Bank;
import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory;
import net.runelite.client.plugins.microbot.util.magic.Rs2Magic;
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.player.Rs2Player;

import javax.inject.Inject;
import java.util.concurrent.TimeUnit;

public class SpinFlaxScript extends Script {

private MagicState state;
private int castsDone;

private final AIOMagicPlugin plugin;

@Inject
public SpinFlaxScript(AIOMagicPlugin plugin) {
this.plugin = plugin;
}

public boolean run() {
Microbot.enableAutoRunOn = false;
Rs2Antiban.resetAntibanSettings();
Rs2Antiban.antibanSetupTemplates.applyGeneralBasicSetup();
Rs2AntibanSettings.simulateAttentionSpan = true;
Rs2AntibanSettings.nonLinearIntervals = true;
Rs2AntibanSettings.contextualVariability = true;
Rs2AntibanSettings.usePlayStyle = true;
Rs2Antiban.setActivity(Activity.CASTING_SPIN_FLAX);

mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
if (!Microbot.isLoggedIn()) return;
if (!super.run()) return;

if (!Rs2Player.getSkillRequirement(Skill.MAGIC, 76)) {
Microbot.showMessage("Spin Flax requires 76 Magic.");
shutdown();
return;
}

if (state == null) {
state = MagicState.BANKING;
castsDone = 0;
}

switch (state) {
case BANKING:
Microbot.status = "Banking: prepare 25 flax";
boolean isBankOpen = Rs2Bank.isNearBank(15) ? Rs2Bank.useBank() : Rs2Bank.walkToBankAndUseBank();
if (!isBankOpen || !Rs2Bank.isOpen()) return;

Rs2Bank.depositAll(ItemID.BOW_STRING);
Rs2Inventory.waitForInventoryChanges(1200);

boolean hasAstralInv = Rs2Inventory.hasItem(Runes.ASTRAL.getItemId());
boolean hasNatureInv = Rs2Inventory.hasItem(Runes.NATURE.getItemId());
boolean hasAirInv = Rs2Inventory.hasItem(Runes.AIR.getItemId());

boolean hasAstralBank = Rs2Bank.hasItem(Runes.ASTRAL.getItemId());
boolean hasNatureBank = Rs2Bank.hasItem(Runes.NATURE.getItemId());
boolean hasAirBank = Rs2Bank.hasItem(Runes.AIR.getItemId());

if (!hasAstralBank && !hasAstralInv) { Microbot.showMessage("Astral runes not found in bank."); shutdown(); return; }
if (!hasNatureBank && !hasNatureInv) { Microbot.showMessage("Nature runes not found in bank."); shutdown(); return; }
if (!hasAirBank && !hasAirInv) { Microbot.showMessage("Air runes not found in bank."); shutdown(); return; }

if (hasAstralBank) { if (!Rs2Bank.withdrawAll(Runes.ASTRAL.getItemId())) return; Rs2Inventory.waitForInventoryChanges(1200); }
if (hasNatureBank) { if (!Rs2Bank.withdrawAll(Runes.NATURE.getItemId())) return; Rs2Inventory.waitForInventoryChanges(1200); }
if (hasAirBank) { if (!Rs2Bank.withdrawAll(Runes.AIR.getItemId())) return; Rs2Inventory.waitForInventoryChanges(1200); }

Comment on lines +69 to +84
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

Critical: False shutdown when runes are in rune pouch

The early rune checks only consider inventory/bank and ignore the rune pouch. Players with runes in the pouch will get an unnecessary shutdown despite being able to cast. Use Rs2Magic.hasRequiredRunes(...) (which already accounts for inventory/equipment/pouch) to decide shutdown vs. withdrawal.

Apply this diff to make the bank step pouch-aware and only stop when neither local sources nor bank can satisfy runes:

-                        boolean hasAstralInv = Rs2Inventory.hasItem(Runes.ASTRAL.getItemId());
-                        boolean hasNatureInv = Rs2Inventory.hasItem(Runes.NATURE.getItemId());
-                        boolean hasAirInv = Rs2Inventory.hasItem(Runes.AIR.getItemId());
-
+                        boolean haveRunesLocal = Rs2Magic.hasRequiredRunes(Rs2Spells.SPIN_FLAX);
                         boolean hasAstralBank = Rs2Bank.hasItem(Runes.ASTRAL.getItemId());
                         boolean hasNatureBank = Rs2Bank.hasItem(Runes.NATURE.getItemId());
                         boolean hasAirBank = Rs2Bank.hasItem(Runes.AIR.getItemId());
 
-                        if (!hasAstralBank && !hasAstralInv) { Microbot.showMessage("Astral runes not found in bank."); shutdown(); return; }
-                        if (!hasNatureBank && !hasNatureInv) { Microbot.showMessage("Nature runes not found in bank."); shutdown(); return; }
-                        if (!hasAirBank && !hasAirInv) { Microbot.showMessage("Air runes not found in bank."); shutdown(); return; }
+                        if (!haveRunesLocal && !hasAstralBank && !hasNatureBank && !hasAirBank) {
+                            Microbot.showMessage("Spin Flax: no required runes in inventory/equipment/pouch or bank. Stopping.");
+                            shutdown();
+                            return;
+                        }
 
                         if (hasAstralBank) { if (!Rs2Bank.withdrawAll(Runes.ASTRAL.getItemId())) return; Rs2Inventory.waitForInventoryChanges(1200); }
                         if (hasNatureBank) { if (!Rs2Bank.withdrawAll(Runes.NATURE.getItemId())) return; Rs2Inventory.waitForInventoryChanges(1200); }
                         if (hasAirBank)    { if (!Rs2Bank.withdrawAll(Runes.AIR.getItemId())) return;    Rs2Inventory.waitForInventoryChanges(1200); }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
runelite-client/src/main/java/net/runelite/client/plugins/microbot/magic/aiomagic/scripts/SpinFlaxScript.java
around lines 69 to 84, the code checks only inventory and bank for
astral/nature/air runes and performs a shutdown even if the player has runes in
the pouch; replace those inventory-only prechecks with a single check using
Rs2Magic.hasRequiredRunes(...) which accounts for inventory, equipment and rune
pouch to decide whether to continue or shutdown; if
Rs2Magic.hasRequiredRunes(...) returns false then check the bank for required
runes and withdraw them (as the current withdraw calls do), otherwise skip
shutdown/withdrawal because the pouch covers the requirement; ensure the
shutdown occurs only when neither Rs2Magic.hasRequiredRunes(...) nor the bank
can supply the runes.

if (!Rs2Bank.hasBankItem(ItemID.FLAX, 1)) {
Microbot.showMessage("No flax in bank.");
shutdown();
return;
}

int empty = Rs2Inventory.emptySlotCount();
if (empty < 25) {
Rs2Bank.depositAll(ItemID.BOW_STRING);
Rs2Inventory.waitForInventoryChanges(1200);
empty = Rs2Inventory.emptySlotCount();
if (empty < 25) return; // wait next tick
}

if (!Rs2Bank.withdrawX(ItemID.FLAX, 25)) return;
Rs2Inventory.waitForInventoryChanges(1200);

Rs2Bank.closeBank();
castsDone = 0;
state = MagicState.CASTING;
break;

case CASTING:
Microbot.status = "Casting: Spin Flax (" + castsDone + "/5)";

if (!Rs2Inventory.hasItem(ItemID.FLAX)) {
state = MagicState.BANKING;
break;
}

if (!Rs2Magic.hasRequiredRunes(Rs2Spells.SPIN_FLAX)) {
Microbot.showMessage("Out of runes for Spin Flax");
shutdown();
return;
}

if (castsDone >= 5) {
state = MagicState.BANKING;
break;
}

if (!Rs2Magic.cast(Rs2Spells.SPIN_FLAX)) {
Microbot.log("Unable to cast Spin Flax");
state = MagicState.BANKING;
break;
}
Rs2Player.waitForXpDrop(Skill.MAGIC, 10000, false);
castsDone++;
break;
}

} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}, 0, 1000, TimeUnit.MILLISECONDS);
return true;
}

@Override
public void shutdown() {
Rs2Antiban.resetAntibanSettings();
super.shutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ public boolean run() {
if (!super.run()) return;
long startTime = System.currentTimeMillis();

if (!Rs2Magic.canCast(plugin.getCombatSpell().getMagicAction())) {
Microbot.showMessage("Out of runes for " + plugin.getCombatSpell().name());
shutdown();
return;
}
Comment on lines +43 to +47
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

Don’t use canCast() to gate “out of runes” shutdown; it conflates UI/spellbook/level with rune shortage

canCast(MagicAction) can fail for reasons other than runes (e.g., wrong spellbook/UI state), causing premature shutdown with a misleading message. Check runes explicitly.

Use a rune-only check and keep autocast setup logic intact:

-                if (!Rs2Magic.canCast(plugin.getCombatSpell().getMagicAction())) {
-                    Microbot.showMessage("Out of runes for " + plugin.getCombatSpell().name());
-                    shutdown();
-                    return;
-                }
+                if (!Rs2Magic.hasRequiredRunes(plugin.getCombatSpell().getRs2Spell())) {
+                    Microbot.showMessage("Out of runes for " + plugin.getCombatSpell().name());
+                    shutdown();
+                    return;
+                }
📝 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
if (!Rs2Magic.canCast(plugin.getCombatSpell().getMagicAction())) {
Microbot.showMessage("Out of runes for " + plugin.getCombatSpell().name());
shutdown();
return;
}
if (!Rs2Magic.hasRequiredRunes(plugin.getCombatSpell().getRs2Spell())) {
Microbot.showMessage("Out of runes for " + plugin.getCombatSpell().name());
shutdown();
return;
}


if (Rs2Magic.getCurrentAutoCastSpell() != plugin.getCombatSpell()) {
Rs2Combat.setAutoCastSpell(plugin.getCombatSpell(), false);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,14 @@ public boolean run() {
}

if (!Rs2Magic.hasRequiredRunes(plugin.getAlchSpell())) {
Microbot.log("Unable to cast alchemy spell");
Microbot.showMessage("Out of runes for alchemy");
shutdown();
return;
}

if (!Rs2Magic.hasRequiredRunes(plugin.getStunSpell().getRs2Spell())) {
Microbot.showMessage("Out of runes for " + plugin.getStunSpell().name());
shutdown();
return;
}

Expand Down
Loading