Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
20 changes: 18 additions & 2 deletions src/main/java/com/pettheanimals/PetResponses.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public final class PetResponses
"Seagull"
));

private static final Map<String, java.util.List<String>> RESPONSES;
static final Map<String, java.util.List<String>> RESPONSES;
static
{
Map<String, java.util.List<String>> m = new HashMap<>();
Expand Down Expand Up @@ -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<String> 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<String, java.util.List<String>> e : RESPONSES.entrySet())
{
if (key.contains(e.getKey()))
Expand All @@ -134,4 +140,14 @@ public static String buildLine(String npcName)
}
return "You gently pet the " + name.toLowerCase(Locale.ROOT) + ".";
}

public static java.util.Set<String> getAnimals()
{
return RESPONSES.keySet();
}

public static java.util.List<String> getDefaults(String key)
{
return RESPONSES.getOrDefault(key, java.util.Collections.emptyList());
}
}
113 changes: 74 additions & 39 deletions src/main/java/com/pettheanimals/PetTheAnimalsConfig.java
Original file line number Diff line number Diff line change
@@ -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();
}
}

145 changes: 126 additions & 19 deletions src/main/java/com/pettheanimals/PetTheAnimalsPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -54,6 +61,7 @@ public class PetTheAnimalsPlugin extends Plugin
protected void startUp() throws Exception
{
registerPetMenu();
updateSummary();
log.info("Pet the Animals started");
}

Expand Down Expand Up @@ -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<String> 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())
Expand All @@ -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<String> 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<String> 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);
}
}
17 changes: 17 additions & 0 deletions src/test/java/com/pettheanimals/PetResponsesTest.java
Original file line number Diff line number Diff line change
@@ -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<String> custom = java.util.Collections.singletonList("Custom line");
String result = PetResponses.buildLine("dog", custom);
assertEquals("Custom line", result);
}
}