diff --git a/README.md b/README.md index 163fcac6..e78afc6f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Emote Clue Items v4.1.1 [![Plugin Installs](http://img.shields.io/endpoint?url=https://i.pluginhub.info/shields/installs/plugin/emote-clue-items&label=Active%20installs)](https://runelite.net/plugin-hub/Lars%20van%20Soest) +## Emote Clue Items v4.2.0 [![Plugin Installs](http://img.shields.io/endpoint?url=https://i.pluginhub.info/shields/installs/plugin/emote-clue-items&label=Active%20installs)](https://runelite.net/plugin-hub/Lars%20van%20Soest) Emote Clue Items is a RuneLite plugin which highlights items required for emote clue steps and provides a user-friendly item collection log with STASHUnit integration. @@ -9,11 +9,14 @@ Maintaining bank space can be quite cumbersome, especially when you are not sure clue scrolls. With this plugin, throwing away items may be a bit less stressful, as this plugin aims to highlight all emote clue items. -### 4.1.0 Patch notes +### 4.2.0 Feature overivew +- The new 4.2.0 patch enables fill status synchronisation for the noticeboard in Watson's house. + > To enable this feature, enable "Sync Watson Board" in the plugin settings. + +![Watson notice board sync](/readme/watson-sync.gif) + +- In previous news, the recent [v4.1.0 update](https://github.com/larsvansoest/emote-clue-items/releases/tag/v4.1.0) allows [marking STASH unit locations](#mark-stash-unit-locations-on-the-map) on the map and highlights construction level requirements. -This update features an update to the collection panel, which now allows [marking STASH unit locations](#mark-stash-unit-locations-on-the-map) on the map and highlights construction level requirements. -What's more, highlights can now be toggled for each emote clue difficulty. See -the [v4.1.0 release notes](https://github.com/larsvansoest/emote-clue-items/releases/tag/v4.1.0) for the full list of changes. #### Filling stashes updates the emote clue item requirement status diff --git a/build.gradle b/build.gradle index 3bee38af..aefdf822 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ repositories { mavenCentral() } -def runeLiteVersion = '1.9.11' +def runeLiteVersion = '1.9.11.2' dependencies { compileOnly group: 'net.runelite', name: 'client', version: runeLiteVersion @@ -24,7 +24,7 @@ dependencies { } group = 'com.larsvansoest.runelite' -version = '4.1.1' +version = '4.2.0' sourceCompatibility = '1.8' tasks.withType(JavaCompile) { diff --git a/readme/watson-sync.gif b/readme/watson-sync.gif new file mode 100644 index 00000000..e9281ec9 Binary files /dev/null and b/readme/watson-sync.gif differ diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/EmoteClueItemsConfig.java b/src/main/java/com/larsvansoest/runelite/clueitems/EmoteClueItemsConfig.java index c1466d40..44af1557 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/EmoteClueItemsConfig.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/EmoteClueItemsConfig.java @@ -87,6 +87,16 @@ default boolean notifyUnopenedInterfaces() return true; } + @ConfigItem(keyName = "AutoSyncWatsonBoard", + name = "Sync watson board", + description = "Sync STASH unit fill statuses after opening the notice board in Watson's house.", + section = Section_collectionLogPanel, + position = 1) + default boolean autoSyncWatsonBoard() + { + return false; + } + // Interface Tracking @ConfigItem(keyName = "TrackBank", diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/EmoteClueItemsPlugin.java b/src/main/java/com/larsvansoest/runelite/clueitems/EmoteClueItemsPlugin.java index a051e27b..8e41efd0 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/EmoteClueItemsPlugin.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/EmoteClueItemsPlugin.java @@ -33,6 +33,8 @@ import com.larsvansoest.runelite.clueitems.data.StashUnit; import com.larsvansoest.runelite.clueitems.map.StashUnitWorldMapMarker; import com.larsvansoest.runelite.clueitems.overlay.EmoteClueItemsOverlay; +import com.larsvansoest.runelite.clueitems.overlay.Widget; +import com.larsvansoest.runelite.clueitems.overlay.WidgetInspector; import com.larsvansoest.runelite.clueitems.progress.ProgressManager; import com.larsvansoest.runelite.clueitems.ui.EmoteClueItemsPalette; import com.larsvansoest.runelite.clueitems.ui.EmoteClueItemsPanel; @@ -100,6 +102,7 @@ public class EmoteClueItemsPlugin extends Plugin private boolean showUnopenedInterfaceNotification; private Integer cachedPlayerConstructionLevel; + private boolean readWatsonOnNextGameTick; @Override protected void startUp() @@ -108,11 +111,11 @@ protected void startUp() this.emoteClueItemsPanel = new EmoteClueItemsPanel(emoteClueItemsPalette, this.itemManager, - this::onStashUnitFilledChanged, + this::onUserSetStashUnitFillStatus, this::addStashUnitMarkerToMap, this::removeStashUnitMarkerFromMap, "Emote Clue Items", - "v4.1.1", + "v4.2.0", "https://github.com/larsvansoest/emote-clue-items", "https://www.paypal.com/donate/?hosted_button_id=72AFNGL28LFEN" ); @@ -122,9 +125,9 @@ protected void startUp() this.configManager, this.config, this.itemManager, - this::onEmoteClueItemQuantityChanged, - this::onEmoteClueItemInventoryStatusChanged, - this::onEmoteClueItemStatusChanged + this.emoteClueItemsPanel::setEmoteClueItemQuantity, + this.emoteClueItemsPanel::setEmoteClueItemCollectionLogStatus, + this.emoteClueItemsPanel::setEmoteClueItemStatus ); this.navigationButton = NavigationButton @@ -143,6 +146,10 @@ protected void startUp() this.reset(); } + private void onUserSetStashUnitFillStatus(StashUnit stashUnit, Boolean filled) { + this.progressManager.setStashUnitFilled(stashUnit, filled); + } + private void reset() { this.progressManager.reset(); @@ -158,6 +165,7 @@ private void reset() this.emoteClueItemsPanel.setSTASHUnitGridDisclaimer(loginDisclaimer); this.updateStashBuiltStatusOnNextGameTick = false; + this.readWatsonOnNextGameTick = false; this.showUnopenedInterfaceNotification = this.config.notifyUnopenedInterfaces(); this.cachedPlayerConstructionLevel = null; @@ -185,26 +193,6 @@ private void removeStashUnitMarkerFromMap() { this.overlay.clearWorldMarkers(); } - private void onStashUnitFilledChanged(final StashUnit stashUnit, final boolean filled) - { - this.progressManager.setStashUnitFilled(stashUnit, filled); - } - - private void onEmoteClueItemQuantityChanged(final EmoteClueItem emoteClueItem, final int quantity) - { - this.emoteClueItemsPanel.setEmoteClueItemQuantity(emoteClueItem, quantity); - } - - private void onEmoteClueItemInventoryStatusChanged(final EmoteClueItem emoteClueItem, final StatusPanel.Status status) - { - this.emoteClueItemsPanel.setEmoteClueItemCollectionLogStatus(emoteClueItem, status); - } - - private void onEmoteClueItemStatusChanged(final EmoteClueItem emoteClueItem, final StatusPanel.Status status) - { - this.emoteClueItemsPanel.setEmoteClueItemStatus(emoteClueItem, status); - } - private void updateStashUnitBuildStatuses() { this.clientThread.invoke(() -> @@ -272,6 +260,20 @@ private void toggleCollectionLog(final boolean visible) } } + @Subscribe + protected void onWidgetLoaded(final WidgetLoaded event) { + if (event.getGroupId() == Widget.WATSON_NOTICE_BOARD.groupId && this.config.autoSyncWatsonBoard()) { + this.readWatsonOnNextGameTick = true; + } + } + + @Subscribe + protected void onWidgetClosed(final WidgetClosed event) { + if (event.getGroupId() == Widget.WATSON_NOTICE_BOARD.groupId) { + this.readWatsonOnNextGameTick = false; + } + } + @Subscribe protected void onGameStateChanged(final GameStateChanged event) { @@ -316,43 +318,55 @@ public void onGameTick(final GameTick event) this.updateStashBuiltStatusOnNextGameTick = false; this.updateStashUnitBuildStatuses(); } + if (this.readWatsonOnNextGameTick) + { + final boolean readComplete = WidgetInspector.TryReadWatsonBoard(this.client, (watsonLocation, filled) -> { + StashUnit stashUnit = StashUnit.fromWatsonLocation(watsonLocation); + if(Objects.nonNull(stashUnit)) { + this.progressManager.setStashUnitFilled(stashUnit, filled); + this.emoteClueItemsPanel.setStashUnitFilledStatus(stashUnit, filled); + } + }); + this.readWatsonOnNextGameTick = !readComplete; + } } @Subscribe protected void onConfigChanged(final ConfigChanged event) { - this.clientThread.invoke(() -> + final String key = event.getKey(); + switch (key) { - final String key = event.getKey(); - switch (key) - { - case "TrackBank": - this.progressManager.toggleBankTracking(event.getNewValue().equals("true")); - this.setupUnopenedInterfaceNotification(); - break; - case "TrackInventory": - this.progressManager.toggleInventoryTracking(event.getNewValue().equals("true")); - this.setupUnopenedInterfaceNotification(); - break; - case "TrackEquipment": - this.progressManager.toggleEquipmentTracking(event.getNewValue().equals("true")); - this.setupUnopenedInterfaceNotification(); - break; - case "TrackGroupStorage": - this.progressManager.toggleGroupStorageTracking(event.getNewValue().equals("true")); - this.setupUnopenedInterfaceNotification(); - break; - case "NotifyUnopenedInterfaces": - this.showUnopenedInterfaceNotification = event.getNewValue().equals("true"); - this.setupUnopenedInterfaceNotification(); - break; - case "ShowNavigation": - this.toggleCollectionLog(event.getNewValue().equals("true")); - break; - default: - break; - } - }); + case "TrackBank": + this.progressManager.toggleBankTracking(event.getNewValue().equals("true")); + this.setupUnopenedInterfaceNotification(); + break; + case "TrackInventory": + this.progressManager.toggleInventoryTracking(event.getNewValue().equals("true")); + this.setupUnopenedInterfaceNotification(); + break; + case "TrackEquipment": + this.progressManager.toggleEquipmentTracking(event.getNewValue().equals("true")); + this.setupUnopenedInterfaceNotification(); + break; + case "TrackGroupStorage": + this.progressManager.toggleGroupStorageTracking(event.getNewValue().equals("true")); + this.setupUnopenedInterfaceNotification(); + break; + case "NotifyUnopenedInterfaces": + this.showUnopenedInterfaceNotification = event.getNewValue().equals("true"); + this.setupUnopenedInterfaceNotification(); + break; + case "ShowNavigation": + this.toggleCollectionLog(event.getNewValue().equals("true")); + break; + case "AutoSyncWatsonBoard": + final boolean isWatsonBoardOpen = Objects.nonNull(this.client.getWidget(493, 0)); + this.readWatsonOnNextGameTick = event.getNewValue().equals("true") && isWatsonBoardOpen; + break; + default: + break; + } } @Override diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/data/StashUnit.java b/src/main/java/com/larsvansoest/runelite/clueitems/data/StashUnit.java index b0161209..a5f2a659 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/data/StashUnit.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/data/StashUnit.java @@ -4,6 +4,8 @@ import lombok.RequiredArgsConstructor; import net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit; +import java.util.Arrays; + /** * Contains and wraps all {@link net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit} used by {@link net.runelite.client.plugins.cluescrolls.clues.EmoteClue}, integrated in vendored {@link com.larsvansoest.runelite.clueitems.data.EmoteClue} class. *

@@ -17,7 +19,6 @@ * @since 3.0.0 */ @Getter -@RequiredArgsConstructor public enum StashUnit { NEAR_A_SHED_IN_LUMBRIDGE_SWAMP("Lumbridge Swamp Shed", STASHUnit.NEAR_A_SHED_IN_LUMBRIDGE_SWAMP, Type.Hole), @@ -44,7 +45,7 @@ public enum StashUnit ROAD_JUNCTION_SOUTH_OF_SINCLAIR_MANSION("Sinclaire Mansion Junction", STASHUnit.ROAD_JUNCTION_SOUTH_OF_SINCLAIR_MANSION, Type.Rock), OUTSIDE_THE_DIGSITE_EXAM_CENTRE("Digsite Exam Centre", STASHUnit.OUTSIDE_THE_DIGSITE_EXAM_CENTRE, Type.Bush), NEAR_THE_SAWMILL_OPERATORS_BOOTH("Sawmill Operators Booth", STASHUnit.NEAR_THE_SAWMILL_OPERATORS_BOOTH, Type.Bush), - PVP_ARENA_TICKET_OFFICE("PvP Arena Ticket Office", STASHUnit.PVP_ARENA_TICKET_OFFICE, Type.Crate), + PVP_ARENA_TICKET_OFFICE("PvP Arena Ticket Office", "Mubariz's room at the Emir's Arena", STASHUnit.PVP_ARENA_TICKET_OFFICE, Type.Crate), OUTSIDE_VARROCK_PALACE_COURTYARD("Varrock Palace Courtyard", STASHUnit.OUTSIDE_VARROCK_PALACE_COURTYARD, Type.Bush), NEAR_HERQUINS_SHOP_IN_FALADOR("Falador Herquins Shop", STASHUnit.NEAR_HERQUINS_SHOP_IN_FALADOR, Type.Bush), SOUTH_OF_THE_GRAND_EXCHANGE("Varrock Grand Exchange", STASHUnit.SOUTH_OF_THE_GRAND_EXCHANGE, Type.Bush), @@ -54,11 +55,11 @@ public enum StashUnit EAST_OF_THE_BARBARIAN_VILLAGE_BRIDGE("Barbarian Village Bridge", STASHUnit.EAST_OF_THE_BARBARIAN_VILLAGE_BRIDGE, Type.Bush), SOUTH_OF_THE_SHRINE_IN_TAI_BWO_WANNAI_VILLAGE("Tai Bwo Wannai Shrine", STASHUnit.SOUTH_OF_THE_SHRINE_IN_TAI_BWO_WANNAI_VILLAGE, Type.Crate), CASTLE_WARS_BANK("Castle Wars Bank", STASHUnit.CASTLE_WARS_BANK, Type.Crate), - BARBARIAN_OUTPOST_OBSTACLE_COURSE("Barbarian Outpost Course", STASHUnit.BARBARIAN_OUTPOST_OBSTACLE_COURSE, Type.Bush), + BARBARIAN_OUTPOST_OBSTACLE_COURSE("Barbarian Outpost Course", "Barbarian Outpost obstacle course", STASHUnit.BARBARIAN_OUTPOST_OBSTACLE_COURSE, Type.Bush), GNOME_STRONGHOLD_BALANCING_ROPE("Gnome Stronghold Rope", STASHUnit.GNOME_STRONGHOLD_BALANCING_ROPE, Type.Crate), OUTSIDE_YANILLE_BANK("Yanille Bank", STASHUnit.OUTSIDE_YANILLE_BANK, Type.Rock), OBSERVATORY("Observatory", STASHUnit.OBSERVATORY, Type.Crate), - OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP("Lathas Camp Ogre Cage", STASHUnit.OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP, Type.Hole), + OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP("Lathas Camp Ogre Cage", "Ogre cage in the Ardougne Training Camp", STASHUnit.OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP, Type.Hole), DIGSITE("Digsite", STASHUnit.DIGSITE, Type.Rock), HICKTONS_ARCHERY_EMPORIUM("Hickton's Archery Emporium", STASHUnit.HICKTONS_ARCHERY_EMPORIUM, Type.Crate), SHANTAY_PASS("Shantay Pass", STASHUnit.SHANTAY_PASS, Type.Crate), @@ -68,7 +69,7 @@ public enum StashUnit OUTSIDE_HARRYS_FISHING_SHOP_IN_CATHERBY("Catherby Harry's Fishing Shop", STASHUnit.OUTSIDE_HARRYS_FISHING_SHOP_IN_CATHERBY, Type.Bush), TZHAAR_WEAPONS_STORE("TzHaar Weapons Store", STASHUnit.TZHAAR_WEAPONS_STORE, Type.Hole), NORTH_OF_EVIL_DAVES_HOUSE_IN_EDGEVILLE("Edgeville Evil Dave's House", STASHUnit.NORTH_OF_EVIL_DAVES_HOUSE_IN_EDGEVILLE, Type.Bush), - WEST_OF_THE_SHAYZIEN_COMBAT_RING("Shayzien Combat Ring", STASHUnit.WEST_OF_THE_SHAYZIEN_COMBAT_RING, Type.Crate), + WEST_OF_THE_SHAYZIEN_COMBAT_RING("Shayzien Combat Ring", "North of the Shayzien combat ring", STASHUnit.WEST_OF_THE_SHAYZIEN_COMBAT_RING, Type.Crate), ENTRANCE_OF_THE_ARCEUUS_LIBRARY("Arceuus Library", STASHUnit.ENTRANCE_OF_THE_ARCEUUS_LIBRARY, Type.Crate), OUTSIDE_DRAYNOR_VILLAGE_JAIL("Draynor Village Jail", STASHUnit.OUTSIDE_DRAYNOR_VILLAGE_JAIL, Type.Bush), CHAOS_TEMPLE_IN_THE_SOUTHEASTERN_WILDERNESS("Wilderness Chaos Temple", STASHUnit.CHAOS_TEMPLE_IN_THE_SOUTHEASTERN_WILDERNESS, Type.Rock), @@ -84,7 +85,7 @@ public enum StashUnit NORTHEAST_CORNER_OF_THE_KHARAZI_JUNGLE("Khazari Jungle", STASHUnit.NORTHEAST_CORNER_OF_THE_KHARAZI_JUNGLE, Type.Hole), VOLCANO_IN_THE_NORTHEASTERN_WILDERNESS("Wilderness Volcano", STASHUnit.VOLCANO_IN_THE_NORTHEASTERN_WILDERNESS, Type.Rock), IN_THE_MIDDLE_OF_JIGGIG("Jiggig", STASHUnit.IN_THE_MIDDLE_OF_JIGGIG, Type.Rock), - AGILITY_PYRAMID("Agility Pyramid", STASHUnit.AGILITY_PYRAMID, Type.Hole), + AGILITY_PYRAMID("Agility Pyramid", "Agility Pyramid", STASHUnit.AGILITY_PYRAMID, Type.Hole), HOSIDIUS_MESS("Hosidius Mess", STASHUnit.HOSIDIUS_MESS, Type.Crate), CHAPEL_IN_WEST_ARDOUGNE("West Ardougne Chapel", STASHUnit.CHAPEL_IN_WEST_ARDOUGNE, Type.Crate), NEAR_A_RUNITE_ROCK_IN_THE_FREMENNIK_ISLES("Fremennik Isles Runite Rock", STASHUnit.NEAR_A_RUNITE_ROCK_IN_THE_FREMENNIK_ISLES, Type.Rock), @@ -124,13 +125,46 @@ public enum StashUnit BEHIND_MISS_SCHISM_IN_DRAYNOR_VILLAGE("Draynor Village Miss Chism", STASHUnit.BEHIND_MISS_SCHISM_IN_DRAYNOR_VILLAGE, Type.Bush), NORTHWESTERN_CORNER_OF_THE_ENCHANTED_VALLEY("Enchanted Valley", STASHUnit.NORTHWESTERN_CORNER_OF_THE_ENCHANTED_VALLEY, Type.Bush), NORTH_OF_MOUNT_KARUULM("Mount Karuulm", STASHUnit.NORTH_OF_MOUNT_KARUULM, Type.Hole), - GYPSY_TENT_ENTRANCE("Varrock Gypsy Tent", STASHUnit.GYPSY_TENT_ENTRANCE, Type.Bush), - FINE_CLOTHES_ENTRANCE("Varrock Fine Clothes", STASHUnit.FINE_CLOTHES_ENTRANCE, Type.Bush), - BOB_AXES_ENTRANCE("Lumbridge Bob's Axes", STASHUnit.BOB_AXES_ENTRANCE, Type.Bush), - CRYSTALLINE_MAPLE_TREES("Crystalline Maple Trees", STASHUnit.CRYSTALLINE_MAPLE_TREES, Type.Hole), - CHARCOAL_BURNERS("Charcoal Burners", STASHUnit.CHARCOAL_BURNERS, Type.Crate); + GYPSY_TENT_ENTRANCE("Varrock Gypsy Tent", "Aris's tent", STASHUnit.GYPSY_TENT_ENTRANCE, Type.Bush), + FINE_CLOTHES_ENTRANCE("Varrock Fine Clothes", "Iffie Nitter in Varrock", STASHUnit.FINE_CLOTHES_ENTRANCE, Type.Bush), + BOB_AXES_ENTRANCE("Lumbridge Bob's Axes", "Bob's Brilliant Axes in Lumbridge", STASHUnit.BOB_AXES_ENTRANCE, Type.Bush), + CRYSTALLINE_MAPLE_TREES("Crystalline Maple Trees", "North of Prifddinas by several maple trees", STASHUnit.CRYSTALLINE_MAPLE_TREES, Type.Hole), + CHARCOAL_BURNERS("Charcoal Burners", "Near the Charcoal Burners", STASHUnit.CHARCOAL_BURNERS, Type.Crate); + + StashUnit(String name, STASHUnit stashUnit, Type type) { + this.name = name; + this.watsonLocation = formatWatsonLocation(this.name()); + this.stashUnit = stashUnit; + this.type = type; + } + + StashUnit(String name, String watsonLocation, STASHUnit stashUnit, Type type) { + this.name = name; + this.watsonLocation = formatWatsonLocation(watsonLocation); + this.stashUnit = stashUnit; + this.type = type; + } + + /** + * Returns the StashUnit corresponding to the text on the Watson notice board. + * @param watsonLocation - The text from the watson notice board. + * @return the StashUnit, null if no match was found. + */ + public static StashUnit fromWatsonLocation(String watsonLocation) { + for(StashUnit stashUnit : StashUnit.values()) { + if (stashUnit.getWatsonLocation().equals(formatWatsonLocation(watsonLocation))) { + return stashUnit; + } + } + return null; + } + + private static String formatWatsonLocation(String watsonLocation) { + return watsonLocation.replace("'", "").replace("-", "").replace("_", " ").trim().toLowerCase(); + } private final String name; + private final String watsonLocation; private final STASHUnit stashUnit; private final Type type; diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/overlay/EmoteClueItemsOverlay.java b/src/main/java/com/larsvansoest/runelite/clueitems/overlay/EmoteClueItemsOverlay.java index abad9186..1e8e9c23 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/overlay/EmoteClueItemsOverlay.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/overlay/EmoteClueItemsOverlay.java @@ -62,7 +62,7 @@ public class EmoteClueItemsOverlay extends WidgetItemOverlay private final ItemManager itemManager; private final ProgressManager progressManager; // Single object allocations, re-used every sequential iteration. - private final WidgetData widgetData; + private final ItemContainerWidgetData itemContainerWidgetData; private final Point point; private final ArrayList worldMapMarkers; private final Client client; @@ -79,7 +79,7 @@ public EmoteClueItemsOverlay(final Client client, final ClientThread clientThrea this.clientThread = clientThread; this.config = config; - this.widgetData = new WidgetData(); + this.itemContainerWidgetData = new ItemContainerWidgetData(); this.point = new Point(); this.worldMapMarkers = new ArrayList<>(); @@ -98,9 +98,9 @@ public void clearWorldMarkers() { @Override public void renderItemOverlay(final Graphics2D graphics, final int itemId, final WidgetItem itemWidget) { - WidgetInspector.Inspect(itemWidget, this.widgetData, 3); - final WidgetContainer widgetContainer = this.widgetData.getWidgetContainer(); - final WidgetContext widgetContext = this.widgetData.getWidgetContext(); + WidgetInspector.InspectItemContainer(itemWidget, this.itemContainerWidgetData, 3); + final WidgetContainer widgetContainer = this.itemContainerWidgetData.getWidgetContainer(); + final WidgetContext widgetContext = this.itemContainerWidgetData.getWidgetContext(); // Filter unsupported and turned off interfaces. if (Objects.isNull(widgetContext) || Objects.isNull(widgetContainer) || !this.interfaceGroupSettingEnabled(widgetContainer)) diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/overlay/WidgetData.java b/src/main/java/com/larsvansoest/runelite/clueitems/overlay/ItemContainerWidgetData.java similarity index 98% rename from src/main/java/com/larsvansoest/runelite/clueitems/overlay/WidgetData.java rename to src/main/java/com/larsvansoest/runelite/clueitems/overlay/ItemContainerWidgetData.java index 47e0700f..027930a8 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/overlay/WidgetData.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/overlay/ItemContainerWidgetData.java @@ -36,7 +36,7 @@ */ @Getter @Setter -class WidgetData +class ItemContainerWidgetData { private WidgetContainer widgetContainer; private WidgetContext widgetContext; diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/overlay/Widget.java b/src/main/java/com/larsvansoest/runelite/clueitems/overlay/Widget.java index f0b96a34..1c3a6d9f 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/overlay/Widget.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/overlay/Widget.java @@ -28,7 +28,10 @@ package com.larsvansoest.runelite.clueitems.overlay; -enum Widget +/** + * Includes Widget definitions for widgets used by the plugin. + */ +public enum Widget { BANK(12, 10), @@ -60,7 +63,15 @@ enum Widget GROUP_STORAGE(724, 10), - GROUP_STORAGE_INVENTORY(725, 0); + GROUP_STORAGE_INVENTORY(725, 0), + + WATSON_NOTICE_BOARD(493, 0), + WATSON_NOTICE_BOARD_BEGINNER(493, 4), + WATSON_NOTICE_BOARD_EASY(493, 6), + WATSON_NOTICE_BOARD_MEDIUM(493, 8), + WATSON_NOTICE_BOARD_HARD(493, 10), + WATSON_NOTICE_BOARD_ELITE(493, 12), + WATSON_NOTICE_BOARD_MASTER(493, 14); /** * id of the widget diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/overlay/WidgetInspector.java b/src/main/java/com/larsvansoest/runelite/clueitems/overlay/WidgetInspector.java index e1c3b8eb..40a20eac 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/overlay/WidgetInspector.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/overlay/WidgetInspector.java @@ -28,8 +28,12 @@ package com.larsvansoest.runelite.clueitems.overlay; +import net.runelite.api.Client; import net.runelite.api.widgets.WidgetItem; +import java.util.Objects; +import java.util.function.BiConsumer; + /** * Utility class with Runescape item container widget inspection functionality. * @@ -39,19 +43,19 @@ public abstract class WidgetInspector { /** - * Identifies the origin of given widgetItem, writes found data into given {@link WidgetData} object. The method iterates over the ancestors (parents of parents), and compares it to the ids of all entries of the {@link Widget} enum. + * Identifies the origin of given widgetItem, writes found data into given {@link ItemContainerWidgetData} object. The method iterates over the ancestors (parents of parents), and compares it to the ids of all entries of the {@link Widget} enum. * * @param widgetItem the {@link WidgetItem} to analyse. - * @param widgetDataRef the {@link WidgetData} to write found data to. + * @param itemContainerWidgetDataRef the {@link ItemContainerWidgetData} to write found data to. * @param maxDepth the maximum steps from initial widgetItem parameter to one of the parents specified. * @since 1.2.0 */ - public static void Inspect(final WidgetItem widgetItem, final WidgetData widgetDataRef, final int maxDepth) + public static void InspectItemContainer(final WidgetItem widgetItem, final ItemContainerWidgetData itemContainerWidgetDataRef, final int maxDepth) { net.runelite.api.widgets.Widget widget = widgetItem.getWidget(); - widgetDataRef.setWidgetContainer(null); - widgetDataRef.setWidgetContext(null); + itemContainerWidgetDataRef.setWidgetContainer(null); + itemContainerWidgetDataRef.setWidgetContext(null); int i = 0; while (i < maxDepth && widget != null) @@ -60,110 +64,151 @@ public static void Inspect(final WidgetItem widgetItem, final WidgetData widgetD if (id == Widget.BANK.id) { - widgetDataRef.setWidgetContext(WidgetContext.InBank); - widgetDataRef.setWidgetContainer(WidgetContainer.Bank); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InBank); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Bank); return; } else if (id == Widget.BANK_EQUIPMENT.id) { - widgetDataRef.setWidgetContext(WidgetContext.InBank); - widgetDataRef.setWidgetContainer(WidgetContainer.Equipment); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InBank); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Equipment); return; } else if (id == Widget.BANK_EQUIPMENT_INVENTORY.id) { - widgetDataRef.setWidgetContext(WidgetContext.InBank); - widgetDataRef.setWidgetContainer(WidgetContainer.Inventory); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InBank); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Inventory); return; } else if (id == Widget.BANK_INVENTORY.id) { - widgetDataRef.setWidgetContext(WidgetContext.InBank); - widgetDataRef.setWidgetContainer(WidgetContainer.Inventory); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InBank); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Inventory); return; } else if (id == Widget.EQUIPMENT.id) { - widgetDataRef.setWidgetContext(WidgetContext.Default); - widgetDataRef.setWidgetContainer(WidgetContainer.Equipment); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.Default); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Equipment); return; } else if (id == Widget.EQUIPMENT_EQUIPMENT.id) { - widgetDataRef.setWidgetContext(WidgetContext.InEquipment); - widgetDataRef.setWidgetContainer(WidgetContainer.Equipment); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InEquipment); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Equipment); return; } else if (id == Widget.EQUIPMENT_INVENTORY.id) { - widgetDataRef.setWidgetContext(WidgetContext.InEquipment); - widgetDataRef.setWidgetContainer(WidgetContainer.Inventory); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InEquipment); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Inventory); return; } else if (id == Widget.DEPOSIT_BOX.id) { - widgetDataRef.setWidgetContext(WidgetContext.InDepositBox); - widgetDataRef.setWidgetContainer(WidgetContainer.DepositBox); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InDepositBox); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.DepositBox); return; } else if (id == Widget.GUIDE_PRICES.id) { - widgetDataRef.setWidgetContext(WidgetContext.InGuidePrices); - widgetDataRef.setWidgetContainer(WidgetContainer.GuidePrices); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InGuidePrices); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.GuidePrices); return; } else if (id == Widget.GUIDE_PRICES_INVENTORY.id) { - widgetDataRef.setWidgetContext(WidgetContext.InGuidePrices); - widgetDataRef.setWidgetContainer(WidgetContainer.Inventory); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InGuidePrices); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Inventory); return; } else if (id == Widget.INVENTORY.id) { - widgetDataRef.setWidgetContext(WidgetContext.Default); - widgetDataRef.setWidgetContainer(WidgetContainer.Inventory); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.Default); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Inventory); return; } else if (id == Widget.KEPT_ON_DEATH.id) { - widgetDataRef.setWidgetContext(WidgetContext.InKeptOnDeath); - widgetDataRef.setWidgetContainer(WidgetContainer.KeptOnDeath); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InKeptOnDeath); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.KeptOnDeath); return; } else if (id == Widget.SHOP.id) { - widgetDataRef.setWidgetContext(WidgetContext.InShop); - widgetDataRef.setWidgetContainer(WidgetContainer.Shop); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InShop); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Shop); return; } else if (id == Widget.SHOP_INVENTORY.id) { - widgetDataRef.setWidgetContext(WidgetContext.InShop); - widgetDataRef.setWidgetContainer(WidgetContainer.Inventory); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InShop); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Inventory); return; } else if (id == Widget.GROUP_STORAGE.id) { - widgetDataRef.setWidgetContext(WidgetContext.InGroupStorage); - widgetDataRef.setWidgetContainer(WidgetContainer.GroupStorage); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InGroupStorage); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.GroupStorage); } else if (id == Widget.GROUP_STORAGE_INVENTORY.id) { - widgetDataRef.setWidgetContext(WidgetContext.InGroupStorage); - widgetDataRef.setWidgetContainer(WidgetContainer.Inventory); + itemContainerWidgetDataRef.setWidgetContext(WidgetContext.InGroupStorage); + itemContainerWidgetDataRef.setWidgetContainer(WidgetContainer.Inventory); } widget = widget.getParent(); i++; } } + + public static boolean TryReadWatsonBoard(final Client client, final BiConsumer stashUnitFillStatusCallback) { + return TryReadWatsonBoard(Widget.WATSON_NOTICE_BOARD_BEGINNER, client, stashUnitFillStatusCallback) + | TryReadWatsonBoard(Widget.WATSON_NOTICE_BOARD_EASY, client, stashUnitFillStatusCallback) + | TryReadWatsonBoard(Widget.WATSON_NOTICE_BOARD_MEDIUM, client, stashUnitFillStatusCallback) + | TryReadWatsonBoard(Widget.WATSON_NOTICE_BOARD_HARD, client, stashUnitFillStatusCallback) + | TryReadWatsonBoard(Widget.WATSON_NOTICE_BOARD_ELITE, client, stashUnitFillStatusCallback) + | TryReadWatsonBoard(Widget.WATSON_NOTICE_BOARD_MASTER, client, stashUnitFillStatusCallback); + } + + private static boolean TryReadWatsonBoard(final Widget watsonNoticeBoard, final Client client, final BiConsumer stashUnitFillStatusCallback) { + final net.runelite.api.widgets.Widget stashListWidget = client.getWidget(watsonNoticeBoard.groupId, watsonNoticeBoard.childId); + if (Objects.isNull(stashListWidget)) return false; + final net.runelite.api.widgets.Widget[] stashListWidgetChildren = stashListWidget.getChildren(); + if (Objects.isNull(stashListWidgetChildren)) return false; + + String location = null; + int checkMarkCount = 0; + for(net.runelite.api.widgets.Widget widget : stashListWidgetChildren) { + final boolean widgetContainsLocationName = widget.getType() == 4; + if (widgetContainsLocationName) { + if (Objects.nonNull(location)) { + final boolean stashUnitFilled = checkMarkCount == 2; + stashUnitFillStatusCallback.accept(location, stashUnitFilled); + checkMarkCount = 0; + } + location = widget.getText(); + } + final boolean widgetContainsCheckMark = Objects.nonNull(location) && widget.getType() == 5; + if(widgetContainsCheckMark) { + checkMarkCount++; + } + } + + if (Objects.nonNull(location)) { + final boolean stashUnitFilled = checkMarkCount == 2; + stashUnitFillStatusCallback.accept(location, stashUnitFilled); + } + + return true; + } } \ No newline at end of file diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/progress/ProgressManager.java b/src/main/java/com/larsvansoest/runelite/clueitems/progress/ProgressManager.java index 809ca3e2..ec3ad7cd 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/progress/ProgressManager.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/progress/ProgressManager.java @@ -30,7 +30,6 @@ public class ProgressManager { private final Client client; - private final ClientThread clientThread; private final EmoteClueItemsConfig config; private final InventoryMonitor inventoryMonitor; private final StashMonitor stashMonitor; @@ -46,7 +45,6 @@ public ProgressManager( final BiConsumer onEmoteClueItemStatusChanged) { this.client = client; - this.clientThread = clientThread; this.config = config; this.inventoryMonitor = new InventoryMonitor(config, itemManager); this.stashMonitor = new StashMonitor(configManager); diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/ui/EmoteClueItemsPanel.java b/src/main/java/com/larsvansoest/runelite/clueitems/ui/EmoteClueItemsPanel.java index dca827f5..defdb168 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/ui/EmoteClueItemsPanel.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/ui/EmoteClueItemsPanel.java @@ -285,6 +285,11 @@ public void setSTASHUnitStatus(final StashUnit stashUnit, final boolean built, f } } + public void setStashUnitFilledStatus(final StashUnit stashUnit, final boolean filled) { + final StashUnitPanel stashUnitPanel = this.stashUnitPanelMap.get(stashUnit); + if(filled != stashUnitPanel.isFilled()) stashUnitPanel.setFilled(filled); + } + /** * Turn on the stash unit filled button of the {@link com.larsvansoest.runelite.clueitems.ui.stashes.StashUnitPanel} of the {@link com.larsvansoest.runelite.clueitems.ui.EmoteClueItemsPanel} that corresponds to given STASHUnit, if a mapping to {@link com.larsvansoest.runelite.clueitems.ui.stashes.StashUnitPanel} exists. *

diff --git a/src/main/java/com/larsvansoest/runelite/clueitems/ui/stashes/StashUnitPanel.java b/src/main/java/com/larsvansoest/runelite/clueitems/ui/stashes/StashUnitPanel.java index 108ae38d..8181e452 100644 --- a/src/main/java/com/larsvansoest/runelite/clueitems/ui/stashes/StashUnitPanel.java +++ b/src/main/java/com/larsvansoest/runelite/clueitems/ui/stashes/StashUnitPanel.java @@ -25,7 +25,7 @@ */ public class StashUnitPanel extends RequirementPanel { - private final CycleButton filledButton; + private CycleButton filledButton; private final int filledButtonComplete; private final int filledButtonInComplete; private final EmoteClueItemsPalette palette; @@ -43,8 +43,6 @@ public class StashUnitPanel extends RequirementPanel private boolean filled; @Getter private boolean built; - private Color headerColorBeforeTurnOff; - private boolean filledButtonTurnedOn; @Getter private ItemCollectionPanel itemCollectionPanel; @@ -69,20 +67,22 @@ public StashUnitPanel(final EmoteClueItemsPalette palette, final StashUnit stash this.filled = true; final String toolTipTextFormat = "Set stash unit as %s."; - this.filledButtonTurnedOn = false; + this.filledButton = new CycleButton(palette, new ImageIcon(EmoteClueItemsImages.Icons.CheckSquare.INCOMPLETE_EMPTY), () -> { - if (this.filledButtonTurnedOn) + if (Objects.nonNull(this.filledButton) && this.filledButton.isTurnedOn()) { onStashFillStatusChanged.accept(stash, false); super.setStatus(Status.InComplete); + super.setHeaderColor(null); this.filled = false; } }, DataGrid.getToolTipText(toolTipTextFormat, "filled")); + this.filledButtonInComplete = 0; this.filledButtonComplete = this.filledButton.addOption(new ImageIcon(EmoteClueItemsImages.Icons.CheckSquare.COMPLETE), () -> { - if (this.filledButtonTurnedOn) + if (this.filledButton.isTurnedOn()) { onStashFillStatusChanged.accept(stash, true); super.setStatus(Status.Complete); @@ -189,11 +189,9 @@ private JPanel getDetailsImagePanel(final Color backgroundColor) */ public void turnOffFilledButton(final Icon icon, final String toolTip) { - if (this.filledButtonTurnedOn) + if (this.filledButton.isTurnedOn()) { this.filledButton.turnOff(icon, toolTip); - this.filledButtonTurnedOn = this.filledButton.isTurnedOn(); - this.headerColorBeforeTurnOff = super.getHeaderColor(); super.setHeaderColor(this.palette.getFoldHeaderTextColor()); } } @@ -207,12 +205,10 @@ public void turnOffFilledButton(final Icon icon, final String toolTip) */ public void turnOnFilledButton() { - if (!this.filledButtonTurnedOn) + if (!this.filledButton.isTurnedOn()) { this.filledButton.turnOn(); - this.filledButtonTurnedOn = this.filledButton.isTurnedOn(); - super.setHeaderColor(this.headerColorBeforeTurnOff); - this.headerColorBeforeTurnOff = null; + super.setHeaderColor(this.filled ? null : super.getStatus().colour); } } @@ -250,8 +246,10 @@ public void setBuilt(final boolean built) */ public void setFilled(final boolean filled) { - this.filledButton.cycleToStage(filled ? this.filledButtonComplete : this.filledButtonInComplete); - this.filled = filled; + if(this.built) { + this.filledButton.cycleToStage(filled ? this.filledButtonComplete : this.filledButtonInComplete); + this.filled = filled; + } } public void setMapLinkShowDelete(boolean showDelete) {