diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 22bd5bf227..b693ce07ef 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -25,7 +25,7 @@ object ProjectVersions { const val launcherVersion = "2.2.0" - const val rlVersion = "1.7.11.1" + const val rlVersion = "1.7.11.2" const val openosrsVersion = "4.8.1" diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index b9a9f6037e..0800d2f5f4 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -673,12 +673,19 @@ public interface Client extends GameEngine boolean isMenuOpen(); /** - * Gets the angle of the map, or camera yaw. + * Gets the angle of the map, or target camera yaw. * * @return the map angle */ int getMapAngle(); + /** + * Set the target camera yaw + * + * @param cameraYawTarget + */ + void setCameraYawTarget(int cameraYawTarget); + /** * Checks whether the client window is currently resized. * diff --git a/runelite-client/src/main/java/net/runelite/client/config/ChatColorConfig.java b/runelite-client/src/main/java/net/runelite/client/config/ChatColorConfig.java index 90fc5adbe0..da8eb41f12 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ChatColorConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ChatColorConfig.java @@ -185,7 +185,7 @@ public interface ChatColorConfig extends Config @ConfigItem( position = 14, - keyName = "opaqueClanChatMessageHighlight", + keyName = "opaqueClanMessageHighlight", name = "Clan chat message highlight", description = "Color of highlights in Clan Chat messages", section = opaqueSection @@ -582,7 +582,7 @@ public interface ChatColorConfig extends Config @ConfigItem( position = 64, - keyName = "transparentClanChatMessageHighlight", + keyName = "transparentClanMessageHighlight", name = "Clan chat message highlight (transparent)", description = "Color of highlights in Clan Chat messages (transparent)", section = transparentSection diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java index a33e58d77e..be41c03807 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java @@ -448,7 +448,7 @@ public class ConfigManager public void setConfiguration(String groupName, String profile, String key, @NonNull String value) { - if (Strings.isNullOrEmpty(groupName) || Strings.isNullOrEmpty(key)) + if (Strings.isNullOrEmpty(groupName) || Strings.isNullOrEmpty(key) || key.indexOf(':') != -1) { throw new IllegalArgumentException(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java index 5f019c82ca..250cb8f247 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java @@ -191,4 +191,15 @@ public interface CameraConfig extends Config { return false; } + + @ConfigItem( + keyName = "preserveYaw", + name = "Preserve yaw on world hop", + description = "Preserves the camera yaw (left/right) when world hopping.", + position = 14 + ) + default boolean preserveYaw() + { + return false; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java index f650d3efba..b2ac448629 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java @@ -43,6 +43,7 @@ import net.runelite.api.VarPlayer; import net.runelite.api.events.BeforeRender; import net.runelite.api.events.ClientTick; import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.api.events.ScriptPreFired; @@ -89,7 +90,8 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener * Whether or not the current menu has any non-ignored menu entries */ private boolean menuHasEntries; - + private int savedCameraYaw; + @Inject private Client client; @@ -418,6 +420,24 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener } } + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + switch (gameStateChanged.getGameState()) + { + case HOPPING: + savedCameraYaw = client.getMapAngle(); + break; + case LOGGED_IN: + if (savedCameraYaw != 0 && config.preserveYaw()) + { + client.setCameraYawTarget(savedCameraYaw); + } + savedCameraYaw = 0; + break; + } + } + /** * The event that is triggered when a mouse button is pressed * In this method the right click is changed to a middle-click to enable rotating the camera 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 33f282d513..6a2cfc1323 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 @@ -98,7 +98,7 @@ public class ChatCommandsPlugin extends Plugin private static final String COX_TEAM_SIZES = "(?:\\d+(?:\\+|-\\d+)? players|Solo)"; private static final Pattern RAIDS_PB_PATTERN = Pattern.compile("Congratulations - your raid is complete!
Team size: " + COX_TEAM_SIZES + " Duration: (?[0-9:]+(?:\\.[0-9]+)?) \\(new personal best\\)"); private static final Pattern RAIDS_DURATION_PATTERN = Pattern.compile("Congratulations - your raid is complete!
Team size: " + COX_TEAM_SIZES + " Duration: [0-9:.]+ Personal best: (?[0-9:]+(?:\\.[0-9]+)?)"); - private static final Pattern TOB_WAVE_PB_PATTERN = Pattern.compile("^.*Theatre of Blood wave completion time: (?[0-9:]+(?:\\.[0-9]+)?) \\(Personal best!\\)"); + private static final Pattern TOB_WAVE_PB_PATTERN = Pattern.compile("^.*Theatre of Blood wave completion time: (?[0-9:]+(?:\\.[0-9]+)?) \\(new personal best\\)"); private static final Pattern TOB_WAVE_DURATION_PATTERN = Pattern.compile("^.*Theatre of Blood wave completion time: [0-9:.]+
Personal best: (?[0-9:]+(?:\\.[0-9]+)?)"); private static final Pattern KILL_DURATION_PATTERN = Pattern.compile("(?i)^(?:(?:Fight |Lap |Challenge |Corrupted challenge )?duration:|Subdued in) [0-9:.]+\\. Personal best: (?:)?(?[0-9:]+(?:\\.[0-9]+)?)"); private static final Pattern NEW_PB_PATTERN = Pattern.compile("(?i)^(?:(?:Fight |Lap |Challenge |Corrupted challenge )?duration:|Subdued in) (?[0-9:]+(?:\\.[0-9]+)?) \\(new personal best\\)"); @@ -245,6 +245,11 @@ public class ChatCommandsPlugin extends Plugin configManager.setRSProfileConfiguration("killcount", boss.toLowerCase(), killcount); } + private void unsetKc(String boss) + { + configManager.unsetRSProfileConfiguration("killcount", boss.toLowerCase()); + } + private int getKc(String boss) { Integer killCount = configManager.getRSProfileConfiguration("killcount", boss.toLowerCase(), int.class); @@ -256,6 +261,11 @@ public class ChatCommandsPlugin extends Plugin configManager.setRSProfileConfiguration("personalbest", boss.toLowerCase(), seconds); } + private void unsetPb(String boss) + { + configManager.unsetRSProfileConfiguration("personalbest", boss.toLowerCase()); + } + private double getPb(String boss) { Double personalBest = configManager.getRSProfileConfiguration("personalbest", boss.toLowerCase(), double.class); @@ -280,19 +290,30 @@ public class ChatCommandsPlugin extends Plugin String boss = matcher.group(1); int kc = Integer.parseInt(matcher.group(2)); - boss = KILLCOUNT_RENAMES.getOrDefault(boss, boss); + String renamedBoss = KILLCOUNT_RENAMES + .getOrDefault(boss, boss) + // The config service doesn't support keys with colons in them + .replace(":", ""); + if (boss != renamedBoss) + { + // Unset old TOB kc + unsetKc(boss); + unsetPb(boss); + unsetKc(boss.replace(":", ".")); + unsetPb(boss.replace(":", ".")); + } - setKc(boss, kc); + setKc(renamedBoss, kc); // We either already have the pb, or need to remember the boss for the upcoming pb if (lastPb > -1) { - log.debug("Got out-of-order personal best for {}: {}", boss, lastPb); - setPb(boss, lastPb); + log.debug("Got out-of-order personal best for {}: {}", renamedBoss, lastPb); + setPb(renamedBoss, lastPb); lastPb = -1; } else { - lastBossKill = boss; + lastBossKill = renamedBoss; lastBossTime = client.getTickCount(); } return; @@ -1687,6 +1708,19 @@ public class ChatCommandsPlugin extends Plugin case "raids 2": return "Theatre of Blood"; + case "Theatre of Blood: Story Mode": + case "tob sm": + case "tob story mode": + case "tob story": + return "Theatre of Blood Story Mode"; + + case "Theatre of Blood: Hard Mode": + case "tob cm": + case "tob hm": + case "tob hard mode": + case "tob hard": + return "Theatre of Blood Hard Mode"; + // agility course case "prif": case "prifddinas": diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index 3cde11fec9..5f9a99deee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -330,6 +330,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc private final String text; private final String npc; private final int objectId; + @Nullable private final WorldPoint location; private final String solution; @Nullable @@ -371,7 +372,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc this(text, npc, objectId, location, solution, null); } - private CrypticClue(String text, String npc, int objectId, WorldPoint location, String solution, @Nullable String questionText) + private CrypticClue(String text, String npc, int objectId, @Nullable WorldPoint location, String solution, @Nullable String questionText) { this.text = text; this.npc = npc; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClue.java index 52c78d94c8..9672d4b351 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClue.java @@ -30,6 +30,7 @@ import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import lombok.Getter; import lombok.RequiredArgsConstructor; import net.runelite.api.InventoryID; @@ -167,6 +168,7 @@ public class ThreeStepCrypticClue extends ClueScroll implements TextClueScroll, return clueSteps.stream() .filter(s -> !s.getValue()) .map(s -> s.getKey().getLocation()) + .filter(Objects::nonNull) .toArray(WorldPoint[]::new); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java index 2c54f1744b..93d0046a9f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java @@ -199,7 +199,6 @@ public class GpuPlugin extends Plugin implements DrawCallbacks private int vboUiHandle; private int fboSceneHandle; - private int texSceneHandle; private int rboSceneHandle; // scene vertex buffer @@ -297,7 +296,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks { try { - texSceneHandle = fboSceneHandle = rboSceneHandle = -1; // AA FBO + fboSceneHandle = rboSceneHandle = -1; // AA FBO unorderedModels = smallModels = largeModels = 0; drawingModel = false; @@ -737,28 +736,13 @@ public class GpuPlugin extends Plugin implements DrawCallbacks gl.glRenderbufferStorageMultisample(gl.GL_RENDERBUFFER, aaSamples, gl.GL_RGBA, width, height); gl.glFramebufferRenderbuffer(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_RENDERBUFFER, rboSceneHandle); - // Create texture - texSceneHandle = glGenTexture(gl); - gl.glBindTexture(gl.GL_TEXTURE_2D_MULTISAMPLE, texSceneHandle); - gl.glTexImage2DMultisample(gl.GL_TEXTURE_2D_MULTISAMPLE, aaSamples, gl.GL_RGBA, width, height, true); - - // Bind texture - gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D_MULTISAMPLE, texSceneHandle, 0); - // Reset - gl.glBindTexture(gl.GL_TEXTURE_2D_MULTISAMPLE, 0); gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0); gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, 0); } private void shutdownAAFbo() { - if (texSceneHandle != -1) - { - glDeleteTexture(gl, texSceneHandle); - texSceneHandle = -1; - } - if (fboSceneHandle != -1) { glDeleteFrameBuffer(gl, fboSceneHandle); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java index f25c479d77..bfc455b405 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java @@ -110,6 +110,13 @@ public class IdleNotifierPlugin extends Plugin return configManager.getConfig(IdleNotifierConfig.class); } + @Override + protected void startUp() throws Exception + { + // can't tell when 6hr will be if enabled while already logged in + sixHourWarningTime = null; + } + @Subscribe public void onAnimationChanged(AnimationChanged event) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java index 81d28d584e..a68231eeb5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java @@ -419,6 +419,17 @@ public interface MenuEntrySwapperConfig extends Config return false; } + @ConfigItem( + keyName = "swapTeleToPoh", + name = "Tele to POH", + description = "Swap Wear with Tele to POH on the construction cape", + section = itemSection + ) + default boolean swapTeleToPoh() + { + return false; + } + @ConfigItem( keyName = "swapAbyssTeleport", name = "Teleport to Abyss", 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 151ebbe5f4..6345148989 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 @@ -348,6 +348,8 @@ public class MenuEntrySwapperPlugin extends Plugin swap("value", "sell 10", () -> shiftModifier() && config.shopSell() == SellMode.SELL_10); swap("value", "sell 50", () -> shiftModifier() && config.shopSell() == SellMode.SELL_50); + swap("wear", "tele to poh", config::swapTeleToPoh); + swap("wear", "rub", config::swapTeleportItem); swap("wear", "teleport", config::swapTeleportItem); swap("wield", "teleport", config::swapTeleportItem); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoom.java b/runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoom.java index 5e8918ac07..485a7f6d91 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoom.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoom.java @@ -96,6 +96,7 @@ public class AlchemyRoom extends MTARoom private AlchemyItem best; private Cupboard suggestion; + private boolean hintSet; @Inject private AlchemyRoom(Client client, MTAConfig config, MTAPlugin plugin, ItemManager itemManager, InfoBoxManager infoBoxManager) @@ -221,6 +222,11 @@ public class AlchemyRoom extends MTARoom if (!inside()) { reset(); + if (hintSet) + { + client.clearHintArrow(); + hintSet = false; + } } } } @@ -381,6 +387,7 @@ public class AlchemyRoom extends MTARoom { client.setHintArrow(object.getWorldLocation()); found = true; + hintSet = true; } BufferedImage image = itemManager.getImage(alchemyItem.getId()); @@ -395,6 +402,7 @@ public class AlchemyRoom extends MTARoom if (!found && suggestion != null) { client.setHintArrow(suggestion.gameObject.getWorldLocation()); + hintSet = true; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mta/enchantment/EnchantmentRoom.java b/runelite-client/src/main/java/net/runelite/client/plugins/mta/enchantment/EnchantmentRoom.java index aeb029fb81..56e9f31057 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mta/enchantment/EnchantmentRoom.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mta/enchantment/EnchantmentRoom.java @@ -50,6 +50,7 @@ public class EnchantmentRoom extends MTARoom private final Client client; private final List dragonstones = new ArrayList<>(); + private boolean hintSet; @Inject private EnchantmentRoom(MTAConfig config, Client client) @@ -64,6 +65,11 @@ public class EnchantmentRoom extends MTARoom if (gameStateChanged.getGameState() == GameState.LOADING) { dragonstones.clear(); + if (hintSet) + { + client.clearHintArrow(); + hintSet = false; + } } } @@ -79,10 +85,12 @@ public class EnchantmentRoom extends MTARoom if (nearest != null) { client.setHintArrow(nearest); + hintSet = true; } else { client.clearHintArrow(); + hintSet = false; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java index 44d9d58b51..1dd5c53174 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java @@ -253,11 +253,23 @@ public interface ScreenshotConfig extends Config return false; } + @ConfigItem( + keyName = "collectionLogEntries", + name = "Screenshot collection log entries", + description = "Take a screenshot when completing an entry in the collection log", + position = 18, + section = whatSection + ) + default boolean screenshotCollectionLogEntries() + { + return true; + } + @ConfigItem( keyName = "hotkey", name = "Screenshot hotkey", description = "When you press this key a screenshot will be taken", - position = 18 + position = 19 ) default Keybind hotkey() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java index dbda81a49c..28449b69ca 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java @@ -95,6 +95,7 @@ import net.runelite.client.util.Text; @Slf4j public class ScreenshotPlugin extends Plugin { + private static final String COLLECTION_LOG_TEXT = "New item added to your collection log: "; private static final String CHEST_LOOTED_MESSAGE = "You find some treasure in the chest!"; private static final Map CHEST_LOOT_EVENTS = ImmutableMap.of(12127, "The Gauntlet"); private static final int GAUNTLET_REGION = 7512; @@ -456,6 +457,13 @@ public class ScreenshotPlugin extends Plugin takeScreenshot(fileName, "Duels"); } } + + if (config.screenshotCollectionLogEntries() && chatMessage.startsWith(COLLECTION_LOG_TEXT)) + { + String entry = Text.removeTags(chatMessage).substring(COLLECTION_LOG_TEXT.length()); + String fileName = "Collection log (" + entry + ")"; + takeScreenshot(fileName, "Collection Log"); + } } @Subscribe 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 index 295194a961..e0ba59d3d6 100644 --- 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 @@ -45,7 +45,8 @@ enum Boss 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); + 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; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/BarRenderer.java b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/BarRenderer.java index 84742e2f63..03cc2f326c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/BarRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/BarRenderer.java @@ -25,12 +25,14 @@ */ package net.runelite.client.plugins.statusbars; -import lombok.RequiredArgsConstructor; -import net.runelite.client.ui.FontManager; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; +import java.awt.Point; import java.util.function.Supplier; +import lombok.RequiredArgsConstructor; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.overlay.components.TextComponent; @RequiredArgsConstructor class BarRenderer @@ -100,28 +102,26 @@ class BarRenderer private void renderIconsAndCounters(StatusBarsConfig config, Graphics2D graphics, int x, int y) { - graphics.setFont(FontManager.getRunescapeSmallFont()); - graphics.setColor(Color.WHITE); - String counterText = Integer.toString(currentValue); - final int widthOfCounter = graphics.getFontMetrics().stringWidth(counterText); - int centerText = (WIDTH - PADDING) / 2 - (widthOfCounter / 2); - final Image icon = iconSupplier.get(); + final boolean skillIconEnabled = config.enableSkillIcon(); + + if (skillIconEnabled) + { + final Image icon = iconSupplier.get(); + graphics.drawImage(icon, x + ICON_AND_COUNTER_OFFSET_X + PADDING, y + ICON_AND_COUNTER_OFFSET_Y - icon.getWidth(null), null); + } if (config.enableCounter()) { - if (config.enableSkillIcon()) - { - graphics.drawImage(icon, x + ICON_AND_COUNTER_OFFSET_X + PADDING, y + ICON_AND_COUNTER_OFFSET_Y - icon.getWidth(null), null); - graphics.drawString(counterText, x + centerText + PADDING, y + SKILL_ICON_HEIGHT); - } - else - { - graphics.drawString(counterText, x + centerText + PADDING, y + COUNTER_ICON_HEIGHT); - } - } - else if (config.enableSkillIcon()) - { - graphics.drawImage(icon, x + ICON_AND_COUNTER_OFFSET_X + PADDING, y + ICON_AND_COUNTER_OFFSET_Y - icon.getWidth(null), null); + graphics.setFont(FontManager.getRunescapeSmallFont()); + final String counterText = Integer.toString(currentValue); + final int widthOfCounter = graphics.getFontMetrics().stringWidth(counterText); + final int centerText = (WIDTH - PADDING) / 2 - (widthOfCounter / 2); + final int yOffset = skillIconEnabled ? SKILL_ICON_HEIGHT : COUNTER_ICON_HEIGHT; + + final TextComponent textComponent = new TextComponent(); + textComponent.setText(counterText); + textComponent.setPosition(new Point(x + centerText + PADDING, y + yOffset)); + textComponent.render(graphics); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java index 8b2fc1d187..d2e13ccad3 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java @@ -131,7 +131,24 @@ public class WorldMapOverlay extends Overlay if (worldPoint.isSnapToEdge()) { - if (worldMapRectangle.contains(drawPoint.getX(), drawPoint.getY())) + // Get a smaller rect for edge-snapped icons so they display correctly at the edge + final Rectangle snappedRect = widget.getBounds(); + snappedRect.grow(-image.getWidth() / 2, -image.getHeight() / 2); + + final Rectangle unsnappedRect = new Rectangle(snappedRect); + if (worldPoint.getImagePoint() != null) + { + int dx = worldPoint.getImagePoint().getX() - (image.getWidth() / 2); + int dy = worldPoint.getImagePoint().getY() - (image.getHeight() / 2); + unsnappedRect.translate(dx, dy); + } + // Make the unsnap rect slightly smaller so a smaller snapped image doesn't cause a freak out + if (worldPoint.isCurrentlyEdgeSnapped()) + { + unsnappedRect.grow(-image.getWidth(), -image.getHeight()); + } + + if (unsnappedRect.contains(drawPoint.getX(), drawPoint.getY())) { if (worldPoint.isCurrentlyEdgeSnapped()) { @@ -141,7 +158,7 @@ public class WorldMapOverlay extends Overlay } else { - drawPoint = clipToRectangle(drawPoint, worldMapRectangle); + drawPoint = clipToRectangle(drawPoint, snappedRect); if (!worldPoint.isCurrentlyEdgeSnapped()) { worldPoint.setCurrentlyEdgeSnapped(true); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlayMouseListener.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlayMouseListener.java index 949c578ec2..71af9a55dc 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlayMouseListener.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlayMouseListener.java @@ -60,6 +60,12 @@ public class WorldMapOverlayMouseListener extends MouseAdapter if (SwingUtilities.isLeftMouseButton(e) && !worldMapPoints.isEmpty()) { Point mousePos = client.getMouseCanvasPosition(); + final Widget view = client.getWidget(WidgetInfo.WORLD_MAP_VIEW); + + if (view == null) + { + return e; + } for (WorldMapPoint worldMapPoint : worldMapPoints) { @@ -77,6 +83,7 @@ public class WorldMapOverlayMouseListener extends MouseAdapter RenderOverview renderOverview = client.getRenderOverview(); renderOverview.setWorldMapPositionTarget(target); } + e.consume(); return worldMapPoint.onClick(e); } } diff --git a/runelite-client/src/test/java/net/runelite/client/config/ChatColorConfigTest.java b/runelite-client/src/test/java/net/runelite/client/config/ChatColorConfigTest.java new file mode 100644 index 0000000000..e3b140fe34 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/config/ChatColorConfigTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021, 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.config; + +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; +import static org.junit.Assert.fail; +import org.junit.Test; + +public class ChatColorConfigTest +{ + @Test + public void testUniqueKeys() + { + final Set configKeyNames = new HashSet<>(); + + for (Method method : ChatColorConfig.class.getMethods()) + { + final ConfigItem annotation = method.getAnnotation(ConfigItem.class); + if (annotation == null) + { + continue; + } + + final String configKeyName = annotation.keyName(); + if (configKeyNames.contains(configKeyName)) + { + fail("keyName " + configKeyName + " is duplicated in " + ChatColorConfig.class); + } + + configKeyNames.add(configKeyName); + } + } +} \ No newline at end of file diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java index c089368bac..788437d165 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java @@ -157,7 +157,7 @@ public class ChatCommandsPluginTest @Test public void testTheatreOfBlood() { - ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Wave 'The Final Challenge' complete! Duration: 5:04
Theatre of Blood wave completion time: 37:04 (Personal best!)", null, 0); + ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Wave 'The Final Challenge' complete! Duration: 5:04
Theatre of Blood wave completion time: 37:04 (new personal best)", null, 0); chatCommandsPlugin.onChatMessage(chatMessage); ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood count is: 73.", null, 0); @@ -167,7 +167,7 @@ public class ChatCommandsPluginTest verify(configManager).setRSProfileConfiguration("personalbest", "theatre of blood", 37 * 60 + 4.0); // Precise times - ChatMessage chatMessagePrecise = new ChatMessage(null, GAMEMESSAGE, "", "Wave 'The Final Challenge' complete! Duration: 5:04
Theatre of Blood wave completion time: 37:04.20 (Personal best!)", null, 0); + ChatMessage chatMessagePrecise = new ChatMessage(null, GAMEMESSAGE, "", "Wave 'The Final Challenge' complete! Duration: 5:04
Theatre of Blood wave completion time: 37:04.20 (new personal best)", null, 0); chatCommandsPlugin.onChatMessage(chatMessagePrecise); chatCommandsPlugin.onChatMessage(chatMessageEvent); @@ -194,6 +194,21 @@ public class ChatCommandsPluginTest verify(configManager).setRSProfileConfiguration("personalbest", "theatre of blood", 37 * 60 + 4.4); } + @Test + public void testTheatreOfBloodStoryMode() + { + ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", + "Theatre of Blood wave completion time: 5:04 (new personal best)
" + + "Theatre of Blood total completion time: 24:39 (new personal best)", null, 0); + chatCommandsPlugin.onChatMessage(chatMessage); + + ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood: Story Mode count is: 73.", null, 0); + chatCommandsPlugin.onChatMessage(chatMessageEvent); + + verify(configManager).setRSProfileConfiguration("killcount", "theatre of blood story mode", 73); + verify(configManager).setRSProfileConfiguration("personalbest", "theatre of blood story mode", 5 * 60 + 4.0); + } + @Test public void testWintertodt() { diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java new file mode 100644 index 0000000000..f9ed47a555 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import com.google.common.base.Joiner; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.util.Text; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class ThreeStepCrypticClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(ThreeStepCrypticClue.forText("", "")); + } + + @Test + public void nonNullLocations() + { + final String clueText = Joiner.on("

").join(CrypticClue.CLUES.stream().map(CrypticClue::getText).toArray()); + final ThreeStepCrypticClue clue = ThreeStepCrypticClue.forText(Text.sanitizeMultilineText(clueText).toLowerCase(), clueText); + + assertNotNull(clue); + for (final WorldPoint location : clue.getLocations()) + { + assertNotNull(location); + } + } +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index 317515d053..d8e1ec0eaf 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -86,6 +86,10 @@ public interface RSClient extends RSGameEngine, Client @Override int getMapAngle(); + @Import("camAngleY") + @Override + void setCameraYawTarget(int cameraYawTarget); + @Import("Tiles_heights") @Override int[][][] getTileHeights();