Repository: pajlads/DinkPlugin (java)

Issue:
Option to let the Loot notifier ignore Clue drops?
It would be nice to prevent duplicate clue notifications. They way I did it on UniversalDiscordPlugin: https://github.com/TomBolks/UniversalDiscordNotifier/commit/6da978c1f7ba73afc44999134577f109df5f7c73#diff-ddb861fd31a9f9e62e73b89e9b9a6d24439ff3a173130e6829c997f9a016b121R46
Always ignoring all loot from clue's.

But now I think a checkbox in the config would be a bit nicer.

![image](https://user-images.githubusercontent.com/17124771/213288962-1881e624-bb3b-4b61-b0d7-4b0b8af5a8c4.png)


Pull request description:
feat: allow loot notifier to skip clue scrolls
Closes #133

Note: Relevant loot tracker code is [here](https://github.com/runelite/runelite/blob/f036a0605af90643138f56f764ec20badf46325f/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java#L869-L901)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 750b1e4..f7cf64d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 ## Unreleased
 
+- Minor: Add setting to ignore clue scrolls for loot notifications. (#135)
 - Minor: Add setting to skip notifications for low tier clue scrolls. (#134)
 - Minor: Add embed field on a max level up indicating total 99+ skills. (#115)
 - Minor: Include all lost items in extra death notification data. (#132)
diff --git a/src/main/java/dinkplugin/DinkPluginConfig.java b/src/main/java/dinkplugin/DinkPluginConfig.java
index 5b7aa9c..3c91378 100644
--- a/src/main/java/dinkplugin/DinkPluginConfig.java
+++ b/src/main/java/dinkplugin/DinkPluginConfig.java
@@ -542,11 +542,22 @@ public interface DinkPluginConfig extends Config {
         return true;
     }
 
+    @ConfigItem(
+        keyName = "lootIncludeClueScrolls",
+        name = "Include Clue Loot",
+        description = "Allow notifications for loot from Clue Scrolls",
+        position = 36,
+        section = lootSection
+    )
+    default boolean lootIncludeClueScrolls() {
+        return true;
+    }
+
     @ConfigItem(
         keyName = "lootNotifMessage",
         name = "Notification Message",
         description = "The message to be sent through the webhook. Use %USERNAME% to insert your username, %LOOT% to insert the loot and %SOURCE% to show the source of the loot",
-        position = 36,
+        position = 37,
         section = lootSection
     )
     default String lootNotifyMessage() {
diff --git a/src/main/java/dinkplugin/notifiers/LootNotifier.java b/src/main/java/dinkplugin/notifiers/LootNotifier.java
index fca8383..0a47e82 100644
--- a/src/main/java/dinkplugin/notifiers/LootNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/LootNotifier.java
@@ -66,6 +66,11 @@ public class LootNotifier extends BaseNotifier {
 
         // only consider non-NPC and non-PK loot
         if (lootReceived.getType() == LootRecordType.EVENT || lootReceived.getType() == LootRecordType.PICKPOCKET) {
+            if (!config.lootIncludeClueScrolls() && StringUtils.startsWithIgnoreCase(lootReceived.getName(), "Clue Scroll")) {
+                // skip clue scroll loot, depending on config
+                return;
+            }
+
             this.handleNotify(lootReceived.getItems(), lootReceived.getName());
         }
     }


Test patch:
diff --git a/src/test/java/dinkplugin/notifiers/LootNotifierTest.java b/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
index 0afd97a..aa0d8ac 100644
--- a/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
+++ b/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
@@ -55,6 +55,7 @@ class LootNotifierTest extends MockedNotifierTest {
         when(config.lootIcons()).thenReturn(false);
         when(config.minLootValue()).thenReturn(500);
         when(config.includePlayerLoot()).thenReturn(true);
+        when(config.lootIncludeClueScrolls()).thenReturn(true);
         when(config.lootNotifyMessage()).thenReturn("%USERNAME% has looted: %LOOT% from %SOURCE% for %TOTAL_VALUE% gp");
 
         // init client mocks
@@ -107,7 +108,7 @@ class LootNotifierTest extends MockedNotifierTest {
     @Test
     void testNotifyPickpocket() {
         // fire event
-        LootReceived event = new LootReceived(LOOTED_NAME, 99, LootRecordType.PICKPOCKET, Collections.singletonList(new ItemStack(ItemID.RUBY, 1, null)), RUBY_PRICE);
+        LootReceived event = new LootReceived(LOOTED_NAME, 99, LootRecordType.PICKPOCKET, Collections.singletonList(new ItemStack(ItemID.RUBY, 1, null)), 1);
         plugin.onLootReceived(event);
 
         // verify notification message
@@ -125,7 +126,39 @@ class LootNotifierTest extends MockedNotifierTest {
     @Test
     void testIgnorePickpocket() {
         // fire event
-        LootReceived event = new LootReceived(LOOTED_NAME, 99, LootRecordType.PICKPOCKET, Collections.singletonList(new ItemStack(ItemID.TUNA, 1, null)), TUNA_PRICE);
+        LootReceived event = new LootReceived(LOOTED_NAME, 99, LootRecordType.PICKPOCKET, Collections.singletonList(new ItemStack(ItemID.TUNA, 1, null)), 1);
+        plugin.onLootReceived(event);
+
+        // ensure no notification
+        verify(messageHandler, never()).createMessage(any(), anyBoolean(), any());
+    }
+
+    @Test
+    void testNotifyClue() {
+        // fire event
+        String source = "Clue Scroll (Medium)";
+        LootReceived event = new LootReceived(source, -1, LootRecordType.EVENT, Collections.singletonList(new ItemStack(ItemID.RUBY, 1, null)), 1);
+        plugin.onLootReceived(event);
+
+        // verify notification message
+        verify(messageHandler).createMessage(
+            PRIMARY_WEBHOOK_URL,
+            false,
+            NotificationBody.builder()
+                .text(String.format("%s has looted: %s from %s for %d gp", PLAYER_NAME, "1 x Ruby (" + RUBY_PRICE + ")", source, RUBY_PRICE))
+                .extra(new LootNotificationData(Collections.singletonList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby")), source))
+                .type(NotificationType.LOOT)
+                .build()
+        );
+    }
+
+    @Test
+    void testIgnoreClue() {
+        // update config mock
+        when(config.lootIncludeClueScrolls()).thenReturn(false);
+
+        // fire event
+        LootReceived event = new LootReceived("Clue Scroll (Medium)", -1, LootRecordType.EVENT, Collections.singletonList(new ItemStack(ItemID.RUBY, 1, null)), 1);
         plugin.onLootReceived(event);
 
         // ensure no notification
@@ -182,7 +215,7 @@ class LootNotifierTest extends MockedNotifierTest {
                 new ItemStack(ItemID.OPAL, 1, null),
                 new ItemStack(ItemID.TUNA, 1, null)
             ),
-            total
+            3
         );
         plugin.onLootReceived(event);
 
@@ -214,7 +247,7 @@ class LootNotifierTest extends MockedNotifierTest {
                 new ItemStack(ItemID.TUNA, 1, null),
                 new ItemStack(ItemID.TUNA, 1, null)
             ),
-            total
+            5
         );
         plugin.onLootReceived(event);
 
@@ -266,7 +299,6 @@ class LootNotifierTest extends MockedNotifierTest {
     @Test
     void testIgnoreRepeated() {
         // fire event
-        int total = TUNA_PRICE * 4;
         LootReceived event = new LootReceived(
             LOOTED_NAME,
             99,
@@ -277,7 +309,7 @@ class LootNotifierTest extends MockedNotifierTest {
                 new ItemStack(ItemID.TUNA, 1, null),
                 new ItemStack(ItemID.TUNA, 1, null)
             ),
-            total
+            4
         );
         plugin.onLootReceived(event);
 
@@ -291,7 +323,7 @@ class LootNotifierTest extends MockedNotifierTest {
         when(config.notifyLoot()).thenReturn(false);
 
         // fire event
-        LootReceived event = new LootReceived(LOOTED_NAME, 99, LootRecordType.PICKPOCKET, Collections.singletonList(new ItemStack(ItemID.RUBY, 1, null)), RUBY_PRICE);
+        LootReceived event = new LootReceived(LOOTED_NAME, 99, LootRecordType.PICKPOCKET, Collections.singletonList(new ItemStack(ItemID.RUBY, 1, null)), 1);
         plugin.onLootReceived(event);
 
         // ensure no notification