diff --git a/README.md b/README.md index f76209d..151030a 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,10 @@ The plugin exposes several options in the RuneLite configuration panel: | Option | Description | | --- | --- | | Enable Chat Message | Send pet message to chatbox. | -| Enable Overhead Text | Show message over your player. | +| Enable Overhead Text | Show message over the pet. | | Max Distance | Maximum number of tiles you can be from the NPC (default 2). | | Additional NPCs | Extra comma-separated NPC names that are allowed to be petted. | +| Pet Responses | Collapsible section with a summary and a popup editor for per-animal lines. | ## Building This is a standard RuneLite plugin and can be built with `./gradlew build`. diff --git a/src/main/java/com/pettheanimals/PetResponses.java b/src/main/java/com/pettheanimals/PetResponses.java index 0dfd75e..7b791b0 100644 --- a/src/main/java/com/pettheanimals/PetResponses.java +++ b/src/main/java/com/pettheanimals/PetResponses.java @@ -29,7 +29,7 @@ public final class PetResponses "Seagull" )); - private static final Map> RESPONSES; + static final Map> RESPONSES; static { Map> m = new HashMap<>(); @@ -118,10 +118,16 @@ public final class PetResponses private PetResponses() { } - public static String buildLine(String npcName) + public static String buildLine(String npcName, java.util.List customLines) { final String name = npcName == null ? "creature" : npcName; final String key = name.toLowerCase(Locale.ROOT); + + if (customLines != null && !customLines.isEmpty()) + { + return customLines.get(new java.util.Random().nextInt(customLines.size())); + } + for (Map.Entry> e : RESPONSES.entrySet()) { if (key.contains(e.getKey())) @@ -134,4 +140,14 @@ public static String buildLine(String npcName) } return "You gently pet the " + name.toLowerCase(Locale.ROOT) + "."; } + + public static java.util.Set getAnimals() + { + return RESPONSES.keySet(); + } + + public static java.util.List getDefaults(String key) + { + return RESPONSES.getOrDefault(key, java.util.Collections.emptyList()); + } } diff --git a/src/main/java/com/pettheanimals/PetTheAnimalsConfig.java b/src/main/java/com/pettheanimals/PetTheAnimalsConfig.java index 55ffedf..2f64480 100644 --- a/src/main/java/com/pettheanimals/PetTheAnimalsConfig.java +++ b/src/main/java/com/pettheanimals/PetTheAnimalsConfig.java @@ -1,49 +1,84 @@ package com.pettheanimals; +import net.runelite.client.config.Button; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigSection; @ConfigGroup("pettheanimals") public interface PetTheAnimalsConfig extends Config { - @ConfigItem( - keyName = "enableChatMessage", - name = "Enable Chat Message", - description = "Also send the pet message to the chatbox." - ) - default boolean enableChatMessage() - { - return true; - } - - @ConfigItem( - keyName = "enableOverheadText", - name = "Enable Overhead Text", - description = "Show the pet message above your player." - ) - default boolean enableOverheadText() - { - return true; - } - - @ConfigItem( - keyName = "petDistance", - name = "Max Distance", - description = "Maximum tiles away you can be to pet an NPC." - ) - default int petDistance() - { - return 2; - } - - @ConfigItem( - keyName = "additionalNpcNames", - name = "Additional NPCs", - description = "Comma-separated list of extra NPC names that can be petted." - ) - default String additionalNpcNames() - { - return ""; - } + @ConfigItem( + keyName = "enableChatMessage", + name = "Enable Chat Message", + description = "Also send the pet message to the chatbox." + ) + default boolean enableChatMessage() + { + return true; + } + + @ConfigItem( + keyName = "enableOverheadText", + name = "Enable Overhead Text", + description = "Show the pet message above the pet." + ) + default boolean enableOverheadText() + { + return true; + } + + @ConfigItem( + keyName = "petDistance", + name = "Max Distance", + description = "Maximum tiles away you can be to pet an NPC." + ) + default int petDistance() + { + return 2; + } + + @ConfigItem( + keyName = "additionalNpcNames", + name = "Additional NPCs", + description = "Comma-separated list of extra NPC names that can be petted." + ) + default String additionalNpcNames() + { + return ""; + } + + @ConfigSection( + name = "Pet Responses", + description = "Customize animal dialogue.", + position = 98, + closedByDefault = true + ) + String petLinesSection = "petLinesSection"; + + @ConfigItem( + keyName = "linesSummary", + name = "Summary", + description = "Overview of customised animals.", + section = petLinesSection, + position = 0 + ) + default String linesSummary() + { + return "Using defaults"; + } + + @ConfigItem( + keyName = "editPetLines", + name = "Edit Responses", + description = "Open a popup to edit pet lines.", + section = petLinesSection, + position = 1 + ) + default Button editPetLines() + { + return new Button(); + } } + diff --git a/src/main/java/com/pettheanimals/PetTheAnimalsPlugin.java b/src/main/java/com/pettheanimals/PetTheAnimalsPlugin.java index 55d5436..5c7208b 100644 --- a/src/main/java/com/pettheanimals/PetTheAnimalsPlugin.java +++ b/src/main/java/com/pettheanimals/PetTheAnimalsPlugin.java @@ -13,16 +13,23 @@ import net.runelite.api.events.MenuEntryAdded; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigButtonClicked; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.menus.MenuManager; import net.runelite.client.util.Text; +import javax.swing.*; +import java.awt.BorderLayout; import java.lang.reflect.Method; import java.util.function.Predicate; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; @Slf4j @PluginDescriptor( @@ -54,6 +61,7 @@ public class PetTheAnimalsPlugin extends Plugin protected void startUp() throws Exception { registerPetMenu(); + updateSummary(); log.info("Pet the Animals started"); } @@ -435,37 +443,33 @@ public void onMenuOptionClicked(MenuOptionClicked event) return; } + NPC npc = getNpcByIndex(event.getId()); + // Require player to be within 2 tiles of the target NPC - if (client.getLocalPlayer() != null) + if (client.getLocalPlayer() != null && npc != null) { - NPC npc = getNpcByIndex(event.getId()); - if (npc != null) + WorldPoint me = client.getLocalPlayer().getWorldLocation(); + WorldPoint them = npc.getWorldLocation(); + if (!withinTiles(me, them, config.petDistance())) { - WorldPoint me = client.getLocalPlayer().getWorldLocation(); - WorldPoint them = npc.getWorldLocation(); - if (!withinTiles(me, them, config.petDistance())) - { - client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "You need to be closer to do that.", null); - event.consume(); - return; - } + client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "You need to be closer to do that.", null); + event.consume(); + return; } } - final String line = PetResponses.buildLine(rawName); + List customLines = getCustomLinesFor(rawName); + final String line = PetResponses.buildLine(rawName, customLines); // Show overhead text and optional chat message - if (config.enableOverheadText() && client.getLocalPlayer() != null) + if (config.enableOverheadText() && npc != null) { - client.getLocalPlayer().setOverheadText(line); + npc.setOverheadText(line); if (clearOverheadTask != null && !clearOverheadTask.isDone()) { clearOverheadTask.cancel(true); } - clearOverheadTask = scheduler.schedule(() -> { - if (client.getLocalPlayer() != null) { - client.getLocalPlayer().setOverheadText(null); - } - }, OVERHEAD_TEXT_DURATION_MS, TimeUnit.MILLISECONDS); + final NPC npcToClear = npc; + clearOverheadTask = scheduler.schedule(() -> npcToClear.setOverheadText(null), OVERHEAD_TEXT_DURATION_MS, TimeUnit.MILLISECONDS); } if (config.enableChatMessage()) @@ -482,4 +486,107 @@ PetTheAnimalsConfig provideConfig(ConfigManager configManager) { return configManager.getConfig(PetTheAnimalsConfig.class); } + + @Subscribe + public void onConfigButtonClicked(ConfigButtonClicked event) + { + if (!"pettheanimals".equals(event.getGroup()) || !"editPetLines".equals(event.getKey())) + { + return; + } + + SwingUtilities.invokeLater(this::openEditor); + } + + private void openEditor() + { + JDialog dialog = new JDialog(); + dialog.setTitle("Pet Responses"); + + String[] keys = PetResponses.getAnimals().stream().sorted().toArray(String[]::new); + JComboBox combo = new JComboBox<>(keys); + JTextArea area = new JTextArea(5, 20); + + combo.addActionListener(e -> { + String sel = (String) combo.getSelectedItem(); + String stored = configManager.getConfiguration("pettheanimals", "line." + sel); + if (stored == null || stored.isEmpty()) + { + area.setText(String.join("\n", PetResponses.getDefaults(sel))); + } + else + { + area.setText(stored.replace('|', '\n')); + } + }); + + JButton save = new JButton("Save"); + save.addActionListener(e -> { + String sel = (String) combo.getSelectedItem(); + String text = Arrays.stream(area.getText().split("\n")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.joining("|")); + configManager.setConfiguration("pettheanimals", "line." + sel, text); + updateSummary(); + }); + + JButton close = new JButton("Close"); + close.addActionListener(e -> dialog.dispose()); + + JPanel buttons = new JPanel(); + buttons.add(save); + buttons.add(close); + + JPanel panel = new JPanel(new BorderLayout(5, 5)); + panel.add(combo, BorderLayout.NORTH); + panel.add(new JScrollPane(area), BorderLayout.CENTER); + panel.add(buttons, BorderLayout.SOUTH); + + dialog.getContentPane().add(panel); + combo.setSelectedIndex(0); + dialog.pack(); + dialog.setLocationRelativeTo(null); + dialog.setVisible(true); + } + + private List getCustomLinesFor(String npcName) + { + if (npcName == null) + { + return java.util.Collections.emptyList(); + } + + String key = npcName.toLowerCase(Locale.ROOT); + for (String k : PetResponses.getAnimals()) + { + if (key.contains(k)) + { + String stored = configManager.getConfiguration("pettheanimals", "line." + k); + if (stored != null && !stored.trim().isEmpty()) + { + return Arrays.stream(stored.split("\\|")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); + } + } + } + return java.util.Collections.emptyList(); + } + + private void updateSummary() + { + int count = 0; + for (String k : PetResponses.getAnimals()) + { + String stored = configManager.getConfiguration("pettheanimals", "line." + k); + if (stored != null && !stored.trim().isEmpty()) + { + count++; + } + } + String summary = count == 0 ? "Using defaults" : count + " customised"; + configManager.setConfiguration("pettheanimals", "linesSummary", summary); + } } diff --git a/src/test/java/com/pettheanimals/PetResponsesTest.java b/src/test/java/com/pettheanimals/PetResponsesTest.java new file mode 100644 index 0000000..862ae45 --- /dev/null +++ b/src/test/java/com/pettheanimals/PetResponsesTest.java @@ -0,0 +1,17 @@ +package com.pettheanimals; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class PetResponsesTest +{ + @Test + public void testCustomLineOverridesDefault() + { + java.util.List custom = java.util.Collections.singletonList("Custom line"); + String result = PetResponses.buildLine("dog", custom); + assertEquals("Custom line", result); + } +} +