Repository: pajlads/DinkPlugin
Pull request #431 (2024-02-26 06:28:20)

feat: add wiki link to loot source
![image](https://github.com/pajlads/DinkPlugin/assets/8106344/17c7779a-350d-4170-b5b7-bc61c68c3193)


iProdigy: works in-game :)

![image](https://github.com/pajlads/DinkPlugin/assets/8106344/344020de-3f6c-43ba-8a23-2483283a35da)

![image](https://github.com/pajlads/DinkPlugin/assets/8106344/63fb0e98-989d-4fd5-a8fb-c0f2b55e5d35)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 84c61d9..c610592 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 ## Unreleased
 
 - Major: Add item rarity to NPC loot notifications. (#425)
+- Minor: Add wiki link for loot source in rich embeds. (#431)
 - Minor: Add chat message upon noteworthy plugin updates. (#429)
 - Minor: Allow loot notifications for rare items below the min value threshold. (#426)
 - Minor: Include relevant kill count in collection log notifications. (#424)
diff --git a/src/main/java/dinkplugin/notifiers/LootNotifier.java b/src/main/java/dinkplugin/notifiers/LootNotifier.java
index c5b049e..ec8787f 100644
--- a/src/main/java/dinkplugin/notifiers/LootNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/LootNotifier.java
@@ -210,13 +210,16 @@ public class LootNotifier extends BaseNotifier {
             SerializedItemStack keyItem = rarest != null ? rarest.getKey() : max;
             Double rarity = rarest != null ? rarest.getValue() : null;
             boolean screenshot = config.lootSendImage() && totalStackValue >= config.lootImageMinValue();
+            Evaluable source = type == LootRecordType.PLAYER
+                ? Replacements.ofLink(dropper, config.playerLookupService().getPlayerUrl(dropper))
+                : Replacements.ofWiki(dropper);
             Template notifyMessage = Template.builder()
                 .template(config.lootNotifyMessage())
                 .replacementBoundary("%")
                 .replacement("%USERNAME%", Replacements.ofText(Utils.getPlayerName(client)))
                 .replacement("%LOOT%", lootMsg)
                 .replacement("%TOTAL_VALUE%", Replacements.ofText(QuantityFormatter.quantityToStackSize(totalStackValue)))
-                .replacement("%SOURCE%", Replacements.ofText(dropper))
+                .replacement("%SOURCE%", source)
                 .build();
             createMessage(overrideUrl, screenshot,
                 NotificationBody.builder()


Test patch:
diff --git a/src/test/java/dinkplugin/notifiers/LootNotifierTest.java b/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
index 254eb58..e2184cd 100644
--- a/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
+++ b/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
@@ -101,8 +101,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from %s for %d gp", PLAYER_NAME, RUBY_PRICE, name, RUBY_PRICE))
+                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from {{source}} for %d gp", PLAYER_NAME, RUBY_PRICE, RUBY_PRICE))
                         .replacement("{{ruby}}", Replacements.ofWiki("Ruby"))
+                        .replacement("{{source}}", Replacements.ofWiki(name))
                         .build()
                 )
                 .extra(new LootNotificationData(Collections.singletonList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby")), name, LootRecordType.NPC, kc + 1, null))
@@ -135,8 +136,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: Various items including: 1 x {{key}} from %s for %s gp", PLAYER_NAME, name, value))
+                        .template(String.format("%s has looted: Various items including: 1 x {{key}} from {{source}} for %s gp", PLAYER_NAME, value))
                         .replacement("{{key}}", Replacements.ofWiki("Larran's key"))
+                        .replacement("{{source}}", Replacements.ofWiki(name))
                         .build()
                 )
                 .extra(new LootNotificationData(List.of(new SerializedItemStack(ItemID.LARRANS_KEY, 1, LARRAN_PRICE, "Larran's key")), name, LootRecordType.NPC, 1, rarity))
@@ -184,8 +186,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{tuna}} (%d) from %s for %d gp", PLAYER_NAME, TUNA_PRICE, LOOTED_NAME, TUNA_PRICE))
+                        .template(String.format("%s has looted: 1 x {{tuna}} (%d) from {{source}} for %d gp", PLAYER_NAME, TUNA_PRICE, TUNA_PRICE))
                         .replacement("{{tuna}}", Replacements.ofWiki("Tuna"))
+                        .replacement("{{source}}", Replacements.ofLink(LOOTED_NAME, config.playerLookupService().getPlayerUrl(LOOTED_NAME)))
                         .build()
                 )
                 .extra(new LootNotificationData(Collections.singletonList(new SerializedItemStack(ItemID.TUNA, 1, TUNA_PRICE, "Tuna")), LOOTED_NAME, LootRecordType.PLAYER, 1, null))
@@ -212,8 +215,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{tuna}} (%d) from %s for %d gp", PLAYER_NAME, TUNA_PRICE, LOOTED_NAME, TUNA_PRICE))
+                        .template(String.format("%s has looted: 1 x {{tuna}} (%d) from {{source}} for %d gp", PLAYER_NAME, TUNA_PRICE, TUNA_PRICE))
                         .replacement("{{tuna}}", Replacements.ofWiki("Tuna"))
+                        .replacement("{{source}}", Replacements.ofLink(LOOTED_NAME, config.playerLookupService().getPlayerUrl(LOOTED_NAME)))
                         .build()
                 )
                 .extra(new LootNotificationData(Collections.singletonList(new SerializedItemStack(ItemID.TUNA, 1, TUNA_PRICE, "Tuna")), LOOTED_NAME, LootRecordType.PLAYER, 1, null))
@@ -260,8 +264,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from %s for %d gp", PLAYER_NAME, RUBY_PRICE, name, RUBY_PRICE))
+                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from {{source}} for %d gp", PLAYER_NAME, RUBY_PRICE, RUBY_PRICE))
                         .replacement("{{ruby}}", Replacements.ofWiki("Ruby"))
+                        .replacement("{{source}}", Replacements.ofWiki(name))
                         .build()
                 )
                 .extra(new LootNotificationData(Collections.singletonList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby")), name, LootRecordType.NPC, 1, null))
@@ -314,8 +319,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from %s for %d gp", PLAYER_NAME, RUBY_PRICE, LOOTED_NAME, RUBY_PRICE))
+                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from {{source}} for %d gp", PLAYER_NAME, RUBY_PRICE, RUBY_PRICE))
                         .replacement("{{ruby}}", Replacements.ofWiki("Ruby"))
+                        .replacement("{{source}}", Replacements.ofWiki(LOOTED_NAME))
                         .build()
                 )
                 .extra(new LootNotificationData(Collections.singletonList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby")), LOOTED_NAME, LootRecordType.PICKPOCKET, 1, null))
@@ -351,8 +357,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from %s for %d gp", PLAYER_NAME, RUBY_PRICE, source, RUBY_PRICE))
+                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from {{source}} for %d gp", PLAYER_NAME, RUBY_PRICE, RUBY_PRICE))
                         .replacement("{{ruby}}", Replacements.ofWiki("Ruby"))
+                        .replacement("{{source}}", Replacements.ofWiki(source))
                         .build()
                 )
                 .extra(new LootNotificationData(Collections.singletonList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby")), source, LootRecordType.EVENT, 42, null))
@@ -393,8 +400,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from %s for %s gp", PLAYER_NAME, RUBY_PRICE, LOOTED_NAME, QuantityFormatter.quantityToStackSize(RUBY_PRICE + TUNA_PRICE)))
+                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from {{source}} for %s gp", PLAYER_NAME, RUBY_PRICE, QuantityFormatter.quantityToStackSize(RUBY_PRICE + TUNA_PRICE)))
                         .replacement("{{ruby}}", Replacements.ofWiki("Ruby"))
+                        .replacement("{{source}}", Replacements.ofLink(LOOTED_NAME, config.playerLookupService().getPlayerUrl(LOOTED_NAME)))
                         .build()
                 )
                 .extra(new LootNotificationData(Arrays.asList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby"), new SerializedItemStack(ItemID.TUNA, 1, TUNA_PRICE, "Tuna")), LOOTED_NAME, LootRecordType.PLAYER, 1, null))
@@ -423,8 +431,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from %s for %s gp", PLAYER_NAME, RUBY_PRICE, LOOTED_NAME, QuantityFormatter.quantityToStackSize(RUBY_PRICE + TUNA_PRICE)))
+                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from {{source}} for %s gp", PLAYER_NAME, RUBY_PRICE, QuantityFormatter.quantityToStackSize(RUBY_PRICE + TUNA_PRICE)))
                         .replacement("{{ruby}}", Replacements.ofWiki("Ruby"))
+                        .replacement("{{source}}", Replacements.ofLink(LOOTED_NAME, config.playerLookupService().getPlayerUrl(LOOTED_NAME)))
                         .build()
                 )
                 .extra(new LootNotificationData(Arrays.asList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby"), new SerializedItemStack(ItemID.TUNA, 1, TUNA_PRICE, "Tuna")), LOOTED_NAME, LootRecordType.PLAYER, 1, null))
@@ -452,8 +461,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from %s for %s gp", PLAYER_NAME, RUBY_PRICE, LOOTED_NAME, QuantityFormatter.quantityToStackSize(RUBY_PRICE + TUNA_PRICE)))
+                        .template(String.format("%s has looted: 1 x {{ruby}} (%d) from {{source}} for %s gp", PLAYER_NAME, RUBY_PRICE, QuantityFormatter.quantityToStackSize(RUBY_PRICE + TUNA_PRICE)))
                         .replacement("{{ruby}}", Replacements.ofWiki("Ruby"))
+                        .replacement("{{source}}", Replacements.ofLink(LOOTED_NAME, config.playerLookupService().getPlayerUrl(LOOTED_NAME)))
                         .build()
                 )
                 .extra(new LootNotificationData(Arrays.asList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby"), new SerializedItemStack(ItemID.TUNA, 1, TUNA_PRICE, "Tuna")), LOOTED_NAME, LootRecordType.PLAYER, 1, null))
@@ -483,8 +493,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: Various items including: 1 x {{opal}} (%d) from %s for %s gp", PLAYER_NAME, OPAL_PRICE, source, QuantityFormatter.quantityToStackSize(totalValue)))
+                        .template(String.format("%s has looted: Various items including: 1 x {{opal}} (%d) from {{source}} for %s gp", PLAYER_NAME, OPAL_PRICE, QuantityFormatter.quantityToStackSize(totalValue)))
                         .replacement("{{opal}}", Replacements.ofWiki("Opal"))
+                        .replacement("{{source}}", Replacements.ofWiki(source))
                         .build()
                 )
                 .extra(new LootNotificationData(List.of(new SerializedItemStack(ItemID.OPAL, 1, OPAL_PRICE, "Opal"), new SerializedItemStack(ItemID.TUNA, 2, TUNA_PRICE, "Tuna")), source, LootRecordType.EVENT, 1, null))
@@ -550,9 +561,10 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 1 x {{ruby}} (%d)\n1 x {{opal}} (%d) from %s for %s gp", PLAYER_NAME, RUBY_PRICE, OPAL_PRICE, LOOTED_NAME, QuantityFormatter.quantityToStackSize(total)))
+                        .template(String.format("%s has looted: 1 x {{ruby}} (%d)\n1 x {{opal}} (%d) from {{source}} for %s gp", PLAYER_NAME, RUBY_PRICE, OPAL_PRICE, QuantityFormatter.quantityToStackSize(total)))
                         .replacement("{{ruby}}", Replacements.ofWiki("Ruby"))
                         .replacement("{{opal}}", Replacements.ofWiki("Opal"))
+                        .replacement("{{source}}", Replacements.ofWiki(LOOTED_NAME))
                         .build()
                 )
                 .extra(new LootNotificationData(Arrays.asList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby"), new SerializedItemStack(ItemID.OPAL, 1, OPAL_PRICE, "Opal"), new SerializedItemStack(ItemID.TUNA, 1, TUNA_PRICE, "Tuna")), LOOTED_NAME, LootRecordType.EVENT, 1, null))
@@ -587,8 +599,9 @@ class LootNotifierTest extends MockedNotifierTest {
             NotificationBody.builder()
                 .text(
                     Template.builder()
-                        .template(String.format("%s has looted: 5 x {{tuna}} (%d) from %s for %s gp", PLAYER_NAME, 5 * TUNA_PRICE, LOOTED_NAME, QuantityFormatter.quantityToStackSize(total)))
+                        .template(String.format("%s has looted: 5 x {{tuna}} (%d) from {{source}} for %s gp", PLAYER_NAME, 5 * TUNA_PRICE, QuantityFormatter.quantityToStackSize(total)))
                         .replacement("{{tuna}}", Replacements.ofWiki("Tuna"))
+                        .replacement("{{source}}", Replacements.ofWiki(LOOTED_NAME))
                         .build()
                 )
                 .extra(new LootNotificationData(Collections.singletonList(new SerializedItemStack(ItemID.TUNA, 5, TUNA_PRICE, "Tuna")), LOOTED_NAME, LootRecordType.EVENT, 1, null))