diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 56856151a9..d188ca0b90 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -25,9 +25,9 @@ object ProjectVersions { const val launcherVersion = "3.0.0" - const val rlVersion = "1.8.24.1" + const val rlVersion = "1.8.24.2" - const val openosrsVersion = "4.31.0" + const val openosrsVersion = "4.31.1" const val rsversion = 206 const val cacheversion = 165 diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java index e567ceeaaa..a51864eb99 100644 --- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java +++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java @@ -427,4 +427,10 @@ public final class ScriptID */ @ScriptArguments(integer = 6) public static final int TRADE_MAIN_INIT = 755; + + /** + * Transitions the tob hud into the white flash that happens when sotetseg teleports the players to the maze. + */ + @ScriptArguments(string = 1) + public static final int TOB_HUD_SOTETSEG_FADE = 2308; } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/RuntimeConfig.java b/runelite-client/src/main/java/net/runelite/client/RuntimeConfig.java index fc7fdb4492..fe5f0e733d 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuntimeConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/RuntimeConfig.java @@ -27,6 +27,7 @@ package net.runelite.client; import com.google.common.base.Strings; import java.util.Collections; import java.util.Map; +import java.util.Set; import javax.swing.SwingUtilities; import lombok.Data; import net.runelite.client.ui.FatalErrorDialog; @@ -41,6 +42,8 @@ public class RuntimeConfig private String outageMessage; private Map outageLinks; + private Set ignoreDeadNpcs; + public boolean showOutageMessage() { if (Strings.isNullOrEmpty(getOutageMessage())) diff --git a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java index 0a687f02c5..91b27cd166 100644 --- a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java +++ b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java @@ -248,7 +248,12 @@ public class SessionManager // Save session to disk saveSession(); - req.getResponseHeaders().set("Location", oauthRedirect); + final HttpUrl redirect = HttpUrl.get(oauthRedirect).newBuilder() + .addQueryParameter("username", username) + .addQueryParameter("sessionId", sessionId.toString()) + .build(); + + req.getResponseHeaders().set("Location", redirect.toString()); req.sendResponseHeaders(302, 0); } catch (Exception e) diff --git a/runelite-client/src/main/java/net/runelite/client/game/NpcUtil.java b/runelite-client/src/main/java/net/runelite/client/game/NpcUtil.java index cb7fd3cdda..ee4f580512 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/NpcUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/game/NpcUtil.java @@ -25,11 +25,24 @@ */ package net.runelite.client.game; +import java.util.Set; +import javax.inject.Inject; import net.runelite.api.NPC; +import net.runelite.api.NPCComposition; import net.runelite.api.NpcID; +import net.runelite.client.RuntimeConfig; +import org.apache.commons.lang3.ArrayUtils; public class NpcUtil { + private final RuntimeConfig runtimeConfig; + + @Inject + private NpcUtil(RuntimeConfig runtimeConfig) + { + this.runtimeConfig = runtimeConfig; + } + /** * Returns whether an NPC is dying and can no longer be interacted with, or if it is still alive or in some special * state where it can be 0hp without dying. (For example, Gargoyles and other slayer monsters with item weaknesses @@ -38,7 +51,7 @@ public class NpcUtil * @param npc NPC to check whether it is dying * @return {@code true} if the NPC is dying */ - public static boolean isDying(final NPC npc) + public boolean isDying(final NPC npc) { final int id = npc.getId(); switch (id) @@ -72,14 +85,22 @@ public class NpcUtil case NpcID.DESERT_LIZARD: case NpcID.DESERT_LIZARD_460: case NpcID.DESERT_LIZARD_461: + case NpcID.LIZARD: + case NpcID.SMALL_LIZARD: + case NpcID.SMALL_LIZARD_463: case NpcID.GROWTHLING: - case NpcID.KALPHITE_QUEEN_963: - case NpcID.KALPHITE_QUEEN_965: - case NpcID.VETION: - case NpcID.VETION_REBORN: + case NpcID.KALPHITE_QUEEN_963: // KQ's first form sometimes regenerates 1hp after reaching 0hp, thus not dying return false; default: - return npc.isDead(); + Set ignoredNpcs = runtimeConfig.getIgnoreDeadNpcs(); + if (ignoredNpcs != null && ignoredNpcs.contains(id)) + { + return false; + } + + final NPCComposition npcComposition = npc.getTransformedComposition(); + boolean hasAttack = npcComposition != null && ArrayUtils.contains(npcComposition.getActions(), "Attack"); + return hasAttack && npc.isDead(); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java index 106f64cc75..8446bbb5d0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java @@ -107,7 +107,7 @@ public class KourendDiaryRequirement extends GenericDiaryRequirement new QuestRequirement(Quest.DREAM_MENTOR)); //ELITE - add("Craft one or more Blood runes from Essence.", + add("Craft one or more Blood runes from Dark essence fragments.", new SkillRequirement(Skill.RUNECRAFT, 77), new SkillRequirement(Skill.MINING, 38), new SkillRequirement(Skill.CRAFTING, 38), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostIndicator.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostIndicator.java index 001e8ae5c8..ff286f409f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostIndicator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostIndicator.java @@ -32,7 +32,7 @@ import net.runelite.api.Skill; import net.runelite.client.ui.overlay.infobox.InfoBox; import net.runelite.client.ui.overlay.infobox.InfoBoxPriority; -public class BoostIndicator extends InfoBox +class BoostIndicator extends InfoBox { private final BoostsPlugin plugin; private final BoostsConfig config; @@ -87,7 +87,7 @@ public class BoostIndicator extends InfoBox @Override public boolean render() { - return config.displayInfoboxes() && plugin.canShowBoosts() && plugin.getSkillsToDisplay().contains(getSkill()); + return plugin.canShowBoosts() && plugin.getSkillsToDisplay().contains(getSkill()) && config.displayInfoboxes(); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java index 0711d17fb3..86b9629081 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java @@ -59,7 +59,7 @@ public interface BoostsConfig extends Config @ConfigItem( keyName = "relativeBoost", - name = "Use Relative Boosts", + name = "Show relative boosts", description = "Configures whether or not relative boost is used", position = 2 ) @@ -70,8 +70,8 @@ public interface BoostsConfig extends Config @ConfigItem( keyName = "displayIndicators", - name = "Display as infoboxes", - description = "Configures whether or not to display the boost as infoboxes", + name = "Display infoboxes", + description = "Configures whether to display boost infoboxes", position = 3 ) default boolean displayInfoboxes() @@ -79,11 +79,33 @@ public interface BoostsConfig extends Config return true; } + @ConfigItem( + keyName = "displayPanel", + name = "Display panel", + description = "Configures whether to display the boost panel", + position = 3 + ) + default boolean displayPanel() + { + return false; + } + + @ConfigItem( + keyName = "compactDisplay", + name = "Compact display", + description = "Displays skill boosts in a more compact panel", + position = 4 + ) + default boolean compactDisplay() + { + return false; + } + @ConfigItem( keyName = "displayNextBuffChange", name = "Next buff change", description = "Configures whether or not to display when the next buffed stat change will be", - position = 4 + position = 10 ) default DisplayChangeMode displayNextBuffChange() { @@ -94,7 +116,7 @@ public interface BoostsConfig extends Config keyName = "displayNextDebuffChange", name = "Next debuff change", description = "Configures whether or not to display when the next debuffed stat change will be", - position = 5 + position = 11 ) default DisplayChangeMode displayNextDebuffChange() { @@ -105,7 +127,7 @@ public interface BoostsConfig extends Config keyName = "boostThreshold", name = "Boost threshold", description = "The threshold at which boosted levels will be displayed in a different color. A value of 0 will disable the feature.", - position = 6 + position = 12 ) default int boostThreshold() { @@ -116,7 +138,7 @@ public interface BoostsConfig extends Config keyName = "notifyOnBoost", name = "Notify on boost threshold", description = "Configures whether or not a notification will be sent for boosted stats.", - position = 7 + position = 13 ) default boolean notifyOnBoost() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java index fd53503444..16d454acf0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java @@ -30,10 +30,7 @@ import java.awt.Graphics2D; import java.util.Set; import javax.inject.Inject; import net.runelite.api.Client; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; import net.runelite.api.Skill; -import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; -import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.OverlayPanel; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; @@ -55,19 +52,18 @@ class BoostsOverlay extends OverlayPanel this.config = config; setPosition(OverlayPosition.TOP_LEFT); setPriority(OverlayPriority.MED); - getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Boosts overlay")); } @Override public Dimension render(Graphics2D graphics) { - if (config.displayInfoboxes()) + final Set boostedSkills = plugin.getSkillsToDisplay(); + if (boostedSkills.isEmpty() || !config.displayPanel()) { return null; } int nextChange = plugin.getChangeDownTicks(); - if (nextChange != -1) { panelComponent.getChildren().add(LineComponent.builder() @@ -77,7 +73,6 @@ class BoostsOverlay extends OverlayPanel } nextChange = plugin.getChangeUpTicks(); - if (nextChange != -1) { panelComponent.getChildren().add(LineComponent.builder() @@ -86,13 +81,6 @@ class BoostsOverlay extends OverlayPanel .build()); } - final Set boostedSkills = plugin.getSkillsToDisplay(); - - if (boostedSkills.isEmpty()) - { - return super.render(graphics); - } - if (plugin.canShowBoosts()) { for (Skill skill : boostedSkills) @@ -136,6 +124,5 @@ class BoostsOverlay extends OverlayPanel } return boost <= config.boostThreshold() ? Color.YELLOW : Color.GREEN; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java index dac873dbf7..cd47e26719 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java @@ -34,19 +34,22 @@ import javax.inject.Singleton; import lombok.Getter; import net.runelite.api.Client; import net.runelite.api.Constants; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; import net.runelite.api.Prayer; import net.runelite.api.Skill; -import net.runelite.client.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.StatChanged; import net.runelite.client.Notifier; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.game.SkillIconManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.OverlayManager; +import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; +import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.ImageUtil; @@ -85,6 +88,9 @@ public class BoostsPlugin extends Plugin @Inject private BoostsOverlay boostsOverlay; + @Inject + private CompactBoostsOverlay compactBoostsOverlay; + @Inject private BoostsConfig config; @@ -113,14 +119,20 @@ public class BoostsPlugin extends Plugin @Override protected void startUp() throws Exception { + OverlayMenuEntry menuEntry = new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Boosts overlay"); + + boostsOverlay.getMenuEntries().add(menuEntry); + compactBoostsOverlay.getMenuEntries().add(menuEntry);; + overlayManager.add(boostsOverlay); + overlayManager.add(compactBoostsOverlay); updateShownSkills(); Arrays.fill(lastSkillLevels, -1); // Add infoboxes for everything at startup and then determine inside if it will be rendered - infoBoxManager.addInfoBox(new StatChangeIndicator(true, ImageUtil.loadImageResource(getClass(), "debuffed.png"), this, config)); - infoBoxManager.addInfoBox(new StatChangeIndicator(false, ImageUtil.loadImageResource(getClass(), "buffed.png"), this, config)); + infoBoxManager.addInfoBox(new StatChangeIndicator(true, ImageUtil.loadImageResource(getClass(), "buffed.png"), this, config)); + infoBoxManager.addInfoBox(new StatChangeIndicator(false, ImageUtil.loadImageResource(getClass(), "debuffed.png"), this, config)); for (final Skill skill : Skill.values()) { @@ -134,7 +146,10 @@ public class BoostsPlugin extends Plugin @Override protected void shutDown() throws Exception { + boostsOverlay.getMenuEntries().clear(); + compactBoostsOverlay.getMenuEntries().clear(); overlayManager.remove(boostsOverlay); + overlayManager.remove(compactBoostsOverlay); infoBoxManager.removeIf(t -> t instanceof BoostIndicator || t instanceof StatChangeIndicator); preserveBeenActive = false; lastChangeDown = -1; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/CompactBoostsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/CompactBoostsOverlay.java new file mode 100644 index 0000000000..ee66149dda --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/CompactBoostsOverlay.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2022, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.boosts; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.util.Set; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Skill; +import net.runelite.client.game.SkillIconManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.TextComponent; +import net.runelite.client.util.ImageUtil; + +class CompactBoostsOverlay extends Overlay +{ + private static final int H_PADDING = 2; + private static final int V_PADDING = 1; + private static final int TEXT_WIDTH = 22; + private static final BufferedImage BUFFED = ImageUtil.loadImageResource(CompactBoostsOverlay.class, "buffedsmall.png"); + private static final BufferedImage DEBUFFED = ImageUtil.loadImageResource(CompactBoostsOverlay.class, "debuffedsmall.png"); + + private final Client client; + private final BoostsConfig config; + private final BoostsPlugin plugin; + private final SkillIconManager skillIconManager; + + private int curY; + private int maxX; + + @Inject + private CompactBoostsOverlay(Client client, BoostsConfig config, BoostsPlugin plugin, SkillIconManager skillIconManager) + { + super(plugin); + this.client = client; + this.config = config; + this.plugin = plugin; + this.skillIconManager = skillIconManager; + setPosition(OverlayPosition.TOP_LEFT); + setPriority(OverlayPriority.MED); + } + + @Override + public Dimension render(Graphics2D graphics) + { + final Set boostedSkills = plugin.getSkillsToDisplay(); + if (boostedSkills.isEmpty() || !config.compactDisplay()) + { + return null; + } + + curY = maxX = 0; + + final FontMetrics fontMetrics = graphics.getFontMetrics(); + final int fontHeight = fontMetrics.getHeight(); + for (Skill skill : boostedSkills) + { + final int boosted = client.getBoostedSkillLevel(skill); + final int base = client.getRealSkillLevel(skill); + final int boost = boosted - base; + + if (boost == 0) + { + continue; + } + + drawBoost(graphics, fontMetrics, fontHeight, + skillIconManager.getSkillImage(skill, true), + getTextColor(boost), + getBoostText(boost, base, boosted)); + } + + int time = plugin.getChangeUpTicks(); + if (time != -1) + { + drawBoost(graphics, fontMetrics, fontHeight, + BUFFED, + time < 10 ? Color.RED.brighter() : Color.WHITE, + Integer.toString(plugin.getChangeTime(time))); + } + + time = plugin.getChangeDownTicks(); + if (time != -1) + { + drawBoost(graphics, fontMetrics, fontHeight, + DEBUFFED, + time < 10 ? Color.RED.brighter() : Color.WHITE, + Integer.toString(plugin.getChangeTime(time))); + } + + return new Dimension(maxX, curY); + } + + private void drawBoost(Graphics2D graphics, FontMetrics fontMetrics, int fontHeight, BufferedImage image, Color color, String text) + { + graphics.drawImage(image, 0, curY, null); + + final int stringWidth = fontMetrics.stringWidth(text); + final TextComponent textComponent = new TextComponent(); + textComponent.setColor(color); + textComponent.setText(text); + textComponent.setOutline(true); + textComponent.setPosition(new Point( + image.getWidth() + + H_PADDING // add a little bit of padding to get the text off the side of the image + + (TEXT_WIDTH - stringWidth), // right justify to TEXT_WIDTH + // this really should be y + (image.getHeight() / 2) + (fontHeight / 2), but in practice + // it is the same + curY + fontHeight)); + textComponent.render(graphics); + + curY += Math.max(image.getHeight(), fontHeight) + + V_PADDING; // padding to keep images from touching + maxX = Math.max(maxX, image.getWidth() + H_PADDING + TEXT_WIDTH); + } + + private String getBoostText(int boost, int base, int boosted) + { + if (config.useRelativeBoost()) + { + return boost > 0 ? "+" + boost : "-" + boost; + } + else + { + return Integer.toString(boosted); + } + } + + private Color getTextColor(int boost) + { + if (boost < 0) + { + return new Color(238, 51, 51); + } + + return boost <= config.boostThreshold() ? Color.YELLOW : Color.GREEN; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/StatChangeIndicator.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/StatChangeIndicator.java index 5c9ef73762..f93bae6086 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/StatChangeIndicator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/StatChangeIndicator.java @@ -29,7 +29,7 @@ import java.awt.image.BufferedImage; import net.runelite.client.ui.overlay.infobox.InfoBox; import net.runelite.client.ui.overlay.infobox.InfoBoxPriority; -public class StatChangeIndicator extends InfoBox +class StatChangeIndicator extends InfoBox { private final boolean up; private final BoostsPlugin plugin; @@ -61,6 +61,6 @@ public class StatChangeIndicator extends InfoBox public boolean render() { final int time = up ? plugin.getChangeUpTicks() : plugin.getChangeDownTicks(); - return config.displayInfoboxes() && time != -1; + return time != -1 && config.displayInfoboxes(); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderPlugin.java index a3932376e3..50232a82a2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderPlugin.java @@ -59,6 +59,9 @@ public class EntityHiderPlugin extends Plugin @Inject private Hooks hooks; + @Inject + private NpcUtil npcUtil; + private boolean hideOthers; private boolean hideOthers2D; private boolean hideFriends; @@ -191,7 +194,7 @@ public class EntityHiderPlugin extends Plugin } // dead npcs can also be interacting so prioritize it over the interacting check - if (NpcUtil.isDying(npc) && hideDeadNpcs) + if (npcUtil.isDying(npc) && hideDeadNpcs) { return false; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java index 31cbe87301..f13a3ea37b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java @@ -192,6 +192,9 @@ public class MenuEntrySwapperPlugin extends Plugin @Inject private ChatMessageManager chatMessageManager; + @Inject + private NpcUtil npcUtil; + private boolean configuringShiftClick = false; private boolean configuringLeftClick = false; @@ -1285,7 +1288,7 @@ public class MenuEntrySwapperPlugin extends Plugin .filter(e -> { final NPC npc = e.getNpc(); - return npc == null || !NpcUtil.isDying(npc); + return npc == null || !npcUtil.isDying(npc); }) .toArray(MenuEntry[]::new); if (oldEntries.length != newEntries.length) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java index fd8553ad5a..aed562340d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java @@ -28,6 +28,7 @@ package net.runelite.client.plugins.party; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Keybind; @ConfigGroup(PartyConfig.GROUP) public interface PartyConfig extends Config @@ -37,7 +38,7 @@ public interface PartyConfig extends Config @ConfigItem( keyName = "pings", name = "Pings", - description = "Enables party pings (shift + left-click)", + description = "Enables party pings", position = 1 ) default boolean pings() @@ -60,13 +61,24 @@ public interface PartyConfig extends Config keyName = "recolorNames", name = "Recolor names", description = "Recolor party members names based on unique color hash", - position = 4 + position = 3 ) default boolean recolorNames() { return true; } + @ConfigItem( + keyName = "pingHotkey", + name = "Ping hotkey", + description = "Key to hold to send a tile ping", + position = 4 + ) + default Keybind pingHotkey() + { + return Keybind.NOT_SET; + } + @ConfigItem( keyName = "previousPartyId", name = "", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java index 068f3e0efc..4f9f438d6c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java @@ -45,7 +45,6 @@ import lombok.Getter; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.GameState; -import net.runelite.api.KeyCode; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; import net.runelite.api.Player; @@ -54,6 +53,7 @@ import net.runelite.api.SoundEffectID; import net.runelite.api.Tile; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.CommandExecuted; +import net.runelite.api.events.FocusChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.MenuOptionClicked; @@ -66,6 +66,7 @@ import net.runelite.client.events.ConfigChanged; import net.runelite.client.events.OverlayMenuClicked; import net.runelite.client.events.PartyChanged; import net.runelite.client.events.PartyMemberAvatar; +import net.runelite.client.input.KeyManager; import net.runelite.client.party.PartyMember; import net.runelite.client.party.PartyService; import net.runelite.client.party.WSClient; @@ -87,6 +88,7 @@ import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.HotkeyListener; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; @@ -128,6 +130,9 @@ public class PartyPlugin extends Plugin @Inject private ClientToolbar clientToolbar; + @Inject + private KeyManager keyManager; + @Inject @Named("developerMode") boolean developerMode; @@ -145,6 +150,23 @@ public class PartyPlugin extends Plugin private String lastCharacterName = ""; private WorldPoint lastLocation; + private final HotkeyListener hotkeyListener = new HotkeyListener(() -> config.pingHotkey()) + { + @Override + public void hotkeyPressed() + { + hotkeyPressed = true; + } + + @Override + public void hotkeyReleased() + { + hotkeyPressed = false; + } + }; + + private boolean hotkeyPressed = false; + @Override public void configure(Binder binder) { @@ -168,6 +190,7 @@ public class PartyPlugin extends Plugin clientToolbar.addNavigation(navButton); overlayManager.add(partyPingOverlay); + keyManager.registerKeyListener(hotkeyListener); wsClient.registerMessage(SkillUpdate.class); wsClient.registerMessage(TilePing.class); wsClient.registerMessage(LocationUpdate.class); @@ -187,6 +210,7 @@ public class PartyPlugin extends Plugin pendingTilePings.clear(); worldMapManager.removeIf(PartyWorldMapPoint.class::isInstance); overlayManager.remove(partyPingOverlay); + keyManager.unregisterKeyListener(hotkeyListener); wsClient.unregisterMessage(SkillUpdate.class); wsClient.unregisterMessage(TilePing.class); wsClient.unregisterMessage(LocationUpdate.class); @@ -200,6 +224,15 @@ public class PartyPlugin extends Plugin return configManager.getConfig(PartyConfig.class); } + @Subscribe + public void onFocusChanged(FocusChanged focusChanged) + { + if (!focusChanged.isFocused()) + { + hotkeyPressed = false; + } + } + @Subscribe public void onOverlayMenuClicked(OverlayMenuClicked event) { @@ -229,7 +262,7 @@ public class PartyPlugin extends Plugin @Subscribe public void onMenuOptionClicked(MenuOptionClicked event) { - if (!client.isKeyPressed(KeyCode.KC_SHIFT) || client.isMenuOpen() || party.getMembers().isEmpty() || !config.pings()) + if (!hotkeyPressed || client.isMenuOpen() || party.getMembers().isEmpty() || !config.pings()) { return; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/Boss.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/Boss.java deleted file mode 100644 index e0ba59d3d6..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/Boss.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2018, Raqes - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.specialcounter; - -import com.google.common.collect.Sets; -import java.util.Set; -import lombok.Getter; -import lombok.ToString; -import net.runelite.api.NpcID; - -@Getter -@ToString -enum Boss -{ - ABYSSAL_SIRE(NpcID.ABYSSAL_SIRE, NpcID.ABYSSAL_SIRE_5887, NpcID.ABYSSAL_SIRE_5888, NpcID.ABYSSAL_SIRE_5889, NpcID.ABYSSAL_SIRE_5890, NpcID.ABYSSAL_SIRE_5891, NpcID.ABYSSAL_SIRE_5908), - CALLISTO(NpcID.CALLISTO, NpcID.CALLISTO_6609), - CERBERUS(NpcID.CERBERUS, NpcID.CERBERUS_5863, NpcID.CERBERUS_5866), - CHAOS_ELEMENTAL(NpcID.CHAOS_ELEMENTAL, NpcID.CHAOS_ELEMENTAL_6505), - CORPOREAL_BEAST(NpcID.CORPOREAL_BEAST), - GENERAL_GRAARDOR(NpcID.GENERAL_GRAARDOR, NpcID.GENERAL_GRAARDOR_6494), - GIANT_MOLE(NpcID.GIANT_MOLE, NpcID.GIANT_MOLE_6499), - KALPHITE_QUEEN(NpcID.KALPHITE_QUEEN, NpcID.KALPHITE_QUEEN_963, NpcID.KALPHITE_QUEEN_965, NpcID.KALPHITE_QUEEN_4303, NpcID.KALPHITE_QUEEN_4304, NpcID.KALPHITE_QUEEN_6500, NpcID.KALPHITE_QUEEN_6501), - KING_BLACK_DRAGON(NpcID.KING_BLACK_DRAGON, NpcID.KING_BLACK_DRAGON_2642, NpcID.KING_BLACK_DRAGON_6502), - KRIL_TSUROTH(NpcID.KRIL_TSUTSAROTH, NpcID.KRIL_TSUTSAROTH_6495), - VENETENATIS(NpcID.VENENATIS, NpcID.VENENATIS_6610), - VETION(NpcID.VETION, NpcID.VETION_REBORN), - ALCHEMICAL_HYDRA(NpcID.ALCHEMICAL_HYDRA, NpcID.ALCHEMICAL_HYDRA_8616, NpcID.ALCHEMICAL_HYDRA_8617, NpcID.ALCHEMICAL_HYDRA_8618, NpcID.ALCHEMICAL_HYDRA_8619, NpcID.ALCHEMICAL_HYDRA_8620, NpcID.ALCHEMICAL_HYDRA_8621, NpcID.ALCHEMICAL_HYDRA_8622, NpcID.ALCHEMICAL_HYDRA_8634); - - private final Set ids; - - Boss(Integer... ids) - { - this.ids = Sets.newHashSet(ids); - } - - static Boss getBoss(int id) - { - for (Boss boss : values()) - { - if (boss.ids.contains(id)) - { - return boss; - } - } - - return null; - } - -} \ No newline at end of file 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 7183d2c0d5..0ed6652019 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 @@ -48,6 +48,7 @@ import net.runelite.api.Item; import net.runelite.api.ItemContainer; import net.runelite.api.NPC; import net.runelite.api.NpcID; +import net.runelite.api.ScriptID; import net.runelite.api.VarPlayer; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.CommandExecuted; @@ -56,6 +57,7 @@ import net.runelite.api.events.GameTick; import net.runelite.api.events.HitsplatApplied; import net.runelite.api.events.InteractingChanged; import net.runelite.api.events.NpcDespawned; +import net.runelite.api.events.ScriptPostFired; import net.runelite.api.events.VarbitChanged; import net.runelite.client.Notifier; import net.runelite.client.callback.ClientThread; @@ -101,7 +103,7 @@ public class SpecialCounterPlugin extends Plugin private boolean wasInInstance; private SpecialWeapon specialWeapon; - private final Set interactedNpcIds = new HashSet<>(); + private final Set interactedNpcIndexes = new HashSet<>(); private final SpecialCounter[] specialCounter = new SpecialCounter[SpecialWeapon.values().length]; @Getter(AccessLevel.PACKAGE) @@ -156,7 +158,7 @@ public class SpecialCounterPlugin extends Plugin specialPercentage = -1; lastSpecTarget = null; lastSpecTick = -1; - interactedNpcIds.clear(); + interactedNpcIndexes.clear(); } @Override @@ -166,7 +168,17 @@ public class SpecialCounterPlugin extends Plugin overlayManager.remove(playerInfoDropOverlay); wsClient.unregisterMessage(SpecialCounterUpdate.class); } - + + @Subscribe + public void onScriptPostFired(ScriptPostFired event) + { + if (event.getScriptId() == ScriptID.TOB_HUD_SOTETSEG_FADE) + { + log.debug("Resetting spec counter as sotetseg maze script was ran"); + removeCounters(); + } + } + @Subscribe public void onGameTick(GameTick event) { @@ -275,6 +287,7 @@ public class SpecialCounterPlugin extends Plugin NPC npc = (NPC) target; int interactingId = npc.getId(); + int npcIndex = npc.getIndex(); if (IGNORED_NPCS.contains(interactingId)) { @@ -282,10 +295,10 @@ public class SpecialCounterPlugin extends Plugin } // If this is a new NPC reset the counters - if (!interactedNpcIds.contains(interactingId)) + if (!interactedNpcIndexes.contains(npcIndex)) { removeCounters(); - addInteracting(interactingId); + interactedNpcIndexes.add(npcIndex); } if (wasSpec && specialWeapon != null && hitsplat.getAmount() > 0) @@ -300,7 +313,7 @@ public class SpecialCounterPlugin extends Plugin if (!party.getMembers().isEmpty()) { - final SpecialCounterUpdate specialCounterUpdate = new SpecialCounterUpdate(interactingId, specialWeapon, hit, client.getWorld(), localPlayerId); + final SpecialCounterUpdate specialCounterUpdate = new SpecialCounterUpdate(npcIndex, specialWeapon, hit, client.getWorld(), localPlayerId); specialCounterUpdate.setMemberId(party.getLocalMember().getMemberId()); party.send(specialCounterUpdate); } @@ -309,18 +322,6 @@ public class SpecialCounterPlugin extends Plugin } } - private void addInteracting(int npcId) - { - interactedNpcIds.add(npcId); - - // Add alternate forms of bosses - final Boss boss = Boss.getBoss(npcId); - if (boss != null) - { - interactedNpcIds.addAll(boss.getIds()); - } - } - @Subscribe public void onNpcDespawned(NpcDespawned npcDespawned) { @@ -331,7 +332,7 @@ public class SpecialCounterPlugin extends Plugin lastSpecTarget = null; } - if (actor.isDead() && interactedNpcIds.contains(actor.getId())) + if (actor.isDead() && interactedNpcIndexes.contains(actor.getIndex())) { removeCounters(); } @@ -340,7 +341,8 @@ public class SpecialCounterPlugin extends Plugin @Subscribe public void onSpecialCounterUpdate(SpecialCounterUpdate event) { - if (party.getLocalMember().getMemberId().equals(event.getMemberId())) + if (party.getLocalMember().getMemberId().equals(event.getMemberId()) + || event.getWorld() != client.getWorld()) { return; } @@ -354,13 +356,13 @@ public class SpecialCounterPlugin extends Plugin clientThread.invoke(() -> { // If not interacting with any npcs currently, add to interacting list - if (interactedNpcIds.isEmpty()) + if (interactedNpcIndexes.isEmpty()) { - addInteracting(event.getNpcId()); + interactedNpcIndexes.add(event.getNpcIndex()); } // Otherwise we only add the count if it is against a npc we are already tracking - if (interactedNpcIds.contains(event.getNpcId())) + if (interactedNpcIndexes.contains(event.getNpcIndex())) { if (config.infobox()) { @@ -368,10 +370,7 @@ public class SpecialCounterPlugin extends Plugin } } - if (event.getWorld() == client.getWorld()) - { - playerInfoDrops.add(createSpecInfoDrop(event.getWeapon(), event.getHit(), event.getPlayerId())); - } + playerInfoDrops.add(createSpecInfoDrop(event.getWeapon(), event.getHit(), event.getPlayerId())); }); } @@ -453,7 +452,7 @@ public class SpecialCounterPlugin extends Plugin private void removeCounters() { - interactedNpcIds.clear(); + interactedNpcIndexes.clear(); for (int i = 0; i < specialCounter.length; ++i) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java index d9416ecdf7..09e99f6356 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java @@ -32,7 +32,7 @@ import net.runelite.client.party.messages.PartyMemberMessage; @EqualsAndHashCode(callSuper = true) public class SpecialCounterUpdate extends PartyMemberMessage { - private final int npcId; + private final int npcIndex; private final SpecialWeapon weapon; private final int hit; private final int world; diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/boosts/buffedsmall.png b/runelite-client/src/main/resources/net/runelite/client/plugins/boosts/buffedsmall.png new file mode 100644 index 0000000000..f4757d0ca3 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/boosts/buffedsmall.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/boosts/debuffedsmall.png b/runelite-client/src/main/resources/net/runelite/client/plugins/boosts/debuffedsmall.png new file mode 100644 index 0000000000..6e02339e74 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/boosts/debuffedsmall.png differ diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java index 3166552b6a..4cce2034fc 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java @@ -48,6 +48,7 @@ import java.util.Set; import net.runelite.api.Client; import net.runelite.client.RuneLite; import net.runelite.client.RuneLiteModule; +import net.runelite.client.RuntimeConfig; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigItem; import net.runelite.client.eventbus.EventBus; @@ -93,7 +94,7 @@ public class PluginManagerTest .thenThrow(new RuntimeException("in plugin manager test")); Injector injector = Guice.createInjector(Modules - .override(new RuneLiteModule(okHttpClient, () -> null, () -> null, true, false, + .override(new RuneLiteModule(okHttpClient, () -> null, () -> mock(RuntimeConfig.class), true, false, RuneLite.DEFAULT_SESSION_FILE, RuneLite.DEFAULT_CONFIG_FILE)) .with(BoundFieldModule.of(this))); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java index 55bfdc6237..25a1c1e1db 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java @@ -238,7 +238,10 @@ public class SpecialCounterPluginTest { NPC targetA = mock(NPC.class); NPC targetB = mock(NPC.class); - when(targetB.getId()).thenReturn(1); // a different npc type + + // a different npc type + when(targetB.getId()).thenReturn(1); + when(targetB.getIndex()).thenReturn(1); Player player = mock(Player.class); when(client.getLocalPlayer()).thenReturn(player);