diff --git a/runelite-api/src/main/java/net/runelite/api/HeadIcon.java b/runelite-api/src/main/java/net/runelite/api/HeadIcon.java index ad8f00cc08..08fe44b5bd 100644 --- a/runelite-api/src/main/java/net/runelite/api/HeadIcon.java +++ b/runelite-api/src/main/java/net/runelite/api/HeadIcon.java @@ -56,5 +56,37 @@ public enum HeadIcon /** * Protect from range and mage. (ie. used by Kalphite Queen) */ - RANGE_MAGE + RANGE_MAGE, + /** + * Protect from range and melee + */ + RANGE_MELEE, + /** + * Protect from mage and melee + */ + MAGE_MELEE, + /** + * Protect from range, mage, and melee + */ + RANGE_MAGE_MELEE, + /** + * Wrath curse + */ + WRATH, + /** + * Soult split curse + */ + SOUL_SPLIT, + /** + * Deflect melee curse + */ + DEFLECT_MELEE, + /** + * Deflect range curse + */ + DEFLECT_RANGE, + /** + * Deflect magic curse + */ + DEFLECT_MAGE; } diff --git a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginManager.java b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginManager.java index c68f62a1f3..c1471a3463 100644 --- a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginManager.java @@ -35,6 +35,8 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URL; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -167,6 +169,9 @@ public class ExternalPluginManager SplashScreen.init(); } + Instant now = Instant.now(); + Instant keepAfter = now.minus(3, ChronoUnit.DAYS); + SplashScreen.stage(splashStart, null, "Downloading external plugins"); Set externalPlugins = new HashSet<>(); @@ -189,6 +194,7 @@ public class ExternalPluginManager { externalPlugins.add(manifest); + manifest.getJarFile().setLastModified(now.toEpochMilli()); if (!manifest.isValid()) { needsDownload.add(manifest); @@ -206,7 +212,7 @@ public class ExternalPluginManager { for (File fi : files) { - if (!keep.contains(fi)) + if (!keep.contains(fi) && fi.lastModified() < keepAfter.toEpochMilli()) { fi.delete(); } diff --git a/runelite-client/src/main/java/net/runelite/client/game/LootManager.java b/runelite-client/src/main/java/net/runelite/client/game/LootManager.java index 124f7f8e94..8550aa9320 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/LootManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/LootManager.java @@ -353,6 +353,7 @@ public class LootManager case NpcID.VORKATH_8059: case NpcID.VORKATH_8060: case NpcID.VORKATH_8061: + { int x = worldLocation.getX() + 3; int y = worldLocation.getY() + 3; if (playerLocationLastTick.getX() < x) @@ -373,6 +374,27 @@ public class LootManager } worldLocation = new WorldPoint(x, y, worldLocation.getPlane()); break; + } + case NpcID.NEX: + case NpcID.NEX_11279: + case NpcID.NEX_11280: + case NpcID.NEX_11281: + case NpcID.NEX_11282: + { + // Nex loot is under the player, or under nex + LocalPoint localPoint = LocalPoint.fromWorld(client, playerLocationLastTick); + if (localPoint != null) + { + int x = localPoint.getSceneX(); + int y = localPoint.getSceneY(); + final int packed = x << 8 | y; + if (itemSpawns.containsKey(packed)) + { + return playerLocationLastTick; + } + } + break; + } } return worldLocation; diff --git a/runelite-client/src/main/java/net/runelite/client/hiscore/HiscoreEndpoint.java b/runelite-client/src/main/java/net/runelite/client/hiscore/HiscoreEndpoint.java index df7146ad61..0bf3e6e4e5 100644 --- a/runelite-client/src/main/java/net/runelite/client/hiscore/HiscoreEndpoint.java +++ b/runelite-client/src/main/java/net/runelite/client/hiscore/HiscoreEndpoint.java @@ -25,7 +25,9 @@ */ package net.runelite.client.hiscore; +import java.util.Set; import lombok.Getter; +import net.runelite.api.WorldType; import okhttp3.HttpUrl; @Getter @@ -47,4 +49,21 @@ public enum HiscoreEndpoint this.name = name; this.hiscoreURL = HttpUrl.get(hiscoreURL); } -} \ No newline at end of file + + public static HiscoreEndpoint fromWorldTypes(Set worldTypes) + { + if (worldTypes.contains(WorldType.SEASONAL)) + { + // this changes between LEAGUE and TOURNAMENT + return HiscoreEndpoint.LEAGUE; + } + else if (worldTypes.contains(WorldType.DEADMAN)) + { + return HiscoreEndpoint.DEADMAN; + } + else + { + return HiscoreEndpoint.NORMAL; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java index 4973401812..61da99f6fd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java @@ -1740,9 +1740,10 @@ public class ChatCommandsPlugin extends Plugin if (chatMessage.getType() == ChatMessageType.PUBLICCHAT || chatMessage.getType() == ChatMessageType.MODCHAT) { // Public chat on a seasonal world is always seasonal or tournament hiscores, regardless of icon - if (client.getWorldType().contains(WorldType.SEASONAL)) + HiscoreEndpoint endpoint = HiscoreEndpoint.fromWorldTypes(client.getWorldType()); + if (endpoint != HiscoreEndpoint.NORMAL) { - return new HiscoreLookup(player, HiscoreEndpoint.TOURNAMENT); + return new HiscoreLookup(player, endpoint); } } @@ -1788,9 +1789,11 @@ public class ChatCommandsPlugin extends Plugin private HiscoreEndpoint getLocalHiscoreEndpointType() { EnumSet worldType = client.getWorldType(); - if (worldType.contains(WorldType.SEASONAL)) + HiscoreEndpoint endpoint = HiscoreEndpoint.fromWorldTypes(worldType); + if (endpoint != HiscoreEndpoint.NORMAL) { - return HiscoreEndpoint.TOURNAMENT; + // leagues/dmmt or dmm + return endpoint; } return toEndPoint(client.getAccountType()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/Pet.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/Pet.java index 9c84c17fda..2583be2d22 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/Pet.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/Pet.java @@ -79,7 +79,8 @@ enum Pet YOUNGLLEF("Youngllef", ItemID.YOUNGLLEF), LITTLE_NIGHTMARE("Little nightmare", ItemID.LITTLE_NIGHTMARE), LIL_CREATOR("Lil' creator", ItemID.LIL_CREATOR), - TINY_TEMPOR("Tiny tempor", ItemID.TINY_TEMPOR); + TINY_TEMPOR("Tiny tempor", ItemID.TINY_TEMPOR), + NEXLING("Nexling", ItemID.NEXLING); private final String name; private final Integer iconID; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java index 5359796536..a7674a28b1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java @@ -81,6 +81,7 @@ enum DiscordGameEventType BOSS_KRAKEN("Kraken", DiscordAreaType.BOSSES, 9116), BOSS_KREEARRA("Kree'arra", DiscordAreaType.BOSSES, 11346), BOSS_KRIL_TSUTSAROTH("K'ril Tsutsaroth", DiscordAreaType.BOSSES, 11603), + BOSS_NEX("Nex", DiscordAreaType.BOSSES, 11601), BOSS_NIGHTMARE("Nightmare of Ashihama", DiscordAreaType.BOSSES, 15515), BOSS_SARACHNIS("Sarachnis", DiscordAreaType.BOSSES, 7322), BOSS_SKOTIZO("Skotizo", DiscordAreaType.BOSSES, 6810), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index 63f2c84669..18129f5870 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -623,14 +623,19 @@ public class GrandExchangePlugin extends Plugin } } - @Subscribe + @Subscribe( + // run after the bank tags plugin, and potentially anything + // else which wants to consume the event and override + // the search behavior + priority = -100 + ) public void onGrandExchangeSearched(GrandExchangeSearched event) { wasFuzzySearch = false; GrandExchangeSearchMode searchMode = config.geSearchMode(); final String input = client.getVar(VarClientStr.INPUT_TEXT); - if (searchMode == GrandExchangeSearchMode.DEFAULT || input.isEmpty()) + if (searchMode == GrandExchangeSearchMode.DEFAULT || input.isEmpty() || event.isConsumed()) { return; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index 8fb08840af..221094b01f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -84,6 +84,7 @@ public class GroundItemsOverlay extends Overlay private static final int GRAARDOR_REGION = 11347; private static final int KRIL_TSUTSAROTH_REGION = 11603; private static final int KREEARRA_REGION = 11346; + private static final int NEX_REGION = 11601; private static final int NIGHTMARE_REGION = 15515; private static final int TEMPOROSS_REGION = 12078; @@ -457,6 +458,7 @@ public class GroundItemsOverlay extends Overlay } else if (playerRegionID == ZILYANA_REGION || playerRegionID == GRAARDOR_REGION || playerRegionID == KRIL_TSUTSAROTH_REGION || playerRegionID == KREEARRA_REGION || + playerRegionID == NEX_REGION || playerRegionID == NIGHTMARE_REGION || playerRegionID == TEMPOROSS_REGION || playerRegionID == CLAN_HALL_REGION) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java index 8e567d37d7..693412bcb3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java @@ -26,7 +26,6 @@ package net.runelite.client.plugins.hiscore; import com.google.inject.Provides; import java.awt.image.BufferedImage; -import java.util.EnumSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Nullable; @@ -39,7 +38,6 @@ import net.runelite.api.Client; import net.runelite.api.IconID; import net.runelite.api.MenuAction; import net.runelite.api.Player; -import net.runelite.api.WorldType; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuOptionClicked; @@ -49,6 +47,7 @@ import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; +import net.runelite.client.hiscore.HiscoreEndpoint; import net.runelite.client.menus.MenuManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -56,7 +55,6 @@ import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; -import net.runelite.client.hiscore.HiscoreEndpoint; @PluginDescriptor( name = "HiScore", @@ -240,16 +238,7 @@ public class HiscorePlugin extends Plugin { if (client != null) { - EnumSet wTypes = client.getWorldType(); - - if (wTypes.contains(WorldType.SEASONAL)) - { - return HiscoreEndpoint.TOURNAMENT; - } - else if (wTypes.contains(WorldType.DEADMAN)) - { - return HiscoreEndpoint.DEADMAN; - } + return HiscoreEndpoint.fromWorldTypes(client.getWorldType()); } return HiscoreEndpoint.NORMAL; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenOverride.java b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenOverride.java index ca433573f6..e083db40b0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenOverride.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenOverride.java @@ -44,7 +44,8 @@ public enum LoginScreenOverride PRIFDDINAS("prifddinas.jpg"), THEATRE_OF_BLOOD("tob.jpg"), A_KINGDOM_DIVIDED("akd.jpg"), - CUSTOM; + CUSTOM, + RANDOM; @Getter private final String fileName; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java index a4ede4f9dc..25ca2bb80d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java @@ -33,6 +33,8 @@ import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.util.Arrays; +import java.util.Random; import javax.imageio.ImageIO; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; @@ -287,6 +289,14 @@ public class LoginScreenPlugin extends Plugin implements KeyListener } } } + else if (config.loginScreen() == LoginScreenOverride.RANDOM) + { + LoginScreenOverride[] filtered = Arrays.stream(LoginScreenOverride.values()) + .filter(screen -> screen.getFileName() != null) + .toArray(LoginScreenOverride[]::new); + LoginScreenOverride randomScreen = filtered[new Random().nextInt(filtered.length)]; + pixels = getFileSpritePixels(randomScreen.getFileName()); + } else { pixels = getFileSpritePixels(config.loginScreen().getFileName()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index 056022045c..e407644d89 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -487,7 +487,7 @@ public class LootTrackerPlugin extends Plugin private Integer getLootWorldId() { - // For the wiki to determine drop rates based on dmm brackets + // For the wiki to determine drop rates based on dmm brackets / identify leagues drops return client.getWorldType().contains(WorldType.SEASONAL) ? client.getWorld() : null; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoPlugin.java index 855ac8953c..17c2bf39b7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoPlugin.java @@ -29,7 +29,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.inject.Provides; import java.time.Duration; import java.time.Instant; -import java.util.EnumSet; import javax.inject.Inject; import lombok.AccessLevel; import lombok.Getter; @@ -39,17 +38,16 @@ import net.runelite.api.GameState; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; import net.runelite.api.NPC; -import net.runelite.api.WorldType; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.InteractingChanged; import net.runelite.api.events.MenuEntryAdded; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.hiscore.HiscoreEndpoint; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.hiscore.HiscoreEndpoint; @PluginDescriptor( name = "Opponent Information", @@ -115,19 +113,7 @@ public class OpponentInfoPlugin extends Plugin return; } - final EnumSet worldType = client.getWorldType(); - if (worldType.contains(WorldType.SEASONAL)) - { - hiscoreEndpoint = HiscoreEndpoint.TOURNAMENT; - } - else if (worldType.contains(WorldType.DEADMAN)) - { - hiscoreEndpoint = HiscoreEndpoint.DEADMAN; - } - else - { - hiscoreEndpoint = HiscoreEndpoint.NORMAL; - } + hiscoreEndpoint = HiscoreEndpoint.fromWorldTypes(client.getWorldType()); } @Subscribe diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java index 3b35670873..0a2333ae2e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java @@ -63,6 +63,7 @@ import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ActorDeath; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.CommandExecuted; +import net.runelite.api.events.FakeXpDrop; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.HitsplatApplied; @@ -550,6 +551,21 @@ public class SlayerPlugin extends Plugin final int delta = slayerExp - cachedXp; cachedXp = slayerExp; + xpChanged(delta); + } + + @Subscribe + public void onFakeXpDrop(FakeXpDrop fakeXpDrop) + { + if (fakeXpDrop.getSkill() == SLAYER) + { + int delta = fakeXpDrop.getXp(); + xpChanged(delta); + } + } + + private void xpChanged(int delta) + { log.debug("Slayer xp change delta: {}, killed npcs: {}", delta, taggedNpcsDiedPrevTick); final Task task = Task.getTask(taskName); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpupdater/XpUpdaterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpupdater/XpUpdaterPlugin.java index 4595a9f722..4a823d0727 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpupdater/XpUpdaterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpupdater/XpUpdaterPlugin.java @@ -192,13 +192,13 @@ public class XpUpdaterPlugin extends Plugin private void updateWom(String username, EnumSet worldTypes) { if (config.wiseoldman() - && !worldTypes.contains(WorldType.SEASONAL) && !worldTypes.contains(WorldType.DEADMAN) && !worldTypes.contains(WorldType.NOSAVE_MODE)) { + String host = worldTypes.contains(WorldType.SEASONAL) ? "seasonal.wiseoldman.net" : "wiseoldman.net"; HttpUrl url = new HttpUrl.Builder() .scheme("https") - .host("wiseoldman.net") + .host(host) .addPathSegment("api") .addPathSegment("players") .addPathSegment("track") diff --git a/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java b/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java index 2e00dae0d6..11d3ab4bb6 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java @@ -187,7 +187,7 @@ public class SwingUtil @Override public void mouseClicked(MouseEvent e) { - if (OSType.getOSType() == OSType.MacOS) + if (OSType.getOSType() == OSType.MacOS && !frame.isFocused()) { // On macOS, frame.setVisible(true) only restores focus when the visibility was previously false. // The frame's visibility is not set to false when the window loses focus, so we set it manually.