diff --git a/.gitignore b/.gitignore index a28bff2..7e939cd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ build .classpath nbactions.xml nb-configuration.xml -nbproject/ \ No newline at end of file +nbproject/ +bin/ diff --git a/banner_black.png b/banner_black.png deleted file mode 100644 index 53d3766..0000000 Binary files a/banner_black.png and /dev/null differ diff --git a/banner_white.png b/banner_white.png deleted file mode 100644 index cf19be2..0000000 Binary files a/banner_white.png and /dev/null differ diff --git a/readme_gifs/best-mould.webp b/readme_gifs/best-mould.webp deleted file mode 100644 index 89d7730..0000000 Binary files a/readme_gifs/best-mould.webp and /dev/null differ diff --git a/readme_gifs/crucible-value.png b/readme_gifs/crucible-value.png deleted file mode 100644 index d6cfc5a..0000000 Binary files a/readme_gifs/crucible-value.png and /dev/null differ diff --git a/readme_gifs/info-panel.webp b/readme_gifs/info-panel.webp deleted file mode 100644 index 22b9384..0000000 Binary files a/readme_gifs/info-panel.webp and /dev/null differ diff --git a/readme_gifs/lava-waterfall-estimate.webp b/readme_gifs/lava-waterfall-estimate.webp deleted file mode 100644 index 6d82e87..0000000 Binary files a/readme_gifs/lava-waterfall-estimate.webp and /dev/null differ diff --git a/readme_gifs/tool-damage-warning.webp b/readme_gifs/tool-damage-warning.webp deleted file mode 100644 index 50076a8..0000000 Binary files a/readme_gifs/tool-damage-warning.webp and /dev/null differ diff --git a/readme_gifs/tools-bonus-notification.webp b/readme_gifs/tools-bonus-notification.webp deleted file mode 100644 index da16a5e..0000000 Binary files a/readme_gifs/tools-bonus-notification.webp and /dev/null differ diff --git a/settings.gradle b/settings.gradle index 9fec846..ad77a14 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -rootProject.name = 'easy-giantsfoundry' +rootProject.name = 'k4rli-plugins' diff --git a/src/main/java/ee/futur/baseapi/collections/BankItemWidget.java b/src/main/java/ee/futur/baseapi/collections/BankItemWidget.java index 0f871c8..e8850ac 100644 --- a/src/main/java/ee/futur/baseapi/collections/BankItemWidget.java +++ b/src/main/java/ee/futur/baseapi/collections/BankItemWidget.java @@ -655,6 +655,26 @@ public class BankItemWidget implements Widget { } + @Override + public boolean isFlippedVertically() { + return false; + } + + @Override + public void setFlippedVertically(boolean b) { + + } + + @Override + public boolean isFlippedHorizontally() { + return false; + } + + @Override + public void setFlippedHorizontally(boolean b) { + + } + @Override public boolean getTextShadowed() { return false; diff --git a/src/main/java/ee/futur/baseapi/collections/EquipmentItemWidget.java b/src/main/java/ee/futur/baseapi/collections/EquipmentItemWidget.java index 6b02386..faf6084 100644 --- a/src/main/java/ee/futur/baseapi/collections/EquipmentItemWidget.java +++ b/src/main/java/ee/futur/baseapi/collections/EquipmentItemWidget.java @@ -585,6 +585,26 @@ public class EquipmentItemWidget implements Widget { } + @Override + public boolean isFlippedVertically() { + return false; + } + + @Override + public void setFlippedVertically(boolean b) { + + } + + @Override + public boolean isFlippedHorizontally() { + return false; + } + + @Override + public void setFlippedHorizontally(boolean b) { + + } + @Override public boolean getTextShadowed() { return false; diff --git a/src/main/java/ee/futur/easygotr/EasyGOTRActionHint.java b/src/main/java/ee/futur/easygotr/EasyGOTRActionHint.java new file mode 100644 index 0000000..ea48ba6 --- /dev/null +++ b/src/main/java/ee/futur/easygotr/EasyGOTRActionHint.java @@ -0,0 +1,28 @@ +package ee.futur.easygotr; + +import lombok.Builder; +import lombok.Singular; +import lombok.Value; + +import java.util.Collections; +import java.util.List; + +@Value +@Builder(toBuilder = true) +public class EasyGOTRActionHint { + EasyGOTRState state; + String currentAction; + String nextAction; + @Singular + List notes; + @Singular + List highlights; + + public List getNotesSafe() { + return notes == null ? Collections.emptyList() : notes; + } + + public List getHighlightsSafe() { + return highlights == null ? Collections.emptyList() : highlights; + } +} diff --git a/src/main/java/ee/futur/easygotr/EasyGOTRConfig.java b/src/main/java/ee/futur/easygotr/EasyGOTRConfig.java index abb5e02..d7e0701 100644 --- a/src/main/java/ee/futur/easygotr/EasyGOTRConfig.java +++ b/src/main/java/ee/futur/easygotr/EasyGOTRConfig.java @@ -55,33 +55,44 @@ public interface EasyGOTRConfig extends Config { return ""; } + @ConfigItem( + keyName = "collectUnchargedCells", + name = "Collect Uncharged Cells", + description = "When disabled, the plugin will no longer recommend picking up uncharged cells.", + position = 6, + section = easyGOTRConfig + ) + default boolean collectUnchargedCells() { + return true; + } + + @ConfigItem( + keyName = "keepImbueRunes", + name = "Keep Imbue Runes", + description = "Ignore water and fire runes when deciding to deposit runes (useful for Magic Imbue).", + position = 7, + section = easyGOTRConfig + ) + default boolean keepImbueRunes() { + return false; + } + @ConfigItem( keyName = "usePouches", name = "Use Essence Pouches?", description = "Requires NPC Contact runes in Rune Pouch or Redwood lit Lantern", - position = 6, + position = 8, 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, + position = 10, section = easyGOTRConfig ) default int startingFrags() { diff --git a/src/main/java/ee/futur/easygotr/EasyGOTRHighlightTarget.java b/src/main/java/ee/futur/easygotr/EasyGOTRHighlightTarget.java new file mode 100644 index 0000000..dd21ade --- /dev/null +++ b/src/main/java/ee/futur/easygotr/EasyGOTRHighlightTarget.java @@ -0,0 +1,57 @@ +package ee.futur.easygotr; + +import lombok.Getter; +import net.runelite.api.NPC; +import net.runelite.api.TileObject; +import net.runelite.api.coords.WorldPoint; + +import java.awt.*; +import java.util.Optional; + +/** + * Represents an entity or tile that should be highlighted for the player. + */ +@Getter +public class EasyGOTRHighlightTarget { + private final TileObject tileObject; + private final NPC npc; + private final WorldPoint worldPoint; + private final Color color; + private final String label; + + private EasyGOTRHighlightTarget(TileObject tileObject, NPC npc, WorldPoint worldPoint, Color color, String label) { + this.tileObject = tileObject; + this.npc = npc; + this.worldPoint = worldPoint; + this.color = color; + this.label = label; + } + + public static EasyGOTRHighlightTarget forTileObject(TileObject tileObject, Color color, String label) { + return new EasyGOTRHighlightTarget(tileObject, null, null, color, label); + } + + public static EasyGOTRHighlightTarget forNpc(NPC npc, Color color, String label) { + return new EasyGOTRHighlightTarget(null, npc, null, color, label); + } + + public static EasyGOTRHighlightTarget forWorldPoint(WorldPoint worldPoint, Color color, String label) { + return new EasyGOTRHighlightTarget(null, null, worldPoint, color, label); + } + + public Optional getTileObjectOptional() { + return Optional.ofNullable(tileObject); + } + + public Optional getNpcOptional() { + return Optional.ofNullable(npc); + } + + public Optional getWorldPointOptional() { + return Optional.ofNullable(worldPoint); + } + + public Color getColorOrDefault(Color defaultColor) { + return color != null ? color : defaultColor; + } +} diff --git a/src/main/java/ee/futur/easygotr/EasyGOTROverlay.java b/src/main/java/ee/futur/easygotr/EasyGOTROverlay.java index c309ba8..dbd66e1 100644 --- a/src/main/java/ee/futur/easygotr/EasyGOTROverlay.java +++ b/src/main/java/ee/futur/easygotr/EasyGOTROverlay.java @@ -16,6 +16,7 @@ public class EasyGOTROverlay extends OverlayPanel { private final Client client; private final EasyGOTRPlugin plugin; public String overlayState = ""; + private EasyGOTRActionHint hint; @Inject private EasyGOTROverlay(Client client, EasyGOTRPlugin plugin) { @@ -24,8 +25,13 @@ public class EasyGOTROverlay extends OverlayPanel { setPosition(OverlayPosition.BOTTOM_LEFT); } + public void setHint(EasyGOTRActionHint hint) { + this.hint = hint; + } + @Override public Dimension render(Graphics2D graphics) { + panelComponent.getChildren().clear(); String timeFormat = (plugin.runningDuration.toHours() < 1) ? "mm:ss" : "HH:mm:ss"; panelComponent.getChildren().add(TitleComponent.builder() .text("EasyGOTR") @@ -63,6 +69,71 @@ public class EasyGOTROverlay extends OverlayPanel { .right(String.valueOf(plugin.riftState.hasFirstPortalSpawned)) .rightColor(Color.WHITE) .build()); + + plugin.getPortalTimerText().ifPresent(timer -> panelComponent.getChildren().add(LineComponent.builder() + .left("Portal:") + .leftColor(Color.WHITE) + .right(timer) + .rightColor(Color.WHITE) + .build())); + + plugin.getPortalTimingSummary().ifPresent(summary -> panelComponent.getChildren().add(LineComponent.builder() + .left("Portal Timing:") + .leftColor(Color.WHITE) + .right(summary) + .rightColor(Color.WHITE) + .build())); + + plugin.getMainTimerText().ifPresent(mainTimer -> panelComponent.getChildren().add(LineComponent.builder() + .left("Main Timer:") + .leftColor(Color.WHITE) + .right(mainTimer) + .rightColor(Color.WHITE) + .build())); + + plugin.getNextAltarName().ifPresent(name -> panelComponent.getChildren().add(LineComponent.builder() + .left("Next Altar:") + .leftColor(Color.WHITE) + .right(name) + .rightColor(Color.WHITE) + .build())); + + plugin.getEnergySummary().ifPresent(summary -> panelComponent.getChildren().add(LineComponent.builder() + .left("Energy:") + .leftColor(Color.WHITE) + .right(summary) + .rightColor(Color.WHITE) + .build())); + + EasyGOTRActionHint localHint = hint; + if (localHint != null) { + if (localHint.getCurrentAction() != null && !localHint.getCurrentAction().isEmpty()) { + panelComponent.getChildren().add(LineComponent.builder() + .left("Current:") + .leftColor(Color.WHITE) + .right(localHint.getCurrentAction()) + .rightColor(Color.WHITE) + .build()); + } + if (localHint.getNextAction() != null && !localHint.getNextAction().isEmpty()) { + panelComponent.getChildren().add(LineComponent.builder() + .left("Next:") + .leftColor(Color.WHITE) + .right(localHint.getNextAction()) + .rightColor(Color.WHITE) + .build()); + } + + for (String note : localHint.getNotesSafe()) { + panelComponent.getChildren().add(LineComponent.builder() + .left("Tip:") + .leftColor(Color.LIGHT_GRAY) + .right(note) + .rightColor(Color.LIGHT_GRAY) + .build()); + } + } + panelComponent.setPreferredSize(new Dimension(250, 250)); } return super.render(graphics); diff --git a/src/main/java/ee/futur/easygotr/EasyGOTRPlugin.java b/src/main/java/ee/futur/easygotr/EasyGOTRPlugin.java index 5be1d6f..46e9e21 100644 --- a/src/main/java/ee/futur/easygotr/EasyGOTRPlugin.java +++ b/src/main/java/ee/futur/easygotr/EasyGOTRPlugin.java @@ -4,11 +4,11 @@ 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.BaseApiPlugin; 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.easygotr.data.GOTRGameConstants; import ee.futur.utils.InventoryUtil; import lombok.extern.slf4j.Slf4j; import net.runelite.api.*; @@ -23,11 +23,14 @@ 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 net.runelite.client.util.Text; import org.apache.commons.lang3.RandomUtils; +import java.awt.*; import java.time.Duration; import java.time.Instant; import java.util.*; +import java.util.List; import java.util.concurrent.ThreadLocalRandom; @PluginDescriptor( @@ -45,6 +48,8 @@ public class EasyGOTRPlugin extends Plugin { @Inject private EasyGOTROverlay overlay; @Inject + private EasyGOTRSceneOverlay sceneOverlay; + @Inject private KeyManager keyManager; @Inject private OverlayManager overlayManager; @@ -103,12 +108,14 @@ public class EasyGOTRPlugin extends Plugin { ItemID.CRYSTAL_PICKAXE_INACTIVE, ItemID.INFERNAL_PICKAXE_OR); private final List PoweredCellList = ImmutableList.of(ItemID.WEAK_CELL, ItemID.OVERCHARGED_CELL, ItemID.STRONG_CELL, ItemID.MEDIUM_CELL); + private static final Duration PORTAL_ACTIVE_DURATION = Duration.ofMillis(43L * 600); public boolean started = false; public int timeout = 0; private boolean startingRun = false; private boolean needsMoreStartingFragments = false; private boolean canEnterBarrier = false; + private EasyGOTRActionHint currentHint; @Provides private EasyGOTRConfig getConfig(ConfigManager configManager) { @@ -119,30 +126,44 @@ public class EasyGOTRPlugin extends Plugin { protected void startUp() throws Exception { keyManager.registerKeyListener(toggle); overlayManager.add(overlay); + overlayManager.add(sceneOverlay); timeout = 0; timer = Instant.now(); pouchManager.register(); riftState.register(); + currentHint = null; + overlay.setHint(null); + sceneOverlay.setHint(null); } @Override protected void shutDown() throws Exception { keyManager.unregisterKeyListener(toggle); overlayManager.remove(overlay); + overlayManager.remove(sceneOverlay); pouchManager.deregister(); riftState.deregister(); timeout = 0; toggle(); timer = Instant.now(); + currentHint = null; + overlay.setHint(null); + sceneOverlay.setHint(null); } @Subscribe private void onGameTick(GameTick event) { if (timeout > 0) { timeout--; + } + + if (client.getGameState() != GameState.LOGGED_IN) { return; } - if (client.getGameState() != GameState.LOGGED_IN || !started) { + + if (!started) { + overlay.setHint(null); + sceneOverlay.setHint(null); return; } @@ -161,22 +182,11 @@ public class EasyGOTRPlugin extends Plugin { 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(); + overlay.overlayState = formatStateName(state); + currentHint = buildHint(state); + overlay.setHint(currentHint); + sceneOverlay.setHint(currentHint); if (BaseApiPlugin.isMoving()) { //Attempt to put runes in pouch where possible @@ -204,70 +214,11 @@ public class EasyGOTRPlugin extends Plugin { } } - 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; + if (config.startingFrags() > 0) { + needsMoreStartingFragments = getFragmentCount() > config.startingFrags(); } else if (config.startingFrags() == 0) { needsMoreStartingFragments = true; } @@ -340,7 +291,7 @@ public class EasyGOTRPlugin extends Plugin { return EasyGOTRState.POWER_GUARDIAN; } - if (hasPowerCell()) { + if (config.collectUnchargedCells() && hasPowerCell()) { return EasyGOTRState.USE_CELL; } @@ -351,7 +302,11 @@ public class EasyGOTRPlugin extends Plugin { return EasyGOTRState.CRAFTING_ESSENCE; } - if (getCellCount() == 0) { + if (hasPowerEssence()) { + return EasyGOTRState.POWER_GUARDIAN; + } + + if (config.collectUnchargedCells() && getCellCount() == 0) { return EasyGOTRState.GET_CELLS; } @@ -386,7 +341,7 @@ public class EasyGOTRPlugin extends Plugin { return EasyGOTRState.POWER_GUARDIAN; } - if (hasPowerCell()) { + if (config.collectUnchargedCells() && hasPowerCell()) { return EasyGOTRState.USE_CELL; } @@ -423,7 +378,7 @@ public class EasyGOTRPlugin extends Plugin { } if (riftState.isInLargeMine()) { - if (hasPowerCell()) { + if (config.collectUnchargedCells() && hasPowerCell()) { Inventory.search().idInList(PoweredCellList).first().ifPresent(widget -> { //InventoryInteraction.useItem(widget, "Drop"); }); @@ -437,7 +392,7 @@ public class EasyGOTRPlugin extends Plugin { //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) { + if (config.collectUnchargedCells() && getCellCount() < 10) { return EasyGOTRState.GET_CELLS; } @@ -463,11 +418,15 @@ public class EasyGOTRPlugin extends Plugin { return EasyGOTRState.LEAVE_ALTAR; } + if (hasPowerEssence()) { + return EasyGOTRState.POWER_GUARDIAN; + } + if (getInventoryRunes().isPresent()) { return EasyGOTRState.DEPOSIT_RUNES; } - if (getCellCount() < 10) { + if (config.collectUnchargedCells() && getCellCount() < 10) { return EasyGOTRState.GET_CELLS; } @@ -479,7 +438,7 @@ public class EasyGOTRPlugin extends Plugin { } private void waitForGame() { - if (client.getLocalPlayer().getWorldLocation().getX() == Constants.LARGE_MINE_X) { + if (client.getLocalPlayer().getWorldLocation().getX() == GOTRGameConstants.LARGE_MINE_X) { if (tickDelay() % 2 == 0) { //MousePackets.queueClickPacket(); //MovementPackets.queueMovement(3639, 9500, false); @@ -549,6 +508,10 @@ public class EasyGOTRPlugin extends Plugin { } private void getCells() { + if (!config.collectUnchargedCells()) { + return; + } + if (Inventory.full() && Inventory.getItemAmount(ItemID.UNCHARGED_CELL) == 0) { Inventory.search().withId(ItemID.GUARDIAN_ESSENCE).first().ifPresent(widget -> { //InventoryInteraction.useItem(widget, "Drop"); @@ -567,7 +530,7 @@ public class EasyGOTRPlugin extends Plugin { private void craftEssence() { if (riftState.isGameStarted()) { - Optional tileObject = TileObjects.search().nameContains(Constants.WORKBENCH).nearestToPlayer(); + Optional tileObject = TileObjects.search().nameContains(GOTRGameConstants.WORKBENCH).nearestToPlayer(); if (tileObject.isEmpty()) { return; } @@ -578,7 +541,7 @@ public class EasyGOTRPlugin extends Plugin { } private void mineHugeGuardians() { - Optional tileObject = TileObjects.search().nameContains(Constants.HUGE_REMAINS).nearestToPlayer(); + Optional tileObject = TileObjects.search().nameContains(GOTRGameConstants.HUGE_REMAINS).nearestToPlayer(); if (tileObject.isEmpty()) { return; } @@ -594,7 +557,7 @@ public class EasyGOTRPlugin extends Plugin { }); } - Optional tileObject = TileObjects.search().nameContains(Constants.LARGE_REMAINS).nearestToPlayer(); + Optional tileObject = TileObjects.search().nameContains(GOTRGameConstants.LARGE_REMAINS).nearestToPlayer(); if (tileObject.isEmpty()) { return; } @@ -606,11 +569,13 @@ public class EasyGOTRPlugin extends Plugin { } private Optional getInventoryRunes() { - return Inventory.search().idInList(RuneList).first(); + return Inventory.search().idInList(RuneList) + .filter(widget -> !isProtectedImbueRune(widget.getItemId())) + .first(); } private void mineGameGuardians() { - Optional tileObject = nameContainsNoCase(Constants.GAME_PARTS).nearestToPlayer(); + Optional tileObject = nameContainsNoCase(GOTRGameConstants.GAME_PARTS).nearestToPlayer(); if (tileObject.isEmpty()) { return; } @@ -635,7 +600,7 @@ public class EasyGOTRPlugin extends Plugin { } if (RandomUtils.nextInt(0, 100) == 30) { - TileObjects.search().withId(Constants.BARRIER_BUSY_ID).first().ifPresent(tileObject -> { + TileObjects.search().withId(GOTRGameConstants.BARRIER_BUSY_ID).first().ifPresent(tileObject -> { // TileObjectInteraction.interact(tileObject, "Peek"); }); } @@ -686,6 +651,9 @@ public class EasyGOTRPlugin extends Plugin { //breakHandler.startPlugin(this); } else { + currentHint = null; + overlay.setHint(null); + sceneOverlay.setHint(null); //breakHandler.stopPlugin(this); } } @@ -716,6 +684,390 @@ public class EasyGOTRPlugin extends Plugin { client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", message, null); } + private EasyGOTRActionHint buildHint(EasyGOTRState state) { + EasyGOTRActionHint.EasyGOTRActionHintBuilder builder = EasyGOTRActionHint.builder() + .state(state); + + switch (state) { + case WAITING_FOR_GAME: + builder.currentAction("Wait in the lobby for the next round."); + builder.nextAction("Quick-pass the barrier when it opens."); + findBarrier().ifPresent(barrier -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(barrier, Color.YELLOW, "Barrier"))); + break; + case MOVE_TO_EAST_MINE: + builder.currentAction("Head down into the east mine."); + builder.nextAction("Mine the highlighted remains for fragments."); + findClimbableRubble().ifPresent(rubble -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(rubble, Color.ORANGE, "Climb down"))); + break; + case LEAVE_EAST_MINE: + builder.currentAction("Leave the east mine."); + builder.nextAction("Return to crafting or enter the portal."); + findClimbableRubble().ifPresent(rubble -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(rubble, Color.ORANGE, "Climb up"))); + break; + case ENTER_PORTAL: + builder.currentAction("Enter the guardian portal."); + builder.nextAction("Continue with the highlighted activity in the temple."); + findPortal().ifPresent(portal -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(portal, Color.MAGENTA, "Enter portal"))); + break; + case ENTER_GAME: + builder.currentAction("Quick-pass the barrier to join the round."); + builder.nextAction("Move to the mine once inside."); + findBarrier().ifPresent(barrier -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(barrier, Color.YELLOW, "Quick-pass"))); + break; + case GAME_BUSY: + builder.currentAction("Wait by the barrier until the game opens."); + builder.nextAction("Quick-pass the barrier as soon as it is available."); + findBarrier().ifPresent(barrier -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(barrier, Color.YELLOW, "Barrier"))); + builder.note("Combine your fragments and prepare while you wait."); + break; + case GET_CELLS: + if (config.collectUnchargedCells()) { + builder.currentAction("Take uncharged cells from the table."); + builder.nextAction("Craft guardian essence at the workbench."); + findUnchargedCells().ifPresent(cells -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(cells, Color.CYAN, "Take cells"))); + } else { + builder.currentAction("Cell collection disabled in config."); + builder.nextAction("Continue with your current rotation."); + builder.note("Enable \"Collect Uncharged Cells\" to receive guidance here."); + } + break; + case CRAFT_ESSENCE: + case CRAFTING_ESSENCE: + builder.currentAction("Use the workbench to make guardian essence."); + builder.nextAction("Refill pouches or mine more fragments when done."); + findWorkbench().ifPresent(workbench -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(workbench, Color.CYAN, "Work-at"))); + break; + case REPAIR_POUCH: + builder.currentAction("Repair your pouches via NPC Contact (Dark Mage)."); + builder.nextAction("Resume mining once pouches are fixed."); + builder.note("Ensure you have NPC Contact runes or a rune pouch ready."); + break; + case POWER_GUARDIAN: + builder.currentAction("Use stones on the Great Guardian."); + builder.nextAction("Enter the highlighted altar afterwards."); + findGreatGuardian().ifPresent(guardian -> + builder.highlight(EasyGOTRHighlightTarget.forNpc(guardian, Color.GREEN, "Power Guardian"))); + break; + case MINE_HUGE_GUARDIANS: + case MINING: + if (riftState.isInHugeMine()) { + builder.currentAction("Mine the huge guardian remains."); + builder.nextAction("Enter the portal when your inventory is full."); + findHugeRemains().ifPresent(remains -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(remains, Color.ORANGE, "Mine"))); + } else if (riftState.isInLargeMine()) { + builder.currentAction("Mine the large guardian remains."); + builder.nextAction("Craft essence at the workbench after mining."); + findLargeRemains().ifPresent(remains -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(remains, Color.ORANGE, "Mine"))); + } else { + builder.currentAction("Mine guardian remains in the temple."); + builder.nextAction("Craft essence once you have enough fragments."); + findRegularRemains().ifPresent(remains -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(remains, Color.ORANGE, "Mine"))); + } + break; + case MINE_LARGE_GUARDIANS: + builder.currentAction("Mine the large guardian remains."); + builder.nextAction("Return to the workbench to craft essence."); + findLargeRemains().ifPresent(remains -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(remains, Color.ORANGE, "Mine"))); + break; + case MINE_REGULAR_GUARDIANS: + builder.currentAction("Mine guardian remains in the temple."); + builder.nextAction("Craft essence at the workbench once ready."); + findRegularRemains().ifPresent(remains -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(remains, Color.ORANGE, "Mine"))); + break; + case DEPOSIT_RUNES: + builder.currentAction("Deposit your crafted runes."); + builder.nextAction("Return to mining or crafting essence."); + findDepositPool().ifPresent(pool -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(pool, Color.CYAN, "Deposit"))); + break; + case USE_CELL: + builder.currentAction("Place a charged cell on the highlighted tile."); + builder.nextAction("Power the guardian or prepare for the next altar."); + Inventory.search().idInList(PoweredCellList).first() + .ifPresent(widget -> builder.note("Cell tier: " + getCellTierName(CellMapper.GetCellTier(widget.getItemId())))); + determineCellPlacement().ifPresent(builder::highlight); + break; + case CRAFT_RUNES: + builder.currentAction("Craft runes at the active altar."); + builder.nextAction("Exit back to the temple once finished."); + findCraftingAltar().ifPresent(altar -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(altar, Color.GREEN, "Craft-rune"))); + break; + case LEAVE_ALTAR: + builder.currentAction("Exit the altar to return to the temple."); + builder.nextAction("Deposit runes or power the guardian."); + findPortal().ifPresent(portal -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(portal, Color.MAGENTA, "Use portal"))); + break; + case ENTER_ALTAR: + builder.currentAction("Enter the highlighted guardian portal."); + builder.nextAction("Craft runes inside the altar."); + Optional nextAltar = Optional.ofNullable(riftState.getNextAltar()); + nextAltar.ifPresent(altar -> + builder.highlight(EasyGOTRHighlightTarget.forTileObject(altar, Color.GREEN, "Enter altar"))); + if (nextAltar.isEmpty()) { + builder.note("Wait for a guardian to become active."); + } + break; + case BREAK: + builder.currentAction("Idle until the next round begins."); + builder.nextAction("Move to the barrier when a game starts."); + builder.note("Gather fragments or restock supplies while waiting."); + break; + } + + if (getInventoryRunes().isPresent() && config.dropRunes()) { + builder.note("Drop leftover runes to free space (per config)."); + } + + if (config.usePouches() && pouchManager.hasDegradedPouches()) { + builder.note("Repair pouches before continuing."); + } + + int essence = Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE); + if (essence == 0 && getFragmentCount() < neededFrags() && !riftState.isInAltar()) { + builder.note("Mine fragments until you can craft more essence."); + } + + if (riftState.getNextAltar() != null) { + builder.note("Next altar: " + getObjectName(riftState.getNextAltar())); + } + + getInventoryRunes().ifPresent(runeWidget -> { + if (getRunePouch().isPresent() && canDepositRune(runeWidget.getItemId())) { + builder.note("Store spare runes in your rune pouch (click rune \u2192 pouch)."); + } + }); + + EasyGOTRActionHint hint = builder.build(); + if (hint.getCurrentAction() == null || hint.getCurrentAction().isEmpty()) { + return hint.toBuilder().currentAction("Track the highlighted targets.").build(); + } + + return hint; + } + + private Optional determineCellPlacement() { + if (!config.collectUnchargedCells()) { + return Optional.empty(); + } + + Optional optCell = Inventory.search().idInList(PoweredCellList).first(); + if (optCell.isEmpty()) { + return Optional.empty(); + } + + Widget cell = optCell.get(); + TileObject nextAltar = riftState.getNextAltar(); + int cellTier = CellMapper.GetCellTier(cell.getItemId()); + List shieldCells = TileObjects.search().nameContains("cell tile").result(); + for (TileObject tile : shieldCells) { + if (CellMapper.GetShieldTier(tile.getId()) < cellTier) { + return Optional.of(EasyGOTRHighlightTarget.forTileObject(tile, Color.CYAN, "Upgrade shield")); + } + } + + if (nextAltar == null) { + Optional bestBarrier = NPCs.search() + .filter(x -> x.getId() <= 11425 && x.getId() >= 11418) + .result().stream().min(Comparator.comparingDouble(this::getBarrierHealth)); + if (bestBarrier.isPresent()) { + Optional tile = TileObjects.search().nameContains("cell tile").nearestToPoint(bestBarrier.get().getWorldLocation()); + if (tile.isPresent()) { + return Optional.of(EasyGOTRHighlightTarget.forTileObject(tile.get(), Color.CYAN, "Support barrier")); + } + } + } else { + Optional damagedBarrier = NPCs.search() + .filter(x -> x.getId() <= 11425 && x.getId() >= 11418 && getBarrierHealth(x) <= 50) + .first(); + if (damagedBarrier.isPresent()) { + Optional tile = TileObjects.search().nameContains("cell tile").nearestToPoint(damagedBarrier.get().getWorldLocation()); + if (tile.isPresent()) { + return Optional.of(EasyGOTRHighlightTarget.forTileObject(tile.get(), Color.CYAN, "Repair barrier")); + } + } + + Optional 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 tile = TileObjects.search().nameContains("cell tile").nearestToPoint(bestBarrier.get().getWorldLocation()); + if (tile.isPresent()) { + return Optional.of(EasyGOTRHighlightTarget.forTileObject(tile.get(), Color.CYAN, "Boost shield")); + } + } + } + + return Optional.empty(); + } + + private String getCellTierName(int tier) { + switch (tier) { + case 1: + return "Weak"; + case 2: + return "Medium"; + case 3: + return "Strong"; + case 4: + return "Overcharged"; + default: + return "Unknown"; + } + } + + private String getObjectName(TileObject tileObject) { + ObjectComposition composition = TileObjectQuery.getObjectComposition(tileObject); + if (composition == null) { + return "Unknown"; + } + return composition.getName(); + } + + private Optional findClimbableRubble() { + return TileObjects.search().withAction("Climb").nearestToPlayer(); + } + + private Optional findPortal() { + return nameContainsNoCase(GOTRGameConstants.PORTAL).nearestToPlayer(); + } + + private Optional findWorkbench() { + return TileObjects.search().nameContains(GOTRGameConstants.WORKBENCH).nearestToPlayer(); + } + + private Optional findHugeRemains() { + return TileObjects.search().nameContains(GOTRGameConstants.HUGE_REMAINS).nearestToPlayer(); + } + + private Optional findLargeRemains() { + return TileObjects.search().nameContains(GOTRGameConstants.LARGE_REMAINS).nearestToPlayer(); + } + + private Optional findRegularRemains() { + return nameContainsNoCase(GOTRGameConstants.GAME_PARTS).nearestToPlayer(); + } + + private Optional findDepositPool() { + return TileObjects.search().nameContains(GOTRGameConstants.DEPOSIT_POOL).nearestToPlayer(); + } + + private Optional findUnchargedCells() { + return TileObjects.search().nameContains(GOTRGameConstants.UNCHARGED_CELLS).nearestToPlayer(); + } + + private Optional findCraftingAltar() { + return TileObjects.search().withAction(GOTRGameConstants.CRAFT_RUNES).nearestToPlayer(); + } + + private Optional findBarrier() { + return TileObjects.search().withName(GOTRGameConstants.BARRIER).nearestToPlayer(); + } + + private Optional findGreatGuardian() { + return NPCs.search().nameContains(GOTRGameConstants.GREAT_GUARDIAN).nearestToPlayer(); + } + + private String formatStateName(EasyGOTRState state) { + String name = state.name().toLowerCase(Locale.ROOT).replace('_', ' '); + if (name.isEmpty()) { + return name; + } + return Character.toUpperCase(name.charAt(0)) + name.substring(1); + } + + public Optional getPortalTimerText() { + Widget portalWidget = client.getWidget(GOTRGameConstants.PORTAL_TIMER); + if (portalWidget == null || portalWidget.isHidden()) { + return Optional.empty(); + } + + String rawText = portalWidget.getText(); + if (rawText == null || rawText.isEmpty()) { + return Optional.empty(); + } + + String clean = Text.removeTags(rawText).trim(); + return clean.isEmpty() ? Optional.empty() : Optional.of(clean); + } + + public Optional getPortalTimingSummary() { + Instant now = Instant.now(); + if (riftState.isPortalSpawned()) { + return riftState.getPortalSpawnTime().map(spawn -> { + long sinceMillis = Math.max(0L, Duration.between(spawn, now).toMillis()); + long remainingMillis = Math.max(0L, PORTAL_ACTIVE_DURATION.toMillis() - sinceMillis); + double sinceSeconds = sinceMillis / 1000d; + double remainingSeconds = remainingMillis / 1000d; + return String.format("Open %.1fs (closes in %.1fs)", sinceSeconds, remainingSeconds); + }); + } + + return riftState.getLastPortalCloseTime().map(close -> { + long sinceMillis = Math.max(0L, Duration.between(close, now).toMillis()); + double sinceSeconds = sinceMillis / 1000d; + return String.format("Closed %.1fs ago", sinceSeconds); + }); + } + + public Optional getMainTimerText() { + Widget mainTimer = client.getWidget(GOTRGameConstants.MAIN_TIMER); + if (mainTimer == null || mainTimer.isHidden()) { + return Optional.empty(); + } + + String text = Text.removeTags(mainTimer.getText()).trim(); + return text.isEmpty() ? Optional.empty() : Optional.of(text); + } + + public Optional getNextAltarName() { + TileObject next = riftState.getNextAltar(); + if (next == null) { + return Optional.empty(); + } + + String name = getObjectName(next); + if (name == null || name.isEmpty() || "Unknown".equals(name)) { + return Optional.empty(); + } + + return Optional.of(name); + } + + public Optional getEnergySummary() { + int elemental = riftState.getElementalPoints(); + int catalytic = riftState.getCatalyticPoints(); + if (elemental < 0 || catalytic < 0) { + return Optional.empty(); + } + + String summary = String.format("E: %,d | C: %,d", elemental, catalytic); + return Optional.of(summary); + } + + private boolean isProtectedImbueRune(int itemId) { + if (!config.keepImbueRunes()) { + return false; + } + + return itemId == ItemID.WATER_RUNE || itemId == ItemID.FIRE_RUNE; + } + private boolean hasRuneAmount(int runeId, int amount) { return (client.getVarbitValue(Varbits.RUNE_POUCH_RUNE1) == runeId && client.getVarbitValue(Varbits.RUNE_POUCH_AMOUNT1) >= amount) @@ -758,7 +1110,7 @@ public class EasyGOTRPlugin extends Plugin { if (BaseApiPlugin.isMoving()) { return; } - Optional tileObject = nameContainsNoCase(Constants.PORTAL).filter(to -> to.getWorldLocation().getY() >= Constants.OUTSIDE_BARRIER_Y).nearestToPlayer(); + Optional tileObject = nameContainsNoCase(GOTRGameConstants.PORTAL).filter(to -> to.getWorldLocation().getY() >= GOTRGameConstants.OUTSIDE_BARRIER_Y).nearestToPlayer(); if (tileObject.isEmpty()) { //MousePackets.queueClickPacket(); //MovementPackets.queueMovement(new WorldPoint(3615, 9499, 0)); @@ -775,7 +1127,7 @@ public class EasyGOTRPlugin extends Plugin { if (BaseApiPlugin.isMoving()) { return; } - Optional tileObject = TileObjects.search().nameContains(Constants.PORTAL).nearestToPlayer(); + Optional tileObject = TileObjects.search().nameContains(GOTRGameConstants.PORTAL).nearestToPlayer(); if (tileObject.isEmpty()) { return; } @@ -786,7 +1138,7 @@ public class EasyGOTRPlugin extends Plugin { } private void powerGuardian() { - Optional npc = NPCs.search().nameContains(Constants.GREAT_GUARDIAN).nearestToPlayer(); + Optional npc = NPCs.search().nameContains(GOTRGameConstants.GREAT_GUARDIAN).nearestToPlayer(); if (npc.isEmpty()) { return; } @@ -905,7 +1257,10 @@ public class EasyGOTRPlugin extends Plugin { String[] runeFilterConfig = config.dropRunesFilter().split(","); for (String rune : runeFilterConfig) { rune = rune.trim(); - Inventory.search().matchesWildCardNoCase(rune).first().ifPresent(runesToDrop::add); + Inventory.search().matchesWildCardNoCase(rune) + .first() + .filter(widget -> !isProtectedImbueRune(widget.getItemId())) + .ifPresent(runesToDrop::add); } return runesToDrop; } @@ -916,7 +1271,10 @@ public class EasyGOTRPlugin extends Plugin { } if (config.dropRunes()) { - Optional itemWidget = InventoryUtil.nameContainsNoCase("rune").filter(item -> !item.getName().contains("pickaxe")).first(); + Optional itemWidget = InventoryUtil.nameContainsNoCase("rune") + .filter(item -> !item.getName().contains("pickaxe")) + .filter(item -> !isProtectedImbueRune(item.getItemId())) + .first(); if (itemWidget.isEmpty()) { return; } @@ -939,7 +1297,7 @@ public class EasyGOTRPlugin extends Plugin { } private void craftRunes() { - Optional tileObject = TileObjects.search().withAction(Constants.CRAFT_RUNES).nearestToPlayer(); + Optional tileObject = TileObjects.search().withAction(GOTRGameConstants.CRAFT_RUNES).nearestToPlayer(); if (tileObject.isEmpty()) { return; } diff --git a/src/main/java/ee/futur/easygotr/EasyGOTRSceneOverlay.java b/src/main/java/ee/futur/easygotr/EasyGOTRSceneOverlay.java new file mode 100644 index 0000000..0b0beb7 --- /dev/null +++ b/src/main/java/ee/futur/easygotr/EasyGOTRSceneOverlay.java @@ -0,0 +1,111 @@ +package ee.futur.easygotr; + +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.api.Point; +import net.runelite.api.TileObject; +import net.runelite.api.NPC; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.Perspective; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.outline.ModelOutlineRenderer; + +import javax.inject.Inject; +import java.awt.*; + +/** + * Scene overlay that highlights the objects the user should click next. + */ +public class EasyGOTRSceneOverlay extends Overlay { + private static final Color DEFAULT_COLOR = new Color(255, 140, 0, 180); + private static final int OUTLINE_WIDTH = 3; + private static final int OUTLINE_FEATHER = 2; + + private final Client client; + private final ModelOutlineRenderer modelOutlineRenderer; + + @Setter + private EasyGOTRActionHint hint; + + @Inject + private EasyGOTRSceneOverlay(Client client, ModelOutlineRenderer modelOutlineRenderer) { + this.client = client; + this.modelOutlineRenderer = modelOutlineRenderer; + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + } + + @Override + public Dimension render(Graphics2D graphics) { + if (client.getLocalPlayer() == null || hint == null) { + return null; + } + + for (EasyGOTRHighlightTarget target : hint.getHighlightsSafe()) { + Color color = target.getColorOrDefault(DEFAULT_COLOR); + String label = target.getLabel(); + target.getTileObjectOptional().ifPresent(tileObject -> drawTileObject(graphics, tileObject, color, label)); + target.getNpcOptional().ifPresent(npc -> drawNpc(graphics, npc, color, label)); + target.getWorldPointOptional().ifPresent(worldPoint -> drawWorldPoint(graphics, worldPoint, color, label)); + } + + return null; + } + + private void drawTileObject(Graphics2D graphics, TileObject tileObject, Color color, String label) { + modelOutlineRenderer.drawOutline(tileObject, OUTLINE_WIDTH, color, OUTLINE_FEATHER); + if (label == null || label.isEmpty()) { + return; + } + + LocalPoint localLocation = tileObject.getLocalLocation(); + if (localLocation == null) { + return; + } + + Polygon poly = Perspective.getCanvasTilePoly(client, localLocation); + if (poly == null) { + return; + } + + Point labelPoint = new Point(poly.getBounds().x + poly.getBounds().width / 2, poly.getBounds().y); + OverlayUtil.renderTextLocation(graphics, labelPoint, label, color); + } + + private void drawNpc(Graphics2D graphics, NPC npc, Color color, String label) { + modelOutlineRenderer.drawOutline(npc, OUTLINE_WIDTH, color, OUTLINE_FEATHER); + if (label == null || label.isEmpty()) { + return; + } + + net.runelite.api.Point textLocation = npc.getCanvasTextLocation(graphics, label, npc.getLogicalHeight()); + if (textLocation != null) { + OverlayUtil.renderTextLocation(graphics, textLocation, label, color); + } + } + + private void drawWorldPoint(Graphics2D graphics, WorldPoint worldPoint, Color color, String label) { + LocalPoint localPoint = LocalPoint.fromWorld(client, worldPoint); + if (localPoint == null) { + return; + } + + Polygon poly = Perspective.getCanvasTilePoly(client, localPoint); + if (poly == null) { + return; + } + + graphics.setColor(color); + graphics.setStroke(new BasicStroke(2)); + graphics.draw(poly); + + if (label != null && !label.isEmpty()) { + Point labelPoint = new Point(poly.getBounds().x + poly.getBounds().width / 2, poly.getBounds().y); + OverlayUtil.renderTextLocation(graphics, labelPoint, label, color); + } + } +} diff --git a/src/main/java/ee/futur/easygotr/GOTRState.java b/src/main/java/ee/futur/easygotr/GOTRState.java index 9c06671..d33bc29 100644 --- a/src/main/java/ee/futur/easygotr/GOTRState.java +++ b/src/main/java/ee/futur/easygotr/GOTRState.java @@ -5,10 +5,9 @@ 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.GOTRGameConstants; 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; @@ -17,6 +16,7 @@ import net.runelite.api.widgets.Widget; import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.Subscribe; +import java.time.Instant; import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -44,7 +44,6 @@ public class GOTRState { private int catalyticPoints = -1; @Getter private boolean gameStarted; - @Setter private boolean started; public boolean hasFirstPortalSpawned = false; @Inject @@ -62,6 +61,11 @@ public class GOTRState { int timeout = 0; int gameEndTimeout = 10; public boolean isGameEnding = false; + @Getter + private Optional portalSpawnTime = Optional.empty(); + @Getter + private Optional lastPortalCloseTime = Optional.empty(); + private boolean portalVisibleLastTick = false; @Inject public GOTRState(EventBus eventBus, EasyGOTRConfig config) { @@ -78,6 +82,18 @@ public class GOTRState { eventBus.unregister(this); } + public void setStarted(boolean started) { + this.started = started; + if (!started) { + portalSpawnTime = Optional.empty(); + lastPortalCloseTime = Optional.empty(); + portalVisibleLastTick = false; + gameStarted = false; + hasFirstPortalSpawned = false; + isGameEnding = false; + } + } + @Subscribe private void onGameTick(GameTick event) { if (client.getGameState() != GameState.LOGGED_IN || !started) { @@ -95,6 +111,16 @@ public class GOTRState { Quest.MOURNINGS_END_PART_II.getState(client), Quest.SINS_OF_THE_FATHER.getState(client)); } + boolean portalVisible = isPortalSpawned(); + if (portalVisible && !portalVisibleLastTick) { + portalSpawnTime = Optional.of(Instant.now()); + lastPortalCloseTime = Optional.empty(); + } else if (!portalVisible && portalVisibleLastTick) { + lastPortalCloseTime = Optional.of(Instant.now()); + portalSpawnTime = Optional.empty(); + } + portalVisibleLastTick = portalVisible; + Optional frags = Inventory.search().withId(ItemID.GUARDIAN_FRAGMENTS).first(); if (!hasFirstPortalSpawned && (isPortalSpawned() || getPower() > 15 || (frags.isPresent() && frags.get().getItemQuantity() >= 250))) { @@ -146,7 +172,7 @@ public class GOTRState { return; } - if (event.getMessage().contains(ee.futur.easygotr.data.Constants.GAME_STARTED)) { + if (event.getMessage().contains(GOTRGameConstants.GAME_STARTED)) { gameStarted = true; } @@ -182,7 +208,7 @@ public class GOTRState { } private boolean isWidgetVisible() { - Optional widget = Widgets.search().withId(ee.futur.easygotr.data.Constants.PARENT_WIDGET).first(); + Optional widget = Widgets.search().withId(GOTRGameConstants.PARENT_WIDGET).first(); return widget.isPresent() && !widget.get().isHidden(); } @@ -197,19 +223,19 @@ public class GOTRState { } public boolean isOutsideBarrier() { - return client.getLocalPlayer().getWorldLocation().getY() <= ee.futur.easygotr.data.Constants.OUTSIDE_BARRIER_Y && !isInAltar(); + return client.getLocalPlayer().getWorldLocation().getY() <= GOTRGameConstants.OUTSIDE_BARRIER_Y && !isInAltar(); } public boolean isInLargeMine() { - return !isInAltar() && client.getLocalPlayer().getWorldLocation().getX() >= ee.futur.easygotr.data.Constants.LARGE_MINE_X; + return !isInAltar() && client.getLocalPlayer().getWorldLocation().getX() >= GOTRGameConstants.LARGE_MINE_X; } public boolean isInHugeMine() { - return !isInAltar() && client.getLocalPlayer().getWorldLocation().getX() <= ee.futur.easygotr.data.Constants.HUGE_MINE_X; + return !isInAltar() && client.getLocalPlayer().getWorldLocation().getX() <= GOTRGameConstants.HUGE_MINE_X; } public boolean isGameBusy() { - return !isInAltar() && isOutsideBarrier() && TileObjects.search().withId(Constants.BARRIER_BUSY_ID).nearestToPlayer().isPresent(); + return !isInAltar() && isOutsideBarrier() && TileObjects.search().withId(GOTRGameConstants.BARRIER_BUSY_ID).nearestToPlayer().isPresent(); } public boolean isPortalSpawned() { diff --git a/src/main/java/ee/futur/easygotr/PouchManager.java b/src/main/java/ee/futur/easygotr/PouchManager.java index 3ca9a4f..17de72f 100644 --- a/src/main/java/ee/futur/easygotr/PouchManager.java +++ b/src/main/java/ee/futur/easygotr/PouchManager.java @@ -4,7 +4,7 @@ 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.GOTRGameConstants; import ee.futur.easygotr.data.Pouch; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -79,10 +79,22 @@ public class PouchManager { pouches.removeIf(p -> p.getPouchID() == ItemID.COLOSSAL_POUCH); pouches.add(colossalEssPouch); } - - log.info("Setting Pouches: " + pouches); + syncPouchQuantities(); + log.info("Setting Pouches: {}", pouches); } + private Optional getPouchWidget(int pouchId) { + return Inventory.search().withId(pouchId).first(); + } + + private void syncPouchQuantities() { + for (Pouch pouch : pouches) { + int essence = getPouchWidget(pouch.getPouchID()) + .map(Widget::getItemQuantity) + .orElse(0); + pouch.setCurrentEssence(essence); + } + } @Subscribe private void onChatMessage(ChatMessage event) { @@ -97,20 +109,21 @@ public class PouchManager { return; } - if (event.getMessage().contains(ee.futur.easygotr.data.Constants.GAME_STARTED)) { + if (event.getMessage().contains(GOTRGameConstants.GAME_STARTED)) { setEssenceInPouches(0); } - if (event.getMessage().contains(ee.futur.easygotr.data.Constants.GAME_WIN)) { + if (event.getMessage().contains(GOTRGameConstants.GAME_WIN)) { setEssenceInPouches(0); } - if (event.getMessage().contains(Constants.GAME_OVER)) { + if (event.getMessage().contains(GOTRGameConstants.GAME_OVER)) { setEssenceInPouches(0); } } public List getFullPouches() { + syncPouchQuantities(); List result = new ArrayList<>(); for (Pouch pouch : pouches) { if (pouch.getCurrentEssence() > 0) { @@ -121,6 +134,7 @@ public class PouchManager { } public boolean hasFullPouch() { + syncPouchQuantities(); for (Pouch pouch : pouches) { if (pouch.getCurrentEssence() > 0) { return true; @@ -130,6 +144,7 @@ public class PouchManager { } public void fillPouches() { + syncPouchQuantities(); int essenceAmount = Inventory.getItemAmount(ItemID.GUARDIAN_ESSENCE); List result = getEmptyPouches(); for (Pouch pouch : result) { @@ -154,6 +169,7 @@ public class PouchManager { } public void emptyPouches() { + syncPouchQuantities(); int spaces = Inventory.getEmptySlots(); List result = getFullPouches(); for (Pouch pouch : result) { @@ -172,6 +188,7 @@ public class PouchManager { } public List getEmptyPouches() { + syncPouchQuantities(); List result = new ArrayList<>(); for (Pouch pouch : pouches) { if (!isPouchFull(pouch)) { @@ -182,6 +199,7 @@ public class PouchManager { } public boolean hasEmptyPouches() { + syncPouchQuantities(); for (Pouch pouch : pouches) { if (!isPouchFull(pouch)) { return true; @@ -205,10 +223,12 @@ public class PouchManager { } public int getAvailableSpace() { + syncPouchQuantities(); return pouches.stream().mapToInt(pouch -> pouch.getEssenceTotal() - pouch.getCurrentEssence()).sum(); } public int getEssenceInPouches() { + syncPouchQuantities(); return pouches.stream().mapToInt(Pouch::getCurrentEssence).sum(); } } diff --git a/src/main/java/ee/futur/easygotr/data/Altar.java b/src/main/java/ee/futur/easygotr/data/Altar.java index 16eb169..bb6ad2b 100644 --- a/src/main/java/ee/futur/easygotr/data/Altar.java +++ b/src/main/java/ee/futur/easygotr/data/Altar.java @@ -4,18 +4,18 @@ 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); + AIR(43701, GOTRGameConstants.AIR_SPRITE), + MIND(43705, GOTRGameConstants.MIND_SPRITE), + WATER(43702, GOTRGameConstants.WATER_SPRITE), + EARTH(43703, GOTRGameConstants.EARTH_SPRITE), + FIRE(43704, GOTRGameConstants.FIRE_SPRITE), + BODY(43709, GOTRGameConstants.BODY_SPRITE), + COSMIC(43710, GOTRGameConstants.COSMIC_SPRITE), + CHAOS(43706, GOTRGameConstants.CHAOS_SPRITE), + NATURE(43711, GOTRGameConstants.NATURE_SPRITE), + LAW(43712, GOTRGameConstants.LAW_SPRITE), + DEATH(43707, GOTRGameConstants.DEATH_SPRITE), + BLOOD(43708, GOTRGameConstants.BLOOD_SPRITE); final int id; final int spriteId; diff --git a/src/main/java/ee/futur/easygotr/data/Constants.java b/src/main/java/ee/futur/easygotr/data/GOTRGameConstants.java similarity index 99% rename from src/main/java/ee/futur/easygotr/data/Constants.java rename to src/main/java/ee/futur/easygotr/data/GOTRGameConstants.java index 5b5bfb4..693c786 100644 --- a/src/main/java/ee/futur/easygotr/data/Constants.java +++ b/src/main/java/ee/futur/easygotr/data/GOTRGameConstants.java @@ -1,6 +1,6 @@ package ee.futur.easygotr.data; -public class Constants { +public class GOTRGameConstants { //Locations public static final int OUTSIDE_BARRIER_Y = 9482; public static final int LARGE_MINE_X = 3637;