Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ed9a10c
Merge pull request #432 from chsami/development
chsami May 10, 2026
eb958f5
Merge pull request #434 from chsami/development
chsami May 11, 2026
1561554
Merge pull request #441 from chsami/development
chsami May 18, 2026
fcc3ecc
fix(tempoross): remove broken isOnOurSide filter, fix client-thread r…
runsonmypc May 18, 2026
1c602ac
fix(tempoross): skip fish spots adjacent to clouds
runsonmypc May 18, 2026
0840548
fix(tempoross): eliminate wave freeze by short-circuiting script loop…
runsonmypc May 18, 2026
d9e8054
fix(tempoross): LocalPoint-based coordinate handling for instanced re…
runsonmypc May 19, 2026
058ceab
fix(tempoross): wave-priority tethering, cloud radius, item gathering…
runsonmypc May 19, 2026
000e4cd
fix(tempoross): eliminate all remaining WorldPoint coordinate mismatches
runsonmypc May 19, 2026
bc68209
Merge pull request #443 from chsami/development
chsami May 20, 2026
d84584a
fix(tempoross): prevent cooking interruption, Rs2Walker recovery, spe…
runsonmypc May 20, 2026
7a4cfbe
fix(tempoross): fish spot stability, humanized thresholds, repair blo…
runsonmypc May 21, 2026
b3b4a4e
Development (#449)
chsami May 22, 2026
4eb8357
fix(tempoross): improved repair timing, spirit pool action filter
runsonmypc May 22, 2026
936447f
chore(tempoross): bump version to 2.0.0
runsonmypc May 22, 2026
a52629c
Merge branch 'development' of https://github.com/chsami/Microbot-Hub …
runsonmypc May 22, 2026
8cd142f
Merge pull request #459 from chsami/development
chsami May 29, 2026
27f4e33
Merge pull request #465 from chsami/development
chsami Jun 2, 2026
dfa9702
Development (#468)
chsami Jun 5, 2026
2cd3543
Merge pull request #471 from chsami/development
chsami Jun 8, 2026
3e3f051
Fix Animated Armour food handling and armoury navigation
runsonmypc Jun 11, 2026
371a025
feat(slayer): add finishing item support (ice cooler, bag of salt, ro…
runsonmypc Jun 15, 2026
e0e7177
Merge pull request #482 from runsonmypc/fix/animated-armour-food
chsami Jun 16, 2026
6b7a78e
Merge pull request #486 from runsonmypc/feat/slayer-finishing-items
chsami Jun 16, 2026
663529d
Merge pull request #488 from chsami/development
chsami Jun 16, 2026
9e1d17e
chore: promote development to main
chsami Jun 25, 2026
b708788
Merge pull request #504 from chsami/development
chsami Jun 25, 2026
3781a0c
Merge pull request #507 from chsami/development
chsami Jul 1, 2026
bb2b37f
feat(WineMaker): add antiban support and out-of-materials hardening
Jul 1, 2026
02a8e4a
fix(WineMaker): respect user's antiban micro break setting instead of…
Jul 1, 2026
7558cba
fix(WineMaker): overlay user's saved antiban panel settings over the …
Jul 1, 2026
95361c3
fix(WineMaker): trigger action cooldown when batch starts crafting, n…
Jul 1, 2026
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 @@ -26,7 +26,7 @@
@Slf4j
public class AnimatedArmourPlugin extends Plugin {

static final String version = "1.0.1";
static final String version = "1.0.2";
@Inject
private AnimatedArmourConfig config;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package net.runelite.client.plugins.microbot.animatedarmour;

import net.runelite.api.Skill;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.plugins.microbot.Microbot;
import net.runelite.client.plugins.microbot.Script;
import net.runelite.client.plugins.microbot.api.tileobject.models.Rs2TileObjectModel;
import net.runelite.client.plugins.microbot.util.bank.Rs2Bank;
import net.runelite.client.plugins.microbot.util.bank.enums.BankLocation;
import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject;
import net.runelite.client.plugins.microbot.util.grounditem.LootingParameters;
import net.runelite.client.plugins.microbot.util.grounditem.Rs2GroundItem;
import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory;
Expand All @@ -20,6 +22,16 @@ public class AnimatedArmourScript extends Script {

public static boolean test = false;

// Armoury entrance double-door (plane 0). From the shortest-path transport data:
// 2855 3546 0 <-> 2855 3545 0 (Open;Door;24309)
// 2854 3546 0 <-> 2854 3545 0 (Open;Door;24306)
// These are already in the walker's transport graph, so pathfinding opens them
// automatically; the explicit interact below is only a fallback when the walker
// stalls on the wrong side of the door.
private static final int[] ARMOURY_DOOR_IDS = {24309, 24306};
// Armour stand object tile (unchanged from the original plugin).
private static final WorldPoint ARMOUR_STAND_TILE = new WorldPoint(2851, 3536, 0);

public boolean run(AnimatedArmourConfig config) {
Microbot.enableAutoRunOn = false;

Expand All @@ -32,40 +44,95 @@ public boolean run(AnimatedArmourConfig config) {
boolean hasArmorPieces = Rs2Inventory.contains(item -> item.getName().contains("platebody")) &&
Rs2Inventory.contains(item -> item.getName().contains("platelegs")) &&
Rs2Inventory.contains(item -> item.getName().contains("full helm"));
if (Rs2Inventory.getInventoryFood().isEmpty() && config.foodAmount() > 0) {
Rs2Bank.walkToBank(BankLocation.WARRIORS_GUILD);
Rs2Bank.openBank();
Rs2Bank.withdrawX(config.food().getId(), config.foodAmount());
Rs2Walker.walkTo(2855, 3540, 0);
}

if (hasArmorPieces) {
animateArmor();
// Never bank mid-kill. Only restock food before animating the next
// suit, when fewer than two food remain.
if (Rs2Inventory.getInventoryFood().size() < 2 && config.foodAmount() > 0) {
bankForFood(config);
} else {
animateArmor(config);
}
} else {
Rs2Player.eatAt(Rs2Random.randomGaussian(30, 3));
loot();
Rs2Player.eatAt(Rs2Random.randomGaussian(60, 5));
// Emergency only: if we ran dry mid-fight and are about to die,
// abandon the kill and bank rather than dying.
if (Rs2Inventory.getInventoryFood().isEmpty() && config.foodAmount() > 0
&& Rs2Player.getHealthPercentage() <= Rs2Random.randomGaussian(20, 3)) {
bankForFood(config);
} else {
loot();
}
}

long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("Total time for loop " + totalTime);

} catch (Exception ex) {
// A stop/restart can interrupt a client-thread call mid-flight (e.g. the
// door-open fallback). Restore the flag and exit quietly instead of logging
// a misleading ERROR stack trace.
if (ex instanceof InterruptedException || ex.getCause() instanceof InterruptedException) {
Thread.currentThread().interrupt();
return;
}
Microbot.logStackTrace(this.getClass().getSimpleName(), ex);
}
}, 0, 1000, TimeUnit.MILLISECONDS);
return true;
}

public void animateArmor() {
WorldPoint armorStandLocation = new WorldPoint(2851, 3536, 0);
Rs2TileObjectModel armorStand = Microbot.getRs2TileObjectCache().query().within(armorStandLocation, 0).nearest();
private void bankForFood(AnimatedArmourConfig config) {
Rs2Bank.walkToBank(BankLocation.WARRIORS_GUILD);
Rs2Bank.openBank();
Rs2Bank.withdrawX(config.food().getId(), config.foodAmount());
Rs2Bank.closeBank();
walkToArmourRoom();
}

private void walkToArmourRoom() {
// Walk with a distance tolerance instead of demanding the exact tile -- the
// exact-tile invocation is what made the short hop slow and prone to re-pathing.
Rs2Walker.walkTo(ARMOUR_STAND_TILE, 4);
// Fallback: if we stalled on the far side of the door, click it directly. The
// door is located by id once it has loaded, so no approach tile is hardcoded.
WorldPoint loc = Rs2Player.getWorldLocation();
if (loc != null && loc.distanceTo(ARMOUR_STAND_TILE) > 4) {
if (Rs2GameObject.interact(ARMOURY_DOOR_IDS, "Open")) {
sleepUntil(() -> !Rs2Player.isMoving(), 3000);
Rs2Walker.walkTo(ARMOUR_STAND_TILE, 4);
}
}
}

public void animateArmor(AnimatedArmourConfig config) {
// Make sure we actually reached the stand before trying to target it.
WorldPoint loc = Rs2Player.getWorldLocation();
if (loc == null || loc.distanceTo(ARMOUR_STAND_TILE) > 8) {
walkToArmourRoom();
return;
}
Rs2TileObjectModel armorStand = Microbot.getRs2TileObjectCache().query().within(ARMOUR_STAND_TILE, 0).nearest();
if (armorStand != null) {
armorStand.click();
// Eat one tick later, never on the same tick as the animate click (which
// would cancel it). This uses the idle animate delay to top up HP, but
// only when it won't be wasted (missing HP >= the food's heal amount).
sleepUntilNextTick();
eatDuringAnimateIfEfficient(config);
Rs2Player.waitForAnimation();
}

}

private void eatDuringAnimateIfEfficient(AnimatedArmourConfig config) {
if (Rs2Inventory.getInventoryFood().isEmpty()) return;
int missing = Rs2Player.getRealSkillLevel(Skill.HITPOINTS)
- Rs2Player.getBoostedSkillLevel(Skill.HITPOINTS);
if (missing >= config.food().getHeal()) {
Rs2Player.useFood();
}
}

public void loot() {
LootingParameters valueParams = new LootingParameters(
Expand All @@ -86,4 +153,4 @@ public void loot() {
public void shutdown() {
super.shutdown();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
)
@Slf4j
public class WinePlugin extends Plugin {
public final static String version = "1.1.1";
public final static String version = "1.2.0";

@Inject
private Client client;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.microbot.Microbot;
import net.runelite.client.plugins.microbot.Script;
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.bank.Rs2Bank;
import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory;
import net.runelite.client.plugins.microbot.util.keyboard.Rs2Keyboard;
Expand All @@ -14,14 +16,30 @@
public class WineScript extends Script {

public boolean run(WineConfig config) {
// Apply the cooking template as a baseline, then overlay the user's saved
// antiban panel settings so anything toggled there wins over the template.
Rs2Antiban.resetAntibanSettings();
Rs2Antiban.antibanSetupTemplates.applyCookingSetup();
Rs2AntibanSettings.moveMouseRandomly = true;
Rs2AntibanSettings.loadFromProfile();
mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
if (!super.run()) return;
if (!Microbot.isLoggedIn()) return;
if (Rs2AntibanSettings.actionCooldownActive) return;
if (Rs2AntibanSettings.microBreakActive) return;
if (Rs2Inventory.count("grapes") > 0 && (Rs2Inventory.count("jug of water") > 0)) {
Rs2Inventory.combine("jug of water", "grapes");
sleepUntil(() -> Rs2Widget.getWidget(17694734) != null);
Rs2Keyboard.keyPress('1');
// Trigger the cooldown (incl. mouse off screen / random moves) as soon as
// the batch starts crafting, like a human looking away mid-batch, rather
// than after the last wine finishes.
Rs2Inventory.waitForInventoryChanges(3000);
Rs2Antiban.actionCooldown();
if (Rs2AntibanSettings.takeMicroBreaks) {
Rs2Antiban.takeMicroBreakByChance();
}
sleepUntil(() -> !Rs2Inventory.hasItem("jug of water"),25000);
} else {
bank();
Expand All @@ -37,21 +55,30 @@ private void bank(){
Rs2Bank.openBank();
if(Rs2Bank.isOpen()){
Rs2Bank.depositAll();
if(Rs2Bank.hasBankItem("jug of water",14) && Rs2Bank.hasBankItem("grapes",14)) {
Rs2Bank.withdrawDeficit("jug of water", 14);
int jugsInBank = Rs2Bank.count("jug of water");
int grapesInBank = Rs2Bank.count("grapes");
if(jugsInBank > 0 && grapesInBank > 0) {
// Withdraw up to 14 of each, or whatever is left for a final partial batch
int amount = Math.min(14, Math.min(jugsInBank, grapesInBank));
Rs2Bank.withdrawDeficit("jug of water", amount);
sleepUntil(() -> Rs2Inventory.hasItem("jug of water"));
Rs2Bank.withdrawDeficit("grapes", 14);
Rs2Bank.withdrawDeficit("grapes", amount);
sleepUntil(() -> Rs2Inventory.hasItem("grapes"));
} else {
// Out of grapes or jugs of water: log out and stop the plugin
Microbot.getNotifier().notify("Run out of Materials");
Microbot.status = "[Shutting down] - Reason: out of grapes or jugs of water.";
Rs2Bank.closeBank();
sleepUntil(() -> !Rs2Bank.isOpen());
Rs2Player.logout();
sleepUntil(() -> !Microbot.isLoggedIn(), 10000);
Plugin wineMakerPlugin = Microbot.getPluginManager().getPlugins().stream()
.filter(x -> x.getClass().getName().equals(WinePlugin.class.getName()))
.findFirst()
.orElse(null);
Microbot.stopPlugin(wineMakerPlugin);
shutdown();
return;
}
}
Rs2Bank.closeBank();
Expand All @@ -60,6 +87,7 @@ private void bank(){

@Override
public void shutdown() {
Rs2Antiban.resetAntibanSettings();
super.shutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
@Slf4j
public class SlayerPlugin extends Plugin {

static final String version = "1.0.2";
static final String version = "1.1.0";

@Inject
private SlayerConfig config;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Actor;
import net.runelite.api.GameState;
import net.runelite.api.Player;
import net.runelite.api.Skill;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.gameval.ItemID;
import static net.runelite.api.gameval.VarbitID.SLAYER_AUTOKILL_DESERTLIZARDS;
import static net.runelite.api.gameval.VarbitID.SLAYER_AUTOKILL_GARGOYLES;
import static net.runelite.api.gameval.VarbitID.SLAYER_AUTOKILL_ROCKSLUGS;
import net.runelite.api.widgets.Widget;
import net.runelite.client.plugins.microbot.Microbot;
import net.runelite.client.plugins.microbot.Script;
Expand Down Expand Up @@ -1385,7 +1390,8 @@ private void handleBankingState() {

// Check if already matching
if (inventorySetup.doesEquipmentMatch() && inventorySetup.doesInventoryMatch()) {
log.info("Inventory setup matches, closing bank");
log.info("Inventory setup matches");
withdrawFinishingItems();
Rs2Bank.closeBank();
sleepUntil(() -> !Rs2Bank.isOpen(), 2000);
initialSetupDone = true;
Expand All @@ -1408,6 +1414,7 @@ private void handleBankingState() {

if (equipmentLoaded && inventoryLoaded) {
log.info("Inventory setup loaded successfully");
withdrawFinishingItems();
Rs2Bank.closeBank();
sleepUntil(() -> !Rs2Bank.isOpen(), 2000);
initialSetupDone = true;
Expand All @@ -1426,6 +1433,29 @@ private void handleBankingState() {
}
}

private void withdrawFinishingItems() {
int finishingItemId = getRequiredFinishingItemId();
if (finishingItemId == -1) return;

int alreadyHave = Rs2Inventory.itemQuantity(finishingItemId);
int remaining = Rs2Slayer.getSlayerTaskSize();
int needed = remaining - alreadyHave;
if (needed <= 0) return;

if (alreadyHave == 0 && Rs2Inventory.isFull()) {
log.warn("Inventory is full, cannot withdraw finishing items — add a free slot to your inventory setup");
return;
}

if (Rs2Bank.hasBankItem(finishingItemId, 1)) {
log.info("Withdrawing {} finishing items (have {}, task remaining {})", needed, alreadyHave, remaining);
Rs2Bank.withdrawX(finishingItemId, needed);
sleep(300, 600);
} else {
log.warn("Finishing item (ID {}) not found in bank", finishingItemId);
}
}

// Spellbook integer values from InventorySetup
// 0=Standard, 1=Ancient, 2=Lunar, 3=Arceuus, 4=None
private static final int SPELLBOOK_STANDARD = 0;
Expand Down Expand Up @@ -2018,6 +2048,9 @@ private void handleFightingState(boolean hasTask, int remaining) {
// Handle fungicide spray refill (for zygomite tasks)
handleFungicideRefill();

// Handle slayer finishing items (ice cooler, bag of salt, rock hammer)
handleSlayerFinishingItems();

// Handle eating food BEFORE POH check
// This ensures we eat food first, only use POH if still low HP after eating
boolean ateFood = handleEating();
Expand Down Expand Up @@ -2264,6 +2297,57 @@ private int parseFungicideCharges(String name) {
}
}

private static final List<String> LIZARD_VARIANTS = Arrays.asList("Lizard", "Desert Lizard", "Small Lizard");

/**
* Returns the finishing item ID required for the current slayer task, or -1 if none needed.
* Checks the vanilla autokill varbit — if the player already has auto-finish enabled in-game
* for that monster, we don't need to carry the item.
*/
private int getRequiredFinishingItemId() {
String task = Rs2Slayer.getSlayerTask();
if (task == null) return -1;
String taskLower = task.toLowerCase();
if (taskLower.contains("lizard") && !taskLower.contains("lizardm")
&& Microbot.getVarbitValue(SLAYER_AUTOKILL_DESERTLIZARDS) == 0) {
return ItemID.SLAYER_ICY_WATER;
} else if (taskLower.contains("rockslug")
&& Microbot.getVarbitValue(SLAYER_AUTOKILL_ROCKSLUGS) == 0) {
return ItemID.SLAYER_BAG_OF_SALT;
} else if (taskLower.contains("gargoyle")
&& Microbot.getVarbitValue(SLAYER_AUTOKILL_GARGOYLES) == 0) {
return ItemID.SLAYER_ROCK_HAMMER;
}
return -1;
}

private void handleSlayerFinishingItems() {
final Player localPlayer = Microbot.getClient().getLocalPlayer();
if (localPlayer == null) return;

Rs2NpcModel npc = Microbot.getRs2NpcCache().query()
.where(n -> n.isDead() && java.util.Objects.equals(n.getInteracting(), localPlayer))
.first();
if (npc == null) return;

net.runelite.client.plugins.microbot.util.npc.Rs2NpcModel legacyNpc =
new net.runelite.client.plugins.microbot.util.npc.Rs2NpcModel(npc.getNpc());

if (Microbot.getVarbitValue(SLAYER_AUTOKILL_DESERTLIZARDS) == 0
&& LIZARD_VARIANTS.contains(npc.getName()) && npc.getHealthRatio() < 5) {
Rs2Inventory.useItemOnNpc(ItemID.SLAYER_ICY_WATER, legacyNpc);
Rs2Player.waitForAnimation();
} else if (Microbot.getVarbitValue(SLAYER_AUTOKILL_ROCKSLUGS) == 0
&& "Rockslug".equalsIgnoreCase(npc.getName()) && npc.getHealthRatio() < 5) {
Rs2Inventory.useItemOnNpc(ItemID.SLAYER_BAG_OF_SALT, legacyNpc);
Rs2Player.waitForAnimation();
} else if (Microbot.getVarbitValue(SLAYER_AUTOKILL_GARGOYLES) == 0
&& "Gargoyle".equalsIgnoreCase(npc.getName()) && npc.getHealthRatio() < 3) {
Rs2Inventory.useItemOnNpc(ItemID.SLAYER_ROCK_HAMMER, legacyNpc);
Rs2Player.waitForAnimation();
}
}

/**
* Varbit for antifire protection.
* 0 = no protection, >0 = protected (ticks remaining)
Expand Down Expand Up @@ -3265,6 +3349,13 @@ private boolean needsBanking() {
}
}

// Check finishing items (ice cooler, bag of salt, rock hammer)
int finishingItemId = getRequiredFinishingItemId();
if (finishingItemId != -1 && Rs2Inventory.itemQuantity(finishingItemId) == 0) {
log.info("Out of finishing items (item ID {}), need to bank", finishingItemId);
return true;
}

return false;
}

Expand Down
Loading