diff --git a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderConfig.java b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderConfig.java index 1160cdf67a..10335350c9 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderConfig.java +++ b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderConfig.java @@ -5,6 +5,7 @@ import net.runelite.client.config.ConfigInformation; import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigSection; +import net.runelite.client.config.Range; import net.runelite.client.plugins.microbot.autobankstander.processors.SkillType; import net.runelite.client.plugins.microbot.autobankstander.skills.magic.MagicMethod; import net.runelite.client.plugins.microbot.autobankstander.skills.magic.enchanting.BoltType; @@ -99,4 +100,58 @@ default HerblorePotion finishedPotion() { default boolean useAmuletOfChemistry() { return false; } + + @ConfigItem( + keyName = "herbloreTurboMode", + name = "Herblore turbo mode", + description = "Rapid-click the entire grimy-herb inventory (cleaning only). Less human-like.", + hidden = true + ) + default boolean herbloreTurboMode() { + return false; + } + + @ConfigItem( + keyName = "herbloreTurboLimit", + name = "Herblore turbo limit", + description = "Auto-disable turbo after this many herbs cleaned (0 = no limit).", + hidden = true + ) + @Range(min = 0, max = 10000) + default int herbloreTurboLimit() { + return 0; + } + + @ConfigItem( + keyName = "herbloreSleepMin", + name = "Herblore sleep min (ms)", + description = "Lower bound for Gaussian inter-batch sleep during cleaning.", + hidden = true + ) + @Range(min = 30, max = 1000) + default int herbloreSleepMin() { + return 60; + } + + @ConfigItem( + keyName = "herbloreSleepMax", + name = "Herblore sleep max (ms)", + description = "Upper bound for Gaussian inter-batch sleep during cleaning.", + hidden = true + ) + @Range(min = 100, max = 2000) + default int herbloreSleepMax() { + return 300; + } + + @ConfigItem( + keyName = "herbloreSleepTarget", + name = "Herblore sleep target (ms)", + description = "Target (mean anchor) for Gaussian inter-batch sleep during cleaning.", + hidden = true + ) + @Range(min = 50, max = 1500) + default int herbloreSleepTarget() { + return 150; + } } \ No newline at end of file diff --git a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderPlugin.java b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderPlugin.java index 612585110d..4566f6b33a 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderPlugin.java +++ b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderPlugin.java @@ -33,7 +33,7 @@ ) @Slf4j public class AutoBankStanderPlugin extends Plugin { - static final String version = "1.0.2"; + static final String version = "1.0.3"; @Inject private AutoBankStanderConfig config; diff --git a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderScript.java b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderScript.java index 3651c596d4..569f46d381 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderScript.java +++ b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/AutoBankStanderScript.java @@ -202,7 +202,12 @@ private BankStandingProcessor createProcessor() { configData.getCleanHerbMode(), configData.getUnfinishedPotionMode(), configData.getFinishedPotion(), - configData.isUseAmuletOfChemistry() + configData.isUseAmuletOfChemistry(), + configData.isHerbloreTurboMode(), + configData.getHerbloreTurboLimit(), + configData.getHerbloreSleepMin(), + configData.getHerbloreSleepMax(), + configData.getHerbloreSleepTarget() ); case FLETCHING: log.info("Entering fletching processor creation"); diff --git a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/config/ConfigData.java b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/config/ConfigData.java index 1377ec2504..d690a14ecf 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/config/ConfigData.java +++ b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/config/ConfigData.java @@ -32,6 +32,11 @@ public class ConfigData { private UnfinishedPotionMode unfinishedPotionMode = UnfinishedPotionMode.ANY_AND_ALL; private HerblorePotion finishedPotion = HerblorePotion.ATTACK; private boolean useAmuletOfChemistry = false; + private boolean herbloreTurboMode = false; + private int herbloreTurboLimit = 0; + private int herbloreSleepMin = 60; + private int herbloreSleepMax = 300; + private int herbloreSleepTarget = 150; // Fletching settings private FletchingMode fletchingMode = FletchingMode.DARTS; @@ -56,6 +61,11 @@ public ConfigData(ConfigData other) { this.unfinishedPotionMode = other.unfinishedPotionMode; this.finishedPotion = other.finishedPotion; this.useAmuletOfChemistry = other.useAmuletOfChemistry; + this.herbloreTurboMode = other.herbloreTurboMode; + this.herbloreTurboLimit = other.herbloreTurboLimit; + this.herbloreSleepMin = other.herbloreSleepMin; + this.herbloreSleepMax = other.herbloreSleepMax; + this.herbloreSleepTarget = other.herbloreSleepTarget; this.fletchingMode = other.fletchingMode; this.dartType = other.dartType; this.fletchingBoltType = other.fletchingBoltType; @@ -90,7 +100,22 @@ public ConfigData(ConfigData other) { public boolean isUseAmuletOfChemistry() { return useAmuletOfChemistry; } public void setUseAmuletOfChemistry(boolean useAmuletOfChemistry) { this.useAmuletOfChemistry = useAmuletOfChemistry; } - + + public boolean isHerbloreTurboMode() { return herbloreTurboMode; } + public void setHerbloreTurboMode(boolean herbloreTurboMode) { this.herbloreTurboMode = herbloreTurboMode; } + + public int getHerbloreTurboLimit() { return herbloreTurboLimit; } + public void setHerbloreTurboLimit(int herbloreTurboLimit) { this.herbloreTurboLimit = herbloreTurboLimit; } + + public int getHerbloreSleepMin() { return herbloreSleepMin; } + public void setHerbloreSleepMin(int herbloreSleepMin) { this.herbloreSleepMin = herbloreSleepMin; } + + public int getHerbloreSleepMax() { return herbloreSleepMax; } + public void setHerbloreSleepMax(int herbloreSleepMax) { this.herbloreSleepMax = herbloreSleepMax; } + + public int getHerbloreSleepTarget() { return herbloreSleepTarget; } + public void setHerbloreSleepTarget(int herbloreSleepTarget) { this.herbloreSleepTarget = herbloreSleepTarget; } + public FletchingMode getFletchingMode() { return fletchingMode; } public void setFletchingMode(FletchingMode fletchingMode) { this.fletchingMode = fletchingMode; } diff --git a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/skills/herblore/HerbloreProcessor.java b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/skills/herblore/HerbloreProcessor.java index fe1d64f2a3..837095713f 100644 --- a/src/main/java/net/runelite/client/plugins/microbot/autobankstander/skills/herblore/HerbloreProcessor.java +++ b/src/main/java/net/runelite/client/plugins/microbot/autobankstander/skills/herblore/HerbloreProcessor.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; import net.runelite.api.Skill; import net.runelite.api.gameval.ItemID; @@ -15,7 +17,9 @@ import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; 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.inventory.Rs2ItemModel; import net.runelite.client.plugins.microbot.util.inventory.InteractOrder; +import net.runelite.client.plugins.microbot.util.math.Rs2Random; import net.runelite.client.plugins.microbot.util.player.Rs2Player; import net.runelite.client.plugins.microbot.util.keyboard.Rs2Keyboard; import net.runelite.client.plugins.microbot.util.dialogues.Rs2Dialogue; @@ -33,23 +37,45 @@ public class HerbloreProcessor implements BankStandingProcessor { private UnfinishedPotionMode unfinishedPotionMode; private HerblorePotion finishedPotion; private boolean useAmuletOfChemistry; - + + // cleaning tuning (from recovered HerbloreScript) + private final boolean turboModeEnabled; + private final int turboHerbLimit; + private final int sleepMin; + private final int sleepMax; + private final int sleepTarget; + private boolean turboActive; + private int turboHerbsCleanedCount = 0; + private final Random sleepRandom = new Random(); + // processing state private Herb currentHerb; private Herb currentHerbForUnfinished; private HerblorePotion currentPotion; - private boolean currentlyMakingPotions; private int withdrawnAmount; private boolean amuletBroken = false; - - public HerbloreProcessor(Mode mode, CleanHerbMode cleanHerbMode, UnfinishedPotionMode unfinishedPotionMode, + + public HerbloreProcessor(Mode mode, CleanHerbMode cleanHerbMode, UnfinishedPotionMode unfinishedPotionMode, HerblorePotion finishedPotion, boolean useAmuletOfChemistry) { + this(mode, cleanHerbMode, unfinishedPotionMode, finishedPotion, useAmuletOfChemistry, + false, 0, 60, 300, 150); + } + + public HerbloreProcessor(Mode mode, CleanHerbMode cleanHerbMode, UnfinishedPotionMode unfinishedPotionMode, + HerblorePotion finishedPotion, boolean useAmuletOfChemistry, + boolean turboMode, int turboHerbLimit, + int sleepMin, int sleepMax, int sleepTarget) { this.mode = mode; this.cleanHerbMode = cleanHerbMode; this.unfinishedPotionMode = unfinishedPotionMode; this.finishedPotion = finishedPotion; this.useAmuletOfChemistry = useAmuletOfChemistry; - this.currentlyMakingPotions = false; + this.turboModeEnabled = turboMode; + this.turboHerbLimit = turboHerbLimit; + this.sleepMin = sleepMin; + this.sleepMax = sleepMax; + this.sleepTarget = sleepTarget; + this.turboActive = turboMode; this.withdrawnAmount = 0; } @@ -152,17 +178,6 @@ public boolean performBanking() { @Override public boolean process() { - if (currentlyMakingPotions) { - // check if we need to stop making potions - if (!hasRequiredItems()) { - log.info("Finished making - no more ingredients"); - currentlyMakingPotions = false; - return true; // return to banking - } - log.info("Still making potions - waiting for completion"); - return true; - } - switch (mode) { case CLEAN_HERBS: return processCleanHerbs(); @@ -196,10 +211,6 @@ public boolean canContinueProcessing() { @Override public String getStatusMessage() { - if (currentlyMakingPotions) { - return "Making potions..."; - } - switch (mode) { case CLEAN_HERBS: return "Cleaning herbs..."; @@ -332,14 +343,59 @@ private boolean bankForRegularPotion() { } private boolean processCleanHerbs() { - if (Rs2Inventory.hasItem("grimy")) { - log.info("Cleaning herbs using zigzag pattern"); - Rs2Inventory.cleanHerbs(InteractOrder.ZIGZAG); - sleepUntil(() -> !Rs2Inventory.hasItem("grimy"), 5000); + if (turboActive && turboHerbLimit > 0 && turboHerbsCleanedCount >= turboHerbLimit) { + log.info("Turbo auto-disabled after {} herbs (limit {})", turboHerbsCleanedCount, turboHerbLimit); + turboActive = false; + } + + if (!Rs2Inventory.hasItem("grimy")) { + log.info("No grimy herbs in inventory - returning to banking"); return true; } - log.info("No grimy herbs in inventory - returning to banking"); - return true; // return true to go back to banking for more herbs + + if (turboActive) { + cleanHerbsTurbo(); + } else { + cleanHerbsNormal(); + } + return true; + } + + private void cleanHerbsNormal() { + log.info("Cleaning herbs (normal, zigzag)"); + Rs2Inventory.cleanHerbs(InteractOrder.ZIGZAG); + sleepUntil(() -> !Rs2Inventory.hasItem("grimy"), 5000); + sleep(gaussianSleep()); + } + + private void cleanHerbsTurbo() { + List grimy = Rs2Inventory.items() + .filter(item -> item.getName() != null && item.getName().toLowerCase().contains("grimy")) + .collect(Collectors.toList()); + if (grimy.isEmpty()) return; + + log.info("Cleaning {} herbs (turbo)", grimy.size()); + List ordered = Rs2Inventory.calculateInteractOrder(grimy, InteractOrder.ZIGZAG); + for (Rs2ItemModel herb : ordered) { + if (herb == null || herb.getName() == null) continue; + if (!herb.getName().toLowerCase().contains("grimy")) continue; + Rs2Inventory.interact(herb, "Clean"); + turboHerbsCleanedCount++; + sleep(Rs2Random.between(5, 15)); + } + Rs2Inventory.waitForInventoryChanges(3000); + sleep(Rs2Random.between(50, 100)); + } + + private int gaussianSleep() { + double mean = (sleepMin + sleepMax + sleepTarget) / 3.0; + double std = Math.abs(sleepTarget - mean) / 3.0; + if (std <= 0) return sleepTarget; + int duration; + do { + duration = (int) Math.round(mean + sleepRandom.nextGaussian() * std); + } while (duration < sleepMin || duration > sleepMax); + return duration; } private boolean processUnfinishedPotions() { @@ -352,7 +408,6 @@ private boolean processUnfinishedPotions() { sleepUntil(() -> Rs2Dialogue.hasCombinationDialogue(), 3000); Rs2Keyboard.keyPress('1'); } - currentlyMakingPotions = true; log.info("Started making unfinished potions"); return true; } @@ -380,10 +435,9 @@ private boolean processSuperCombat() { if (Rs2Inventory.combine(ItemID.TORSTOL, ItemID._4DOSE2ATTACK)) { sleep(600, 800); if (withdrawnAmount > 1) { - sleepUntil(() -> Rs2Dialogue.hasQuestion("How many do you wish to make?"), 3000); + sleepUntil(() -> Rs2Dialogue.hasCombinationDialogue(), 3000); Rs2Keyboard.keyPress('1'); } - currentlyMakingPotions = true; log.info("Started making super combat potions"); return true; } @@ -398,10 +452,9 @@ private boolean processRegularPotion() { if (Rs2Inventory.combine(currentPotion.unfinished, currentPotion.secondary)) { sleep(600, 800); if (withdrawnAmount > 1) { - sleepUntil(() -> Rs2Dialogue.hasQuestion("How many do you wish to make?"), 3000); + sleepUntil(() -> Rs2Dialogue.hasCombinationDialogue(), 3000); Rs2Keyboard.keyPress('1'); } - currentlyMakingPotions = true; log.info("Started making {} potions", currentPotion.name()); return true; }