diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
index 523c0335c8..50e388076c 100644
--- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
+++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
@@ -533,6 +533,7 @@ public class WidgetID
static final int SPELL_ICON = 27;
static final int SPELL_TEXT = 28;
static final int AUTO_RETALIATE = 29;
+ static final int SPEC_BAR = 34;
}
static class VolcanicMine
diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java
index 78bb2832b4..058e9aa05a 100644
--- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java
+++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java
@@ -313,6 +313,7 @@ public enum WidgetInfo
COMBAT_SPELL_ICON(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPELL_ICON),
COMBAT_SPELL_TEXT(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPELL_TEXT),
COMBAT_AUTO_RETALIATE(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.AUTO_RETALIATE),
+ COMBAT_SPEC_BAR(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPEC_BAR), // Used by CombatInterfaceSP.rs2asm
DIALOG_OPTION(WidgetID.DIALOG_OPTION_GROUP_ID, 0),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
index 05748f87ae..861958613b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
@@ -148,7 +148,7 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati
.put(new WorldPoint(3573, 3425, 0), "North of Dessous's tomb from Desert Treasure.")
.put(new WorldPoint(3828, 2848, 0), "East of Harmony Island.")
.put(new WorldPoint(3225, 2838, 0), "South of Desert Treasure pyramid.")
- .put(new WorldPoint(1773, 3510, 0), "Between magic trees South of Tithe Farm.")
+ .put(new WorldPoint(1773, 3510, 0), "Ruins north of the Hosidius mine.")
.put(new WorldPoint(3822, 3562, 0), "North-east of Dragontooth Island.")
.put(new WorldPoint(3603, 3564, 0), "North of the wrecked ship, outside of Port Phasmatys.")
.put(new WorldPoint(2936, 2721, 0), "Eastern shore of Crash Island.")
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java
index cfd5fca7c6..ebaa54e7cb 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java
@@ -311,6 +311,7 @@ public class ConfigPanel extends PluginPanel
JLabel title = new JLabel(name);
title.setForeground(Color.WHITE);
title.setToolTipText("" + name + ":
" + listItem.getDescription() + "");
+ PluginListItem.addLabelPopupMenu(title, PluginListItem.wikiLinkMenuItem(listItem.getName()));
topPanel.add(title);
for (ConfigItemDescriptor cid : cd.getItems())
@@ -704,4 +705,4 @@ public class ConfigPanel extends PluginPanel
}
}
-}
\ No newline at end of file
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java
index 64b97a6ab8..092b4c9c92 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java
@@ -26,30 +26,43 @@ package net.runelite.client.plugins.config;
import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
+import java.awt.MouseInfo;
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
+import javax.swing.JMenuItem;
import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigDescriptor;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.IconButton;
import net.runelite.client.util.ImageUtil;
+import net.runelite.client.util.LinkBrowser;
import org.apache.commons.text.similarity.JaroWinklerDistance;
class PluginListItem extends JPanel
{
private static final JaroWinklerDistance DISTANCE = new JaroWinklerDistance();
+ private static final String RUNELITE_WIKI_FORMAT = "https://github.com/runelite/runelite/wiki/%s";
private static final ImageIcon CONFIG_ICON;
private static final ImageIcon CONFIG_ICON_HOVER;
@@ -149,6 +162,8 @@ class PluginListItem extends JPanel
Collections.addAll(keywords, description.toLowerCase().split(" "));
Collections.addAll(keywords, tags);
+ final List popupMenuItems = new ArrayList<>();
+
setLayout(new BorderLayout(3, 0));
setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH, 20));
@@ -160,7 +175,6 @@ class PluginListItem extends JPanel
nameLabel.setToolTipText("" + name + ":
" + description + "");
}
- add(nameLabel, BorderLayout.CENTER);
pinButton.setPreferredSize(new Dimension(21, 0));
add(pinButton, BorderLayout.LINE_START);
@@ -186,13 +200,21 @@ class PluginListItem extends JPanel
configButton.addActionListener(e ->
{
configButton.setIcon(CONFIG_ICON);
- configPanel.openGroupConfigPanel(PluginListItem.this, config, configDescriptor);
+ openGroupConfigPanel();
});
configButton.setVisible(true);
configButton.setToolTipText("Edit plugin configuration");
+
+ final JMenuItem configMenuItem = new JMenuItem("Configure");
+ configMenuItem.addActionListener(e -> openGroupConfigPanel());
+ popupMenuItems.add(configMenuItem);
}
+ popupMenuItems.add(wikiLinkMenuItem(name));
+ addLabelPopupMenu(nameLabel, popupMenuItems);
+ add(nameLabel, BorderLayout.CENTER);
+
toggleButton.setPreferredSize(new Dimension(25, 0));
attachToggleButtonListener(toggleButton);
buttonPanel.add(toggleButton);
@@ -267,4 +289,81 @@ class PluginListItem extends JPanel
}
return true;
}
+
+ private void openGroupConfigPanel()
+ {
+ configPanel.openGroupConfigPanel(PluginListItem.this, config, configDescriptor);
+ }
+
+ /**
+ * Adds a mouseover effect to change the text of the passed label to {@link ColorScheme#BRAND_ORANGE} color, and
+ * adds the passed menu item to a popup menu shown when the label is clicked.
+ *
+ * @param label The label to attach the mouseover and click effects to
+ * @param menuItem The menu item to be shown when the label is clicked
+ */
+ static void addLabelPopupMenu(final JLabel label, final JMenuItem menuItem)
+ {
+ addLabelPopupMenu(label, Collections.singletonList(menuItem));
+ }
+
+ /**
+ * Adds a mouseover effect to change the text of the passed label to {@link ColorScheme#BRAND_ORANGE} color, and
+ * adds the passed menu items to a popup menu shown when the label is clicked.
+ *
+ * @param label The label to attach the mouseover and click effects to
+ * @param menuItems The menu items to be shown when the label is clicked
+ */
+ static void addLabelPopupMenu(final JLabel label, final Collection menuItems)
+ {
+ final JPopupMenu menu = new JPopupMenu();
+ menu.setBorder(new EmptyBorder(5, 5, 5, 5));
+
+ for (final JMenuItem menuItem : menuItems)
+ {
+ menu.add(menuItem);
+ }
+
+ label.addMouseListener(new MouseAdapter()
+ {
+ private Color lastForeground;
+
+ @Override
+ public void mouseClicked(MouseEvent mouseEvent)
+ {
+ Component source = (Component) mouseEvent.getSource();
+ Point location = MouseInfo.getPointerInfo().getLocation();
+ SwingUtilities.convertPointFromScreen(location, source);
+ menu.show(source, location.x, location.y);
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent mouseEvent)
+ {
+ lastForeground = label.getForeground();
+ label.setForeground(ColorScheme.BRAND_ORANGE);
+ }
+
+ @Override
+ public void mouseExited(MouseEvent mouseEvent)
+ {
+ label.setForeground(lastForeground);
+ }
+ });
+ }
+
+ /**
+ * Creates a menu item for linking to a wiki page which, when clicked, opens a link to the plugin's wiki page for
+ * the passed plugin name.
+ *
+ * @param pluginName The name of the plugin which should be linked to
+ * @return A {@link JMenuItem} which opens the plugin's wiki page URL in the browser when clicked
+ */
+ static JMenuItem wikiLinkMenuItem(final String pluginName)
+ {
+ final JMenuItem menuItem = new JMenuItem("Wiki");
+ final String sanitizedName = pluginName.replace(' ', '-');
+ menuItem.addActionListener(e -> LinkBrowser.browse(String.format(RUNELITE_WIKI_FORMAT, sanitizedName)));
+ return menuItem;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
index 4f1041a67b..59330554c1 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
@@ -36,6 +36,7 @@ import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import net.runelite.api.NPC;
+import net.runelite.api.NPCComposition;
import net.runelite.api.Player;
import net.runelite.api.Skill;
import net.runelite.api.VarPlayer;
@@ -51,6 +52,7 @@ import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.ws.PartyService;
import net.runelite.client.ws.WSClient;
+import org.apache.commons.lang3.ArrayUtils;
@PluginDescriptor(
name = "Special Attack Counter",
@@ -181,7 +183,16 @@ public class SpecialCounterPlugin extends Plugin
if (interacting instanceof NPC)
{
- int interactingId = ((NPC) interacting).getId();
+ NPC npc = (NPC) interacting;
+ NPCComposition composition = npc.getComposition();
+ int interactingId = npc.getId();
+
+ if (!ArrayUtils.contains(composition.getActions(), "Attack"))
+ {
+ // Skip over non attackable npcs so that eg. talking to bankers doesn't reset
+ // the counters.
+ return -1;
+ }
if (!interactedNpcIds.contains(interactingId))
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java
index 2e0852d6c0..ab2035ae74 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java
@@ -138,6 +138,7 @@ enum TeleportLocationData
PHARAOHS_SCEPTRE_JALSAVRAH(TeleportType.OTHER, "Pharaoh's Sceptre", "Jalsavrah (Pyramid Plunder)", new WorldPoint(3288, 2795, 0), "pharaohs_sceptre_teleport_icon.png"),
PHARAOHS_SCEPTRE_JALEUSTROPHOS(TeleportType.OTHER, "Pharaoh's Sceptre", "Jaleustrophos (Agility Pyramid)", new WorldPoint(3341, 2827, 0), "pharaohs_sceptre_teleport_icon.png"),
PHARAOHS_SCEPTRE_JALDRAOCHT(TeleportType.OTHER, "Pharaoh's Sceptre", "Jaldraocht (Desert Treasure Pyramid)", new WorldPoint(3232, 2897, 0), "pharaohs_sceptre_teleport_icon.png"),
+ CAMULET_TEMPLE(TeleportType.OTHER, "Camulet", "Enakhra's Temple", new WorldPoint(3190, 2923, 0), "camulet_teleport_icon.png"),
// Wilderness
OBELISK_13(TeleportType.OTHER, "Obelisk", "13", new WorldPoint(3156, 3620, 0), "obelisk_icon.png"),
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java
index a891eaba41..01f52d6ad0 100644
--- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java
+++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java
@@ -24,6 +24,7 @@
*/
package net.runelite.client.ui.overlay.components;
+import com.google.common.base.Strings;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
@@ -41,6 +42,7 @@ public class ProgressBarComponent implements LayoutableRenderableEntity
{
PERCENTAGE,
FULL,
+ TEXT_ONLY,
BOTH
}
@@ -53,6 +55,7 @@ public class ProgressBarComponent implements LayoutableRenderableEntity
private long maximum = 100;
private double value;
private LabelDisplayMode labelDisplayMode = LabelDisplayMode.PERCENTAGE;
+ private String centerLabel;
private String leftLabel;
private String rightLabel;
private Color foregroundColor = new Color(82, 161, 82);
@@ -75,20 +78,34 @@ public class ProgressBarComponent implements LayoutableRenderableEntity
final long span = maximum - minimum;
final double currentValue = value - minimum;
final double pc = currentValue / span;
- final String textToWrite;
+ String textToWrite;
switch (labelDisplayMode)
{
+ case TEXT_ONLY:
+ textToWrite = "";
+ break;
case PERCENTAGE:
textToWrite = formatPercentageProgress(pc);
break;
case BOTH:
textToWrite = formatFullProgress(currentValue, maximum) + " (" + formatPercentageProgress(pc) + ")";
break;
+ case FULL:
default:
textToWrite = formatFullProgress(currentValue, maximum);
}
+ if (!Strings.isNullOrEmpty(centerLabel))
+ {
+ if (!textToWrite.isEmpty())
+ {
+ textToWrite += " ";
+ }
+
+ textToWrite += centerLabel;
+ }
+
final int width = preferredSize.width;
final int height = Math.max(preferredSize.height, 16);
final int progressTextX = barX + (width - metrics.stringWidth(textToWrite)) / 2;
diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/worldmap/camulet_teleport_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/worldmap/camulet_teleport_icon.png
new file mode 100644
index 0000000000..7a74119cc8
Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/worldmap/camulet_teleport_icon.png differ
diff --git a/runelite-client/src/main/scripts/CombatInterfaceSP.hash b/runelite-client/src/main/scripts/CombatInterfaceSP.hash
new file mode 100644
index 0000000000..e92e5b127b
--- /dev/null
+++ b/runelite-client/src/main/scripts/CombatInterfaceSP.hash
@@ -0,0 +1 @@
+DDFE4E407122EEEAE2C64A233EA937B2CC20E92D66CB66772C31182A6C60820D
\ No newline at end of file
diff --git a/runelite-client/src/main/scripts/CombatInterfaceSP.rs2asm b/runelite-client/src/main/scripts/CombatInterfaceSP.rs2asm
new file mode 100644
index 0000000000..9f908245af
--- /dev/null
+++ b/runelite-client/src/main/scripts/CombatInterfaceSP.rs2asm
@@ -0,0 +1,29 @@
+.id 327
+.int_stack_count 1
+.string_stack_count 0
+.int_var_count 1
+.string_var_count 0
+ ; Attach specbar redraw listeners to special attack bar instead of to
+ ; auto retaliate text (which is var0). Test by enabling "Hide auto retaliate"
+ ; and using a spec.
+ iconst 38862882 ; 593.34 - spec bar
+ istore 0 ; overwrite script parameter which is the autoretail text
+ iload 0
+ invoke 187
+ iconst 186
+ iload 0
+ iconst 301
+ iconst 300
+ iconst 284
+ iconst 3
+ sconst "IY"
+ iload 0
+ if_setonvartransmit
+ iconst 186
+ iload 0
+ iconst 94
+ iconst 1
+ sconst "IY"
+ iload 0
+ if_setoninvtransmit
+ return