Repository: pajlads/DinkPlugin
Pull request #352 (2023-10-31 17:12:27)

feat(quest): use historical name for first Recipe for Disaster quest
Prefer `Another Cook's Quest` over `Lumbridge Cook... again` (widget text was changed a couple years ago)
https://oldschool.runescape.wiki/w/File:Another_Cook%27s_Quest_reward_scroll.png#filehistory

old quest name is still referenced in official widgets 
![image](https://github.com/pajlads/DinkPlugin/assets/8106344/4457382b-8108-4ac6-a41b-04ed38672714)


iProdigy: widgets also remove `'Bone Crusher'` nickname within one of the RFD quests, will update `parseQuestWidget` to match

![image](https://github.com/pajlads/DinkPlugin/assets/8106344/55230d90-531e-49fd-b296-981c02cb94a3)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d2ae97e..0730515 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 ## Unreleased
 
+- Minor: Prefer historical name for first Recipe for Disaster quest. (#352)
 - Minor: Include owned pets in login notification metadata. (#347)
 - Minor: Include individual skill XP in login notification metadata. (#345)
 - Bugfix: Classify reminisced Galvek deaths as safe. (#351)
diff --git a/src/main/java/dinkplugin/util/QuestUtils.java b/src/main/java/dinkplugin/util/QuestUtils.java
index cda8a65..56feffa 100644
--- a/src/main/java/dinkplugin/util/QuestUtils.java
+++ b/src/main/java/dinkplugin/util/QuestUtils.java
@@ -37,10 +37,10 @@ import com.google.common.collect.ImmutableList;
 import lombok.experimental.UtilityClass;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
-import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Collection;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -52,6 +52,10 @@ public class QuestUtils {
     private final Pattern QUEST_PATTERN_2 = Pattern.compile("'?(?<quest>.+?)'?(?: [Qq]uest)? (?<verb>[a-z]\\w+?ed)?(?: f.*?)?[!.]?$");
     private final Collection<String> RFD_TAGS = ImmutableList.of("Another Cook", "freed", "defeated", "saved");
     private final Collection<String> WORD_QUEST_IN_NAME_TAGS = ImmutableList.of("Another Cook", "Doric", "Heroes", "Legends", "Observatory", "Olaf", "Waterfall");
+    private final Map<String, String> QUEST_REPLACEMENTS = Map.of(
+        "Lumbridge Cook... again", "Another Cook's",
+        "Skrach 'Bone Crusher' Uglogwee", "Skrach Uglogwee"
+    );
 
     @Nullable
     public String parseQuestWidget(final String text) {
@@ -62,6 +66,8 @@ public class QuestUtils {
         }
 
         String quest = matcher.group("quest");
+        quest = QUEST_REPLACEMENTS.getOrDefault(quest, quest);
+
         String verb = StringUtils.defaultString(matcher.group("verb"));
 
         if (verb.contains("kind of")) {


Test patch:
diff --git a/src/test/java/dinkplugin/notifiers/QuestNotifierTest.java b/src/test/java/dinkplugin/notifiers/QuestNotifierTest.java
index 14ef178..f5b7963 100644
--- a/src/test/java/dinkplugin/notifiers/QuestNotifierTest.java
+++ b/src/test/java/dinkplugin/notifiers/QuestNotifierTest.java
@@ -13,8 +13,11 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 
+import static dinkplugin.util.QuestUtils.parseQuestWidget;
 import static net.runelite.api.widgets.WidgetID.QUEST_COMPLETED_GROUP_ID;
 import static net.runelite.api.widgets.WidgetInfo.QUEST_COMPLETED_NAME_TEXT;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.mock;
@@ -99,6 +102,26 @@ class QuestNotifierTest extends MockedNotifierTest {
         verify(messageHandler, never()).createMessage(any(), anyBoolean(), any());
     }
 
+    @Test
+    void parseWidgets() {
+        assertEquals("Recipe for Disaster - Another Cook's Quest", parseQuestWidget("You have completed Another Cook's Quest!"));
+        assertEquals("Recipe for Disaster - Another Cook's Quest", parseQuestWidget("You have assisted the Lumbridge Cook... again!"));
+        assertEquals("Recipe for Disaster - Goblin Generals", parseQuestWidget("You have freed the Goblin Generals!"));
+        assertEquals("Recipe for Disaster - Sir Amik Varze", parseQuestWidget("You have freed Sir Amik Varze!"));
+        assertEquals("Recipe for Disaster - Skrach Uglogwee", parseQuestWidget("You have freed Skrach 'Bone Crusher' Uglogwee!"));
+        assertEquals("Recipe for Disaster", parseQuestWidget("You have completed Recipe for Disaster!"));
+
+        assertEquals("Doric's Quest", parseQuestWidget("You have completed Doric's Quest!"));
+        assertEquals("Heroes Quest", parseQuestWidget("You have completed the Heroes' Quest!"));
+
+        assertEquals("Dragon Slayer II", parseQuestWidget("You have completed Dragon Slayer II!"));
+        assertEquals("Rag and Bone Man II", parseQuestWidget("You have completed Rag and Bone Man II!"));
+        assertEquals("Fairytale II - Cure a Queen", parseQuestWidget("You have completed Fairytale II - Cure a Queen!"));
+
+        assertNull(parseQuestWidget("You have... kind of... completed Hazeel Cult!"));
+        assertEquals("Hazeel Cult", parseQuestWidget("You have completed Hazeel Cult!"));
+    }
+
     private static WidgetLoaded event(int id) {
         WidgetLoaded event = new WidgetLoaded();
         event.setGroupId(id);