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 @@ -23,7 +23,7 @@
isExternal = PluginConstants.IS_EXTERNAL
)
public class FlipperPlugin extends Plugin {
public static final String version = "1.1.0";
public static final String version = "1.2.0";
@Inject
private Client client;
@Inject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,24 @@ enum State {

@Slf4j
public class FlipperScript extends Script {
private static final int DEFAULT_ACTION_COOLDOWN = 1200;
private static final int ACTION_COOLDOWN_VARIANCE = 600;
private static final int DEFAULT_INTERACTION_TIMEOUT = 33000;
private static final int INTERACTION_TIMEOUT_VARIANCE = 11000;
private static final int INVENTORY_WAIT_TIMEOUT = 5000;
private static final int SCHEDULE_INTERVAL_MS = 600;
private static final int KEY_PRESS_DELAY_MIN = 250;
private static final int KEY_PRESS_DELAY_MAX = 400;

private final WorldArea grandExchangeArea = new WorldArea(3136, 3465, 61, 54, 0);
State state = State.GOING_TO_GE;

private Plugin flippingCopilot;
private Object suggestionManager;
private Object highlightController;
private long lastActionTime = 0;
private long actionCooldown = 1500; // randomized cooldown between actions
private long actionCooldown = DEFAULT_ACTION_COOLDOWN;
private long interactionTimeout = DEFAULT_INTERACTION_TIMEOUT;

private int[] grandExchangeSlotIds = new int[] {
InterfaceID.GeOffers.INDEX_0,
Expand Down Expand Up @@ -91,7 +101,7 @@ public boolean run() {
Rs2Bank.depositAll();
sleepUntil(Rs2Inventory::isEmpty);
Rs2Bank.withdrawAll(ItemID.COINS);
Rs2Inventory.waitForInventoryChanges(5000);
Rs2Inventory.waitForInventoryChanges(INVENTORY_WAIT_TIMEOUT);
Rs2Bank.closeBank();
sleepUntil(() -> !Rs2Bank.isOpen());
state = State.MONITORING_COPILOT;
Expand All @@ -104,20 +114,34 @@ public boolean run() {
return;
}

// Check interaction timeout first - reset ge window state if stuck
long currentTime = System.currentTimeMillis();
if (Rs2GrandExchange.isOfferScreenOpen() && (currentTime - lastActionTime > interactionTimeout)) {
Rs2GrandExchange.backToOverview();

lastActionTime = System.currentTimeMillis();
actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE);
interactionTimeout = Rs2Random.randomGaussian(DEFAULT_INTERACTION_TIMEOUT, INTERACTION_TIMEOUT_VARIANCE);

log.info("interactionTimeout reached, returning to GE overview.");
return;
}

// Check for Copilot price/quantity messages in chat
if (checkAndPressCopilotKeybind()) return;

// Check if we need to abort any offers
if (checkAndAbortIfNeeded()) return;
if (checkAndAbortOrModifyIfNeeded()) return;

// Check for highlighted widgets
checkAndClickHighlightedWidgets();
if (checkAndClickHighlightedWidgets()) return;

break;
}
} catch (Exception ex) {
log.error("Error in FlipperScript: {} - ", ex.getMessage(), ex);
}
}, 0, 600, TimeUnit.MILLISECONDS);
}, 0, SCHEDULE_INTERVAL_MS, TimeUnit.MILLISECONDS);

return true;
}
Expand All @@ -129,7 +153,7 @@ public void shutdown()
suggestionManager = null;
highlightController = null;
lastActionTime = 0;
actionCooldown = 1500;
actionCooldown = DEFAULT_ACTION_COOLDOWN;
super.shutdown();
}

Expand Down Expand Up @@ -282,7 +306,7 @@ private Widget getWidgetFromOverlay(Object highlightController, String suggestio
return null;
}

if (Objects.equals(suggestionType, "abort"))
if (Objects.equals(suggestionType, "abort") || Objects.equals(suggestionType, "modify_buy") || Objects.equals(suggestionType, "modify_sell"))
{
return getHighlightWidgets(highlightController).stream()
.filter(Objects::nonNull)
Expand All @@ -301,10 +325,9 @@ private Widget getWidgetFromOverlay(Object highlightController, String suggestio
}
}

private boolean checkAndAbortIfNeeded()
private boolean checkAndAbortOrModifyIfNeeded()
{
long currentTime = System.currentTimeMillis();
if (currentTime - lastActionTime < actionCooldown) return true;
if (System.currentTimeMillis() - lastActionTime < actionCooldown) return false;

if (flippingCopilot == null || highlightController == null || suggestionManager == null) return false;
try
Expand All @@ -314,20 +337,25 @@ private boolean checkAndAbortIfNeeded()

String suggestionType = getSuggestionType(currentSuggestion);

if (!Objects.equals(suggestionType, "abort")) return false;
if (!Objects.equals(suggestionType, "abort") && !Objects.equals(suggestionType, "modify_buy") && !Objects.equals(suggestionType, "modify_sell")) return false;

log.info("Found suggestion type '{}'.", suggestionType);

Widget abortWidget = getWidgetFromOverlay(highlightController, suggestionType);
if (abortWidget != null)
{
NewMenuEntry menuEntry = new NewMenuEntry("Abort offer", "", 2, MenuAction.CC_OP, 2, abortWidget.getId(), false);
{
NewMenuEntry menuEntry;
if (Objects.equals(suggestionType, "modify_buy") || Objects.equals(suggestionType, "modify_sell"))
menuEntry = new NewMenuEntry("Modify offer", "", 3, MenuAction.CC_OP, 2, abortWidget.getId(), false);
else
menuEntry = new NewMenuEntry("Abort offer", "", 2, MenuAction.CC_OP, 2, abortWidget.getId(), false);

Rectangle bounds = abortWidget.getBounds() != null && Rs2UiHelper.isRectangleWithinCanvas(abortWidget.getBounds())
? abortWidget.getBounds()
: Rs2UiHelper.getDefaultRectangle();
Microbot.doInvoke(menuEntry, bounds);
lastActionTime = System.currentTimeMillis();
actionCooldown = Rs2Random.randomGaussian(1200, 300);
actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE);
return true;
}
}
Expand All @@ -339,39 +367,70 @@ private boolean checkAndAbortIfNeeded()
}

private boolean checkAndPressCopilotKeybind() {
boolean isChatboxInputOpen = Rs2Widget.isWidgetVisible(InterfaceID.Chatbox.MES_LAYER);
if (!isChatboxInputOpen) return false;
log.info("Found chatbox input open, pressing 'e' then Enter");
// Press 'e' to trigger FlippingCopilot's keybind
Rs2Keyboard.keyPress(KeyEvent.VK_E);
sleep(250, 400);
Rs2Keyboard.keyPress(KeyEvent.VK_ENTER);

lastActionTime = System.currentTimeMillis();
return true;
// 1. Search MES_LAYER_SCROLLCONTENTS for a widget containing "Copilot" (if it's time to select the item suggestion)
Widget scrollContents = Rs2Widget.getWidget(InterfaceID.Chatbox.MES_LAYER_SCROLLCONTENTS);
Widget copilotWidget = null;

if (scrollContents != null) {
copilotWidget = Rs2Widget.findWidget("Copilot", List.of(scrollContents), false);
if (copilotWidget != null && Rs2Widget.isWidgetVisible(copilotWidget.getId())) {
log.info("Found chat widget '{}'.", copilotWidget.getId());
// 2. Press only Enter if found in scroll contents (selecting item)
Rs2Keyboard.keyPress(KeyEvent.VK_ENTER);

// As these widgets tend to disappear quickly sometimes, we sleep after we interact with it to select the suggested item
sleepUntil(() -> System.currentTimeMillis() - lastActionTime < actionCooldown);
lastActionTime = System.currentTimeMillis();
actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE);
return true;
}
}

if (System.currentTimeMillis() - lastActionTime < actionCooldown) return false;

Widget mesLayer = Rs2Widget.getWidget(InterfaceID.Chatbox.MES_LAYER);
if (mesLayer != null) {
copilotWidget = Rs2Widget.findWidget("Copilot", List.of(mesLayer), false);
}

if (copilotWidget != null && Rs2Widget.isWidgetVisible(copilotWidget.getId())) {
// 3. Press E then Enter (setting price/quantity)
log.info("Found chat widget '{}'.", copilotWidget.getId());
Rs2Keyboard.keyPress(KeyEvent.VK_E);
sleep(KEY_PRESS_DELAY_MIN, KEY_PRESS_DELAY_MAX);
Rs2Keyboard.keyPress(KeyEvent.VK_ENTER);
lastActionTime = System.currentTimeMillis();
actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE);
return true;
}

return false;
}

private void checkAndClickHighlightedWidgets()
private boolean checkAndClickHighlightedWidgets()
{
long currentTime = System.currentTimeMillis();
if (currentTime - lastActionTime < actionCooldown) return;
if (currentTime - lastActionTime < actionCooldown) return false;

if (flippingCopilot == null || highlightController == null) return;
if (flippingCopilot == null || highlightController == null) return false;

try {
Widget highlightedWidget = getWidgetFromOverlay(highlightController, "");
boolean isHighlightedVisible = highlightedWidget != null && Rs2Widget.isWidgetVisible(highlightedWidget.getId());

if (isHighlightedVisible) {
log.info("Clicking highlighted widget: {}", highlightedWidget.getId());
Rs2Widget.clickWidget(highlightedWidget);
sleepUntil(() -> Rs2Widget.clickWidget(highlightedWidget));
lastActionTime = currentTime;
actionCooldown = Rs2Random.randomGaussian(1800, 300);
actionCooldown = Rs2Random.randomGaussian(DEFAULT_ACTION_COOLDOWN, ACTION_COOLDOWN_VARIANCE);
return true;
}
}
catch (Exception e)
{
log.error("Could not process highlight widgets: {} - ", e.getMessage(), e);
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,57 @@
package net.runelite.client.plugins.microbot.karambwans;

import net.runelite.client.config.*;
import net.runelite.client.plugins.microbot.karambwans.enums.KarambwanBankLocation;
import net.runelite.client.plugins.microbot.karambwans.enums.FairyRingAccessMethod;

@ConfigGroup("GabulhasKarambwans")
@ConfigInformation(
"<h3>Setup Instructions</h3>" +
"<ol>" +
"<li>Configure the fairy rings to DKP (last destination must be DKP)</li>" +
"<li>Make sure to have karambwan vessel and raw karambwanji in your inventory</li>" +
"<li>Start the script next to the karambwan fishing spot</li>" +
"</ol>"
"<li>Configure the fairy rings to DKP (last destination must be DKP).</li>" +
"<li>Make sure to have a karambwan vessel and raw karambwanji in your inventory.</li>" +
"<li>Start the script next to the karambwan fishing spot.</li>" +
"</ol>" +
"<h3>Teleports & Banking</h3>" +
"<ul>" +
"<li><b>POH Fairy Ring:</b> Supports Construct./Max cape, House tabs, or House teleport spells.</li>" +
"<li><b>Seers Bank:</b> Requires Kandarin Hard Diary completed and Camelot teleport runes. The script will cast the Seers' teleport variant.</li>" +
"</ul>" +
"<br><i>Note: The script does <b>not</b> automatically restock teleports. Make sure to bring enough runes, a rune pouch, or teleport tabs for your session.</i>"
)
public interface GabulhasKarambwansConfig extends Config {

String startingStateSection = "startingStateSection";

@ConfigSection(
name = "Starting State",
description = "Starting State",
position = 0,
closedByDefault = true
name = "Teleports",
description = "Teleportation methods to bank and return to DKP",
position = 1,
closedByDefault = false
)
String startingStateSection = "startingStateSection";
String teleportsSection = "teleportsSection";

@ConfigItem(
keyName = "bankLocation",
name = "Bank Location",
description = "Bank location to teleport to.",
position = 1,
section = teleportsSection
)
default KarambwanBankLocation bankLocation() {
return KarambwanBankLocation.NONE;
}

@ConfigItem(
keyName = "fairyRingAccessMethod",
name = "Fairy Ring Access",
description = "How to access the fairy ring to return to DKP.",
position = 2,
section = teleportsSection
)
default FairyRingAccessMethod fairyRingAccessMethod() {
return FairyRingAccessMethod.ZANARIS_WALK;
}
@ConfigItem(
keyName = "startingState",
name = "(Debug) Starting State",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
)
@Slf4j
public class GabulhasKarambwansPlugin extends Plugin {
public static final String version = "1.1.0";
public static final String version = "1.2.0";
@Inject
private GabulhasKarambwansConfig config;

Expand Down
Loading