This commit is contained in:
2025-10-12 22:49:30 +03:00
parent 128173339e
commit e3e7de9108
20 changed files with 117 additions and 116 deletions

View File

@@ -0,0 +1,277 @@
package ee.futur.easygotr;
import net.runelite.client.config.*;
@ConfigGroup("EasyGOTR")
public interface EasyGOTRConfig extends Config {
@ConfigItem(
keyName = "Toggle",
name = "Toggle",
description = "",
position = 0
)
default Keybind toggle() {
return Keybind.NOT_SET;
}
@ConfigSection(
name = "Easy GOTR Configuration",
description = "Configure your settings for the Easy GOTR plugin",
position = 1,
closedByDefault = true
)
String easyGOTRConfig = "easyGOTRConfig";
@ConfigItem(
keyName = "prioritizeBloodDeath",
name = "Always use blood/death altars",
description = "Will ignore point balance for these altars and always use them if available.",
position = 2,
section = easyGOTRConfig
)
default boolean prioritizeBloodDeath() {
return true;
}
@ConfigItem(
keyName = "dropRunes",
name = "Drop Runes",
description = "Drop Runes instead of depositing (kek uim)",
position = 3,
section = easyGOTRConfig
)
default boolean dropRunes() {
return false;
}
@ConfigItem(
keyName = "dropRunesFilter",
name = "Drop Runes Filter",
description = "If Drop Runes is not enabled and this has runes entered, the type of rune entered here will still get dropped, others will get deposited (ex: air, Mind, Body). Add runes with full name, air rune, mind rune , cosmic rune, etc... and split with comma ','",
position = 5,
section = easyGOTRConfig
)
default String dropRunesFilter() {
return "";
}
@ConfigItem(
keyName = "usePouches",
name = "Use Essence Pouches?",
description = "Requires NPC Contact runes in Rune Pouch or Redwood lit Lantern",
position = 6,
section = easyGOTRConfig
)
default boolean usePouches() {
return false;
}
@ConfigItem(
keyName = "hasBook",
name = "Abyssal Book in bank? (IMPORTANT FOR NPC CONTACT)",
description = "IMPORTANT TO USE NPC CONTACT",
position = 7,
section = easyGOTRConfig
)
default boolean hasBook() {
return true;
}
@ConfigItem(
keyName = "startFrags",
name = "Starting Fragments (0 to wait for first portal)",
description = "How many fragments you should get before leaving the starting zone",
position = 8,
section = easyGOTRConfig
)
default int startingFrags() {
return 0;
}
@ConfigSection(
name = "Altar Ignore Configuration",
description = "",
position = 60,
closedByDefault = true
)
String ignoreSection = "ignoreSection";
@ConfigItem(
keyName = "ignoreAir",
name = "Ignore Air Altar",
description = "",
position = 61,
section = ignoreSection
)
default boolean ignoreAir() {
return false;
}
@ConfigItem(
keyName = "ignoreMind",
name = "Ignore Mind Altar",
description = "",
position = 62,
section = ignoreSection
)
default boolean ignoreMind() {
return false;
}
@ConfigItem(
keyName = "ignoreWater",
name = "Ignore Water Altar",
description = "",
position = 63,
section = ignoreSection
)
default boolean ignoreWater() {
return false;
}
@ConfigItem(
keyName = "ignoreEarth",
name = "Ignore Earth Altar",
description = "",
position = 64,
section = ignoreSection
)
default boolean ignoreEarth() {
return false;
}
@ConfigItem(
keyName = "ignoreFire",
name = "Ignore Fire Altar",
description = "",
position = 65,
section = ignoreSection
)
default boolean ignoreFire() {
return false;
}
@ConfigItem(
keyName = "ignoreBody",
name = "Ignore Body Altar",
description = "",
position = 66,
section = ignoreSection
)
default boolean ignoreBody() {
return false;
}
@ConfigItem(
keyName = "ignoreCosmic",
name = "Ignore Cosmic Altar",
description = "",
position = 67,
section = ignoreSection
)
default boolean ignoreCosmic() {
return false;
}
@ConfigItem(
keyName = "ignoreChaos",
name = "Ignore Chaos Altar",
description = "",
position = 68,
section = ignoreSection
)
default boolean ignoreChaos() {
return false;
}
@ConfigItem(
keyName = "ignoreNature",
name = "Ignore Nature Altar",
description = "",
position = 69,
section = ignoreSection
)
default boolean ignoreNature() {
return false;
}
@ConfigItem(
keyName = "ignoreLaw",
name = "Ignore Law Altar",
description = "",
position = 70,
section = ignoreSection
)
default boolean ignoreLaw() {
return false;
}
@ConfigItem(
keyName = "ignoreDeath",
name = "Ignore Death Altar",
description = "",
position = 71,
section = ignoreSection
)
default boolean ignoreDeath() {
return false;
}
@ConfigItem(
keyName = "ignoreBlood",
name = "Ignore Blood Altar",
description = "",
position = 72,
section = ignoreSection
)
default boolean ignoreBlood() {
return false;
}
@ConfigSection(
name = "Game Tick Configuration",
description = "Configure how to handles game tick delays, 1 game tick equates to roughly 600ms",
position = 100,
closedByDefault = true
)
String delayTickConfig = "delayTickConfig";
@Range(
max = 10
)
@ConfigItem(
keyName = "tickDelayMin",
name = "Game Tick Min",
description = "",
position = 101,
section = delayTickConfig
)
default int tickDelayMin() {
return 1;
}
@Range(
max = 10
)
@ConfigItem(
keyName = "tickDelayMax",
name = "Game Tick Max",
description = "",
position = 102,
section = delayTickConfig
)
default int tickDelayMax() {
return 3;
}
@ConfigItem(
keyName = "tickDelayEnabled",
name = "Tick delay",
description = "enables some tick delays",
position = 103,
section = delayTickConfig
)
default boolean tickDelay() {
return false;
}
}

View File

@@ -0,0 +1,70 @@
package ee.futur.easygotr;
import net.runelite.api.Client;
import net.runelite.client.ui.overlay.OverlayPanel;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.LineComponent;
import net.runelite.client.ui.overlay.components.TitleComponent;
import javax.inject.Inject;
import java.awt.*;
import static org.apache.commons.lang3.time.DurationFormatUtils.formatDuration;
public class EasyGOTROverlay extends OverlayPanel {
private final Client client;
private final EasyGOTRPlugin plugin;
public String overlayState = "";
@Inject
private EasyGOTROverlay(Client client, EasyGOTRPlugin plugin) {
this.client = client;
this.plugin = plugin;
setPosition(OverlayPosition.BOTTOM_LEFT);
}
@Override
public Dimension render(Graphics2D graphics) {
String timeFormat = (plugin.runningDuration.toHours() < 1) ? "mm:ss" : "HH:mm:ss";
panelComponent.getChildren().add(TitleComponent.builder()
.text("EasyGOTR")
.color(plugin.started ? Color.GREEN : Color.RED)
.build());
if (plugin.started) {
panelComponent.getChildren().add(LineComponent.builder()
.left("Time running:")
.leftColor(Color.WHITE)
.right(formatDuration(plugin.runningDuration.toMillis(), timeFormat))
.rightColor(Color.WHITE)
.build());
panelComponent.getChildren().add(LineComponent.builder()
.left("Status:")
.leftColor(Color.WHITE)
.right(overlayState)
.rightColor(Color.WHITE)
.build());
panelComponent.getChildren().add(LineComponent.builder()
.left("Game Started:")
.leftColor(Color.WHITE)
.right(String.valueOf(plugin.riftState.isGameStarted()))
.rightColor(Color.WHITE)
.build());
panelComponent.getChildren().add(LineComponent.builder()
.left("Portal Spawned:")
.leftColor(Color.WHITE)
.right(String.valueOf(plugin.riftState.isPortalSpawned()))
.rightColor(Color.WHITE)
.build());
panelComponent.getChildren().add(LineComponent.builder()
.left("First Portal Spawned:")
.leftColor(Color.WHITE)
.right(String.valueOf(plugin.riftState.hasFirstPortalSpawned))
.rightColor(Color.WHITE)
.build());
panelComponent.setPreferredSize(new Dimension(250, 250));
}
return super.render(graphics);
}
}

View File

@@ -0,0 +1,994 @@
package ee.futur.easygotr;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.google.inject.Provides;
import ee.futur.baseapi.collections.*;
import ee.futur.baseapi.collections.query.TileObjectQuery;
import ee.futur.baseapi.BaseApiPlugin;
import ee.futur.easygotr.data.CellMapper;
import ee.futur.easygotr.data.Constants;
import ee.futur.utils.InventoryUtil;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.*;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameTick;
import net.runelite.api.widgets.Widget;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.HotkeyListener;
import org.apache.commons.lang3.RandomUtils;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
@PluginDescriptor(
name = "<html><font color=\"#FF9DF9\">[k4rli]</font> GOTR Helper</html>",
description = "Guardians of the Rift",
enabledByDefault = false,
tags = {"gotr", "helper", "k4rli"}
)
@Slf4j
public class EasyGOTRPlugin extends Plugin {
@Inject
private Client client;
@Inject
private EasyGOTRConfig config;
@Inject
private EasyGOTROverlay overlay;
@Inject
private KeyManager keyManager;
@Inject
private OverlayManager overlayManager;
@Inject
private PouchManager pouchManager;
@Inject
public GOTRState riftState;
@Inject
private ClientThread clientThread;
//@Inject
//private ReflectBreakHandler breakHandler;
public Instant timer;
public Duration runningDuration = Duration.ZERO;
private static final Set<Integer> MiningAnimationIDs = ImmutableSet.of(AnimationID.MINING_BRONZE_PICKAXE, AnimationID.MINING_IRON_PICKAXE, AnimationID.MINING_STEEL_PICKAXE, AnimationID.MINING_BLACK_PICKAXE, AnimationID.MINING_MITHRIL_PICKAXE, AnimationID.MINING_ADAMANT_PICKAXE, AnimationID.MINING_RUNE_PICKAXE, AnimationID.MINING_GILDED_PICKAXE, AnimationID.MINING_DRAGON_PICKAXE, AnimationID.MINING_DRAGON_PICKAXE_UPGRADED, AnimationID.MINING_DRAGON_PICKAXE_OR, AnimationID.MINING_DRAGON_PICKAXE_OR_TRAILBLAZER, AnimationID.MINING_INFERNAL_PICKAXE, AnimationID.MINING_3A_PICKAXE, AnimationID.MINING_CRYSTAL_PICKAXE, AnimationID.MINING_TRAILBLAZER_PICKAXE, AnimationID.MINING_TRAILBLAZER_PICKAXE_2, AnimationID.MINING_TRAILBLAZER_PICKAXE_3);
private final List<Integer> RunePouchList = ImmutableList.of(ItemID.RUNE_POUCH, ItemID.DIVINE_RUNE_POUCH, ItemID.RUNE_POUCH_L, ItemID.DIVINE_RUNE_POUCH_L);
private final List<Integer> RuneList = ImmutableList.of(
ItemID.AIR_RUNE,
ItemID.WATER_RUNE,
ItemID.EARTH_RUNE,
ItemID.FIRE_RUNE,
ItemID.MIND_RUNE,
ItemID.CHAOS_RUNE,
ItemID.DEATH_RUNE,
ItemID.BLOOD_RUNE,
ItemID.COSMIC_RUNE,
ItemID.NATURE_RUNE,
ItemID.LAW_RUNE,
ItemID.BODY_RUNE,
ItemID.SOUL_RUNE,
ItemID.ASTRAL_RUNE,
ItemID.MIST_RUNE,
ItemID.MUD_RUNE,
ItemID.DUST_RUNE,
ItemID.LAVA_RUNE,
ItemID.STEAM_RUNE,
ItemID.SMOKE_RUNE,
ItemID.WRATH_RUNE);
private final List<Integer> PickaxeIDs = ImmutableList.of(ItemID.BRONZE_PICKAXE,
ItemID.IRON_PICKAXE,
ItemID.STEEL_PICKAXE,
ItemID.BLACK_PICKAXE,
ItemID.MITHRIL_PICKAXE,
ItemID.ADAMANT_PICKAXE,
ItemID.RUNE_PICKAXE,
ItemID.GILDED_PICKAXE,
ItemID.DRAGON_PICKAXE,
ItemID.DRAGON_PICKAXE_OR,
ItemID.DRAGON_PICKAXE_OR_25376,
ItemID.DRAGON_PICKAXE_12797,
ItemID.INFERNAL_PICKAXE,
ItemID._3RD_AGE_PICKAXE,
ItemID.CRYSTAL_PICKAXE,
ItemID.CRYSTAL_PICKAXE_INACTIVE,
ItemID.INFERNAL_PICKAXE_OR);
private final List<Integer> PoweredCellList = ImmutableList.of(ItemID.WEAK_CELL, ItemID.OVERCHARGED_CELL, ItemID.STRONG_CELL, ItemID.MEDIUM_CELL);
public boolean started = false;
public int timeout = 0;
private boolean startingRun = false;
private boolean needsMoreStartingFragments = false;
private boolean canEnterBarrier = false;
@Provides
private EasyGOTRConfig getConfig(ConfigManager configManager) {
return configManager.getConfig(EasyGOTRConfig.class);
}
@Override
protected void startUp() throws Exception {
keyManager.registerKeyListener(toggle);
overlayManager.add(overlay);
timeout = 0;
timer = Instant.now();
pouchManager.register();
riftState.register();
}
@Override
protected void shutDown() throws Exception {
keyManager.unregisterKeyListener(toggle);
overlayManager.remove(overlay);
pouchManager.deregister();
riftState.deregister();
timeout = 0;
toggle();
timer = Instant.now();
}
@Subscribe
private void onGameTick(GameTick event) {
if (timeout > 0) {
timeout--;
return;
}
if (client.getGameState() != GameState.LOGGED_IN || !started) {
return;
}
if (Inventory.search().idInList(PickaxeIDs).first().isEmpty() && Equipment.search().idInList(PickaxeIDs).first().isEmpty()) {
addMessage("No pickaxe found");
setStarted(false);
return;
}
if (config.usePouches() && !hasDegradePrevention() && (!hasNPCContactRunes() || !isOnLunar())) {
addMessage("Must have a rune pouch with NPC contact runes or some form of prevention to use essence pouches");
setStarted(false);
return;
}
runningDuration = runningDuration.plus(Duration.between(timer, Instant.now()));
timer = Instant.now();
if (Inventory.full()
&& config.usePouches()
&& pouchManager.hasEmptyPouches()
&& Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE) > 0
&& !riftState.isInAltar()) {
pouchManager.fillPouches();
if (riftState.isInHugeMine()) {
mineHugeGuardians();
} else {
craftEssence();
}
return;
}
EasyGOTRState state = getState();
overlay.overlayState = state.toString();
if (BaseApiPlugin.isMoving()) {
//Attempt to put runes in pouch where possible
getInventoryRunes().ifPresent(widget -> {
Optional<Widget> optPouch = getRunePouch();
if (optPouch.isEmpty()) {
return;
}
if (!canDepositRune(widget.getItemId())) {
return;
}
Widget pouch = optPouch.get();
//MousePackets.queueClickPacket();
//MousePackets.queueClickPacket();
//WidgetPackets.queueWidgetOnWidget(widget, pouch);
});
dropRunes();
//Handle moving to the altar differently (allow for re-tasking)
if (state != EasyGOTRState.ENTER_ALTAR) {
return;
}
}
switch (state) {
case WAITING_FOR_GAME:
waitForGame();
break;
case MOVE_TO_EAST_MINE:
case LEAVE_EAST_MINE:
climbLargeMine();
break;
case ENTER_PORTAL:
enterPortal();
break;
case LEAVE_ALTAR:
exitAltar();
break;
case GET_CELLS:
getCells();
break;
case CRAFT_ESSENCE:
craftEssence();
break;
case REPAIR_POUCH:
repairPouch();
break;
case POWER_GUARDIAN:
powerGuardian();
break;
case MINE_HUGE_GUARDIANS:
mineHugeGuardians();
break;
case MINE_LARGE_GUARDIANS:
mineLargeGuardians();
break;
case MINE_REGULAR_GUARDIANS:
mineGameGuardians();
break;
case CRAFTING_ESSENCE:
break;
case DEPOSIT_RUNES:
depositRunes();
break;
case USE_CELL:
usePowerCell();
break;
case CRAFT_RUNES:
craftRunes();
break;
case ENTER_ALTAR:
enterRift();
break;
case ENTER_GAME:
enterGame();
break;
case GAME_BUSY:
gameBusy();
break;
case BREAK:
// @TODO
break;
}
}
private EasyGOTRState getState() {
if (config.startingFrags() > 0 && getFragmentCount() > config.startingFrags()) {
needsMoreStartingFragments = false;
} else if (config.startingFrags() == 0) {
needsMoreStartingFragments = true;
}
if (!riftState.isGameStarted() && !riftState.isInAltar()) {
return EasyGOTRState.BREAK;
}
if (riftState.isGameBusy()) {
return EasyGOTRState.GAME_BUSY;
}
if (riftState.isOutsideBarrier()) {
return EasyGOTRState.ENTER_GAME;
} else {
canEnterBarrier = false;
}
if (pouchManager.hasDegradedPouches()) {
return EasyGOTRState.REPAIR_POUCH;
}
if (!riftState.isGameStarted()) {
return getPregameState();
}
if (!riftState.hasFirstPortalSpawned && needsMoreStartingFragments) {
return getPreFirstPortalState();
}
if (riftState.isGameEnding) {
return getGameEndingState();
}
//After the first portal has spawned, we should always be leaving the east mine
if (riftState.isInLargeMine()) {
return EasyGOTRState.LEAVE_EAST_MINE;
}
//If we're in the huge mine, we should mine until inventory is full and then leave
if (riftState.isInHugeMine()) {
if (Inventory.full()) {
return EasyGOTRState.ENTER_PORTAL;
}
if (isMining()) {
return EasyGOTRState.MINING;
}
return EasyGOTRState.MINE_HUGE_GUARDIANS;
}
if (riftState.isInAltar()) {
startingRun = false;
if (Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE) > 0 || pouchManager.hasFullPouch()) {
return EasyGOTRState.CRAFT_RUNES;
}
return EasyGOTRState.LEAVE_ALTAR;
}
//If we're here, were in the game area
if (riftState.isPortalSpawned() && (pouchManager.hasEmptyPouches() || Inventory.getEmptySlots() > 15)) {
return EasyGOTRState.ENTER_PORTAL;
}
if (Inventory.full() || startingRun) {
startingRun = true;
if (hasPowerEssence()) {
return EasyGOTRState.POWER_GUARDIAN;
}
if (hasPowerCell()) {
return EasyGOTRState.USE_CELL;
}
return EasyGOTRState.ENTER_ALTAR;
}
if (client.getLocalPlayer().getAnimation() == 9365) {
return EasyGOTRState.CRAFTING_ESSENCE;
}
if (getCellCount() == 0) {
return EasyGOTRState.GET_CELLS;
}
if (getInventoryRunes().isPresent() && !config.dropRunes() && getDroppableRunes().isEmpty()) {
return EasyGOTRState.DEPOSIT_RUNES;
}
if (getFragmentCount() < neededFrags()) {
if (isMining()) {
return EasyGOTRState.MINING;
}
return EasyGOTRState.MINE_REGULAR_GUARDIANS;
}
return EasyGOTRState.CRAFT_ESSENCE;
}
private EasyGOTRState getGameEndingState() {
if (riftState.isInAltar()) {
if (pouchManager.getEssenceInPouches() > 0 || Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE) > 0) {
return EasyGOTRState.CRAFT_RUNES;
}
return EasyGOTRState.LEAVE_ALTAR;
}
if (riftState.isInHugeMine()) {
return EasyGOTRState.ENTER_PORTAL;
}
if (hasPowerEssence()) {
return EasyGOTRState.POWER_GUARDIAN;
}
if (hasPowerCell()) {
return EasyGOTRState.USE_CELL;
}
int essence = pouchManager.getEssenceInPouches() + Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE);
if (essence > 20) {
return EasyGOTRState.ENTER_ALTAR;
}
if (getInventoryRunes().isPresent()) {
return EasyGOTRState.DEPOSIT_RUNES;
}
return EasyGOTRState.CRAFT_ESSENCE;
}
private EasyGOTRState getPreFirstPortalState() {
//Safety
if (riftState.isInAltar()) {
return EasyGOTRState.LEAVE_ALTAR;
}
//We're starting the game in the portal area
if (riftState.isInHugeMine()) {
if (Inventory.full()) {
return EasyGOTRState.ENTER_PORTAL;
}
if (isMining()) {
return EasyGOTRState.MINING;
}
return EasyGOTRState.MINE_HUGE_GUARDIANS;
}
if (riftState.isInLargeMine()) {
if (hasPowerCell()) {
Inventory.search().idInList(PoweredCellList).first().ifPresent(widget -> {
//InventoryInteraction.useItem(widget, "Drop");
});
}
if (isMining()) {
return EasyGOTRState.MINING;
}
return EasyGOTRState.MINE_LARGE_GUARDIANS;
}
//If we get here, we're probably walking to east from the portal.
//Make a quick stop at cells if we need too
if (getCellCount() < 10) {
return EasyGOTRState.GET_CELLS;
}
return EasyGOTRState.MOVE_TO_EAST_MINE;
}
private EasyGOTRState getPregameState() {
if (config.startingFrags() > 0) {
needsMoreStartingFragments = true;
}
if (riftState.isInHugeMine()) {
return EasyGOTRState.ENTER_PORTAL;
}
if (riftState.isInLargeMine()) {
return EasyGOTRState.WAITING_FOR_GAME;
}
if (riftState.isInAltar()) {
if (pouchManager.getEssenceInPouches() > 0 || Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE) > 0) {
return EasyGOTRState.CRAFT_RUNES;
}
return EasyGOTRState.LEAVE_ALTAR;
}
if (getInventoryRunes().isPresent()) {
return EasyGOTRState.DEPOSIT_RUNES;
}
if (getCellCount() < 10) {
return EasyGOTRState.GET_CELLS;
}
return EasyGOTRState.MOVE_TO_EAST_MINE;
}
private int getCellCount() {
return Inventory.search().withId(ItemID.UNCHARGED_CELL).first().map(Widget::getItemQuantity).orElse(0);
}
private void waitForGame() {
if (client.getLocalPlayer().getWorldLocation().getX() == Constants.LARGE_MINE_X) {
if (tickDelay() % 2 == 0) {
//MousePackets.queueClickPacket();
//MovementPackets.queueMovement(3639, 9500, false);
} else {
//MousePackets.queueClickPacket();
//MovementPackets.queueMovement(3640, 9500, false);
}
}
}
@Subscribe
private void onChatMessage(ChatMessage event) {
if (client.getGameState() != GameState.LOGGED_IN || !started) {
return;
}
if (event.getType() != ChatMessageType.SPAM && event.getType() != ChatMessageType.GAMEMESSAGE) return;
if (client.getGameState() != GameState.LOGGED_IN) {
return;
}
if (event.getMessage().contains("5 seconds.")) {
int attempt = RandomUtils.nextInt(0, 10);
if (attempt > 7) {
activatePickSpecial();
}
}
if (event.getMessage().contains("3..")) {
int attempt = RandomUtils.nextInt(0, 5);
if (attempt > 2) {
activatePickSpecial();
}
}
if (event.getMessage().contains("2..")) {
activatePickSpecial();
}
if (event.getMessage().contains("already enough adventurers")) {
timeout = 3;
}
}
private void activatePickSpecial() {
if (client.getVarpValue(VarPlayer.SPECIAL_ATTACK_PERCENT) == 1000) {
if (!Equipment.search().matchesWildCardNoCase("*Dragon pickaxe*").empty() || !Equipment.search().matchesWildCardNoCase("*infernal pickaxe*").empty()) {
//MousePackets.queueClickPacket();
//WidgetPackets.queueWidgetActionPacket(1, 38862885, -1, -1);
}
}
}
private void climbLargeMine() {
if (BaseApiPlugin.isMoving()) {
return;
}
Optional<TileObject> tileObject = TileObjects.search().withAction("Climb").nearestToPlayer();
if (tileObject.isEmpty()) {
return;
}
//TileObject rubble = tileObject.get();
//TileObjectInteraction.interact(rubble, "Climb");
timeout = tickDelay();
}
private void getCells() {
if (Inventory.full() && Inventory.getItemAmount(ItemID.UNCHARGED_CELL) == 0) {
Inventory.search().withId(ItemID.GUARDIAN_ESSENCE).first().ifPresent(widget -> {
//InventoryInteraction.useItem(widget, "Drop");
});
}
if (BaseApiPlugin.isMoving()) {
return;
}
TileObjects.search().withName("Uncharged cells").first().ifPresent(tileObject -> {
//TileObjectInteraction.interact(tileObject, "Take-10");
timeout = tickDelay();
});
}
private void craftEssence() {
if (riftState.isGameStarted()) {
Optional<TileObject> tileObject = TileObjects.search().nameContains(Constants.WORKBENCH).nearestToPlayer();
if (tileObject.isEmpty()) {
return;
}
TileObject workbench = tileObject.get();
//TileObjectInteraction.interact(workbench, "Work-at");
timeout = tickDelay();
}
}
private void mineHugeGuardians() {
Optional<TileObject> tileObject = TileObjects.search().nameContains(Constants.HUGE_REMAINS).nearestToPlayer();
if (tileObject.isEmpty()) {
return;
}
TileObject remains = tileObject.get();
//TileObjectInteraction.interact(remains, "Mine");
timeout = tickDelay();
}
private void mineLargeGuardians() {
if (Inventory.full() && Inventory.getItemAmount(ItemID.GUARDIAN_FRAGMENTS) == 0) {
Inventory.search().withId(ItemID.GUARDIAN_ESSENCE).first().ifPresent(widget -> {
//InventoryInteraction.useItem(widget, "Drop");
});
}
Optional<TileObject> tileObject = TileObjects.search().nameContains(Constants.LARGE_REMAINS).nearestToPlayer();
if (tileObject.isEmpty()) {
return;
}
if (client.getLocalPlayer().getAnimation() == -1) {
TileObject remains = tileObject.get();
//TileObjectInteraction.interact(remains, "Mine");
timeout = tickDelay();
}
}
private Optional<Widget> getInventoryRunes() {
return Inventory.search().idInList(RuneList).first();
}
private void mineGameGuardians() {
Optional<TileObject> tileObject = nameContainsNoCase(Constants.GAME_PARTS).nearestToPlayer();
if (tileObject.isEmpty()) {
return;
}
if (client.getLocalPlayer().getAnimation() == -1) {
TileObject remains = tileObject.get();
//TileObjectInteraction.interact(remains, "Mine");
timeout = tickDelay();
}
}
private void gameBusy() {
if (BaseApiPlugin.isMoving()) {
return;
}
if (riftState.getElementalPoints() < 0 && riftState.getCatalyticPoints() < 0) {
TileObjects.search().withId(43695).first().ifPresent(tileObject -> {
//TileObjectInteraction.interact(tileObject, "Check");
});
timeout = tickDelay();
return;
}
if (RandomUtils.nextInt(0, 100) == 30) {
TileObjects.search().withId(Constants.BARRIER_BUSY_ID).first().ifPresent(tileObject -> {
// TileObjectInteraction.interact(tileObject, "Peek");
});
}
}
private void enterGame() {
if (canEnterBarrier) {
//TileObjects.search().withName("Barrier").first().ifPresent(tileObject -> TileObjectInteraction.interact(tileObject, "Quick-pass"));
timeout = 1;
return;
}
Optional<Widget> dialog = Widgets.search().withId(15007475).hiddenState(false).first();
if (dialog.isEmpty()) {
//TileObjects.search().withName("Barrier").first().ifPresent(tileObject -> TileObjectInteraction.interact(tileObject, "Quick-pass"));
return;
}
String dialogText = dialog.get().getText();
if (dialogText.contains("the rift is already being guarded")) {
timeout = 10;
clickContinue();
return;
}
if (dialogText.contains("the adventurers within are just finishing up.")) {
canEnterBarrier = true;
timeout = 1;
}
}
private void clickContinue() {
Widgets.search().withTextContains("Click here to continue").first().ifPresent(widget -> {
//MousePackets.queueClickPacket();
//WidgetPackets.queueResumePause(widget.getId(), -1);
});
}
private void setStarted(boolean started) {
this.started = started;
riftState.setStarted(started);
pouchManager.setStarted(started);
if (started) {
timer = Instant.now();
if (config.usePouches()) {
clientThread.invokeLater(() -> pouchManager.refreshPouches());
}
//breakHandler.startPlugin(this);
} else {
//breakHandler.stopPlugin(this);
}
}
private final HotkeyListener toggle = new HotkeyListener(() -> config.toggle()) {
@Override
public void hotkeyPressed() {
toggle();
}
};
public void toggle() {
if (client.getGameState() != GameState.LOGGED_IN) {
return;
}
setStarted(!started);
}
private int tickDelay() {
return config.tickDelay() ? ThreadLocalRandom.current().nextInt(config.tickDelayMin(), config.tickDelayMax()) : 0;
}
private boolean isMining() {
return MiningAnimationIDs.contains(client.getLocalPlayer().getAnimation());
}
private void addMessage(String message) {
client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", message, null);
}
private boolean hasRuneAmount(int runeId, int amount) {
return (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE1) == runeId
&& client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT1) >= amount)
|| (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE2) == runeId
&& client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT2) >= amount)
|| (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE3) == runeId
&& client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT3) >= amount)
|| (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE4) == runeId
&& client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT4) >= amount);
}
private boolean canDepositRune(int runeId) {
return (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE1) == runeId
&& client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT1) < 16000)
|| (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE2) == runeId
&& client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT2) < 16000)
|| (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE3) == runeId
&& client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT3) < 16000)
|| (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE4) == runeId
&& client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT4) < 16000);
}
private boolean isOnLunar() {
return client.getVarbitValue(4070) == 2;
}
private boolean hasNPCContactRunes() {
return hasRuneAmount(1, 2) && hasRuneAmount(14, 1) && hasRuneAmount(9, 1);
}
private boolean hasPowerEssence() {
return Inventory.getItemAmount(ItemID.CATALYTIC_GUARDIAN_STONE) > 0 || Inventory.getItemAmount(ItemID.ELEMENTAL_GUARDIAN_STONE) > 0;
}
private boolean hasPowerCell() {
return Inventory.search().idInList(PoweredCellList).first().isPresent();
}
private void enterPortal() {
if (BaseApiPlugin.isMoving()) {
return;
}
Optional<TileObject> tileObject = nameContainsNoCase(Constants.PORTAL).filter(to -> to.getWorldLocation().getY() >= Constants.OUTSIDE_BARRIER_Y).nearestToPlayer();
if (tileObject.isEmpty()) {
//MousePackets.queueClickPacket();
//MovementPackets.queueMovement(new WorldPoint(3615, 9499, 0));
return;
}
TileObject portal = tileObject.get();
//TileObjectInteraction.interact(portal, "Enter", "Exit", "Use");
timeout = tickDelay();
}
private void exitAltar() {
lastAltar = null;
if (BaseApiPlugin.isMoving()) {
return;
}
Optional<TileObject> tileObject = TileObjects.search().nameContains(Constants.PORTAL).nearestToPlayer();
if (tileObject.isEmpty()) {
return;
}
TileObject portal = tileObject.get();
//TileObjectInteraction.interact(portal, "Use");
timeout = tickDelay();
}
private void powerGuardian() {
Optional<NPC> npc = NPCs.search().nameContains(Constants.GREAT_GUARDIAN).nearestToPlayer();
if (npc.isEmpty()) {
return;
}
NPC guardian = npc.get();
//NPCInteraction.interact(guardian, "Power-up");
timeout = tickDelay();
}
private void repairPouch() {
if (!Widgets.search().withTextContains("What do you want?").hiddenState(false).empty() || !Widgets.search().withTextContains("Can you repair").hiddenState(false).empty()) {
//MousePackets.queueClickPacket();
//WidgetPackets.queueResumePause(15138821, -1);
//MousePackets.queueClickPacket();
//WidgetPackets.queueResumePause(14352385, config.hasBook() ? 1 : 2);
//MousePackets.queueClickPacket();
//WidgetPackets.queueResumePause(14221317, -1);
//MousePackets.queueClickPacket();
BaseApiPlugin.invoke(-1, -1, 26, -1, -1, -1, "", "", -1, -1);
timeout = 0;
if (config.usePouches()) {
clientThread.invokeLater(() -> pouchManager.refreshPouches());
}
} else {
//MousePackets.queueClickPacket();
//WidgetPackets.queueWidgetActionPacket(2, WidgetInfoExtended.SPELL_NPC_CONTACT.getPackedId(), -1, -1);
timeout = 15;
}
}
private Optional<Widget> getRunePouch() {
return Inventory.search().idInList(RunePouchList).first();
}
private void depositRunes() {
Optional<TileObject> tileObject = TileObjects.search().withAction("Deposit-runes").nearestToPlayer();
if (tileObject.isEmpty()) {
return;
}
TileObject runeDeposit = tileObject.get();
//TileObjectInteraction.interact(runeDeposit, "Deposit-runes");
timeout = tickDelay();
}
private int neededFrags() {
return Inventory.getEmptySlots() + pouchManager.getAvailableSpace() + 5;
}
private void usePowerCell() {
if (BaseApiPlugin.isMoving()) {
return;
}
Optional<Widget> optCell = Inventory.search().idInList(PoweredCellList).first();
if (optCell.isEmpty()) {
return;
}
Widget cell = optCell.get();
TileObject nextAltar = riftState.getNextAltar();
int cellTier = CellMapper.GetCellTier(cell.getItemId());
List<TileObject> shieldCells = TileObjects.search().nameContains("cell tile").result();
//Prioritize upgrading shield cells
for (TileObject c : shieldCells) {
if (CellMapper.GetShieldTier(c.getId()) < cellTier) {
log.info("Upgrading power cell at " + c.getWorldLocation());
//TileObjectInteraction.interact(c, "Place-cell");
timeout = tickDelay();
return;
}
}
if (nextAltar == null) {
Optional<NPC> bestBarrier = NPCs.search()
.filter(x -> x.getId() <= 11425 && x.getId() >= 11418)
.result().stream().min(Comparator.comparingDouble(this::getBarrierHealth));
if (bestBarrier.isPresent()) {
Optional<TileObject> tile = TileObjects.search().nameContains("cell tile").nearestToPoint(bestBarrier.get().getWorldLocation());
if (tile.isPresent()) {
//tile.ifPresent(tileObject -> TileObjectInteraction.interact(tileObject, "Place-cell"));
log.info("Placing power cell at " + tile.get().getWorldLocation() + " with no altar present");
timeout = tickDelay();
}
}
} else {
Optional<NPC> damagedBarrier = NPCs.search().filter(x -> x.getId() <= 11425 && x.getId() >= 11418 && getBarrierHealth(x) <= 50).first();
if (damagedBarrier.isPresent()) {
Optional<TileObject> tile = TileObjects.search().nameContains("cell tile").nearestToPoint(damagedBarrier.get().getWorldLocation());
if (tile.isPresent()) {
log.info("Placing power cell at " + tile.get().getWorldLocation() + " to repair barrier");
//TileObjectInteraction.interact(tile.get(), "Place-cell");
timeout = tickDelay();
return;
}
}
Optional<NPC> bestBarrier = NPCs.search()
.filter(x -> x.getId() <= 11425 && x.getId() >= 11418)
.result().stream().min(Comparator.comparingInt(x -> x.getWorldLocation().distanceTo(nextAltar.getWorldLocation())));
if (bestBarrier.isPresent()) {
Optional<TileObject> tile = TileObjects.search().nameContains("cell tile").nearestToPoint(bestBarrier.get().getWorldLocation());
if (tile.isPresent()) {
log.info("Placing power cell at " + tile.get().getWorldLocation() + " nearest to next altar");
//TileObjectInteraction.interact(tile.get(), "Place-cell");
timeout = tickDelay();
}
}
}
}
private List<Widget> getDroppableRunes() {
List<Widget> runesToDrop = new ArrayList<>();
String[] runeFilterConfig = config.dropRunesFilter().split(",");
for (String rune : runeFilterConfig) {
rune = rune.trim();
Inventory.search().matchesWildCardNoCase(rune).first().ifPresent(runesToDrop::add);
}
return runesToDrop;
}
private void dropRunes() {
if (!config.dropRunes() && config.dropRunesFilter().isEmpty()) {
return;
}
if (config.dropRunes()) {
Optional<Widget> itemWidget = InventoryUtil.nameContainsNoCase("rune").filter(item -> !item.getName().contains("pickaxe")).first();
if (itemWidget.isEmpty()) {
return;
}
Widget item = itemWidget.get();
//InventoryInteraction.useItem(item, "Drop");
} else {
for (Widget rune : getDroppableRunes()) {
// InventoryInteraction.useItem(rune, "Drop");
}
}
}
private double getBarrierHealth(NPC barrier) {
if (barrier.getHealthScale() == -1) {
return 100;
}
return (double) barrier.getHealthRatio() / (double) barrier.getHealthScale() * 100;
}
private void craftRunes() {
Optional<TileObject> tileObject = TileObjects.search().withAction(Constants.CRAFT_RUNES).nearestToPlayer();
if (tileObject.isEmpty()) {
return;
}
if (pouchManager.getEssenceInPouches() > 0 && Inventory.getEmptySlots() > 0) {
pouchManager.emptyPouches();
TileObject altar = tileObject.get();
//TileObjectInteraction.interact(altar, Constants.CRAFT_RUNES);
timeout = tickDelay();
return;
}
if (Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE) > 0) {
TileObject altar = tileObject.get();
//TileObjectInteraction.interact(altar, Constants.CRAFT_RUNES);
timeout = tickDelay();
}
}
private TileObject lastAltar = null;
private void enterRift() {
TileObject nextAltar = riftState.getNextAltar();
if (nextAltar == null) {
return;
}
//This allows us to redirect to a new altar if the state switches
if (nextAltar == lastAltar && BaseApiPlugin.isMoving()) {
return;
}
lastAltar = nextAltar;
//TileObjectInteraction.interact(nextAltar, "Enter");
timeout = tickDelay();
}
public static TileObjectQuery nameContainsNoCase(String name) {
return TileObjects.search().filter(tileObject -> {
ObjectComposition comp = TileObjectQuery.getObjectComposition(tileObject);
if (comp == null)
return false;
return comp.getName().toLowerCase().contains(name.toLowerCase());
});
}
private boolean hasDegradePrevention() {
return Equipment.search().withId(ItemID.ABYSSAL_LANTERN_REDWOOD_LOGS).first().isPresent() || Equipment.search().withId(ItemID.RUNECRAFT_CAPE).first().isPresent() || Equipment.search().withId(ItemID.RUNECRAFT_CAPET).first().isPresent();
}
private int getFragmentCount() {
Optional<Widget> frags = Inventory.search().withId(ItemID.GUARDIAN_FRAGMENTS).first();
return frags.map(Widget::getItemQuantity).orElse(0);
}
}

View File

@@ -0,0 +1,25 @@
package ee.futur.easygotr;
public enum EasyGOTRState {
GET_CELLS,
MOVE_TO_EAST_MINE,
WAITING_FOR_GAME,
ENTER_PORTAL,
MINE_HUGE_GUARDIANS,
MINE_LARGE_GUARDIANS,
MINE_REGULAR_GUARDIANS,
REPAIR_POUCH,
CRAFTING_ESSENCE,
CRAFT_ESSENCE,
DEPOSIT_RUNES,
CRAFT_RUNES,
LEAVE_EAST_MINE,
LEAVE_ALTAR,
POWER_GUARDIAN,
USE_CELL,
ENTER_ALTAR,
MINING,
ENTER_GAME,
GAME_BUSY,
BREAK
}

View File

@@ -0,0 +1,442 @@
package ee.futur.easygotr;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import ee.futur.baseapi.collections.Inventory;
import ee.futur.baseapi.collections.TileObjects;
import ee.futur.baseapi.collections.Widgets;
import ee.futur.easygotr.data.Constants;
import ee.futur.easygotr.data.Utility;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.*;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameTick;
import net.runelite.api.widgets.Widget;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class GOTRState {
public static final int AIR_ALTAR = 43701;
public static final int WATER_ALTAR = 43702;
public static final int EARTH_ALTAR = 43703;
public static final int FIRE_ALTAR = 43704;
public static final int MIND_ALTAR = 43705;
public static final int CHAOS_ALTAR = 43706;
public static final int DEATH_ALTAR = 43707;
public static final int BLOOD_ALTAR = 43708;
public static final int BODY_ALTAR = 43709;
public static final int COSMIC_ALTAR = 43710;
public static final int NATURE_ALTAR = 43711;
public static final int LAW_ALTAR = 43712;
@Getter
private int elementalPoints = -1;
@Getter
private int catalyticPoints = -1;
@Getter
private boolean gameStarted;
@Setter
private boolean started;
public boolean hasFirstPortalSpawned = false;
@Inject
private Client client;
private final EventBus eventBus;
private final EasyGOTRConfig config;
private static final String CHECK_POINT_REGEX = "You have (\\d+) catalytic energy and (\\d+) elemental energy";
private static final Pattern CHECK_POINT_PATTERN = Pattern.compile(CHECK_POINT_REGEX);
private static final String REWARD_POINT_REGEX = "Total elemental energy:[^>]+>([\\d,]+).*Total catalytic energy:[^>]+>([\\d,]+).";
private static final Pattern REWARD_POINT_PATTERN = Pattern.compile(REWARD_POINT_REGEX);
private static final Pattern PERCENT_PATTERN = Pattern.compile("(\\d+)%");
private Set<Integer> accessibleAltars = new HashSet<>();
private static final Set<Integer> GOTR_REGIONS = ImmutableSet.of(14483, 14484);
private static final int PORTAL_WIDGET_ID = 48889884;
int timeout = 0;
int gameEndTimeout = 10;
public boolean isGameEnding = false;
@Inject
public GOTRState(EventBus eventBus, EasyGOTRConfig config) {
eventBus.register(this);
this.eventBus = eventBus;
this.config = config;
}
public void register() {
eventBus.register(this);
}
public void deregister() {
eventBus.unregister(this);
}
@Subscribe
private void onGameTick(GameTick event) {
if (client.getGameState() != GameState.LOGGED_IN || !started) {
return;
}
if (timeout > 0) {
timeout--;
return;
}
if (this.accessibleAltars.isEmpty()) {
this.accessibleAltars = Utility.getAccessibleAltars(client.getRealSkillLevel(Skill.RUNECRAFT),
Quest.LOST_CITY.getState(client), Quest.TROLL_STRONGHOLD.getState(client),
Quest.MOURNINGS_END_PART_II.getState(client), Quest.SINS_OF_THE_FATHER.getState(client));
}
Optional<Widget> frags = Inventory.search().withId(ItemID.GUARDIAN_FRAGMENTS).first();
if (!hasFirstPortalSpawned && (isPortalSpawned() || getPower() > 15 || (frags.isPresent() && frags.get().getItemQuantity() >= 250))) {
hasFirstPortalSpawned = true;
}
if (!gameStarted && isWidgetVisible()) {
gameStarted = true;
}
if (!isInAltar() && !isWidgetVisible()) {
gameEndTimeout--;
if (gameEndTimeout == 0) {
log.info("Setting game to ended");
gameStarted = false;
isGameEnding = false;
hasFirstPortalSpawned = false;
}
} else {
gameEndTimeout = 10;
}
}
private int getPower() {
Optional<Widget> pWidget = Widgets.search().withId(48889874).first();
if (pWidget.isEmpty()) {
return 0;
}
Matcher matcher = PERCENT_PATTERN.matcher(pWidget.get().getText());
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
} else {
return 0;
}
}
@Subscribe
private void onChatMessage(ChatMessage event) {
if (client.getGameState() != GameState.LOGGED_IN || !started) {
return;
}
if (event.getType() != ChatMessageType.SPAM && event.getType() != ChatMessageType.GAMEMESSAGE && event.getType() != ChatMessageType.MESBOX) {
return;
}
if (client.getGameState() != GameState.LOGGED_IN) {
return;
}
if (event.getMessage().contains(ee.futur.easygotr.data.Constants.GAME_STARTED)) {
gameStarted = true;
}
if (event.getType() == ChatMessageType.MESBOX) {
Matcher checkPointMatcher = CHECK_POINT_PATTERN.matcher(event.getMessage());
if (checkPointMatcher.find()) {
catalyticPoints = Integer.parseInt(checkPointMatcher.group(1));
elementalPoints = Integer.parseInt(checkPointMatcher.group(2));
}
}
if (event.getMessage().contains("successfully closed the rift")) {
gameStarted = false;
hasFirstPortalSpawned = false;
isGameEnding = false;
}
if (event.getMessage().contains("Guardian was defeated")) {
gameStarted = false;
hasFirstPortalSpawned = false;
isGameEnding = false;
}
if (event.getMessage().contains("is fully charged")) {
isGameEnding = true;
}
Matcher rewardPointMatcher = REWARD_POINT_PATTERN.matcher(event.getMessage());
if (rewardPointMatcher.find()) {
elementalPoints = Integer.parseInt(rewardPointMatcher.group(1).replaceAll(",", ""));
catalyticPoints = Integer.parseInt(rewardPointMatcher.group(2).replaceAll(",", ""));
}
}
private boolean isWidgetVisible() {
Optional<Widget> widget = Widgets.search().withId(ee.futur.easygotr.data.Constants.PARENT_WIDGET).first();
return widget.isPresent() && !widget.get().isHidden();
}
public boolean isInAltar() {
for (int region : client.getMapRegions()) {
if (GOTR_REGIONS.contains(region)) {
return false;
}
}
return true;
}
public boolean isOutsideBarrier() {
return client.getLocalPlayer().getWorldLocation().getY() <= ee.futur.easygotr.data.Constants.OUTSIDE_BARRIER_Y && !isInAltar();
}
public boolean isInLargeMine() {
return !isInAltar() && client.getLocalPlayer().getWorldLocation().getX() >= ee.futur.easygotr.data.Constants.LARGE_MINE_X;
}
public boolean isInHugeMine() {
return !isInAltar() && client.getLocalPlayer().getWorldLocation().getX() <= ee.futur.easygotr.data.Constants.HUGE_MINE_X;
}
public boolean isGameBusy() {
return !isInAltar() && isOutsideBarrier() && TileObjects.search().withId(Constants.BARRIER_BUSY_ID).nearestToPlayer().isPresent();
}
public boolean isPortalSpawned() {
Widget portalWidget = client.getWidget(PORTAL_WIDGET_ID);
return portalWidget != null && !portalWidget.isHidden();
}
public TileObject getNextAltar() {
int catalytic;
int elemental;
TileObject catalyticAltar = null;
TileObject elementalAltar = null;
List<TileObject> guardians = TileObjects.search().nameContains("Guardian of").result();
for (TileObject guardian : guardians) {
GameObject gameObject = (GameObject) guardian;
Animation animation = ((DynamicObject) gameObject.getRenderable()).getAnimation();
//Active guardians
if (animation.getId() == 9363) {
if (isCatalytic(guardian)) {
if (accessibleAltars.contains(guardian.getId()) && isAltarBetter(catalyticAltar, guardian)) {
catalyticAltar = guardian;
}
} else if (isAltarBetter(elementalAltar, guardian)) {
elementalAltar = guardian;
}
} else {
if (!hasTalisman(guardian)) {
continue;
}
if (isCatalytic(guardian)) {
if (accessibleAltars.contains(guardian.getId()) && isAltarBetter(catalyticAltar, guardian)) {
catalyticAltar = guardian;
}
} else {
if (isAltarBetter(elementalAltar, guardian)) {
elementalAltar = guardian;
}
}
}
}
if (catalyticPoints < 0 && elementalPoints < 0) {
elemental = client.getVarbitValue(13686);
catalytic = client.getVarbitValue(13685);
} else {
elemental = elementalPoints;
catalytic = catalyticPoints;
elemental += (int) Math.floor((double) client.getVarbitValue(13686) / 100);
catalytic += (int) Math.floor((double) client.getVarbitValue(13685) / 100);
}
//log.info("Catalytic: " + catalytic + " Elemental: " + elemental);
if (catalytic == 0 && elemental == 0) {
elemental = 1;
}
Widget catalyticWidget = client.getWidget(48889879);
Widget elementalWidget = client.getWidget(48889876);
if (elementalWidget == null || catalyticWidget == null) {
return null;
}
if (catalyticAltar == null) {
return elementalAltar;
}
if (elementalAltar == null) {
return catalyticAltar;
}
if (config.prioritizeBloodDeath() && isBloodDeath(catalyticAltar)) {
return catalyticAltar;
}
if (isAltarIgnored(catalyticAltar)) {
if (isAltarIgnored(elementalAltar)) {
if (catalytic > elemental) {
return elementalAltar;
} else {
return catalyticAltar;
}
}
return elementalAltar;
}
if (isAltarIgnored(elementalAltar)) {
return catalyticAltar;
}
if (catalytic > elemental) {
return elementalAltar;
}
return catalyticAltar;
}
private boolean isBloodDeath(TileObject altar) {
switch (altar.getId()) {
case BLOOD_ALTAR:
case DEATH_ALTAR:
return true;
default:
return false;
}
}
private boolean isAltarBetter(TileObject oldAltar, TileObject candidate) {
if (oldAltar == null) {
return true;
}
if (getAltarPriority(oldAltar) < getAltarPriority(candidate)) {
return true;
}
if (getAltarPriority(oldAltar) == getAltarPriority(candidate) && hasTalisman(candidate)) {
return true;
}
return false;
}
private boolean isAltarIgnored(TileObject altar) {
switch (altar.getId()) {
case AIR_ALTAR:
return config.ignoreAir();
case MIND_ALTAR:
return config.ignoreMind();
case BODY_ALTAR:
return config.ignoreBody();
case WATER_ALTAR:
return config.ignoreWater();
case COSMIC_ALTAR:
return config.ignoreCosmic();
case CHAOS_ALTAR:
return config.ignoreChaos();
case EARTH_ALTAR:
return config.ignoreEarth();
case NATURE_ALTAR:
return config.ignoreNature();
case LAW_ALTAR:
return config.ignoreLaw();
case FIRE_ALTAR:
return config.ignoreFire();
case DEATH_ALTAR:
return config.ignoreDeath();
case BLOOD_ALTAR:
return config.ignoreBlood();
}
return false;
}
private int getAltarPriority(TileObject altar) {
switch (altar.getId()) {
case AIR_ALTAR:
case MIND_ALTAR:
case BODY_ALTAR:
return 1;
case WATER_ALTAR:
case COSMIC_ALTAR:
case CHAOS_ALTAR:
return 2;
case EARTH_ALTAR:
case NATURE_ALTAR:
case LAW_ALTAR:
return 3;
case FIRE_ALTAR:
case DEATH_ALTAR:
return 4;
case BLOOD_ALTAR:
return 5;
}
return -1;
}
private boolean hasTalisman(TileObject altar) {
int talismanID = 0;
switch (altar.getId()) {
case AIR_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_AIR;
break;
case WATER_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_WATER;
break;
case EARTH_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_EARTH;
break;
case FIRE_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_FIRE;
break;
case MIND_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_MIND;
break;
case CHAOS_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_CHAOS;
break;
case DEATH_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_DEATH;
break;
case BLOOD_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_BLOOD;
break;
case BODY_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_BODY;
break;
case COSMIC_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_COSMIC;
break;
case NATURE_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_NATURE;
break;
case LAW_ALTAR:
talismanID = ItemID.PORTAL_TALISMAN_LAW;
break;
}
return Inventory.getItemAmount(talismanID) > 0;
}
private boolean isCatalytic(TileObject altar) {
Set<Integer> catalyticAltars = Set.of(43705, 43709, 43706, 43710, 43711, 43708, 43712, 43707);
return catalyticAltars.contains(altar.getId());
}
}

View File

@@ -0,0 +1,214 @@
package ee.futur.easygotr;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import ee.futur.baseapi.collections.Inventory;
import ee.futur.easygotr.data.Constants;
import ee.futur.easygotr.data.Pouch;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.*;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.widgets.Widget;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Slf4j
@Singleton
public class PouchManager {
private final List<Pouch> pouches = new ArrayList<>();
@Inject
private Client client;
private final EventBus eventBus;
@Setter
private boolean started;
private final List<Integer> DEGRADED_POUCH_IDS = ImmutableList.of(ItemID.MEDIUM_POUCH_5511, ItemID.LARGE_POUCH_5513, ItemID.GIANT_POUCH_5515,
ItemID.COLOSSAL_POUCH_26786);
@Inject
public PouchManager(EventBus eventBus) {
this.eventBus = eventBus;
}
public void register() {
eventBus.register(this);
}
public void deregister() {
eventBus.unregister(this);
}
public void refreshPouches() {
//pouches.clear();
Optional<Widget> smallpouch = Inventory.search().withId(ItemID.SMALL_POUCH).first();
Optional<Widget> medpouch = Inventory.search().withId(ItemID.MEDIUM_POUCH).first();
Optional<Widget> largepouch = Inventory.search().withId(ItemID.LARGE_POUCH).first();
Optional<Widget> giantpouch = Inventory.search().withId(ItemID.GIANT_POUCH).first();
Optional<Widget> collosalpouch = Inventory.search().withId(ItemID.COLOSSAL_POUCH).first();
if (smallpouch.isPresent()) {
Pouch smallEssPouch = new Pouch(ItemID.SMALL_POUCH, 3);
pouches.removeIf(p -> p.getPouchID() == ItemID.SMALL_POUCH);
pouches.add(smallEssPouch);
}
if (medpouch.isPresent() && client.getRealSkillLevel(Skill.RUNECRAFT) >= 25) {
Pouch medEssPouch = new Pouch(ItemID.MEDIUM_POUCH, 6);
pouches.removeIf(p -> p.getPouchID() == ItemID.MEDIUM_POUCH);
pouches.add(medEssPouch);
}
if (largepouch.isPresent() && client.getRealSkillLevel(Skill.RUNECRAFT) >= 50) {
Pouch largeEssPouch = new Pouch(ItemID.LARGE_POUCH, 9);
pouches.removeIf(p -> p.getPouchID() == ItemID.LARGE_POUCH);
pouches.add(largeEssPouch);
}
if (giantpouch.isPresent() && client.getRealSkillLevel(Skill.RUNECRAFT) >= 75) {
Pouch giantEssPouch = new Pouch(ItemID.GIANT_POUCH, 12);
pouches.removeIf(p -> p.getPouchID() == ItemID.GIANT_POUCH);
pouches.add(giantEssPouch);
}
if (collosalpouch.isPresent() && client.getRealSkillLevel(Skill.RUNECRAFT) >= 85) {
Pouch colossalEssPouch = new Pouch(ItemID.COLOSSAL_POUCH, 40);
pouches.removeIf(p -> p.getPouchID() == ItemID.COLOSSAL_POUCH);
pouches.add(colossalEssPouch);
}
log.info("Setting Pouches: " + pouches);
}
@Subscribe
private void onChatMessage(ChatMessage event) {
//log.info(pouches.toString());
if (client.getGameState() != GameState.LOGGED_IN || !started) {
return;
}
if (event.getType() != ChatMessageType.SPAM && event.getType() != ChatMessageType.GAMEMESSAGE) return;
if (client.getGameState() != GameState.LOGGED_IN) {
return;
}
if (event.getMessage().contains(ee.futur.easygotr.data.Constants.GAME_STARTED)) {
setEssenceInPouches(0);
}
if (event.getMessage().contains(ee.futur.easygotr.data.Constants.GAME_WIN)) {
setEssenceInPouches(0);
}
if (event.getMessage().contains(Constants.GAME_OVER)) {
setEssenceInPouches(0);
}
}
public List<Pouch> getFullPouches() {
List<Pouch> result = new ArrayList<>();
for (Pouch pouch : pouches) {
if (pouch.getCurrentEssence() > 0) {
result.add(pouch);
}
}
return result;
}
public boolean hasFullPouch() {
for (Pouch pouch : pouches) {
if (pouch.getCurrentEssence() > 0) {
return true;
}
}
return false;
}
public void fillPouches() {
int essenceAmount = Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE);
List<Pouch> result = getEmptyPouches();
for (Pouch pouch : result) {
Optional<Widget> emptyPouch = Inventory.search().withId(pouch.getPouchID()).first();
if (emptyPouch.isPresent()) {
Widget p = emptyPouch.get();
//InventoryInteraction.useItem(p, "Fill");
int essenceWithdrawn = pouch.getEssenceTotal() - pouch.getCurrentEssence();
if (essenceAmount - essenceWithdrawn >= 0) {
essenceAmount -= essenceWithdrawn;
pouch.setCurrentEssence(pouch.getEssenceTotal());
} else {
pouch.setCurrentEssence(pouch.getCurrentEssence() + essenceAmount);
essenceAmount = 0;
}
if (essenceAmount == 0) {
break;
}
}
}
}
public void emptyPouches() {
int spaces = Inventory.getEmptySlots();
List<Pouch> result = getFullPouches();
for (Pouch pouch : result) {
Optional<Widget> emptyPouch = Inventory.search().withId(pouch.getPouchID()).first();
if (emptyPouch.isPresent()) {
//InventoryInteraction.useItem(emptyPouch.get(), "Empty");
if (pouch.getCurrentEssence() - spaces < 0) {
spaces -= pouch.getCurrentEssence();
pouch.setCurrentEssence(0);
} else {
pouch.setCurrentEssence(pouch.getCurrentEssence() - spaces);
break;
}
}
}
}
public List<Pouch> getEmptyPouches() {
List<Pouch> result = new ArrayList<>();
for (Pouch pouch : pouches) {
if (!isPouchFull(pouch)) {
result.add(pouch);
}
}
return result;
}
public boolean hasEmptyPouches() {
for (Pouch pouch : pouches) {
if (!isPouchFull(pouch)) {
return true;
}
}
return false;
}
private boolean isPouchFull(Pouch pouch) {
return pouch.getCurrentEssence() == pouch.getEssenceTotal();
}
private void setEssenceInPouches(int amount) {
for (Pouch curr : pouches) {
curr.setCurrentEssence(amount);
}
}
public boolean hasDegradedPouches() {
return Inventory.search().idInList(DEGRADED_POUCH_IDS).first().isPresent();
}
public int getAvailableSpace() {
return pouches.stream().mapToInt(pouch -> pouch.getEssenceTotal() - pouch.getCurrentEssence()).sum();
}
public int getEssenceInPouches() {
return pouches.stream().mapToInt(Pouch::getCurrentEssence).sum();
}
}

View File

@@ -0,0 +1,32 @@
EasyGOTR
Automation plugins for runelite
# Discord
https://discord.gg/kwYBYEg4uu
# [PP] EasyGOTR
**How to setup**:
- Starting Fragments
- How many fragments to mine before leaving the starting area
- Minimum Fragments
- Amount in inventory to start mining more fragments
- Ignore Portal Ess
- Ignores the portal if you have at least this many essence in inventory
- Drop Runes
- Check to drop all runes instead of depositing
- Drop Runes Filter
- Comma delimited, rune names to drop - the rest will be deposited
- Use Essence Pouches?
- Requires NPC Contact runes or redwood lit lantern
- Abyssal Book in bank? (IMPORTANT FOR NPC CONTACT)
- Check if you have the abyssal book in the bank
- This is required because owning the abyssal book changes the dialogue option
- Prioritize Catalytic Energy
- Will try to balance points if not checked
- Prioritize Higher Tier Runes (BETA)
- Prioritizes Nature/Law/Death/Blood runes even if points aren't balanced - Expect some bugs
- Prioritize Portal (BETA)
- Prioritizes the portal, mainly affects when to drop/deposit runes - Expect some bugs

View File

@@ -0,0 +1,45 @@
package ee.futur.easygotr.data;
import lombok.Getter;
@Getter
public enum Altar {
AIR(43701, Constants.AIR_SPRITE),
MIND(43705, Constants.MIND_SPRITE),
WATER(43702, Constants.WATER_SPRITE),
EARTH(43703, Constants.EARTH_SPRITE),
FIRE(43704, Constants.FIRE_SPRITE),
BODY(43709, Constants.BODY_SPRITE),
COSMIC(43710, Constants.COSMIC_SPRITE),
CHAOS(43706, Constants.CHAOS_SPRITE),
NATURE(43711, Constants.NATURE_SPRITE),
LAW(43712, Constants.LAW_SPRITE),
DEATH(43707, Constants.DEATH_SPRITE),
BLOOD(43708, Constants.BLOOD_SPRITE);
final int id;
final int spriteId;
Altar(int id, int spriteId) {
this.id = id;
this.spriteId = spriteId;
}
public static Altar getAltarBySpriteId(int spriteId) {
for (Altar altar : Altar.values()) {
if (altar.getSpriteId() == spriteId) {
return altar;
}
}
return null;
}
public static Altar getAltarByObjectId(int id) {
for (Altar altar : Altar.values()) {
if (altar.getId() == id) {
return altar;
}
}
return null;
}
}

View File

@@ -0,0 +1,38 @@
package ee.futur.easygotr.data;
import net.runelite.api.ItemID;
import net.runelite.api.ObjectID;
public class CellMapper {
public static int GetCellTier(int cellID) {
switch (cellID) {
case ItemID.WEAK_CELL:
return 1;
case ItemID.MEDIUM_CELL:
return 2;
case ItemID.STRONG_CELL:
return 3;
case ItemID.OVERCHARGED_CELL:
return 4;
default:
return -1;
}
}
public static int GetShieldTier(int shieldID) {
switch (shieldID) {
case ObjectID.INACTIVE_CELL_TILE:
return 0;
case ObjectID.WEAK_CELL_TILE:
return 1;
case ObjectID.MEDIUM_CELL_TILE:
return 2;
case ObjectID.STRONG_CELL_TILE:
return 3;
case ObjectID.OVERPOWERED_CELL_TILE:
return 4;
default:
return -1;
}
}
}

View File

@@ -0,0 +1,74 @@
package ee.futur.easygotr.data;
public class Constants {
//Locations
public static final int OUTSIDE_BARRIER_Y = 9482;
public static final int LARGE_MINE_X = 3637;
public static final int HUGE_MINE_X = 3592;
// Game Object IDs
public static final int BARRIER_BUSY_ID = 43849;
public static final int BARRIER_READY_ID = 43700;
public static final int ACTIVE_ALTAR = 9363;
// Widget IDs
public static final int PARENT_WIDGET = 48889857;
public static final int WIDGET_POWER_PC = 48889874;
public static final int MAIN_TIMER = 48889861;
public static final int ELEMENTAL_ENERGY_COUNTER = 48889878;
public static final int CATALYTIC_ENERGY_COUNTER = 48889878;
public static final int GUARDIANS_ALIVE_COUNTER = 48889881;
public static final int PORTAL_TIMER = 48889884;
public static final int WAITING_CATALYTIC_INDICATOR_SPRITE = 4355;
// Widget Text
private static final String OUTSIDE_GUARDED = "It looks like the rift is already being guarded. You must wait until they are done to join.";
private static final String GREAT_GUARDIAN_POWER = "Great Guardian power: ";
// Chat text
public static final String ENTER_ALTAR = "You step through the rift";
public static final String EXIT_ALTAR = "You step through the portal and find yourself back in the temple.";
public static final String GAME_STARTED = "Creatures from the Abyss will attack in 120 seconds.";
public static final String ATTACK_STARTED = "Creatures from the Abyss begin their attack!";
public static final String GAME_OVER = "The Great guardian was defeated";
public static final String GAME_WIN = "The Great Guardian successfully closed the rift!";
// Game Objects
public static final String BARRIER = "Barrier";
public static final String WORKBENCH = "Workbench";
public static final String WEAK_CELLS = "Weak cell";
public static final String UNCHARGED_CELLS = "Uncharged cell";
public static final String DEPOSIT_POOL = "Deposit pool";
public static final String GAME_PARTS = "Guardian parts";
public static final String LARGE_REMAINS = "Large guardian remains";
public static final String HUGE_REMAINS = "Huge guardian remains";
public static final String FRAGS = "Guardian fragments";
public static final String ESS = "Guardian essence";
public static final String PORTAL = "Portal";
public static final int PORTAL_SPAWN = 43729;
public static final String CATALYTIC_ENERGY = "Catalytic guardian stone";
public static final String ELEMENTAL_ENERGY = "Elemental guardian stone";
public static final String GREAT_GUARDIAN = "The Great Guardian";
public static final String CRAFT_RUNES = "Craft-rune";
public static final int AIR_SPRITE = 4353;
public static final int MIND_SPRITE = 4354;
public static final int WATER_SPRITE = 4355;
public static final int EARTH_SPRITE = 4356;
public static final int FIRE_SPRITE = 4357;
public static final int BODY_SPRITE = 4358;
public static final int COSMIC_SPRITE = 4359;
public static final int CHAOS_SPRITE = 4360;
public static final int NATURE_SPRITE = 4361;
public static final int LAW_SPRITE = 4362;
public static final int DEATH_SPRITE = 4363;
public static final int BLOOD_SPRITE = 4364;
}

View File

@@ -0,0 +1,24 @@
package ee.futur.easygotr.data;
import lombok.Getter;
import lombok.Setter;
public class Pouch {
public Pouch(int id, int maxEssence) {
this.pouchID = id;
this.currentEssence = 0;
this.essenceTotal = maxEssence;
}
@Getter
@Setter
int pouchID;
@Getter
@Setter
int currentEssence;
@Getter
int essenceTotal;
}

View File

@@ -0,0 +1,77 @@
package ee.futur.easygotr.data;
/**
* Taken from marcojacobsNL
* https://github.com/marcojacobsNL/runelite-plugins/blob/master/src/main/java/com/koffee/KoffeeUtils/Runes.java
*/
import com.google.common.collect.ImmutableMap;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import java.awt.image.BufferedImage;
import java.util.Map;
import static net.runelite.api.ItemID.*;
public enum Runes {
AIR(1, AIR_RUNE),
WATER(2, WATER_RUNE),
EARTH(3, EARTH_RUNE),
FIRE(4, FIRE_RUNE),
MIND(5, MIND_RUNE),
CHAOS(6, CHAOS_RUNE),
DEATH(7, DEATH_RUNE),
BLOOD(8, BLOOD_RUNE),
COSMIC(9, COSMIC_RUNE),
NATURE(10, NATURE_RUNE),
LAW(11, LAW_RUNE),
BODY(12, BODY_RUNE),
SOUL(13, SOUL_RUNE),
ASTRAL(14, ASTRAL_RUNE),
MIST(15, MIST_RUNE),
MUD(16, MUD_RUNE),
DUST(17, DUST_RUNE),
LAVA(18, LAVA_RUNE),
STEAM(19, STEAM_RUNE),
SMOKE(20, SMOKE_RUNE),
WRATH(21, WRATH_RUNE);
private static final Map<Integer, Runes> runes;
static {
ImmutableMap.Builder<Integer, Runes> builder = new ImmutableMap.Builder<>();
for (Runes rune : values()) {
builder.put(rune.getId(), rune);
}
runes = builder.build();
}
@Getter(AccessLevel.PACKAGE)
private final int id;
@Getter(AccessLevel.PUBLIC)
private final int itemId;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
private BufferedImage image;
Runes(final int id, final int itemId) {
this.id = id;
this.itemId = itemId;
}
public static Runes getRuneVarbit(int runeID) {
return runes.get(runeID);
}
public String getName() {
String name = this.name();
name = name.substring(0, 1) + name.substring(1).toLowerCase();
return name;
}
public static Runes getRune(int varbit) {
return runes.get(varbit);
}
}

View File

@@ -0,0 +1,49 @@
package ee.futur.easygotr.data;
import net.runelite.api.QuestState;
import java.util.HashSet;
import java.util.Set;
public class Utility {
public static int getHighestLevelRuneIndex(int level) {
if (level < 35) {
return 7;
} else if (level < 44) {
return 8;
} else if (level < 54) {
return 9;
} else if (level < 65) {
return 10;
} else if (level < 77) {
return 11;
}
return 12;
}
public static Set<Integer> getAccessibleAltars(int level, QuestState city, QuestState troll, QuestState mep, QuestState sotf) {
Set<Integer> accessibleAltars = new HashSet<>();
for (int i = 0; i < getHighestLevelRuneIndex(level); i++) {
Altar[] altars = Altar.values();
if (altars[i] == Altar.COSMIC && city != QuestState.FINISHED) {
continue;
}
if (altars[i] == Altar.LAW && troll != QuestState.FINISHED) {
continue;
}
if (altars[i] == Altar.DEATH && mep != QuestState.FINISHED) {
continue;
}
if (altars[i] == Altar.BLOOD && sotf != QuestState.FINISHED) {
continue;
}
accessibleAltars.add(altars[i].id);
}
return accessibleAltars;
}
}