diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 89211e5960..144e70c14a 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -25,9 +25,9 @@ object ProjectVersions { const val launcherVersion = "2.2.0" - const val rlVersion = "1.7.15" + const val rlVersion = "1.7.17" - const val openosrsVersion = "4.9.5" + const val openosrsVersion = "4.9.6" const val rsversion = 197 const val cacheversion = 165 diff --git a/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java b/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java index e234fdfb5f..06ca9bb623 100644 --- a/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java +++ b/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java @@ -25,10 +25,13 @@ package net.runelite.http.api.chat; import com.google.gson.JsonParseException; +import com.google.gson.reflect.TypeToken; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Set; import lombok.AllArgsConstructor; import net.runelite.http.api.RuneLiteAPI; import okhttp3.HttpUrl; @@ -362,4 +365,54 @@ public class ChatClient throw new IOException(ex); } } + + public boolean submitPetList(String username, Collection petList) throws IOException + { + HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + .addPathSegment("chat") + .addPathSegment("pets") + .addQueryParameter("name", username) + .build(); + + Request request = new Request.Builder() + .post(RequestBody.create(RuneLiteAPI.JSON, RuneLiteAPI.GSON.toJson(petList))) + .url(url) + .build(); + + try (Response response = client.newCall(request).execute()) + { + return response.isSuccessful(); + } + } + + public Set getPetList(String username) throws IOException + { + HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + .addPathSegment("chat") + .addPathSegment("pets") + .addQueryParameter("name", username) + .build(); + + Request request = new Request.Builder() + .url(url) + .build(); + + try (Response response = client.newCall(request).execute()) + { + if (!response.isSuccessful()) + { + throw new IOException("Unable to look up pet list!"); + } + + InputStream in = response.body().byteStream(); + // CHECKSTYLE:OFF + return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), + new TypeToken>(){}.getType()); + // CHECKSTYLE:ON + } + catch (JsonParseException ex) + { + throw new IOException(ex); + } + } } diff --git a/runelite-api/src/main/java/net/runelite/api/AnimationID.java b/runelite-api/src/main/java/net/runelite/api/AnimationID.java index 122a66c047..fc8303ac04 100644 --- a/runelite-api/src/main/java/net/runelite/api/AnimationID.java +++ b/runelite-api/src/main/java/net/runelite/api/AnimationID.java @@ -204,6 +204,7 @@ public final class AnimationID public static final int LEAGUE_HOME_TELEPORT_4 = 8803; public static final int LEAGUE_HOME_TELEPORT_5 = 8805; public static final int LEAGUE_HOME_TELEPORT_6 = 8807; + public static final int RAID_LIGHT_ANIMATION = 3101; public static final int CONSTRUCTION = 3676; public static final int CONSTRUCTION_IMCANDO = 8912; 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 0800d2f5f4..9cf9b9c310 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1078,6 +1078,35 @@ public interface Client extends GameEngine */ List getGraphicsObjects(); + /** + * Creates a RuneLiteObject, which is a modified {@link GraphicsObject} + */ + RuneLiteObject createRuneLiteObject(); + + /** + * Loads a model from the cache + * + * @param id the ID of the model + */ + Model loadModel(int id); + + /** + * Loads a model from the cache and also recolors it + * + * @param id the ID of the model + * @param colorToFind array of hsl color values to find in the model to replace + * @param colorToReplace array of hsl color values to replace in the model + */ + Model loadModel(int id, short[] colorToFind, short[] colorToReplace); + + /** + * Loads an animation from the cache + * + * @param id the ID of the animation. Any int is allowed, but implementations in the client + * should be defined in {@link AnimationID} + */ + Sequence loadAnimation(int id); + /** * Gets the music volume * @return volume 0-255 inclusive diff --git a/runelite-api/src/main/java/net/runelite/api/Constants.java b/runelite-api/src/main/java/net/runelite/api/Constants.java index bb5c789751..d0a530a4c9 100644 --- a/runelite-api/src/main/java/net/runelite/api/Constants.java +++ b/runelite-api/src/main/java/net/runelite/api/Constants.java @@ -81,6 +81,27 @@ public class Constants public static final int MAX_Z = 4; public static final int TILE_FLAG_BRIDGE = 2; + public static final int TILE_FLAG_UNDER_ROOF = 4; + + /** + * Flag for roof removal to remove the roofs above the player's current position. + */ + public static final int ROOF_FLAG_POSITION = 1; + + /** + * Flag for roof removal to remove the roofs above the currently hovered tile. + */ + public static final int ROOF_FLAG_HOVERED = 2; + + /** + * Flag for roof removal to remove the roofs above the player's destination tile. + */ + public static final int ROOF_FLAG_DESTINATION = 4; + + /** + * Flag for roof removal to remove the roofs that are above any tile between the camera and the player. + */ + public static final int ROOF_FLAG_BETWEEN = 8; /** * The height of the overworld, in tiles. Coordinates above this are in caves and other such zones. diff --git a/runelite-api/src/main/java/net/runelite/api/ItemID.java b/runelite-api/src/main/java/net/runelite/api/ItemID.java index 3898ac23ef..d8173d7769 100644 --- a/runelite-api/src/main/java/net/runelite/api/ItemID.java +++ b/runelite-api/src/main/java/net/runelite/api/ItemID.java @@ -11988,5 +11988,39 @@ public final class ItemID public static final int BOW_OF_FAERDHINEN_C_25892 = 25892; public static final int BOW_OF_FAERDHINEN_C_25894 = 25894; public static final int BOW_OF_FAERDHINEN_C_25896 = 25896; + public static final int TZTOK_SLAYER_HELMET = 25898; + public static final int TZTOK_SLAYER_HELMET_I = 25900; + public static final int TZTOK_SLAYER_HELMET_I_25902 = 25902; + public static final int VAMPYRIC_SLAYER_HELMET = 25904; + public static final int VAMPYRIC_SLAYER_HELMET_I = 25906; + public static final int VAMPYRIC_SLAYER_HELMET_I_25908 = 25908; + public static final int TZKAL_SLAYER_HELMET = 25910; + public static final int TZKAL_SLAYER_HELMET_I = 25912; + public static final int TZKAL_SLAYER_HELMET_I_25914 = 25914; + public static final int DRAGON_HUNTER_CROSSBOW_T = 25916; + public static final int DRAGON_HUNTER_CROSSBOW_B = 25918; + public static final int ANTIQUE_LAMP_25920 = 25920; + public static final int ANTIQUE_LAMP_25921 = 25921; + public static final int ANTIQUE_LAMP_25922 = 25922; + public static final int ANTIQUE_LAMP_25923 = 25923; + public static final int ANTIQUE_LAMP_25924 = 25924; + public static final int ANTIQUE_LAMP_25925 = 25925; + public static final int GHOMMALS_HILT_1 = 25926; + public static final int GHOMMALS_HILT_2 = 25928; + public static final int GHOMMALS_HILT_3 = 25930; + public static final int GHOMMALS_HILT_4 = 25932; + public static final int GHOMMALS_HILT_5 = 25934; + public static final int GHOMMALS_HILT_6 = 25936; + public static final int ANIM_OFFHAND = 25938; + public static final int ANIM_OFFHAND_25941 = 25941; + public static final int ANIM_OFFHAND_25944 = 25944; + public static final int ANIM_OFFHAND_25947 = 25947; + public static final int ANIM_OFFHAND_25950 = 25950; + public static final int ANIM_OFFHAND_25953 = 25953; + public static final int COMBAT_ACHIEVEMENTS = 25956; + public static final int CORRUPTED_PADDLEFISH = 25958; + public static final int CORRUPTED_ESCAPE_CRYSTAL = 25959; + public static final int CRYSTAL_PADDLEFISH = 25960; + public static final int ESCAPE_CRYSTAL = 25961; /* This file is automatically generated. Do not edit. */ } \ No newline at end of file diff --git a/runelite-api/src/main/java/net/runelite/api/JagexColor.java b/runelite-api/src/main/java/net/runelite/api/JagexColor.java new file mode 100644 index 0000000000..618ed002fa --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/JagexColor.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Abex + * 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.api; + +import java.awt.Color; + +public final class JagexColor +{ + public static short packHSL(int hue, int saturation, int luminance) + { + return (short) ((short) (hue & 63) << 10 + | (short) (saturation & 7) << 7 + | (short) (luminance & 127)); + } + + public static short rgbToHSL(int rgb, double brightness) + { + if (rgb == 1) + { + return 0; + } + + brightness = 1.D / brightness; + + double r = (double) (rgb >> 16 & 255) / 256.0D; + double g = (double) (rgb >> 8 & 255) / 256.0D; + double b = (double) (rgb & 255) / 256.0D; + + r = Math.pow(r, brightness); + g = Math.pow(g, brightness); + b = Math.pow(b, brightness); + + float[] hsv = Color.RGBtoHSB((int) (r * 256.D), (int) (g * 256.D), (int) (b * 256.D), null); + double hue = hsv[0]; + double luminance = hsv[2] - ((hsv[2] * hsv[1]) / 2.F); + double saturation = (hsv[2] - luminance) / Math.min(luminance, 1 - luminance); + + return packHSL((int) (Math.ceil(hue * 64.D) % 63.D), + (int) Math.ceil(saturation * 7.D), + (int) Math.ceil(luminance * 127.D)); + } +} diff --git a/runelite-api/src/main/java/net/runelite/api/NpcID.java b/runelite-api/src/main/java/net/runelite/api/NpcID.java index 01479be017..84c1d60367 100644 --- a/runelite-api/src/main/java/net/runelite/api/NpcID.java +++ b/runelite-api/src/main/java/net/runelite/api/NpcID.java @@ -9425,5 +9425,6 @@ public final class NpcID public static final int SRARACHA_11158 = 11158; public static final int SRARACHA_11159 = 11159; public static final int SRARACHA_11160 = 11160; + public static final int DUSTY_ALIV = 11161; /* This file is automatically generated. Do not edit. */ } diff --git a/runelite-api/src/main/java/net/runelite/api/NullItemID.java b/runelite-api/src/main/java/net/runelite/api/NullItemID.java index 3fe975cb45..877196148b 100644 --- a/runelite-api/src/main/java/net/runelite/api/NullItemID.java +++ b/runelite-api/src/main/java/net/runelite/api/NullItemID.java @@ -13699,5 +13699,35 @@ public final class NullItemID public static final int NULL_25893 = 25893; public static final int NULL_25895 = 25895; public static final int NULL_25897 = 25897; + public static final int NULL_25899 = 25899; + public static final int NULL_25901 = 25901; + public static final int NULL_25903 = 25903; + public static final int NULL_25905 = 25905; + public static final int NULL_25907 = 25907; + public static final int NULL_25909 = 25909; + public static final int NULL_25911 = 25911; + public static final int NULL_25913 = 25913; + public static final int NULL_25915 = 25915; + public static final int NULL_25917 = 25917; + public static final int NULL_25919 = 25919; + public static final int NULL_25927 = 25927; + public static final int NULL_25929 = 25929; + public static final int NULL_25931 = 25931; + public static final int NULL_25933 = 25933; + public static final int NULL_25935 = 25935; + public static final int NULL_25937 = 25937; + public static final int NULL_25939 = 25939; + public static final int NULL_25940 = 25940; + public static final int NULL_25942 = 25942; + public static final int NULL_25943 = 25943; + public static final int NULL_25945 = 25945; + public static final int NULL_25946 = 25946; + public static final int NULL_25948 = 25948; + public static final int NULL_25949 = 25949; + public static final int NULL_25951 = 25951; + public static final int NULL_25952 = 25952; + public static final int NULL_25954 = 25954; + public static final int NULL_25955 = 25955; + public static final int NULL_25957 = 25957; /* This file is automatically generated. Do not edit. */ } diff --git a/runelite-api/src/main/java/net/runelite/api/NullObjectID.java b/runelite-api/src/main/java/net/runelite/api/NullObjectID.java index 66971ab20f..5af135a544 100644 --- a/runelite-api/src/main/java/net/runelite/api/NullObjectID.java +++ b/runelite-api/src/main/java/net/runelite/api/NullObjectID.java @@ -20726,5 +20726,24 @@ public final class NullObjectID public static final int NULL_42484 = 42484; public static final int NULL_42485 = 42485; public static final int NULL_42486 = 42486; + public static final int NULL_42488 = 42488; + public static final int NULL_42489 = 42489; + public static final int NULL_42490 = 42490; + public static final int NULL_42491 = 42491; + public static final int NULL_42492 = 42492; + public static final int NULL_42493 = 42493; + public static final int NULL_42494 = 42494; + public static final int NULL_42495 = 42495; + public static final int NULL_42496 = 42496; + public static final int NULL_42497 = 42497; + public static final int NULL_42498 = 42498; + public static final int NULL_42499 = 42499; + public static final int NULL_42500 = 42500; + public static final int NULL_42501 = 42501; + public static final int NULL_42502 = 42502; + public static final int NULL_42503 = 42503; + public static final int NULL_42504 = 42504; + public static final int NULL_42505 = 42505; + public static final int NULL_42514 = 42514; /* This file is automatically generated. Do not edit. */ } diff --git a/runelite-api/src/main/java/net/runelite/api/ObjectID.java b/runelite-api/src/main/java/net/runelite/api/ObjectID.java index 6f3377cc0e..fa4f49d8f9 100644 --- a/runelite-api/src/main/java/net/runelite/api/ObjectID.java +++ b/runelite-api/src/main/java/net/runelite/api/ObjectID.java @@ -21747,5 +21747,13 @@ public final class ObjectID public static final int YEW_42427 = 42427; public static final int GRANDFATHER_CLOCK_42428 = 42428; public static final int LADDER_42487 = 42487; + public static final int TUNNEL_42506 = 42506; + public static final int TUNNEL_42507 = 42507; + public static final int ROCKS_42508 = 42508; + public static final int ROCKS_42509 = 42509; + public static final int ROCKS_42510 = 42510; + public static final int ROCKS_42511 = 42511; + public static final int ROCKS_42512 = 42512; + public static final int ROCKS_42513 = 42513; /* This file is automatically generated. Do not edit. */ } diff --git a/runelite-api/src/main/java/net/runelite/api/Quest.java b/runelite-api/src/main/java/net/runelite/api/Quest.java index 5e98499926..771cb64271 100644 --- a/runelite-api/src/main/java/net/runelite/api/Quest.java +++ b/runelite-api/src/main/java/net/runelite/api/Quest.java @@ -30,12 +30,13 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public enum Quest { + //Free Quests BLACK_KNIGHTS_FORTRESS(299, "Black Knights' Fortress"), COOKS_ASSISTANT(300, "Cook's Assistant"), THE_CORSAIR_CURSE(301, "The Corsair Curse"), DEMON_SLAYER(302, "Demon Slayer"), - DORICS_QUEST(303, "Doric's Quest"), - DRAGON_SLAYER_I(304, "Dragon Slayer I"), + DORICS_QUEST(3138, "Doric's Quest"), + DRAGON_SLAYER_I(3139, "Dragon Slayer I"), ERNEST_THE_CHICKEN(305, "Ernest the Chicken"), GOBLIN_DIPLOMACY(306, "Goblin Diplomacy"), IMP_CATCHER(307, "Imp Catcher"), @@ -50,7 +51,7 @@ public enum Quest SHIELD_OF_ARRAV(316, "Shield of Arrav"), VAMPYRE_SLAYER(1278, "Vampyre Slayer"), WITCHS_POTION(318, "Witch's Potion"), - X_MARKS_THE_SPOT(550, "X Marks the Spot"), + X_MARKS_THE_SPOT(3155, "X Marks the Spot"), BELOW_ICE_MOUNTAIN(2874, "Below Ice Mountain"), //Members' Quests @@ -89,7 +90,7 @@ public enum Quest FIGHT_ARENA(363, "Fight Arena"), FISHING_CONTEST(364, "Fishing Contest"), FORGETTABLE_TALE(365, "Forgettable Tale..."), - BONE_VOYAGE(366, "Bone Voyage"), + BONE_VOYAGE(3135, "Bone Voyage"), THE_FREMENNIK_ISLES(367, "The Fremennik Isles"), THE_FREMENNIK_TRIALS(368, "The Fremennik Trials"), GARDEN_OF_TRANQUILLITY(369, "Garden of Tranquillity"), @@ -103,7 +104,7 @@ public enum Quest THE_HAND_IN_THE_SAND(377, "The Hand in the Sand"), HAUNTED_MINE(378, "Haunted Mine"), HAZEEL_CULT(379, "Hazeel Cult"), - HEROES_QUEST(380, "Heroes' Quest"), + HEROES_QUEST(3142, "Heroes' Quest"), HOLY_GRAIL(381, "Holy Grail"), HORROR_FROM_THE_DEEP(382, "Horror from the Deep"), ICTHLARINS_LITTLE_HELPER(383, "Icthlarin's Little Helper"), @@ -111,7 +112,7 @@ public enum Quest IN_SEARCH_OF_THE_MYREQUE(385, "In Search of the Myreque"), JUNGLE_POTION(386, "Jungle Potion"), KINGS_RANSOM(387, "King's Ransom"), - LEGENDS_QUEST(388, "Legends' Quest"), + LEGENDS_QUEST(3145, "Legends' Quest"), LOST_CITY(389, "Lost City"), THE_LOST_TRIBE(390, "The Lost Tribe"), LUNAR_DIPLOMACY(391, "Lunar Diplomacy"), @@ -122,18 +123,18 @@ public enum Quest MONKEY_MADNESS_II(396, "Monkey Madness II"), MONKS_FRIEND(397, "Monk's Friend"), MOUNTAIN_DAUGHTER(398, "Mountain Daughter"), - MOURNINGS_END_PART_I(399, "Mourning's End Part I"), - MOURNINGS_END_PART_II(400, "Mourning's End Part II"), + MOURNINGS_END_PART_I(3147, "Mourning's End Part I"), + MOURNINGS_END_PART_II(3148, "Mourning's End Part II"), MURDER_MYSTERY(401, "Murder Mystery"), MY_ARMS_BIG_ADVENTURE(402, "My Arm's Big Adventure"), NATURE_SPIRIT(403, "Nature Spirit"), - OBSERVATORY_QUEST(404, "Observatory Quest"), - OLAFS_QUEST(405, "Olaf's Quest"), + OBSERVATORY_QUEST(3149, "Observatory Quest"), + OLAFS_QUEST(3150, "Olaf's Quest"), ONE_SMALL_FAVOUR(406, "One Small Favour"), PLAGUE_CITY(407, "Plague City"), PRIEST_IN_PERIL(408, "Priest in Peril"), THE_QUEEN_OF_THIEVES(409, "The Queen of Thieves"), - RAG_AND_BONE_MAN_I(410, "Rag and Bone Man I"), + RAG_AND_BONE_MAN_I(3152, "Rag and Bone Man I"), RAG_AND_BONE_MAN_II(411, "Rag and Bone Man II"), RATCATCHERS(412, "Ratcatchers"), RECIPE_FOR_DISASTER(413, "Recipe for Disaster"), @@ -166,37 +167,37 @@ public enum Quest TROLL_ROMANCE(440, "Troll Romance"), TROLL_STRONGHOLD(441, "Troll Stronghold"), UNDERGROUND_PASS(442, "Underground Pass"), - CLIENT_OF_KOUREND(443, "Client of Kourend"), + CLIENT_OF_KOUREND(3136, "Client of Kourend"), WANTED(444, "Wanted!"), WATCHTOWER(445, "Watchtower"), - WATERFALL_QUEST(446, "Waterfall Quest"), + WATERFALL_QUEST(3154, "Waterfall Quest"), WHAT_LIES_BELOW(447, "What Lies Below"), WITCHS_HOUSE(448, "Witch's House"), ZOGRE_FLESH_EATERS(449, "Zogre Flesh Eaters"), THE_ASCENT_OF_ARCEUUS(542, "The Ascent of Arceuus"), THE_FORSAKEN_TOWER(543, "The Forsaken Tower"), SONG_OF_THE_ELVES(603, "Song of the Elves"), - THE_FREMENNIK_EXILES(718, "The Fremennik Exiles"), + THE_FREMENNIK_EXILES(3141, "The Fremennik Exiles"), SINS_OF_THE_FATHER(1276, "Sins of the Father"), - A_PORCINE_OF_INTEREST(1690, "A Porcine of Interest"), + A_PORCINE_OF_INTEREST(3151, "A Porcine of Interest"), GETTING_AHEAD(752, "Getting Ahead"), A_KINGDOM_DIVIDED(2971, "A Kingdom Divided"), A_NIGHT_AT_THE_THEATRE(949, "A Night at the Theatre"), //Miniquests - ENTER_THE_ABYSS(319, "Enter the Abyss"), + ENTER_THE_ABYSS(3140, "Enter the Abyss"), ARCHITECTURAL_ALLIANCE(320, "Architectural Alliance"), - BEAR_YOUR_SOUL(321, "Bear Your Soul"), + BEAR_YOUR_SOUL(1275, "Bear Your Soul"), ALFRED_GRIMHANDS_BARCRAWL(322, "Alfred Grimhand's Barcrawl"), - CURSE_OF_THE_EMPTY_LORD(323, "Curse of the Empty Lord"), - ENCHANTED_KEY(324, "Enchanted Key"), + CURSE_OF_THE_EMPTY_LORD(3137, "Curse of the Empty Lord"), + THE_ENCHANTED_KEY(324, "The Enchanted Key"), THE_GENERALS_SHADOW(325, "The General's Shadow"), - SKIPPY_AND_THE_MOGRES(326, "Skippy and the Mogres"), - THE_MAGE_ARENA(327, "The Mage Arena"), - LAIR_OF_TARN_RAZORLOR(328, "Lair of Tarn Razorlor"), + SKIPPY_AND_THE_MOGRES(3153, "Skippy and the Mogres"), + MAGE_ARENA_I(3146, "Mage Arena I"), + LAIR_OF_TARN_RAZORLOR(3144, "Lair of Tarn Razorlor"), FAMILY_PEST(329, "Family Pest"), - THE_MAGE_ARENA_II(330, "The Mage Arena II"), - IN_SEARCH_OF_KNOWLEDGE(602, "In Search of Knowledge"), + MAGE_ARENA_II(330, "Mage Arena II"), + IN_SEARCH_OF_KNOWLEDGE(3143, "In Search of Knowledge"), DADDYS_HOME(1688, "Daddy's Home"); @Getter diff --git a/runelite-api/src/main/java/net/runelite/api/RuneLiteObject.java b/runelite-api/src/main/java/net/runelite/api/RuneLiteObject.java new file mode 100644 index 0000000000..20f2fb001e --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/RuneLiteObject.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, Trevor + * Copyright (c) 2021 Abex + * 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.api; + +import net.runelite.api.coords.LocalPoint; + +/** + * Represents a modified {@link GraphicsObject} + */ +public interface RuneLiteObject extends GraphicsObject +{ + /** + * Sets the model of the RuneLiteObject + */ + void setModel(Model model); + + /** + * Sets the animation of the RuneLiteObject + * If animation is null model will be static + */ + void setAnimation(Sequence animation); + + /** + * Sets whether the animation of the RuneLiteObject should loop when the animation ends. + * If this is false the object will despawn when the animation ends. + * Does nothing if the animation is null. + */ + void setShouldLoop(boolean shouldLoop); + + /** + * Sets the location in the scene for the RuneLiteObject + */ + void setLocation(LocalPoint point, int plane); + + /** + * Sets the state of the RuneLiteObject + * Set to true to spawn the object + * Set to false to despawn the object + */ + void setActive(boolean active); + + /** + * Gets the state of the RuneLiteObject + * + * @return true if the RuneLiteObject is added to the scene + */ + boolean isActive(); +} diff --git a/runelite-api/src/main/java/net/runelite/api/Scene.java b/runelite-api/src/main/java/net/runelite/api/Scene.java index 34983c41ad..c149c9263d 100644 --- a/runelite-api/src/main/java/net/runelite/api/Scene.java +++ b/runelite-api/src/main/java/net/runelite/api/Scene.java @@ -70,4 +70,8 @@ public interface Scene * @param gameObject */ void removeGameObject(GameObject gameObject); + + void generateHouses(); + + void setRoofRemovalMode(int flags); } diff --git a/runelite-api/src/main/java/net/runelite/api/Sequence.java b/runelite-api/src/main/java/net/runelite/api/Sequence.java new file mode 100644 index 0000000000..e7e1c8fcb9 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/Sequence.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021, Trevor + * 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.api; + +/** + * Represents an animation of a renderable + */ +public interface Sequence +{ +} diff --git a/runelite-api/src/main/java/net/runelite/api/Varbits.java b/runelite-api/src/main/java/net/runelite/api/Varbits.java index 90f91a6b14..bf7ffe4ef4 100644 --- a/runelite-api/src/main/java/net/runelite/api/Varbits.java +++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java @@ -324,7 +324,7 @@ public enum Varbits */ FIRE_PIT_GIANT_MOLE(6532), FIRE_PIT_LUMBRIDGE_SWAMP(6533), - FIRE_PIT_MOS_LE_HARMLESS(6544), + FIRE_PIT_MOS_LE_HARMLESS(6534), /** * Theatre of Blood 1=In Party, 2=Inside/Spectator, 3=Dead Spectating diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index 33872b4667..f0625635c2 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -82,6 +82,7 @@ public class WidgetID public static final int BA_DEFENDER_GROUP_ID = 487; public static final int BA_HEALER_GROUP_ID = 488; public static final int BA_REWARD_GROUP_ID = 497; + public static final int BA_TEAM_GROUP_ID = 256; public static final int LEVEL_UP_GROUP_ID = 233; public static final int DIALOG_SPRITE_GROUP_ID = 193; public static final int QUEST_COMPLETED_GROUP_ID = 153; @@ -152,6 +153,7 @@ public class WidgetID public static final int LMS_GROUP_ID = 333; public static final int LMS_INGAME_GROUP_ID = 328; public static final int ADVENTURE_LOG_ID = 187; + public static final int COLLECTION_LOG_ID = 621; public static final int GENERIC_SCROLL_GROUP_ID = 625; public static final int GAUNTLET_TIMER_GROUP_ID = 637; public static final int HALLOWED_SEPULCHRE_TIMER_GROUP_ID = 668; @@ -684,12 +686,15 @@ public class WidgetID static class HLR { + static final int TEAMMATES = 13; static final int TEAMMATE1 = 18; static final int TEAMMATE2 = 22; static final int TEAMMATE3 = 26; static final int TEAMMATE4 = 30; } + static final int TEAM = 2; + static final int ROLE_SPRITE = 10; static final int ROLE = 11; @@ -954,6 +959,15 @@ public class WidgetID static final int CONTAINER = 0; } + static class CollectionLog + { + static final int CONTAINER = 0; + static final int TABS = 3; + static final int ENTRY = 17; + static final int ENTRY_HEADER = 19; + static final int ENTRY_ITEMS = 36; + } + static class GenericScroll { static final int TEXT = 7; diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index 8b3fcb0177..000290fbf6 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -373,9 +373,12 @@ public enum WidgetInfo CHATBOX_TAB_CLAN(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.TAB_CLAN), CHATBOX_TAB_TRADE(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.TAB_TRADE), + BA_TEAM(WidgetID.BA_TEAM_GROUP_ID, WidgetID.BarbarianAssault.TEAM), + BA_HEAL_ROLE_TEXT(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.ROLE), BA_HEAL_ROLE_SPRITE(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.ROLE_SPRITE), + BA_HEAL_TEAMMATES(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATES), BA_HEAL_TEAMMATE1(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE1), BA_HEAL_TEAMMATE2(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE2), BA_HEAL_TEAMMATE3(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE3), @@ -479,6 +482,13 @@ public enum WidgetInfo ADVENTURE_LOG(WidgetID.ADVENTURE_LOG_ID, WidgetID.AdventureLog.CONTAINER), + COLLECTION_LOG(WidgetID.COLLECTION_LOG_ID, WidgetID.CollectionLog.CONTAINER), + + COLLECTION_LOG_TABS(WidgetID.COLLECTION_LOG_ID, WidgetID.CollectionLog.TABS), + COLLECTION_LOG_ENTRY(WidgetID.COLLECTION_LOG_ID, WidgetID.CollectionLog.ENTRY), + COLLECTION_LOG_ENTRY_HEADER(WidgetID.COLLECTION_LOG_ID, WidgetID.CollectionLog.ENTRY_HEADER), + COLLECTION_LOG_ENTRY_ITEMS(WidgetID.COLLECTION_LOG_ID, WidgetID.CollectionLog.ENTRY_ITEMS), + GENERIC_SCROLL_TEXT(WidgetID.GENERIC_SCROLL_GROUP_ID, WidgetID.GenericScroll.TEXT), WORLD_SWITCHER_LIST(WidgetID.WORLD_SWITCHER_GROUP_ID, WidgetID.WorldSwitcher.WORLD_LIST), diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml new file mode 100644 index 0000000000..6fea6c3c4c --- /dev/null +++ b/runelite-client/pom.xml @@ -0,0 +1,428 @@ + + + + 4.0.0 + + + net.runelite + runelite-parent + 1.7.18-SNAPSHOT + + + client + RuneLite Client + + + true + true + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + net.sf.jopt-simple + jopt-simple + 5.0.1 + + + com.google.guava + guava + + + + com.google.code.findbugs + jsr305 + + + com.google.errorprone + error_prone_annotations + + + com.google.j2objc + j2objc-annotations + + + org.codehaus.mojo + animal-sniffer-annotations + + + + + com.google.inject + guice + no_aop + + + com.google.code.gson + gson + + + net.runelite.pushingpixels + substance + 8.0.02 + + + net.runelite.pushingpixels + trident + 1.5.00 + runtime + + + org.projectlombok + lombok + provided + + + org.apache.commons + commons-text + 1.2 + + + net.runelite.jogl + jogl-all + 2.4.0-rc-20200429 + + + net.runelite.jogl + jogl-all + 2.4.0-rc-20200429 + natives-windows-amd64 + runtime + + + net.runelite.jogl + jogl-all + 2.4.0-rc-20200429 + natives-windows-i586 + runtime + + + net.runelite.jogl + jogl-all + 2.4.0-rc-20200429 + natives-linux-amd64 + runtime + + + net.runelite.jogl + jogl-all-natives-macosx + 2.4.0-rc-20210117 + runtime + + + net.runelite.gluegen + gluegen-rt + 2.4.0-rc-20200429 + + + net.runelite.gluegen + gluegen-rt + 2.4.0-rc-20200429 + natives-windows-amd64 + runtime + + + net.runelite.gluegen + gluegen-rt + 2.4.0-rc-20200429 + natives-windows-i586 + runtime + + + net.runelite.gluegen + gluegen-rt + 2.4.0-rc-20200429 + natives-linux-amd64 + runtime + + + net.runelite.gluegen + gluegen-rt-natives-macosx + 2.4.0-rc-20210117 + runtime + + + net.runelite.jocl + jocl + 1.0 + + + net.runelite.jocl + jocl + 1.0 + macos-x64 + runtime + + + net.runelite.jocl + jocl + 1.0 + macos-arm64 + runtime + + + net.runelite + archive-patcher + 1.0 + + + + net.java.dev.jna + jna + 4.5.1 + + + net.java.dev.jna + jna-platform + 4.5.1 + + + com.google.code.findbugs + jsr305 + + + + net.runelite + runelite-api + ${project.version} + + + net.runelite + jshell + ${project.version} + true + + + net.runelite + client-patch + ${project.version} + runtime + + + net.runelite + http-api + ${project.version} + + + net.runelite + discord + 1.4 + + + net.runelite + orange-extensions + 1.0 + provided + + + + junit + junit + 4.12 + test + + + org.hamcrest + hamcrest-library + 1.3 + test + + + org.mockito + mockito-core + 3.1.0 + test + + + com.google.inject.extensions + guice-testlib + test + + + com.google.inject.extensions + guice-grapher + test + + + com.squareup.okhttp3 + mockwebserver + 3.7.0 + test + + + + + + + src/main/resources + + logback.xml + + true + + + src/main/resources + + logback.xml + + false + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.2 + + + ttf + png + gif + wav + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.1 + + + package + + shade + + + true + shaded + + + + net.runelite.client.RuneLite + + + + + + + + + io.github.zlika + reproducible-build-maven-plugin + + + org.apache.maven.plugins + maven-jarsigner-plugin + 1.4 + + + sign + + sign + + + + + ${jarsigner.skip} + ${jarsigner.keystore} + ${jarsigner.alias} + ${jarsigner.storepass} + ${jarsigner.keypass} + + + + net.runelite + script-assembler-plugin + ${project.version} + + + assemble + + assemble + + + src/main/scripts + ${project.build.outputDirectory}/runelite + + + + build-index + + build-index + + + ${project.build.outputDirectory}/runelite + ${project.build.outputDirectory}/runelite/index + + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.13.0 + + + net.sourceforge.pmd + pmd-core + 6.29.0 + + + net.sourceforge.pmd + pmd-java + 6.29.0 + + + + true + true + + ${basedir}/pmd-ruleset.xml + + false + true + + + + + check + + + + + + + diff --git a/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java b/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java index fad7b9246e..08a9f82c9d 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java @@ -275,13 +275,14 @@ public enum ItemMapping ITEM_CRYSTAL_AXE(DRAGON_AXE, CRYSTAL_AXE, CRYSTAL_AXE_INACTIVE), ITEM_CRYSTAL_HARPOON(DRAGON_HARPOON, CRYSTAL_HARPOON, CRYSTAL_HARPOON_INACTIVE), ITEM_CRYSTAL_PICKAXE(DRAGON_PICKAXE, CRYSTAL_PICKAXE, CRYSTAL_PICKAXE_INACTIVE), - ITEM_BLADE_OF_SAELDOR(BLADE_OF_SAELDOR_INACTIVE, BLADE_OF_SAELDOR, BLADE_OF_SAELDOR_C), + ITEM_BLADE_OF_SAELDOR(BLADE_OF_SAELDOR_INACTIVE, BLADE_OF_SAELDOR, BLADE_OF_SAELDOR_C, BLADE_OF_SAELDOR_C_25870, BLADE_OF_SAELDOR_C_25872, BLADE_OF_SAELDOR_C_25874, BLADE_OF_SAELDOR_C_25876, BLADE_OF_SAELDOR_C_25878, BLADE_OF_SAELDOR_C_25880, BLADE_OF_SAELDOR_C_25882), ITEM_CRYSTAL_BOW(CRYSTAL_WEAPON_SEED, CRYSTAL_BOW, CRYSTAL_BOW_24123, CRYSTAL_BOW_INACTIVE), ITEM_CRYSTAL_HALBERD(CRYSTAL_WEAPON_SEED, CRYSTAL_HALBERD, CRYSTAL_HALBERD_24125, CRYSTAL_HALBERD_INACTIVE), ITEM_CRYSTAL_SHIELD(CRYSTAL_WEAPON_SEED, CRYSTAL_SHIELD, CRYSTAL_SHIELD_24127, CRYSTAL_SHIELD_INACTIVE), ITEM_CRYSTAL_HELMET(CRYSTAL_ARMOUR_SEED, CRYSTAL_HELM, CRYSTAL_HELM_INACTIVE), ITEM_CRYSTAL_LEGS(CRYSTAL_ARMOUR_SEED, 2L, CRYSTAL_LEGS, CRYSTAL_LEGS_INACTIVE), ITEM_CRYSTAL_BODY(CRYSTAL_ARMOUR_SEED, 3L, CRYSTAL_BODY, CRYSTAL_BODY_INACTIVE), + ITEM_BOW_OF_FAERDHINEN(BOW_OF_FAERDHINEN_INACTIVE, BOW_OF_FAERDHINEN, BOW_OF_FAERDHINEN_C, BOW_OF_FAERDHINEN_C_25884, BOW_OF_FAERDHINEN_C_25886, BOW_OF_FAERDHINEN_C_25888, BOW_OF_FAERDHINEN_C_25890, BOW_OF_FAERDHINEN_C_25892, BOW_OF_FAERDHINEN_C_25894, BOW_OF_FAERDHINEN_C_25896), // Bird nests ITEM_BIRD_NEST(BIRD_NEST_5075, BIRD_NEST, BIRD_NEST_5071, BIRD_NEST_5072, BIRD_NEST_5073, BIRD_NEST_5074, BIRD_NEST_7413, BIRD_NEST_13653, BIRD_NEST_22798, BIRD_NEST_22800, CLUE_NEST_EASY, CLUE_NEST_MEDIUM, CLUE_NEST_HARD, CLUE_NEST_ELITE), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/DesertDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/DesertDiaryRequirement.java index 4de2c0a4d3..728f5401a7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/DesertDiaryRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/DesertDiaryRequirement.java @@ -81,7 +81,7 @@ public class DesertDiaryRequirement extends GenericDiaryRequirement new QuestRequirement(Quest.DREAM_MENTOR)); add("Complete a lap of the Pollnivneach agility course.", new SkillRequirement(Skill.AGILITY, 70)); - add("Slay a Dust Devil with a Slayer helmet equipped.", + add("Slay a Dust Devil in the desert cave with a Slayer helmet equipped.", new SkillRequirement(Skill.SLAYER, 65), new SkillRequirement(Skill.DEFENCE, 10), new SkillRequirement(Skill.CRAFTING, 55), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/WildernessDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/WildernessDiaryRequirement.java index 0a059a1785..ac978ca4cf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/WildernessDiaryRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/WildernessDiaryRequirement.java @@ -70,7 +70,7 @@ public class WildernessDiaryRequirement extends GenericDiaryRequirement // HARD add("Cast one of the 3 God spells against another player in the Wilderness.", new SkillRequirement(Skill.MAGIC, 60), - new QuestRequirement(Quest.THE_MAGE_ARENA)); + new QuestRequirement(Quest.MAGE_ARENA_I)); add("Charge an Air Orb.", new SkillRequirement(Skill.MAGIC, 66)); add("Catch a Black Salamander in the Wilderness.", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java index a7213a33f1..859aa9f9d1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java @@ -179,6 +179,18 @@ public interface ChatCommandsConfig extends Config @ConfigItem( position = 13, + keyName = "pets", + name = "Pets Command", + description = "Configures whether the player pet list command is enabled
!pets
" + + " Note: Update your pet list by looking at the All Pets tab in the Collection Log" + ) + default boolean pets() + { + return true; + } + + @ConfigItem( + position = 20, keyName = "clearSingleWord", name = "Clear Single Word", description = "Enable hot key to clear single word at a time" @@ -189,7 +201,7 @@ public interface ChatCommandsConfig extends Config } @ConfigItem( - position = 14, + position = 21, keyName = "clearEntireChatBox", name = "Clear Chat Box", description = "Enable hotkey to clear entire chat box" 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 9a998e8aca..fe8b03cd26 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 @@ -28,14 +28,23 @@ package net.runelite.client.plugins.chatcommands; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableMap; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; import com.google.inject.Provides; +import java.awt.image.BufferedImage; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.inject.Inject; import lombok.Value; import lombok.extern.slf4j.Slf4j; @@ -43,6 +52,7 @@ import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.Experience; import net.runelite.api.IconID; +import net.runelite.api.IndexedSprite; import net.runelite.api.ItemComposition; import net.runelite.api.MessageNode; import net.runelite.api.Player; @@ -57,9 +67,11 @@ import net.runelite.api.events.WidgetLoaded; import net.runelite.api.vars.AccountType; import net.runelite.api.widgets.Widget; import static net.runelite.api.widgets.WidgetID.ADVENTURE_LOG_ID; +import static net.runelite.api.widgets.WidgetID.COLLECTION_LOG_ID; import static net.runelite.api.widgets.WidgetID.GENERIC_SCROLL_GROUP_ID; import static net.runelite.api.widgets.WidgetID.KILL_LOGS_GROUP_ID; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; import net.runelite.client.chat.ChatColorType; import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageBuilder; @@ -72,6 +84,7 @@ import net.runelite.client.game.ItemManager; import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.QuantityFormatter; import net.runelite.client.util.Text; import net.runelite.http.api.chat.ChatClient; @@ -112,6 +125,7 @@ public class ChatCommandsPlugin extends Plugin "(?:
Overall time: (?[0-9:]+(?:\\.[0-9]+)?)(?: \\(new personal best\\)|. Personal best: (?[0-9:]+(?:\\.[0-9]+)?)))?"); private static final Pattern HS_KC_FLOOR_PATTERN = Pattern.compile("You have completed Floor (\\d) of the Hallowed Sepulchre! Total completions: ([0-9,]+)\\."); private static final Pattern HS_KC_GHC_PATTERN = Pattern.compile("You have opened the Grand Hallowed Coffin ([0-9,]+) times?!"); + private static final Pattern COLLECTION_LOG_ITEM_PATTERN = Pattern.compile("New item added to your collection log: (.*)"); private static final String TOTAL_LEVEL_COMMAND_STRING = "!total"; private static final String PRICE_COMMAND_STRING = "!price"; @@ -128,9 +142,11 @@ public class ChatCommandsPlugin extends Plugin private static final String DUEL_ARENA_COMMAND = "!duels"; private static final String LEAGUE_POINTS_COMMAND = "!lp"; private static final String SOUL_WARS_ZEAL_COMMAND = "!sw"; + private static final String PET_LIST_COMMAND = "!pets"; @VisibleForTesting static final int ADV_LOG_EXPLOITS_TEXT_INDEX = 1; + static final int COL_LOG_ENTRY_HEADER_TITLE_INDEX = 0; private static final Map KILLCOUNT_RENAMES = ImmutableMap.of( "Barrows chest", "Barrows Chests" @@ -139,15 +155,20 @@ public class ChatCommandsPlugin extends Plugin private boolean bossLogLoaded; private boolean advLogLoaded; private boolean scrollInterfaceLoaded; + private boolean collectionLogLoaded; private String pohOwner; private HiscoreEndpoint hiscoreEndpoint; // hiscore endpoint for current player private String lastBossKill; private int lastBossTime = -1; private double lastPb = -1; + private int modIconIdx = -1; @Inject private Client client; + @Inject + private ClientThread clientThread; + @Inject private ChatCommandsConfig config; @@ -181,6 +202,9 @@ public class ChatCommandsPlugin extends Plugin @Inject private RuneLiteConfig runeLiteConfig; + @Inject + private Gson gson; + @Override public void startUp() { @@ -201,6 +225,9 @@ public class ChatCommandsPlugin extends Plugin chatCommandManager.registerCommandAsync(GC_COMMAND_STRING, this::gambleCountLookup, this::gambleCountSubmit); chatCommandManager.registerCommandAsync(DUEL_ARENA_COMMAND, this::duelArenaLookup, this::duelArenaSubmit); chatCommandManager.registerCommandAsync(SOUL_WARS_ZEAL_COMMAND, this::soulWarsZealLookup); + chatCommandManager.registerCommandAsync(PET_LIST_COMMAND, this::petListLookup, this::petListSubmit); + + clientThread.invoke(this::loadPetIcons); } @Override @@ -226,6 +253,7 @@ public class ChatCommandsPlugin extends Plugin chatCommandManager.unregisterCommand(GC_COMMAND_STRING); chatCommandManager.unregisterCommand(DUEL_ARENA_COMMAND); chatCommandManager.unregisterCommand(SOUL_WARS_ZEAL_COMMAND); + chatCommandManager.unregisterCommand(PET_LIST_COMMAND); } @Provides @@ -272,6 +300,69 @@ public class ChatCommandsPlugin extends Plugin return personalBest == null ? 0 : personalBest; } + private void loadPetIcons() + { + final IndexedSprite[] modIcons = client.getModIcons(); + if (modIconIdx != -1 || modIcons == null) + { + return; + } + + final Pet[] pets = Pet.values(); + final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + pets.length); + modIconIdx = modIcons.length; + + for (int i = 0; i < pets.length; i++) + { + final Pet pet = pets[i]; + + final BufferedImage image = ImageUtil.resizeImage(itemManager.getImage(pet.getIconID()), 18, 16); + final IndexedSprite sprite = ImageUtil.getImageIndexedSprite(image, client); + newModIcons[modIconIdx + i] = sprite; + } + + client.setModIcons(newModIcons); + } + + /** + * Sets the list of owned pets for the local player + * + * @param petList The total list of owned pets for the local player + */ + private void setPetList(List petList) + { + if (petList == null) + { + return; + } + + configManager.setRSProfileConfiguration("chatcommands", "pets", + gson.toJson(petList)); + } + + /** + * Looks up the list of owned pets for the local player + */ + private List getPetList() + { + String petListJson = configManager.getRSProfileConfiguration("chatcommands", "pets", + String.class); + + List petList; + try + { + // CHECKSTYLE:OFF + petList = gson.fromJson(petListJson, new TypeToken>(){}.getType()); + // CHECKSTYLE:ON + } + catch (JsonSyntaxException ex) + { + return Collections.emptyList(); + } + + return petList != null ? petList : Collections.emptyList(); + } + @Subscribe public void onChatMessage(ChatMessage chatMessage) { @@ -431,6 +522,24 @@ public class ChatCommandsPlugin extends Plugin lastBossKill = null; lastBossTime = -1; } + + matcher = COLLECTION_LOG_ITEM_PATTERN.matcher(message); + if (matcher.find()) + { + String item = matcher.group(1); + Pet pet = Pet.findPet(item); + + if (pet != null) + { + List petList = new ArrayList<>(getPetList()); + if (!petList.contains(pet)) + { + log.debug("New pet added: {}", pet); + petList.add(pet); + setPetList(petList); + } + } + } } @VisibleForTesting @@ -490,6 +599,39 @@ public class ChatCommandsPlugin extends Plugin } } + if (collectionLogLoaded && (pohOwner == null || pohOwner.equals(client.getLocalPlayer().getName()))) + { + collectionLogLoaded = false; + + Widget collectionLogEntryHeader = client.getWidget(WidgetInfo.COLLECTION_LOG_ENTRY_HEADER); + if (collectionLogEntryHeader != null && collectionLogEntryHeader.getChildren() != null) + { + Widget entryTitle = collectionLogEntryHeader.getChild(COL_LOG_ENTRY_HEADER_TITLE_INDEX); + // Make sure that the player is looking in the All Pets tab of the collection log + if (entryTitle.getText().equals("All Pets")) + { + Widget collectionLogEntryItems = client.getWidget(WidgetInfo.COLLECTION_LOG_ENTRY_ITEMS); + if (collectionLogEntryItems != null && collectionLogEntryItems.getChildren() != null) + { + List petList = new ArrayList<>(); + for (Widget child : collectionLogEntryItems.getChildren()) + { + if (child.getOpacity() == 0) + { + Pet pet = Pet.findPet(Text.removeTags(child.getName())); + if (pet != null) + { + petList.add(pet); + } + } + } + + setPetList(petList); + } + } + } + } + if (bossLogLoaded && (pohOwner == null || pohOwner.equals(client.getLocalPlayer().getName()))) { bossLogLoaded = false; @@ -566,6 +708,9 @@ public class ChatCommandsPlugin extends Plugin case ADVENTURE_LOG_ID: advLogLoaded = true; break; + case COLLECTION_LOG_ID: + collectionLogLoaded = true; + break; case KILL_LOGS_GROUP_ID: bossLogLoaded = true; break; @@ -583,6 +728,10 @@ public class ChatCommandsPlugin extends Plugin case LOADING: case HOPPING: pohOwner = null; + break; + case LOGGED_IN: + loadPetIcons(); + break; } } @@ -999,6 +1148,103 @@ public class ChatCommandsPlugin extends Plugin return true; } + /** + * Looks up the pet list for the player who triggered !pets + * + * @param chatMessage The chat message containing the command. + * @param message The chat message in string format + *

+ */ + private void petListLookup(ChatMessage chatMessage, String message) + { + if (!config.pets()) + { + return; + } + + ChatMessageType type = chatMessage.getType(); + + final String player; + if (type.equals(ChatMessageType.PRIVATECHATOUT)) + { + player = client.getLocalPlayer().getName(); + } + else + { + player = Text.sanitize(chatMessage.getName()); + } + + Set playerPetList; + try + { + playerPetList = chatClient.getPetList(player); + } + catch (IOException ex) + { + log.debug("unable to lookup pet list", ex); + + if (player.equals(client.getLocalPlayer().getName())) + { + String response = "Open the 'All Pets' tab in the Collection Log to update your pet list"; + log.debug("Setting response {}", response); + final MessageNode messageNode = chatMessage.getMessageNode(); + messageNode.setValue(response); + client.refreshChat(); + } + return; + } + + ChatMessageBuilder responseBuilder = new ChatMessageBuilder().append("Pets: ") + .append("(" + playerPetList.size() + ")"); + + // Append pets that the player owns + Pet[] pets = Pet.values(); + for (Pet pet : pets) + { + if (playerPetList.contains(pet.getIconID())) + { + responseBuilder.append(" ").img(modIconIdx + pet.ordinal()); + } + } + + String response = responseBuilder.build(); + + log.debug("Setting response {}", response); + final MessageNode messageNode = chatMessage.getMessageNode(); + messageNode.setValue(response); + client.refreshChat(); + } + + /** + * Submits the pet list for the local player + * + * @param chatInput The chat message containing the command. + * @param value The chat message + */ + private boolean petListSubmit(ChatInput chatInput, String value) + { + final String playerName = client.getLocalPlayer().getName(); + + executor.execute(() -> + { + try + { + List petList = getPetList().stream().map(Pet::getIconID).collect(Collectors.toList()); + chatClient.submitPetList(playerName, petList); + } + catch (Exception ex) + { + log.warn("unable to submit pet list", ex); + } + finally + { + chatInput.resume(); + } + }); + + return true; + } + /** * Looks up the item price and changes the original message to the * response. 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 new file mode 100644 index 0000000000..b48a810ec5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/Pet.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021, Illya Myshakov + * 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.chatcommands; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.ItemID; + +@AllArgsConstructor +@Getter +enum Pet +{ + ABYSSAL_ORPHAN("Abyssal orphan", ItemID.ABYSSAL_ORPHAN), + IKKLE_HYDRA("Ikkle hydra", ItemID.IKKLE_HYDRA), + CALLISTO_CUB("Callisto cub", ItemID.CALLISTO_CUB), + HELLPUPPY("Hellpuppy", ItemID.HELLPUPPY), + PET_CHAOS_ELEMENTAL("Pet chaos elemental", ItemID.PET_CHAOS_ELEMENTAL), + PET_ZILYANA("Pet zilyana", ItemID.PET_ZILYANA), + PET_DARK_CORE("Pet dark core", ItemID.PET_DARK_CORE), + PET_DAGANNOTH_PRIME("Pet dagannoth prime", ItemID.PET_DAGANNOTH_PRIME), + PET_DAGANNOTH_SUPREME("Pet dagannoth supreme", ItemID.PET_DAGANNOTH_SUPREME), + PET_DAGANNOTH_REX("Pet dagannoth rex", ItemID.PET_DAGANNOTH_REX), + TZREKJAD("Tzrek-jad", ItemID.TZREKJAD), + PET_GENERAL_GRAARDOR("Pet general graardor", ItemID.PET_GENERAL_GRAARDOR), + BABY_MOLE("Baby mole", ItemID.BABY_MOLE), + NOON("Noon", ItemID.NOON), + JALNIBREK("Jal-nib-rek", ItemID.JALNIBREK), + KALPHITE_PRINCESS("Kalphite princess", ItemID.KALPHITE_PRINCESS), + PRINCE_BLACK_DRAGON("Prince black dragon", ItemID.PRINCE_BLACK_DRAGON), + PET_KRAKEN("Pet kraken", ItemID.PET_KRAKEN), + PET_KREEARRA("Pet kree'arra", ItemID.PET_KREEARRA), + PET_KRIL_TSUTSAROTH("Pet k'ril tsutsaroth", ItemID.PET_KRIL_TSUTSAROTH), + SCORPIAS_OFFSPRING("Scorpia's offspring", ItemID.SCORPIAS_OFFSPRING), + SKOTOS("Skotos", ItemID.SKOTOS), + PET_SMOKE_DEVIL("Pet smoke devil", ItemID.PET_SMOKE_DEVIL), + VENENATIS_SPIDERLING("Venenatis spiderling", ItemID.VENENATIS_SPIDERLING), + VETION_JR("Vet'ion jr.", ItemID.VETION_JR), + VORKI("Vorki", ItemID.VORKI), + PHOENIX("Phoenix", ItemID.PHOENIX), + PET_SNAKELING("Pet snakeling", ItemID.PET_SNAKELING), + OLMLET("Olmlet", ItemID.OLMLET), + LIL_ZIK("Lil' zik", ItemID.LIL_ZIK), + BLOODHOUND("Bloodhound", ItemID.BLOODHOUND), + PET_PENANCE_QUEEN("Pet penance queen", ItemID.PET_PENANCE_QUEEN), + HERON("Heron", ItemID.HERON), + ROCK_GOLEM("Rock golem", ItemID.ROCK_GOLEM), + BEAVER("Beaver", ItemID.BEAVER), + BABY_CHINCHOMPA("Baby chinchompa", ItemID.BABY_CHINCHOMPA), + GIANT_SQUIRREL("Giant squirrel", ItemID.GIANT_SQUIRREL), + TANGLEROOT("Tangleroot", ItemID.TANGLEROOT), + ROCKY("Rocky", ItemID.ROCKY), + RIFT_GUARDIAN("Rift guardian", ItemID.RIFT_GUARDIAN), + HERBI("Herbi", ItemID.HERBI), + CHOMPY_CHICK("Chompy chick", ItemID.CHOMPY_CHICK), + SRARACHA("Sraracha", ItemID.SRARACHA), + SMOLCANO("Smolcano", ItemID.SMOLCANO), + 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); + + private final String name; + private final Integer iconID; + + static Pet findPet(String petName) + { + for (Pet pet : values()) + { + if (pet.name.equals(petName)) + { + return pet; + } + } + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java index 58b98cd6cd..6b9cf11999 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java @@ -207,8 +207,8 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati .put(new WorldPoint(2484, 4016, 0), new CoordinateClueInfo("Northeast corner of the Island of Stone.", ARMADYLEAN_OR_BANDOSIAN_GUARD)) .put(new WorldPoint(2222, 3331, 0), new CoordinateClueInfo("Prifddinas, west of the Tower of Voices", ARMADYLEAN_OR_BANDOSIAN_GUARD)) .put(new WorldPoint(3560, 3987, 0), new CoordinateClueInfo("Lithkren. Digsite pendant teleport if unlocked, otherwise take rowboat from west of Mushroom Meadow Mushtree.", ARMADYLEAN_OR_BANDOSIAN_GUARD)) - .put(new WorldPoint(2318, 2954, 0), new CoordinateClueInfo("North-east corner of the Isle of Souls.", ARMADYLEAN_OR_BANDOSIAN_GUARD)) - .put(new WorldPoint(2094, 2889, 0), new CoordinateClueInfo("West side of the Isle of Souls.", ARMADYLEAN_OR_BANDOSIAN_GUARD)) + .put(new WorldPoint(2318, 2954, 0), new CoordinateClueInfo("North-east corner of the Isle of Souls.", BANDOSIAN_GUARD)) + .put(new WorldPoint(2094, 2889, 0), new CoordinateClueInfo("West side of the Isle of Souls.", ARMADYLEAN_GUARD)) .put(new WorldPoint(1451, 3509, 0), new CoordinateClueInfo("Ruins of Morra.", ARMADYLEAN_OR_BANDOSIAN_GUARD)) // Master .put(new WorldPoint(2178, 3209, 0), new CoordinateClueInfo("South of Iorwerth Camp.", BRASSICAN_MAGE)) @@ -237,7 +237,7 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati .put(new WorldPoint(3188, 3939, 0), new CoordinateClueInfo("Wilderness. Resource Area.", BRASSICAN_MAGE)) .put(new WorldPoint(3304, 3941, 0), new CoordinateClueInfo("Wilderness. East of Rogues' Castle.", ANCIENT_WIZARDS)) .put(new WorldPoint(2994, 3961, 0), new CoordinateClueInfo("Wilderness. Inside Agility Training Area.", BRASSICAN_MAGE)) - .put(new WorldPoint(1770, 3417, 0), new CoordinateClueInfo("Crabclaw Isle", ANCIENT_WIZARDS)) + .put(new WorldPoint(1769, 3418, 0), new CoordinateClueInfo("Crabclaw Isle", ANCIENT_WIZARDS)) .build(); private final String text; 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 2fd4418fe9..e4748262a5 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 @@ -327,7 +327,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Elvish onions.", new WorldPoint(3303, 6092, 0), "Dig in the onion patch east of the Prifddinas allotments."), new CrypticClue("Dig by the Giant's Den entrance, looking out over Lake Molch.", new WorldPoint(1418, 3591, 0), "South-east of Lake Molch in Zeah, outside the cave entrance."), new CrypticClue("Search the crates in the fruit store just east of the Hosidius town centre.", CRATES_27533, new WorldPoint(1798, 3612, 0), "Search the crates in the back room of the Hosidius fruit store."), - new CrypticClue("A graceful man of many colours, his crates must be full of many delights.", "Hill Giant", CRATE_42067, new WorldPoint(1506, 3591, 2), "Kill any Hill Giant for a medium key. Then search the crate on the top floor of Osten's clothing shop in Shayzien."), + new CrypticClue("A graceful man of many colours, his crates must be full of many delights.", "Hill Giant", CRATE_42067, new WorldPoint(1506, 3590, 2), "Kill any Hill Giant for a medium key. Then search the crate on the top floor of Osten's clothing shop in Shayzien."), new CrypticClue("Search the basket of apples in an orchard, south of the unknown grave surrounded by white roses.", APPLE_BASKET, new WorldPoint(1718, 3626, 0), "Search the middle apple basket in the apple orchard north of Hosidius."), new CrypticClue("Dig in the lair of red wings, within the temple of the Sun and Moon.", new WorldPoint(1820, 9935, 0), "Forthos Dungeon. In the center of the red dragons.") ); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/Enemy.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/Enemy.java index 1aef9b493d..eef96b5312 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/Enemy.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/Enemy.java @@ -41,8 +41,12 @@ public enum Enemy ZAMORAK_WIZARD("Zamorak Wizard"), //appears for hard clue coordinate steps not in the wilderness SARADOMIN_WIZARD("Saradomin Wizard"), - //appears for elite clue coordinate steps all areas + //appears for elite clue coordinate steps in most areas ARMADYLEAN_OR_BANDOSIAN_GUARD("Armadylean OR Bandosian Guard"), + //appears for elite clue coordinate steps on the west side of the Isle of Souls + ARMADYLEAN_GUARD("Armadylean Guard"), + //appears for elite clue coordinate steps on the east side of the Isle of Souls + BANDOSIAN_GUARD("Bandosian Guard"), //appears for master clue coordinate and hot cold clues when single-way combat BRASSICAN_MAGE("Brassican Mage"), //appears for master clue coordinate and hot cold clues when multi-way combat diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java index 5c639b6205..84fa9bb01f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java @@ -27,7 +27,6 @@ package net.runelite.client.plugins.crowdsourcing; import java.time.temporal.ChronoUnit; import javax.inject.Inject; -import lombok.extern.slf4j.Slf4j; import net.runelite.client.eventbus.EventBus; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -40,7 +39,6 @@ import net.runelite.client.plugins.crowdsourcing.woodcutting.CrowdsourcingWoodcu import net.runelite.client.plugins.crowdsourcing.zmi.CrowdsourcingZMI; import net.runelite.client.task.Schedule; -@Slf4j @PluginDescriptor( name = "OSRS Wiki Crowdsourcing", description = "Send data to the wiki to help figure out skilling success rates, burn rates, more. See osrs.wiki/RS:CROWD" diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java index 208107e836..d7c293d0e9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java @@ -56,6 +56,7 @@ import net.runelite.api.Tile; import net.runelite.api.TileItem; import net.runelite.api.TileObject; import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetItem; @@ -134,9 +135,50 @@ class DevToolsOverlay extends Overlay renderGraphicsObjects(graphics); } + if (plugin.getRoofs().isActive()) + { + renderRoofs(graphics); + } + return null; } + private void renderRoofs(Graphics2D graphics) + { + Scene scene = client.getScene(); + Tile[][][] tiles = scene.getTiles(); + byte[][][] settings = client.getTileSettings(); + int z = client.getPlane(); + String text = "R"; + + for (int x = 0; x < Constants.SCENE_SIZE; ++x) + { + for (int y = 0; y < Constants.SCENE_SIZE; ++y) + { + Tile tile = tiles[z][x][y]; + + if (tile == null) + { + continue; + } + + int flag = settings[z][x][y]; + if ((flag & Constants.TILE_FLAG_UNDER_ROOF) == 0) + { + continue; + } + + Point loc = Perspective.getCanvasTextLocation(client, graphics, tile.getLocalLocation(), text, z); + if (loc == null) + { + continue; + } + + OverlayUtil.renderTextLocation(graphics, loc, text, Color.RED); + } + } + } + private void renderPlayers(Graphics2D graphics) { List players = client.getPlayers(); @@ -248,7 +290,11 @@ class DevToolsOverlay extends Overlay Polygon poly = Perspective.getCanvasTilePoly(client, tile.getLocalLocation()); if (poly != null && poly.contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY())) { - toolTipManager.add(new Tooltip("World Location: " + tile.getWorldLocation().getX() + ", " + tile.getWorldLocation().getY() + ", " + client.getPlane())); + WorldPoint worldLocation = tile.getWorldLocation(); + String tooltip = String.format("World location: %d, %d, %d
" + + "Region ID: %d location: %d, %d", worldLocation.getX(), worldLocation.getY(), worldLocation.getPlane(), + worldLocation.getRegionID(), worldLocation.getRegionX(), worldLocation.getRegionY()); + toolTipManager.add(new Tooltip(tooltip)); OverlayUtil.renderPolygon(graphics, poly, GREEN); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java index 516a92609f..34700e10cb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java @@ -180,6 +180,8 @@ class DevToolsPanel extends PluginPanel disconnectBtn.addActionListener(e -> clientThread.invoke(() -> client.setGameState(GameState.CONNECTION_LOST))); container.add(disconnectBtn); + container.add(plugin.getRoofs()); + try { ShellFrame sf = plugin.getInjector().getInstance(ShellFrame.class); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java index 9a7149ff77..64e12e7841 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java @@ -145,6 +145,7 @@ public class DevToolsPlugin extends Plugin private DevToolsButton soundEffects; private DevToolsButton scriptInspector; private DevToolsButton inventoryInspector; + private DevToolsButton roofs; private DevToolsButton shell; private NavigationButton navButton; @@ -191,6 +192,7 @@ public class DevToolsPlugin extends Plugin soundEffects = new DevToolsButton("Sound Effects"); scriptInspector = new DevToolsButton("Script Inspector"); inventoryInspector = new DevToolsButton("Inventory Inspector"); + roofs = new DevToolsButton("Roofs"); shell = new DevToolsButton("Shell"); overlayManager.add(overlay); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/VarInspector.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/VarInspector.java index 8b104e2035..2859112308 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/VarInspector.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/VarInspector.java @@ -45,7 +45,6 @@ import javax.swing.JScrollPane; import javax.swing.SwingUtilities; import javax.swing.border.CompoundBorder; import lombok.Getter; -import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.IndexDataBase; import net.runelite.api.VarClientInt; @@ -63,7 +62,6 @@ import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.DynamicGridLayout; import net.runelite.client.ui.FontManager; -@Slf4j class VarInspector extends DevToolsFrame { @Getter 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 788a284740..5359796536 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 @@ -289,7 +289,8 @@ enum DiscordGameEventType MG_CLAN_WARS("Clan Wars", DiscordAreaType.MINIGAMES, 12621, 12622, 12623, 13130, 13131, 13133, 13134, 13135, 13386, 13387, 13390, 13641, 13642, 13643, 13644, 13645, 13646, 13647, 13899, 13900, 14155, 14156), MG_DUEL_ARENA("Duel Arena", DiscordAreaType.MINIGAMES, 13362, 13363), MG_FISHING_TRAWLER("Fishing Trawler", DiscordAreaType.MINIGAMES, 7499), - MG_GAUNTLET("The Gauntlet", DiscordAreaType.MINIGAMES, 12127, 7512, 7768), + MG_GAUNTLET("The Gauntlet", DiscordAreaType.MINIGAMES, 12127, 7512), + MG_CORRUPTED_GAUNTLET("Corrupted Gauntlet", DiscordAreaType.MINIGAMES, 7768), MG_HALLOWED_SEPULCHRE("Hallowed Sepulchre", DiscordAreaType.MINIGAMES, 8797, 9051, 9052, 9053, 9054, 9309, 9563, 9565, 9821, 10074, 10075, 10077), MG_INFERNO("The Inferno", DiscordAreaType.MINIGAMES, 9043), MG_KELDAGRIM_RAT_PITS("Keldagrim Rat Pits", DiscordAreaType.MINIGAMES, 7753), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java index 0b926d30e0..f07a5a6bbc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java @@ -29,7 +29,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import lombok.Builder; import lombok.Data; -import lombok.Value; import net.runelite.api.coords.WorldPoint; @Data @@ -66,11 +65,4 @@ class GroundItem { return lootType != LootType.UNKNOWN; } - - @Value - static class GroundItemKey - { - private int itemId; - private WorldPoint location; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java index 96f454cd1c..01693334e1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -403,4 +403,26 @@ public interface GroundItemsConfig extends Config { return false; } + + @ConfigItem( + keyName = "showLootbeamForHighlighted", + name = "Highlighted item lootbeams", + description = "Configures lootbeams to show for all highlighted items.", + position = 30 + ) + default boolean showLootbeamForHighlighted() + { + return false; + } + + @ConfigItem( + keyName = "showLootbeamTier", + name = "Lootbeam tier", + description = "Configures which price tiers will trigger a lootbeam", + position = 31 + ) + default HighlightTier showLootbeamTier() + { + return HighlightTier.HIGH; + } } 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 e939470613..9fb512c688 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 @@ -49,6 +49,7 @@ import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.grounditems.GroundItemsPlugin.MAX_QUANTITY; import net.runelite.client.plugins.grounditems.config.DespawnTimerMode; import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.MENU; +import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.NONE; import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -107,7 +108,8 @@ public class GroundItemsOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - final boolean dontShowOverlay = (config.itemHighlightMode() == MENU || plugin.isHideAll()) && !plugin.isHotKeyPressed(); + final boolean dontShowOverlay = (config.itemHighlightMode() == MENU || config.itemHighlightMode() == NONE + || plugin.isHideAll()) && !plugin.isHotKeyPressed(); if (dontShowOverlay && !config.highlightTiles()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java index b7a8fc6500..a9e479885e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java @@ -28,7 +28,9 @@ package net.runelite.client.plugins.grounditems; import com.google.common.cache.CacheBuilder; import com.google.common.cache.LoadingCache; import com.google.common.collect.EvictingQueue; +import com.google.common.collect.HashBasedTable; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Table; import com.google.inject.Provides; import java.awt.Color; import java.awt.Rectangle; @@ -38,7 +40,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; @@ -71,6 +73,7 @@ import net.runelite.api.events.ItemSpawned; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuOptionClicked; import net.runelite.client.Notifier; +import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; @@ -83,7 +86,7 @@ import net.runelite.client.input.MouseManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.grounditems.config.HighlightTier; -import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.OVERLAY; +import net.runelite.client.plugins.grounditems.config.ItemHighlightMode; import net.runelite.client.plugins.grounditems.config.MenuHighlightMode; import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.BOTH; import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.NAME; @@ -158,6 +161,9 @@ public class GroundItemsPlugin extends Plugin @Inject private Client client; + @Inject + private ClientThread clientThread; + @Inject private ItemManager itemManager; @@ -177,12 +183,13 @@ public class GroundItemsPlugin extends Plugin private ScheduledExecutorService executor; @Getter - private final Map collectedGroundItems = new LinkedHashMap<>(); + private final Table collectedGroundItems = HashBasedTable.create(); private List priceChecks = ImmutableList.of(); private LoadingCache highlightedItems; private LoadingCache hiddenItems; private final Queue droppedItemQueue = EvictingQueue.create(16); // recently dropped items private int lastUsedItem; + private final Map lootbeams = new HashMap<>(); @Provides GroundItemsConfig provideConfig(ConfigManager configManager) @@ -213,6 +220,7 @@ public class GroundItemsPlugin extends Plugin hiddenItemList = null; highlightedItemsList = null; collectedGroundItems.clear(); + clientThread.invokeLater(this::removeAllLootbeams); } @Subscribe @@ -230,6 +238,7 @@ public class GroundItemsPlugin extends Plugin if (event.getGameState() == GameState.LOADING) { collectedGroundItems.clear(); + lootbeams.clear(); } } @@ -240,19 +249,23 @@ public class GroundItemsPlugin extends Plugin Tile tile = itemSpawned.getTile(); GroundItem groundItem = buildGroundItem(tile, item); - - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); - GroundItem existing = collectedGroundItems.putIfAbsent(groundItemKey, groundItem); + GroundItem existing = collectedGroundItems.get(tile.getWorldLocation(), item.getId()); if (existing != null) { existing.setQuantity(existing.getQuantity() + groundItem.getQuantity()); // The spawn time remains set at the oldest spawn } + else + { + collectedGroundItems.put(tile.getWorldLocation(), item.getId(), groundItem); + } if (!config.onlyShowLoot()) { notifyHighlightedItem(groundItem); } + + handleLootbeam(tile.getWorldLocation()); } @Subscribe @@ -261,8 +274,7 @@ public class GroundItemsPlugin extends Plugin TileItem item = itemDespawned.getItem(); Tile tile = itemDespawned.getTile(); - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); - GroundItem groundItem = collectedGroundItems.get(groundItemKey); + GroundItem groundItem = collectedGroundItems.get(tile.getWorldLocation(), item.getId()); if (groundItem == null) { return; @@ -270,7 +282,7 @@ public class GroundItemsPlugin extends Plugin if (groundItem.getQuantity() <= item.getQuantity()) { - collectedGroundItems.remove(groundItemKey); + collectedGroundItems.remove(tile.getWorldLocation(), item.getId()); } else { @@ -280,6 +292,8 @@ public class GroundItemsPlugin extends Plugin // time groundItem.setSpawnTime(null); } + + handleLootbeam(tile.getWorldLocation()); } @Subscribe @@ -291,12 +305,13 @@ public class GroundItemsPlugin extends Plugin int newQuantity = itemQuantityChanged.getNewQuantity(); int diff = newQuantity - oldQuantity; - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); - GroundItem groundItem = collectedGroundItems.get(groundItemKey); + GroundItem groundItem = collectedGroundItems.get(tile.getWorldLocation(), item.getId()); if (groundItem != null) { groundItem.setQuantity(groundItem.getQuantity() + diff); } + + handleLootbeam(tile.getWorldLocation()); } @Subscribe @@ -366,8 +381,7 @@ public class GroundItemsPlugin extends Plugin for (ItemStack itemStack : items) { WorldPoint location = WorldPoint.fromLocal(client, itemStack.getLocation()); - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(itemStack.getId(), location); - GroundItem groundItem = collectedGroundItems.get(groundItemKey); + GroundItem groundItem = collectedGroundItems.get(location, itemStack.getId()); if (groundItem != null) { groundItem.setLootType(lootType); @@ -460,12 +474,14 @@ public class GroundItemsPlugin extends Plugin } priceChecks = priceCheckBuilder.build(); + + clientThread.invokeLater(this::handleLootbeams); } @Subscribe public void onMenuEntryAdded(MenuEntryAdded event) { - if (config.itemHighlightMode() != OVERLAY) + if (config.itemHighlightMode() == ItemHighlightMode.MENU || config.itemHighlightMode() == ItemHighlightMode.BOTH) { final boolean telegrabEntry = event.getOption().equals("Cast") && event.getTarget().startsWith(TELEGRAB_TEXT) && event.getType() == CAST_ON_ITEM; if (!(event.getOption().equals("Take") && event.getType() == THIRD_OPTION) && !telegrabEntry) @@ -481,8 +497,7 @@ public class GroundItemsPlugin extends Plugin MenuEntry lastEntry = menuEntries[menuEntries.length - 1]; final WorldPoint worldPoint = WorldPoint.fromScene(client, sceneX, sceneY, client.getPlane()); - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(itemId, worldPoint); - GroundItem groundItem = collectedGroundItems.get(groundItemKey); + GroundItem groundItem = collectedGroundItems.get(worldPoint, itemId); int quantity = groundItem.getQuantity(); final int gePrice = groundItem.getGePrice(); @@ -705,4 +720,103 @@ public class GroundItemsPlugin extends Plugin lastUsedItem = clickedItem.getId(); } } + + private void handleLootbeam(WorldPoint worldPoint) + { + /* + * Return and remove the lootbeam from this location if lootbeam are disabled + * Lootbeam can be at this location if the config was just changed + */ + if (!(config.showLootbeamForHighlighted() || config.showLootbeamTier() != HighlightTier.OFF)) + { + removeLootbeam(worldPoint); + return; + } + + int price = -1; + Collection groundItems = collectedGroundItems.row(worldPoint).values(); + for (GroundItem groundItem : groundItems) + { + if ((config.onlyShowLoot() && !groundItem.isMine())) + { + continue; + } + + /* + * highlighted items have the highest priority so if an item is highlighted at this location + * we can early return + */ + NamedQuantity item = new NamedQuantity(groundItem); + if (config.showLootbeamForHighlighted() + && TRUE.equals(highlightedItems.getUnchecked(item))) + { + addLootbeam(worldPoint, config.highlightedColor()); + return; + } + + // Explicit hide takes priority over implicit highlight + if (TRUE.equals(hiddenItems.getUnchecked(item))) + { + continue; + } + + int itemPrice = getValueByMode(groundItem.getGePrice(), groundItem.getHaPrice()); + price = Math.max(itemPrice, price); + } + + if (config.showLootbeamTier() != HighlightTier.OFF) + { + for (PriceHighlight highlight : priceChecks) + { + if (price > highlight.getPrice() && price > config.showLootbeamTier().getValueFromTier(config)) + { + addLootbeam(worldPoint, highlight.color); + return; + } + } + } + + removeLootbeam(worldPoint); + } + + private void handleLootbeams() + { + for (WorldPoint worldPoint : collectedGroundItems.rowKeySet()) + { + handleLootbeam(worldPoint); + } + } + + private void removeAllLootbeams() + { + for (Lootbeam lootbeam : lootbeams.values()) + { + lootbeam.remove(); + } + + lootbeams.clear(); + } + + private void addLootbeam(WorldPoint worldPoint, Color color) + { + Lootbeam lootbeam = lootbeams.get(worldPoint); + if (lootbeam == null) + { + lootbeam = new Lootbeam(client, worldPoint, color); + lootbeams.put(worldPoint, lootbeam); + } + else + { + lootbeam.setColor(color); + } + } + + private void removeLootbeam(WorldPoint worldPoint) + { + Lootbeam lootbeam = lootbeams.remove(worldPoint); + if (lootbeam != null) + { + lootbeam.remove(); + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java new file mode 100644 index 0000000000..1d95a39dc1 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021, Trevor + * 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.grounditems; + +import net.runelite.api.AnimationID; +import net.runelite.api.Client; +import net.runelite.api.JagexColor; +import net.runelite.api.RuneLiteObject; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import java.awt.Color; + +class Lootbeam +{ + private static final int RAID_LIGHT_MODEL = 5809; + private static final short RAID_LIGHT_FIND_COLOR = 6371; + + private final RuneLiteObject runeLiteObject; + private final Client client; + private Color color; + + public Lootbeam(Client client, WorldPoint worldPoint, Color color) + { + this.client = client; + runeLiteObject = client.createRuneLiteObject(); + + setColor(color); + runeLiteObject.setAnimation(client.loadAnimation(AnimationID.RAID_LIGHT_ANIMATION)); + runeLiteObject.setShouldLoop(true); + + LocalPoint lp = LocalPoint.fromWorld(client, worldPoint); + runeLiteObject.setLocation(lp, client.getPlane()); + + runeLiteObject.setActive(true); + } + + public void setColor(Color color) + { + if (this.color != null && this.color.equals(color)) + { + return; + } + + this.color = color; + runeLiteObject.setModel(client.loadModel( + RAID_LIGHT_MODEL, + new short[]{RAID_LIGHT_FIND_COLOR}, + new short[]{JagexColor.rgbToHSL(color.getRGB(), 1.0d)} + )); + } + + public void remove() + { + runeLiteObject.setActive(false); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/ItemHighlightMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/ItemHighlightMode.java index 9b873a639e..23d7060ef9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/ItemHighlightMode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/ItemHighlightMode.java @@ -31,6 +31,7 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public enum ItemHighlightMode { + NONE("None"), OVERLAY("Overlay"), MENU("Right-click menu"), BOTH("Both"); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java index 8901ffaab9..934a0d1116 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java @@ -26,6 +26,8 @@ package net.runelite.client.plugins.itemidentification; import com.google.common.collect.ImmutableMap; import java.util.Map; +import java.util.function.Predicate; +import lombok.AllArgsConstructor; import net.runelite.api.ItemID; enum ItemIdentification @@ -364,7 +366,25 @@ enum ItemIdentification TARGET_TELEPORT(Type.TABLET, "Target", "TRG", ItemID.TARGET_TELEPORT), VOLCANIC_MINE_TELEPORT(Type.TABLET, "V.Mine", "VM", ItemID.VOLCANIC_MINE_TELEPORT), - WILDERNESS_CRABS_TELEPORT(Type.TABLET, "W.Crab", "CRAB", ItemID.WILDERNESS_CRABS_TELEPORT); + WILDERNESS_CRABS_TELEPORT(Type.TABLET, "W.Crab", "CRAB", ItemID.WILDERNESS_CRABS_TELEPORT), + + // Scrolls + NARDAH_TELEPORT(Type.SCROLL, "Nardah", "NAR", ItemID.NARDAH_TELEPORT), + DIGSITE_TELEPORT(Type.SCROLL, "Digsite", "DIG", ItemID.DIGSITE_TELEPORT), + FELDIP_HILLS_TELEPORT(Type.SCROLL, "F.Hills", "F.H", ItemID.FELDIP_HILLS_TELEPORT), + LUNAR_ISLE_TELEPORT(Type.SCROLL, "L.Isle", "L.I", ItemID.LUNAR_ISLE_TELEPORT), + MORTTON_TELEPORT(Type.SCROLL, "Mort'ton", "MORT", ItemID.MORTTON_TELEPORT), + PEST_CONTROL_TELEPORT(Type.SCROLL, "P.Cont", "PEST", ItemID.PEST_CONTROL_TELEPORT), + PISCATORIS_TELEPORT(Type.SCROLL, "Pisca", "PISC", ItemID.PISCATORIS_TELEPORT), + TAI_BWO_WANNAI_TELEPORT(Type.SCROLL, "TaiBwo", "TAI", ItemID.TAI_BWO_WANNAI_TELEPORT), + IORWERTH_CAMP_TELEPORT(Type.SCROLL, "Iorwerth", "IOR", ItemID.IORWERTH_CAMP_TELEPORT), + MOS_LEHARMLESS_TELEPORT(Type.SCROLL, "M.LeHarm", "M.L", ItemID.MOS_LEHARMLESS_TELEPORT), + LUMBERYARD_TELEPORT(Type.SCROLL, "Lumber", "LUMB", ItemID.LUMBERYARD_TELEPORT), + + ZUL_ANDRA_TELEPORT(Type.SCROLL, "Zul-andra", "ZUL", ItemID.ZULANDRA_TELEPORT), + KEY_MASTER_TELEPORT(Type.SCROLL, "Key master", "KEY", ItemID.KEY_MASTER_TELEPORT), + REVENANT_CAVE_TELEPORT(Type.SCROLL, "Rev cave", "REV", ItemID.REVENANT_CAVE_TELEPORT), + WATSON_TELEPORT(Type.SCROLL, "Watson", "WATS", ItemID.WATSON_TELEPORT); final Type type; final String medName; @@ -401,20 +421,24 @@ enum ItemIdentification return itemIdentifications.get(id); } + @AllArgsConstructor enum Type { - SEED, - SACK, - HERB, - LOGS, - PLANK, - SAPLING, - COMPOST, - ORE, - BAR, - GEM, - POTION, - IMPLING_JAR, - TABLET + SEED(ItemIdentificationConfig::showSeeds), + SACK(ItemIdentificationConfig::showSacks), + HERB(ItemIdentificationConfig::showHerbs), + LOGS(ItemIdentificationConfig::showLogs), + PLANK(ItemIdentificationConfig::showPlanks), + SAPLING(ItemIdentificationConfig::showSaplings), + COMPOST(ItemIdentificationConfig::showComposts), + ORE(ItemIdentificationConfig::showOres), + BAR(ItemIdentificationConfig::showBars), + GEM(ItemIdentificationConfig::showGems), + POTION(ItemIdentificationConfig::showPotions), + IMPLING_JAR(ItemIdentificationConfig::showImplingJars), + TABLET(ItemIdentificationConfig::showTablets), + SCROLL(ItemIdentificationConfig::showTeleportScrolls); + + final Predicate enabled; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationConfig.java index 8387e857f2..b1eb5135ea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationConfig.java @@ -203,4 +203,15 @@ public interface ItemIdentificationConfig extends Config { return false; } + + @ConfigItem( + keyName = "showTeleportScrolls", + name = "Teleport Scrolls", + description = "Show identification on teleport scrolls", + section = identificationSection + ) + default boolean showTeleportScrolls() + { + return false; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationOverlay.java index 2d8aeeb6f0..8ac2125237 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentificationOverlay.java @@ -58,93 +58,11 @@ class ItemIdentificationOverlay extends WidgetItemOverlay public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem) { ItemIdentification iden = findItemIdentification(itemId); - if (iden == null) + if (iden == null || !iden.type.enabled.test(config)) { return; } - switch (iden.type) - { - case SEED: - if (!config.showSeeds()) - { - return; - } - break; - case SACK: - if (!config.showSacks()) - { - return; - } - break; - case HERB: - if (!config.showHerbs()) - { - return; - } - break; - case LOGS: - if (!config.showLogs()) - { - return; - } - break; - case PLANK: - if (!config.showPlanks()) - { - return; - } - break; - case SAPLING: - if (!config.showSaplings()) - { - return; - } - break; - case COMPOST: - if (!config.showComposts()) - { - return; - } - break; - case ORE: - if (!config.showOres()) - { - return; - } - break; - case BAR: - if (!config.showBars()) - { - return; - } - break; - case GEM: - if (!config.showGems()) - { - return; - } - break; - case POTION: - if (!config.showPotions()) - { - return; - } - break; - case IMPLING_JAR: - if (!config.showImplingJars()) - { - return; - } - break; - case TABLET: - if (!config.showTablets()) - { - return; - } - break; - } - graphics.setFont(FontManager.getRunescapeSmallFont()); renderText(graphics, widgetItem.getCanvasBounds(), iden); } 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 6af10eb5b8..bb3d0f9fc6 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 @@ -247,6 +247,8 @@ public class MenuEntrySwapperPlugin extends Plugin swap("inspect", "trapdoor", "travel", config::swapTravel); swap("board", "travel cart", "pay-fare", config::swapTravel); + swap("board", "sacrificial boat", "quick-board", config::swapQuick); + swap("cage", "harpoon", config::swapHarpoon); swap("big net", "harpoon", config::swapHarpoon); swap("net", "harpoon", config::swapHarpoon); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mining/Pickaxe.java b/runelite-client/src/main/java/net/runelite/client/plugins/mining/Pickaxe.java index 9ad4604607..1e27566b01 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mining/Pickaxe.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mining/Pickaxe.java @@ -25,7 +25,10 @@ package net.runelite.client.plugins.mining; import com.google.common.collect.ImmutableMap; +import java.util.Arrays; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import lombok.Getter; import static net.runelite.api.AnimationID.MINING_3A_PICKAXE; import static net.runelite.api.AnimationID.MINING_ADAMANT_PICKAXE; @@ -135,4 +138,11 @@ enum Pickaxe { return PICKAXE_ANIM_IDS.get(animId); } + + public static Set all() + { + return Arrays.stream(values()) + .map(pickaxe -> pickaxe.itemId) + .collect(Collectors.toSet()); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java index 63dbc6274d..36081a3e10 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java @@ -42,7 +42,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; -import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.GameState; @@ -86,7 +85,6 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.tooltip.Tooltip; import net.runelite.client.ui.overlay.tooltip.TooltipManager; -@Slf4j @PluginDescriptor( name = "Music", description = "Adds search and filter for the music list, and additional volume control", @@ -750,7 +748,7 @@ public class MusicPlugin extends Plugin s.update(); s.getChannel().setWindowSlider(s); } - + if (ev.getScriptId() == ScriptID.TOPLEVEL_REDRAW && musicConfig.granularSliders()) { // we have to set the var to our value so toplevel_redraw doesn't try to set @@ -859,11 +857,12 @@ public class MusicPlugin extends Plugin windowSlider.update(); } } - + public void updateVar() { int val = getValue(); - client.getVarps()[this.var.getId()] = val * 100 / this.max; + int varVal = Math.round((float) val / (max / 100.f)); + client.getVarps()[this.var.getId()] = varVal; } public void shutDown() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/reportbutton/ReportButtonPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/reportbutton/ReportButtonPlugin.java index 8ad7c9d8ec..04145be754 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/reportbutton/ReportButtonPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/reportbutton/ReportButtonPlugin.java @@ -37,6 +37,7 @@ import java.time.temporal.ChronoUnit; import java.util.Date; import javax.inject.Inject; import net.runelite.api.Client; +import net.runelite.api.Constants; import net.runelite.api.GameState; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; @@ -49,6 +50,7 @@ import net.runelite.client.events.ConfigChanged; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.task.Schedule; +import org.apache.commons.lang3.time.DurationFormatUtils; @PluginDescriptor( name = "Report Button", @@ -180,6 +182,9 @@ public class ReportButtonPlugin extends Plugin case LOGIN_TIME: reportButton.setText(getLoginTime()); break; + case IDLE_TIME: + reportButton.setText(getIdleTime()); + break; case DATE: reportButton.setText(getDate()); break; @@ -192,6 +197,12 @@ public class ReportButtonPlugin extends Plugin } } + private String getIdleTime() + { + long lastActivity = Long.min(client.getMouseIdleTicks(), client.getKeyboardIdleTicks()); + return DurationFormatUtils.formatDuration(lastActivity * Constants.CLIENT_TICK_LENGTH, "mm:ss"); + } + private String getLoginTime() { if (loginTime == null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/reportbutton/TimeStyle.java b/runelite-client/src/main/java/net/runelite/client/plugins/reportbutton/TimeStyle.java index a6a0a9a617..58307a70ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/reportbutton/TimeStyle.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/reportbutton/TimeStyle.java @@ -32,7 +32,8 @@ public enum TimeStyle UTC("UTC Time"), JAGEX("Jagex HQ Time"), LOCAL_TIME("Local Time"), - GAME_TICKS("Game Ticks"); + GAME_TICKS("Game Ticks"), + IDLE_TIME("Idle Time"); private final String name; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfig.java new file mode 100644 index 0000000000..39bf615853 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfig.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021, Hydrox6 + * 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.roofremoval; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup(RoofRemovalConfig.CONFIG_GROUP) +public interface RoofRemovalConfig extends Config +{ + String CONFIG_GROUP = "roofremoval"; + + @ConfigItem( + keyName = "removePosition", + name = "Player's position", + description = "Remove roofs above the player's position" + ) + default boolean removePosition() + { + return true; + } + + @ConfigItem( + keyName = "removeHovered", + name = "Hovered tile", + description = "Remove roofs above the hovered tile" + ) + default boolean removeHovered() + { + return true; + } + + @ConfigItem( + keyName = "removeDestination", + name = "Destination tile", + description = "Remove roofs above the destination tile" + ) + default boolean removeDestination() + { + return true; + } + + @ConfigItem( + keyName = "removeBetween", + name = "Between camera & player", + description = "Remove roofs between the camera and the player at low camera angles" + ) + default boolean removeBetween() + { + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java new file mode 100644 index 0000000000..a9e92f4420 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2021 Hydrox6 + * 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.roofremoval; + +import com.google.common.base.Stopwatch; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.inject.Provides; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.Constants; +import static net.runelite.api.Constants.ROOF_FLAG_BETWEEN; +import static net.runelite.api.Constants.ROOF_FLAG_DESTINATION; +import static net.runelite.api.Constants.ROOF_FLAG_HOVERED; +import static net.runelite.api.Constants.ROOF_FLAG_POSITION; +import net.runelite.api.GameState; +import net.runelite.api.Tile; +import net.runelite.api.events.GameStateChanged; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; + +@PluginDescriptor( + name = "Roof Removal", + description = "Remove only the needed roofs above your player, hovered tile, or destination", + enabledByDefault = false +) +@Slf4j +public class RoofRemovalPlugin extends Plugin +{ + private static class FlaggedArea + { + int rx1; + int ry1; + int rx2; + int ry2; + int z1; + int z2; + } + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private Gson gson; + + @Inject + private RoofRemovalConfig config; + + private final Map overrides = new HashMap<>(); + + @Provides + RoofRemovalConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(RoofRemovalConfig.class); + } + + @Override + public void startUp() throws IOException + { + loadRoofOverrides(); + clientThread.invoke(() -> + { + if (client.getGameState() == GameState.LOGGED_IN) + { + performRoofRemoval(); + } + client.getScene().setRoofRemovalMode(buildRoofRemovalFlags()); + }); + } + + @Override + public void shutDown() + { + overrides.clear(); + clientThread.invoke(() -> + { + client.getScene().setRoofRemovalMode(0); + // Reload the scene to clear roof flag overrides + if (client.getGameState() == GameState.LOGGED_IN) + { + client.setGameState(GameState.LOADING); + } + }); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged e) + { + if (e.getGameState() == GameState.LOGGED_IN) + { + performRoofRemoval(); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged e) + { + if (!e.getGroup().equals(RoofRemovalConfig.CONFIG_GROUP)) + { + return; + } + + client.getScene().setRoofRemovalMode(buildRoofRemovalFlags()); + } + + private int buildRoofRemovalFlags() + { + int roofRemovalMode = 0; + if (config.removePosition()) + { + roofRemovalMode |= ROOF_FLAG_POSITION; + } + if (config.removeHovered()) + { + roofRemovalMode |= ROOF_FLAG_HOVERED; + } + if (config.removeDestination()) + { + roofRemovalMode |= ROOF_FLAG_DESTINATION; + } + if (config.removeBetween()) + { + roofRemovalMode |= ROOF_FLAG_BETWEEN; + } + return roofRemovalMode; + } + + private void performRoofRemoval() + { + assert client.isClientThread(); + applyRoofOverrides(); + + Stopwatch sw = Stopwatch.createStarted(); + client.getScene().generateHouses(); + log.debug("House generation duration: {}", sw.stop()); + } + + private void loadRoofOverrides() throws IOException + { + try (InputStream in = getClass().getResourceAsStream("overrides.jsonc")) + { + final InputStreamReader data = new InputStreamReader(in, StandardCharsets.UTF_8); + //CHECKSTYLE:OFF + final Type type = new TypeToken>>() {}.getType(); + //CHECKSTYLE:ON + Map> parsed = gson.fromJson(data, type); + overrides.clear(); + for (Map.Entry> entry : parsed.entrySet()) + { + for (FlaggedArea fla : entry.getValue()) + { + for (int z = fla.z1; z <= fla.z2; z++) + { + // Given that each region is 64x64, and the override data is a boolean, one of the axis can be stored as + // bits in a long. This removes the need for a boolean[64][64] and an extra array lookup in favour of + // a bitwise &, and results in a consistently smaller amount of memory required to store the overrides. + int packedRegion = entry.getKey() << 2 | z; + long[] regionData = overrides.computeIfAbsent(packedRegion, k -> new long[Constants.REGION_SIZE]); + for (int y = fla.ry1; y <= fla.ry2; y++) + { + long row = regionData[y]; + for (int x = fla.rx1; x <= fla.rx2; x++) + { + row |= (1L << x); + } + regionData[y] = row; + } + } + } + } + } + } + + private void applyRoofOverrides() + { + Stopwatch sw = Stopwatch.createStarted(); + boolean regionsHaveOverrides = false; + + outer: + for (int regionID : client.getMapRegions()) + { + for (int z = 0; z < Constants.MAX_Z; z++) + { + if (overrides.containsKey(regionID << 2 | z)) + { + regionsHaveOverrides = true; + break outer; + } + } + } + if (!regionsHaveOverrides) + { + return; + } + + Tile[][][] tiles = client.getScene().getTiles(); + byte[][][] settings = client.getTileSettings(); + + for (int z = 0; z < Constants.MAX_Z; z++) + { + for (int x = 0; x < Constants.SCENE_SIZE; x++) + { + for (int y = 0; y < Constants.SCENE_SIZE; y++) + { + Tile tile = tiles[z][x][y]; + if (tile == null) + { + continue; + } + + int regionID = tile.getWorldLocation().getRegionID() << 2 | z; + if (!overrides.containsKey(regionID)) + { + continue; + } + + int rx = tile.getWorldLocation().getRegionX(); + int ry = tile.getWorldLocation().getRegionY(); + long[] region = overrides.get(regionID); + if ((region[ry] & (1L << rx)) != 0) + { + settings[z][x][y] |= Constants.TILE_FLAG_UNDER_ROOF; + } + } + } + } + log.debug("Roof override duration: {}", sw.stop()); + } +} 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 58f0942de2..8cc18aa550 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 @@ -520,12 +520,12 @@ public class SlayerPlugin extends Plugin log.debug("Slayer xp change delta: {}, killed npcs: {}", delta, taggedNpcsDiedPrevTick); final Task task = Task.getTask(taskName); - if (task != null && task.getExpectedKillExp() > 0) + if (task != null && task.getMinimumKillXp() > 0) { - // Only decrement a kill if the xp drop matches the expected drop. This is just for Tzhaar tasks. - if (task.getExpectedKillExp() == delta) + // Only decrement a kill if the xp drop is above the minimum threshold. This is for Tzhaar and Sire tasks. + if (delta >= task.getMinimumKillXp()) { - killed(1); + killed(max(taggedNpcsDiedPrevTick, 1)); } } else diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java index 29867dc042..bb90740f61 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java @@ -39,8 +39,12 @@ enum Task { // ABERRANT_SPECTRES("Aberrant spectres", ItemID.ABERRANT_SPECTRE, "Spectre"), - ABYSSAL_DEMONS("Abyssal demons", ItemID.ABYSSAL_DEMON), - ABYSSAL_SIRE("Abyssal Sire", ItemID.ABYSSAL_ORPHAN), + // Abyssal demon - 150 xp + // Greater abyssal demon - 4200 xp + // Abyssal sire - 450 xp + // Use 51 for minimum xp to avoid a kill triggering from killing the sire vents + ABYSSAL_DEMONS("Abyssal demons", ItemID.ABYSSAL_DEMON, 51), + ABYSSAL_SIRE("Abyssal Sire", ItemID.ABYSSAL_ORPHAN, 51), ADAMANT_DRAGONS("Adamant dragons", ItemID.ADAMANT_DRAGON_MASK), ALCHEMICAL_HYDRA("Alchemical Hydra", ItemID.IKKLE_HYDRA), ANKOU("Ankou", ItemID.ANKOU_MASK), @@ -238,7 +242,7 @@ enum Task private final String[] targetNames; private final int weaknessThreshold; private final int weaknessItem; - private final int expectedKillExp; + private final int minimumKillXp; static { @@ -260,7 +264,7 @@ enum Task this.weaknessThreshold = -1; this.weaknessItem = -1; this.targetNames = targetNames; - this.expectedKillExp = 0; + this.minimumKillXp = 0; } Task(String name, int itemSpriteId, int weaknessThreshold, int weaknessItem, String... targetNames) @@ -271,10 +275,10 @@ enum Task this.weaknessThreshold = weaknessThreshold; this.weaknessItem = weaknessItem; this.targetNames = targetNames; - this.expectedKillExp = 0; + this.minimumKillXp = 0; } - Task(String name, int itemSpriteId, int expectedKillExp) + Task(String name, int itemSpriteId, int minimumKillXp) { Preconditions.checkArgument(itemSpriteId >= 0); this.name = name; @@ -282,7 +286,7 @@ enum Task this.weaknessThreshold = -1; this.weaknessItem = -1; this.targetNames = new String[0]; - this.expectedKillExp = expectedKillExp; + this.minimumKillXp = minimumKillXp; } @Nullable diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsConfig.java index 0624edbdc6..cbce85bab4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsConfig.java @@ -27,11 +27,14 @@ package net.runelite.client.plugins.statusbars; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; import net.runelite.client.plugins.statusbars.config.BarMode; -@ConfigGroup("statusbars") +@ConfigGroup(StatusBarsConfig.GROUP) public interface StatusBarsConfig extends Config { + String GROUP = "statusbars"; + @ConfigItem( keyName = "enableCounter", name = "Show counters", @@ -81,4 +84,15 @@ public interface StatusBarsConfig extends Config { return BarMode.PRAYER; } + + @ConfigItem( + keyName = "hideAfterCombatDelay", + name = "Hide after combat delay", + description = "Amount of ticks before hiding status bars after no longer in combat. 0 = always show status bars." + ) + @Units(Units.TICKS) + default int hideAfterCombatDelay() + { + return 0; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsOverlay.java index 3710944577..c406bf0d1f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsOverlay.java @@ -80,6 +80,7 @@ class StatusBarsOverlay extends Overlay private static final int MAX_RUN_ENERGY_VALUE = 100; private final Client client; + private final StatusBarsPlugin plugin; private final StatusBarsConfig config; private final ItemStatChangesService itemStatService; private final SpriteManager spriteManager; @@ -94,11 +95,12 @@ class StatusBarsOverlay extends Overlay private final Map barRenderers = new EnumMap<>(BarMode.class); @Inject - private StatusBarsOverlay(Client client, StatusBarsConfig config, SkillIconManager skillIconManager, ItemStatChangesService itemstatservice, SpriteManager spriteManager) + private StatusBarsOverlay(Client client, StatusBarsPlugin plugin, StatusBarsConfig config, SkillIconManager skillIconManager, ItemStatChangesService itemstatservice, SpriteManager spriteManager) { setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_WIDGETS); this.client = client; + this.plugin = plugin; this.config = config; this.itemStatService = itemstatservice; this.spriteManager = spriteManager; @@ -216,6 +218,11 @@ class StatusBarsOverlay extends Overlay @Override public Dimension render(Graphics2D g) { + if (!plugin.isBarsDisplayed()) + { + return null; + } + Viewport curViewport = null; Widget curWidget = null; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsPlugin.java index cb36b42d0d..21e9553b5d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsPlugin.java @@ -26,12 +26,24 @@ package net.runelite.client.plugins.statusbars; import javax.inject.Inject; import com.google.inject.Provides; +import lombok.AccessLevel; +import lombok.Getter; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.Player; +import net.runelite.api.Varbits; +import net.runelite.api.events.GameTick; +import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDependency; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.itemstats.ItemStatPlugin; import net.runelite.client.ui.overlay.OverlayManager; +import org.apache.commons.lang3.ArrayUtils; @PluginDescriptor( name = "Status Bars", @@ -47,9 +59,24 @@ public class StatusBarsPlugin extends Plugin @Inject private OverlayManager overlayManager; + @Inject + private Client client; + + @Inject + private StatusBarsConfig config; + + @Inject + private ClientThread clientThread; + + @Getter(AccessLevel.PACKAGE) + private boolean barsDisplayed; + + private int lastCombatActionTickCount; + @Override protected void startUp() throws Exception { + clientThread.invokeLater(this::checkStatusBars); overlayManager.add(overlay); } @@ -57,6 +84,7 @@ public class StatusBarsPlugin extends Plugin protected void shutDown() throws Exception { overlayManager.remove(overlay); + barsDisplayed = false; } @Provides @@ -64,4 +92,45 @@ public class StatusBarsPlugin extends Plugin { return configManager.getConfig(StatusBarsConfig.class); } + + @Subscribe + public void onGameTick(GameTick gameTick) + { + checkStatusBars(); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (StatusBarsConfig.GROUP.equals(event.getGroup()) && event.getKey().equals("hideAfterCombatDelay")) + { + clientThread.invokeLater(this::checkStatusBars); + } + } + + private void checkStatusBars() + { + final Player localPlayer = client.getLocalPlayer(); + if (localPlayer == null) + { + return; + } + + final Actor interacting = localPlayer.getInteracting(); + + if (config.hideAfterCombatDelay() == 0) + { + barsDisplayed = true; + } + else if ((interacting instanceof NPC && ArrayUtils.contains(((NPC) interacting).getComposition().getActions(), "Attack")) + || (interacting instanceof Player && client.getVar(Varbits.PVP_SPEC_ORB) == 1)) + { + lastCombatActionTickCount = client.getTickCount(); + barsDisplayed = true; + } + else if (client.getTickCount() - lastCombatActionTickCount >= config.hideAfterCombatDelay()) + { + barsDisplayed = false; + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java index 9fa302e6d4..6278889dde 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java @@ -45,6 +45,7 @@ enum GameTimer EXANTIFIRE(ItemID.EXTENDED_ANTIFIRE4, GameTimerImageType.ITEM, "Extended antifire", 12, ChronoUnit.MINUTES), OVERLOAD(ItemID.OVERLOAD_4, GameTimerImageType.ITEM, "Overload", 5, ChronoUnit.MINUTES, true), CANNON(ItemID.CANNON_BARRELS, GameTimerImageType.ITEM, "Cannon", 25, ChronoUnit.MINUTES), + CANNON_REPAIR(ItemID.TOOLKIT, GameTimerImageType.ITEM, "Broken Cannon", 10, ChronoUnit.MINUTES), MAGICIMBUE(SpriteID.SPELL_MAGIC_IMBUE, GameTimerImageType.SPRITE, "Magic imbue", 21, GAME_TICKS), SUPERANTIFIRE(ItemID.SUPER_ANTIFIRE_POTION4, GameTimerImageType.ITEM, "Super antifire", 3, ChronoUnit.MINUTES), BIND(SpriteID.SPELL_BIND, GameTimerImageType.SPRITE, "Bind", GraphicID.BIND, 8, GAME_TICKS, true), @@ -85,7 +86,9 @@ enum GameTimer RESURRECT_THRALL_COOLDOWN(SpriteID.SPELL_RESURRECT_SUPERIOR_SKELETON_DISABLED, GameTimerImageType.SPRITE, "Resurrect thrall cooldown", 12, GAME_TICKS), WARD_OF_ARCEUUS_COOLDOWN(SpriteID.SPELL_WARD_OF_ARCEUUS_DISABLED, GameTimerImageType.SPRITE, "Ward of Arceuus cooldown", 30, ChronoUnit.SECONDS), DEATH_CHARGE_COOLDOWN(SpriteID.SPELL_DEATH_CHARGE_DISABLED, GameTimerImageType.SPRITE, "Death charge cooldown", 60, ChronoUnit.SECONDS), - CORRUPTION_COOLDOWN(SpriteID.SPELL_GREATER_CORRUPTION_DISABLED, GameTimerImageType.SPRITE, "Corruption cooldown", 30, ChronoUnit.SECONDS); + CORRUPTION_COOLDOWN(SpriteID.SPELL_GREATER_CORRUPTION_DISABLED, GameTimerImageType.SPRITE, "Corruption cooldown", 30, ChronoUnit.SECONDS), + PICKPOCKET_STUN(SpriteID.SKILL_THIEVING, GameTimerImageType.SPRITE, "Stunned", true) + ; @Nullable private final Duration duration; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersConfig.java index 5874b62125..b7c0245187 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersConfig.java @@ -283,4 +283,14 @@ public interface TimersConfig extends Config { return false; } + + @ConfigItem( + keyName = "showPickpocketStun", + name = "Pickpocket stun timer", + description = "Configures whether pickpocket stun timer is displayed" + ) + default boolean showPickpocketStun() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java index 5f71fb4e40..8efa8c2ed5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java @@ -55,7 +55,6 @@ import net.runelite.api.Varbits; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ActorDeath; import net.runelite.api.events.AnimationChanged; -import net.runelite.api.events.StatChanged; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; @@ -63,6 +62,7 @@ import net.runelite.api.events.GraphicChanged; import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.NpcDespawned; +import net.runelite.api.events.StatChanged; import net.runelite.api.events.VarbitChanged; import net.runelite.api.widgets.Widget; import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE; @@ -82,7 +82,7 @@ import org.apache.commons.lang3.ArrayUtils; @PluginDescriptor( name = "Timers", description = "Show various timers in an infobox", - tags = {"combat", "items", "magic", "potions", "prayer", "overlay", "abyssal", "sire", "inferno", "fight", "caves", "cape", "timer", "tzhaar"} + tags = {"combat", "items", "magic", "potions", "prayer", "overlay", "abyssal", "sire", "inferno", "fight", "caves", "cape", "timer", "tzhaar", "thieving", "pickpocket"} ) @Slf4j public class TimersPlugin extends Plugin @@ -90,10 +90,14 @@ public class TimersPlugin extends Plugin private static final String ABYSSAL_SIRE_STUN_MESSAGE = "The Sire has been disorientated temporarily."; private static final String ANTIFIRE_DRINK_MESSAGE = "You drink some of your antifire potion."; private static final String ANTIFIRE_EXPIRED_MESSAGE = "Your antifire potion has expired."; + private static final String CANNON_BASE_MESSAGE = "You place the cannon base on the ground."; + private static final String CANNON_STAND_MESSAGE = "You add the stand."; + private static final String CANNON_BARRELS_MESSAGE = "You add the barrels."; private static final String CANNON_FURNACE_MESSAGE = "You add the furnace."; private static final String CANNON_PICKUP_MESSAGE = "You pick up the cannon. It's really heavy."; private static final String CANNON_REPAIR_MESSAGE = "You repair your cannon, restoring it to working order."; private static final String CANNON_DESTROYED_MESSAGE = "Your cannon has been destroyed!"; + private static final String CANNON_BROKEN_MESSAGE = "Your cannon has broken!"; private static final String CHARGE_EXPIRED_MESSAGE = "Your magical charge fades away."; private static final String CHARGE_MESSAGE = "You feel charged with magic power."; private static final String EXTENDED_ANTIFIRE_DRINK_MESSAGE = "You drink some of your extended antifire potion."; @@ -122,6 +126,7 @@ public class TimersPlugin extends Plugin private static final String RESURRECT_THRALL_DISAPPEAR_MESSAGE_START = ">Your "; private static final String RESURRECT_THRALL_DISAPPEAR_MESSAGE_END = " thrall returns to the grave."; private static final String WARD_OF_ARCEUUS_MESSAGE = ">Your defence against Arceuus magic has been strengthened."; + private static final String PICKPOCKET_FAILURE_MESSAGE = "You fail to pick the "; private static final Pattern TELEBLOCK_PATTERN = Pattern.compile("A Tele Block spell has been cast on you(?: by .+)?\\. It will expire in (?\\d+) minutes?(?:, (?\\d+) seconds?)?\\."); private static final Pattern DIVINE_POTION_PATTERN = Pattern.compile("You drink some of your divine (.+) potion\\."); @@ -498,6 +503,18 @@ public class TimersPlugin extends Plugin return; } + if (message.contains(PICKPOCKET_FAILURE_MESSAGE) && config.showPickpocketStun() && message.contains("pocket")) + { + if (message.contains("hero") || message.contains("elf")) + { + createGameTimer(PICKPOCKET_STUN, Duration.ofSeconds(6)); + } + else + { + createGameTimer(PICKPOCKET_STUN, Duration.ofSeconds(5)); + } + } + if (message.equals(ABYSSAL_SIRE_STUN_MESSAGE) && config.showAbyssalSireStun()) { createGameTimer(ABYSSAL_SIRE_STUN); @@ -559,15 +576,27 @@ public class TimersPlugin extends Plugin } - if (config.showCannon() && (message.equals(CANNON_FURNACE_MESSAGE) || message.contains(CANNON_REPAIR_MESSAGE))) + if (config.showCannon()) { - TimerTimer cannonTimer = createGameTimer(CANNON); - cannonTimer.setTooltip(cannonTimer.getTooltip() + " - World " + client.getWorld()); - } - - if (config.showCannon() && (message.equals(CANNON_PICKUP_MESSAGE) || message.equals(CANNON_DESTROYED_MESSAGE))) - { - removeGameTimer(CANNON); + if (message.equals(CANNON_BASE_MESSAGE) || message.equals(CANNON_STAND_MESSAGE) + || message.equals(CANNON_BARRELS_MESSAGE) || message.equals(CANNON_FURNACE_MESSAGE) + || message.contains(CANNON_REPAIR_MESSAGE)) + { + removeGameTimer(CANNON_REPAIR); + TimerTimer cannonTimer = createGameTimer(CANNON); + cannonTimer.setTooltip(cannonTimer.getTooltip() + " - World " + client.getWorld()); + } + else if (message.equals(CANNON_BROKEN_MESSAGE)) + { + removeGameTimer(CANNON); + TimerTimer cannonTimer = createGameTimer(CANNON_REPAIR); + cannonTimer.setTooltip(cannonTimer.getTooltip() + " - World " + client.getWorld()); + } + else if (message.equals(CANNON_PICKUP_MESSAGE) || message.equals(CANNON_DESTROYED_MESSAGE)) + { + removeGameTimer(CANNON); + removeGameTimer(CANNON_REPAIR); + } } if (config.showMagicImbue() && message.equals(MAGIC_IMBUE_MESSAGE)) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/OverviewTabPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/OverviewTabPanel.java index 8ac4c9979e..3fbe3ac505 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/OverviewTabPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/OverviewTabPanel.java @@ -31,10 +31,10 @@ import java.time.Instant; import java.util.Map; import java.util.function.Function; import java.util.stream.Stream; -import javax.annotation.Nullable; import net.runelite.api.ItemID; import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.timetracking.clocks.ClockManager; +import net.runelite.client.plugins.timetracking.farming.CropState; import net.runelite.client.plugins.timetracking.farming.FarmingContractManager; import net.runelite.client.plugins.timetracking.farming.FarmingTracker; import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker; @@ -124,14 +124,13 @@ class OverviewTabPanel extends TabContentPanel } farmingOverviews.forEach((patchType, panel) -> - updateItemPanel(panel, farmingTracker.getSummary(patchType), farmingTracker.getCompletionTime(patchType), null)); + updateItemPanel(panel, farmingTracker.getSummary(patchType), farmingTracker.getCompletionTime(patchType))); - updateItemPanel(birdHouseOverview, birdHouseTracker.getSummary(), birdHouseTracker.getCompletionTime(), null); - updateItemPanel(farmingContractOverview, farmingContractManager.getSummary(), farmingContractManager.getCompletionTime(), - farmingContractManager.getContractName()); + updateItemPanel(birdHouseOverview, birdHouseTracker.getSummary(), birdHouseTracker.getCompletionTime()); + updateContractPanel(); } - private void updateItemPanel(OverviewItemPanel panel, SummaryState summary, long completionTime, @Nullable String farmingContract) + private void updateItemPanel(OverviewItemPanel panel, SummaryState summary, long completionTime) { switch (summary) { @@ -151,10 +150,7 @@ class OverviewTabPanel extends TabContentPanel break; } case EMPTY: - panel.updateStatus(farmingContract == null ? "Empty" : farmingContract, Color.GRAY); - break; - case OCCUPIED: - panel.updateStatus(farmingContract == null ? "" : farmingContract, Color.RED); + panel.updateStatus("Empty", Color.GRAY); break; case UNKNOWN: default: @@ -162,4 +158,45 @@ class OverviewTabPanel extends TabContentPanel break; } } + + private void updateContractPanel() + { + switch (farmingContractManager.getSummary()) + { + case COMPLETED: + case IN_PROGRESS: + switch (farmingContractManager.getContractCropState()) + { + case HARVESTABLE: + case GROWING: + long duration = farmingContractManager.getCompletionTime() - Instant.now().getEpochSecond(); + + if (duration <= 0) + { + farmingContractOverview.updateStatus("Ready", ColorScheme.PROGRESS_COMPLETE_COLOR); + return; + } + + farmingContractOverview.updateStatus("Ready " + getFormattedEstimate(duration, config.timeFormatMode()), Color.GRAY); + return; + case DISEASED: + farmingContractOverview.updateStatus("Diseased", CropState.DISEASED.getColor()); + return; + case DEAD: + farmingContractOverview.updateStatus("Dead", CropState.DEAD.getColor()); + return; + } + // fallthrough + case UNKNOWN: + default: + farmingContractOverview.updateStatus("Unknown", Color.GRAY); + return; + case EMPTY: + farmingContractOverview.updateStatus(farmingContractManager.getContractName(), Color.GRAY); + return; + case OCCUPIED: + farmingContractOverview.updateStatus(farmingContractManager.getContractName(), Color.RED); + return; + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TabContentPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TabContentPanel.java index 88b6362e26..b24f108182 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TabContentPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TabContentPanel.java @@ -24,13 +24,16 @@ */ package net.runelite.client.plugins.timetracking; +import java.time.DateTimeException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.format.TextStyle; import java.time.temporal.ChronoUnit; import java.util.Locale; import javax.swing.JPanel; +import lombok.extern.slf4j.Slf4j; +@Slf4j public abstract class TabContentPanel extends JPanel { private static final DateTimeFormatter DATETIME_FORMATTER_24H = DateTimeFormatter.ofPattern("HH:mm"); @@ -72,17 +75,25 @@ public abstract class TabContentPanel extends JPanel } else { - StringBuilder sb = new StringBuilder(); - LocalDateTime endTime = LocalDateTime.now().plus(remainingSeconds, ChronoUnit.SECONDS); - LocalDateTime currentTime = LocalDateTime.now(); - if (endTime.getDayOfWeek() != currentTime.getDayOfWeek()) + try { - sb.append(endTime.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.getDefault())).append(" "); - } - sb.append("at "); - sb.append(formatter.format(endTime)); + StringBuilder sb = new StringBuilder(); + LocalDateTime endTime = LocalDateTime.now().plus(remainingSeconds, ChronoUnit.SECONDS); + LocalDateTime currentTime = LocalDateTime.now(); + if (endTime.getDayOfWeek() != currentTime.getDayOfWeek()) + { + sb.append(endTime.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.getDefault())).append(" "); + } + sb.append("at "); + sb.append(formatter.format(endTime)); - return sb.toString(); + return sb.toString(); + } + catch (DateTimeException e) + { + log.warn("error formatting absolute time: now + {}", remainingSeconds, e); + return "Invalid"; + } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeablePanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeablePanel.java index 9796146500..1a8b23a8fa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeablePanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeablePanel.java @@ -35,7 +35,6 @@ import javax.swing.JPanel; import javax.swing.JToggleButton; import javax.swing.border.EmptyBorder; import lombok.Getter; -import lombok.extern.slf4j.Slf4j; import net.runelite.api.Constants; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.FontManager; @@ -44,7 +43,6 @@ import net.runelite.client.ui.components.shadowlabel.JShadowedLabel; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.SwingUtil; -@Slf4j @Getter public class TimeablePanel extends JPanel { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTabPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTabPanel.java index 18d525c1e0..1d16cbeae5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTabPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTabPanel.java @@ -35,7 +35,6 @@ import java.util.Set; import javax.swing.JLabel; import javax.swing.JToggleButton; import javax.swing.border.EmptyBorder; -import lombok.extern.slf4j.Slf4j; import net.runelite.api.ItemID; import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; @@ -45,7 +44,6 @@ import net.runelite.client.plugins.timetracking.TimeablePanel; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.FontManager; -@Slf4j public class FarmingTabPanel extends TabContentPanel { private final FarmingTracker farmingTracker; diff --git a/runelite-client/src/main/java/net/runelite/client/ui/components/CustomScrollBarUI.java b/runelite-client/src/main/java/net/runelite/client/ui/components/CustomScrollBarUI.java index 128c88197a..d953c615e0 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/components/CustomScrollBarUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/components/CustomScrollBarUI.java @@ -90,7 +90,7 @@ public class CustomScrollBarUI extends BasicScrollBarUI { JScrollBar bar = (JScrollBar) c; bar.setUnitIncrement(16); - bar.setPreferredSize(new Dimension(7, 0)); + bar.setPreferredSize(new Dimension(7, 7)); return new CustomScrollBarUI(); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java index f14865a527..d470bbb242 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java @@ -69,7 +69,9 @@ public class WidgetOverlay extends Overlay new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_FIXED, OverlayPosition.BOTTOM_RIGHT), new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_RESIZEABLE_MODERN, OverlayPosition.CANVAS_TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_RESIZEABLE_CLASSIC, OverlayPosition.CANVAS_TOP_RIGHT), - new WidgetOverlay(client, WidgetInfo.TEMPOROSS_STATUS_INDICATOR, OverlayPosition.TOP_LEFT) + new WidgetOverlay(client, WidgetInfo.TEMPOROSS_STATUS_INDICATOR, OverlayPosition.TOP_LEFT), + new WidgetOverlay(client, WidgetInfo.BA_HEAL_TEAMMATES, OverlayPosition.BOTTOM_LEFT), + new WidgetOverlay(client, WidgetInfo.BA_TEAM, OverlayPosition.TOP_RIGHT) ); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/outline/ModelOutlineRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/outline/ModelOutlineRenderer.java index 8fd9daa4ae..e3528433cb 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/outline/ModelOutlineRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/outline/ModelOutlineRenderer.java @@ -450,7 +450,7 @@ public class ModelOutlineRenderer { y3 = clipY2; } - if (y1 == y3 || y3 < 0) + if (y1 == y3 || y3 < clipY1) { return; } @@ -459,16 +459,16 @@ public class ModelOutlineRenderer x2 <<= 14; x3 = x1; - if (y1 < 0) + if (y1 < clipY1) { - x3 -= y1 * slope3; - x1 -= y1 * slope1; - y1 = 0; + x3 -= (y1 - clipY1) * slope3; + x1 -= (y1 - clipY1) * slope1; + y1 = clipY1; } - if (y2 < 0) + if (y2 < clipY1) { - x2 -= slope2 * y2; - y2 = 0; + x2 -= (y2 - clipY1) * slope2; + y2 = clipY1; } int pixelY = y1; 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 0c9a52b7e5..2f2beb0c62 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 @@ -130,7 +130,7 @@ public class WorldMapOverlay extends Overlay Area currentClip = null; Point mousePos = client.getMouseCanvasPosition(); - if (!canvasViewArea.contains(mousePos.getX(), mousePos.getY())) + if (!mapViewArea.contains(mousePos.getX(), mousePos.getY())) { mousePos = null; } diff --git a/runelite-client/src/main/resources/item_variations.json b/runelite-client/src/main/resources/item_variations.json index 1c195a11bc..cb3fa513d4 100644 --- a/runelite-client/src/main/resources/item_variations.json +++ b/runelite-client/src/main/resources/item_variations.json @@ -3765,7 +3765,13 @@ 23072, 23082, 25753, - 25820 + 25820, + 25920, + 25921, + 25922, + 25923, + 25924, + 25925 ], "herb tea mix": [ 4464, @@ -7528,7 +7534,16 @@ 25185, 25187, 25189, - 25191 + 25191, + 25898, + 25900, + 25902, + 25904, + 25906, + 25908, + 25910, + 25912, + 25914 ], "slayer ring": [ 11866, @@ -8641,6 +8656,11 @@ 21009, 21206 ], + "dragon hunter crossbow": [ + 21012, + 25916, + 25918 + ], "ancestral hat": [ 21018, 25518 @@ -9884,5 +9904,21 @@ 25892, 25894, 25896 + ], + "ghommals hilt": [ + 25926, + 25928, + 25930, + 25932, + 25934, + 25936 + ], + "anim offhand": [ + 25938, + 25941, + 25944, + 25947, + 25950, + 25953 ] } \ No newline at end of file diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/roofremoval/overrides.jsonc b/runelite-client/src/main/resources/net/runelite/client/plugins/roofremoval/overrides.jsonc new file mode 100644 index 0000000000..17d5c6140d --- /dev/null +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/roofremoval/overrides.jsonc @@ -0,0 +1,2417 @@ +{ + "12946": [ // Smoke Dungeon + { + "rx1": 0, + "ry1": 0, + "rx2": 35, + "ry2": 63, + "z1": 0, + "z2": 0 + } + ], + "13203": [ // Desert Mining Camp Underground + { + "rx1": 11, + "ry1": 15, + "rx2": 14, + "ry2": 18, + "z1": 0, + "z2": 0 + }, + { + "rx1": 16, + "ry1": 9, + "rx2": 20, + "ry2": 19, + "z1": 0, + "z2": 0 + } + ], + "13358": [ // Polnivneach + { + "rx1": 33, + "ry1": 49, + "rx2": 34, + "ry2": 50, + "z1": 0, + "z2": 0 + }, + { + "rx1": 24, + "ry1": 11, + "rx2": 25, + "ry2": 11, + "z1": 0, + "z2": 0 + } + ], + "11828": [ // Falador Castle Gate + { + "rx1": 18, + "ry1": 21, + "rx2": 21, + "ry2": 22, + "z1": 0, + "z2": 1 + }, + { + "rx1": 17, + "ry1": 17, + "rx2": 17, + "ry2": 21, + "z1": 0, + "z2": 0 + }, + { // Eastern part of the castle + "rx1": 36, + "ry1": 15, + "rx2": 36, + "ry2": 16, + "z1": 0, + "z2": 0 + } + ], + "12895":[ // Prif NW + { // Entrance North + "rx1": 61, + "ry1": 14, + "rx2": 63, + "ry2": 17, + "z1": 0, + "z2": 2 + }, + { // Entrance West + "rx1": 49, + "ry1": 0, + "rx2": 52, + "ry2": 5, + "z1": 0, + "z2": 2 + }, + { // Balcony North + "rx1": 57, + "ry1": 12, + "rx2": 59, + "ry2": 15, + "z1": 0, + "z2": 0 + }, + { // Balcony West + "rx1": 51, + "ry1": 7, + "rx2": 54, + "ry2": 9, + "z1": 0, + "z2": 0 + }, + { // Roof Peak Corner + "rx1": 60, + "ry1": 5, + "rx2": 61, + "ry2": 6, + "z1": 0, + "z2": 0 + }, + { // Roof Peak Centre + "rx1": 61, + "ry1": 0, + "rx2": 63, + "ry2": 4, + "z1": 0, + "z2": 2 + }, + { // Upper Floor Roof + "rx1": 56, + "ry1": 8, + "rx2": 58, + "ry2": 10, + "z1": 2, + "z2": 2 + }, + { // Amlodd Tower Upper Floor + "rx1": 18, + "ry1": 17, + "rx2": 24, + "ry2": 22, + "z1": 2, + "z2": 2 + }, + { // Hefin Tower Upper Floor + "rx1": 44, + "ry1": 42, + "rx2": 49, + "ry2": 48, + "z1": 2, + "z2": 2 + } + ], + "13151":[ // Prif NE + { // Entrance North + "rx1": 0, + "ry1": 14, + "rx2": 2, + "ry2": 17, + "z1": 0, + "z2": 2 + }, + { // Entrance East + "rx1": 11, + "ry1": 0, + "rx2": 14, + "ry2": 5, + "z1": 0, + "z2": 2 + }, + { // Balcony North + "rx1": 4, + "ry1": 12, + "rx2": 6, + "ry2": 15, + "z1": 0, + "z2": 0 + }, + { // Balcony East + "rx1": 9, + "ry1": 7, + "rx2": 12, + "ry2": 9, + "z1": 0, + "z2": 0 + }, + { // Roof Peak Corner + "rx1": 2, + "ry1": 5, + "rx2": 3, + "ry2": 6, + "z1": 0, + "z2": 0 + }, + { // Roof Peak Centre + "rx1": 0, + "ry1": 0, + "rx2": 2, + "ry2": 4, + "z1": 0, + "z2": 2 + }, + { // Upper Floor Roof + "rx1": 5, + "ry1": 8, + "rx2": 7, + "ry2": 10, + "z1": 2, + "z2": 2 + }, + { // Meilyr Tower Upper Floor + "rx1": 14, + "ry1": 42, + "rx2": 19, + "ry2": 48, + "z1": 2, + "z2": 2 + }, + { // Cryws Tower Upper Floor + "rx1": 39, + "ry1": 17, + "rx2": 45, + "ry2": 22, + "z1": 2, + "z2": 2 + } + ], + "12894": [ // Prif SW + { // Entrance South + "rx1": 61, + "ry1": 52, + "rx2": 63, + "ry2": 55, + "z1": 0, + "z2": 2 + }, + { // Balcony South + "rx1": 57, + "ry1": 54, + "rx2": 59, + "ry2": 57, + "z1": 0, + "z2": 0 + }, + { // Balcony West + "rx1": 51, + "ry1": 60, + "rx2": 54, + "ry2": 62, + "z1": 0, + "z2": 0 + }, + { // Roof Peak Corner + "rx1": 60, + "ry1": 63, + "rx2": 61, + "ry2": 63, + "z1": 0, + "z2": 0 + }, + { // Upper Floor Roof + "rx1": 56, + "ry1": 59, + "rx2": 58, + "ry2": 61, + "z1": 2, + "z2": 2 + }, + { // Iowerth Tower Upper Floor + "rx1": 44, + "ry1": 21, + "rx2": 49, + "ry2": 27, + "z1": 2, + "z2": 2 + }, + { // Ithell Tower Upper Floor + "rx1": 18, + "ry1": 47, + "rx2": 24, + "ry2": 52, + "z1": 2, + "z2": 2 + } + ], + "13150": [ // Prif SE + { // Entrance South + "rx1": 0, + "ry1": 52, + "rx2": 2, + "ry2": 55, + "z1": 0, + "z2": 2 + }, + { // Balcony South + "rx1": 4, + "ry1": 54, + "rx2": 6, + "ry2": 57, + "z1": 0, + "z2": 0 + }, + { // Balcony East + "rx1": 9, + "ry1": 60, + "rx2": 12, + "ry2": 62, + "z1": 0, + "z2": 0 + }, + { // Upper Floor Roof + "rx1": 5, + "ry1": 59, + "rx2": 7, + "ry2": 61, + "z1": 2, + "z2": 2 + }, + { // Cadarn Tower Upper Floor + "rx1": 39, + "ry1": 47, + "rx2": 45, + "ry2": 52, + "z1": 2, + "z2": 2 + }, + { // Traehaearn Tower Upper Floor + "rx1": 14, + "ry1": 21, + "rx2": 19, + "ry2": 27, + "z1": 2, + "z2": 2 + } + ], + "14388": [ // Darkmeyer + { + "rx1": 34, + "ry1": 54, + "rx2": 36, + "ry2": 56, + "z1": 0, + "z2": 0 + }, + { + "rx1": 58, + "ry1": 53, + "rx2": 60, + "ry2": 55, + "z1": 0, + "z2": 0 + }, + { + "rx1": 40, + "ry1": 25, + "rx2": 49, + "ry2": 42, + "z1": 0, + "z2": 0 + }, + { + "rx1": 39, + "ry1": 26, + "rx2": 50, + "ry2": 41, + "z1": 0, + "z2": 0 + }, + { + "rx1": 38, + "ry1": 27, + "rx2": 51, + "ry2": 40, + "z1": 0, + "z2": 0 + }, + { + "rx1": 37, + "ry1": 28, + "rx2": 52, + "ry2": 39, + "z1": 0, + "z2": 0 + }, + { + "rx1": 36, + "ry1": 29, + "rx2": 53, + "ry2": 38, + "z1": 0, + "z2": 0 + }, + { + "rx1": 35, + "ry1": 30, + "rx2": 35, + "ry2": 37, + "z1": 0, + "z2": 0 + } + ], + "10291": [ // Ardougne + { + "rx1": 27, + "ry1": 30, + "rx2": 29, + "ry2": 35, + "z1": 0, + "z2": 0 + }, + { + "rx1": 16, + "ry1": 32, + "rx2": 19, + "ry2": 37, + "z1": 0, + "z2": 0 + } + ], + "12854": [ // Varrock Castle + { + "rx1": 0, + "ry1": 11, + "rx2": 23, + "ry2": 11, + "z1": 0, + "z2": 0 + } + ], + "12852": [ // South Varrock + { + "rx1": 42, + "ry1": 58, + "rx2": 52, + "ry2": 58, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 63, + "rx2": 54, + "ry2": 63, + "z1": 0, + "z2": 0 + } + ], + "12596": [ // Champion's Guild + { + "rx1": 52, + "ry1": 22, + "rx2": 58, + "ry2": 23, + "z1": 0, + "z2": 0 + } + ], + "8253": [ // Lunar Isle + { + "rx1": 49, + "ry1": 12, + "rx2": 56, + "ry2": 12, + "z1": 0, + "z2": 0 + }, + { + "rx1": 41, + "ry1": 18, + "rx2": 44, + "ry2": 18, + "z1": 0, + "z2": 0 + }, + { + "rx1": 34, + "ry1": 19, + "rx2": 36, + "ry2": 19, + "z1": 0, + "z2": 0 + }, + { + "rx1": 28, + "ry1": 15, + "rx2": 29, + "ry2": 18, + "z1": 0, + "z2": 0 + }, + { + "rx1": 25, + "ry1": 0, + "rx2": 29, + "ry2": 1, + "z1": 0, + "z2": 0 + }, + { + "rx1": 34, + "ry1": 4, + "rx2": 37, + "ry2": 5, + "z1": 0, + "z2": 0 + }, + { + "rx1": 46, + "ry1": 5, + "rx2": 50, + "ry2": 6, + "z1": 0, + "z2": 0 + } + ], + "8252": [ // Lunar Isle South + { + "rx1": 23, + "ry1": 62, + "rx2": 28, + "ry2": 62, + "z1": 0, + "z2": 0 + } + ], + "6456": [ // Mess Hall + { + "rx1": 47, + "ry1": 38, + "rx2": 48, + "ry2": 47, + "z1": 0, + "z2": 0 + } + ], + "6713": [ // Kourend Castle East + { + "rx1": 28, + "ry1": 20, + "rx2": 28, + "ry2": 21, + "z1": 0, + "z2": 0 + }, + { + "rx1": 28, + "ry1": 29, + "rx2": 28, + "ry2": 30, + "z1": 0, + "z2": 0 + } + ], + "6715": [ // North East Arceuus + { + "rx1": 20, + "ry1": 5, + "rx2": 50, + "ry2": 29, + "z1": 0, + "z2": 2 + }, + { + "rx1": 13, + "ry1": 5, + "rx2": 19, + "ry2": 12, + "z1": 0, + "z2": 0 + }, + { + "rx1": 13, + "ry1": 24, + "rx2": 19, + "ry2": 29, + "z1": 0, + "z2": 0 + } + ], + "6459": [ // Arceuus Library + { + "rx1": 7, + "ry1": 8, + "rx2": 26, + "ry2": 25, + "z1": 0, + "z2": 1 + }, + { + "rx1": 7, + "ry1": 38, + "rx2": 26, + "ry2": 55, + "z1": 0, + "z2": 1 + }, + { + "rx1": 7, + "ry1": 8, + "rx2": 26, + "ry2": 25, + "z1": 0, + "z2": 1 + }, + { + "rx1": 13, + "ry1": 27, + "rx2": 13, + "ry2": 36, + "z1": 0, + "z2": 1 + }, + { + "rx1": 39, + "ry1": 38, + "rx2": 58, + "ry2": 55, + "z1": 0, + "z2": 1 + }, + { + "rx1": 31, + "ry1": 44, + "rx2": 34, + "ry2": 50, + "z1": 0, + "z2": 1 + }, + { + "rx1": 40, + "ry1": 21, + "rx2": 43, + "ry2": 24, + "z1": 0, + "z2": 2 + }, + { + "rx1": 27, + "ry1": 41, + "rx2": 38, + "ry2": 50, + "z1": 1, + "z2": 1 + }, + { + "rx1": 13, + "ry1": 26, + "rx2": 24, + "ry2": 37, + "z1": 1, + "z2": 1 + } + ], + "6970": [ // Piscarilius West + { + "rx1": 60, + "ry1": 8, + "rx2": 60, + "ry2": 8, + "z1": 0, + "z2": 0 + }, + { + "rx1": 43, + "ry1": 41, + "rx2": 45, + "ry2": 42, + "z1": 0, + "z2": 0 + }, + { + "rx1": 23, + "ry1": 17, + "rx2": 24, + "ry2": 19, + "z1": 0, + "z2": 0 + }, + { + "rx1": 56, + "ry1": 49, + "rx2": 59, + "ry2": 60, + "z1": 0, + "z2": 0 + } + ], + "7226": [ // Piscarilius East + { + "rx1": 5, + "ry1": 6, + "rx2": 5, + "ry2": 13, + "z1": 0, + "z2": 0 + }, + { + "rx1": 35, + "ry1": 9, + "rx2": 36, + "ry2": 11, + "z1": 0, + "z2": 0 + }, + { + "rx1": 14, + "ry1": 28, + "rx2": 16, + "ry2": 29, + "z1": 0, + "z2": 0 + } + ], + "6203": [ // Lovakenj North East + { + "rx1": 19, + "ry1": 13, + "rx2": 21, + "ry2": 16, + "z1": 0, + "z2": 0 + }, + { + "rx1": 13, + "ry1": 4, + "rx2": 15, + "ry2": 6, + "z1": 0, + "z2": 0 + } + ], + "10288": [ // Yanille East + { + "rx1": 27, + "ry1": 12, + "rx2": 33, + "ry2": 19, + "z1": 1, + "z2": 1 + }, + { + "rx1": 47, + "ry1": 19, + "rx2": 48, + "ry2": 22, + "z1": 0, + "z2": 0 + }, + { + "rx1": 52, + "ry1": 32, + "rx2": 54, + "ry2": 34, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 31, + "rx2": 55, + "ry2": 33, + "z1": 0, + "z2": 0 + }, + { + "rx1": 54, + "ry1": 30, + "rx2": 56, + "ry2": 32, + "z1": 0, + "z2": 0 + }, + { + "rx1": 55, + "ry1": 29, + "rx2": 57, + "ry2": 31, + "z1": 0, + "z2": 0 + }, + { + "rx1": 48, + "ry1": 8, + "rx2": 48, + "ry2": 8, + "z1": 0, + "z2": 0 + }, + { + "rx1": 57, + "ry1": 26, + "rx2": 57, + "ry2": 26, + "z1": 0, + "z2": 0 + } + ], + "10032": [ // Yanille West + { + "rx1": 35, + "ry1": 23, + "rx2": 36, + "ry2": 25, + "z1": 0, + "z2": 0 + }, + { + "rx1": 35, + "ry1": 14, + "rx2": 36, + "ry2": 16, + "z1": 0, + "z2": 0 + } + ], + "9775": [ // Jigjig + { + "rx1": 50, + "ry1": 32, + "rx2": 50, + "ry2": 32, + "z1": 0, + "z2": 0 + }, + { + "rx1": 56, + "ry1": 33, + "rx2": 56, + "ry2": 33, + "z1": 0, + "z2": 0 + }, + { + "rx1": 55, + "ry1": 43, + "rx2": 55, + "ry2": 43, + "z1": 0, + "z2": 0 + }, + { + "rx1": 45, + "ry1": 41, + "rx2": 46, + "ry2": 41, + "z1": 0, + "z2": 0 + }, + { + "rx1": 49, + "ry1": 43, + "rx2": 51, + "ry2": 45, + "z1": 0, + "z2": 0 + }, + { + "rx1": 45, + "ry1": 36, + "rx2": 45, + "ry2": 36, + "z1": 0, + "z2": 0 + } + ], + "10806": [ // Seers' Village + { + "rx1": 22, + "ry1": 41, + "rx2": 23, + "ry2": 42, + "z1": 0, + "z2": 0 + }, + { + "rx1": 28, + "ry1": 14, + "rx2": 28, + "ry2": 17, + "z1": 0, + "z2": 0 + }, + { + "rx1": 11, + "ry1": 13, + "rx2": 17, + "ry2": 13, + "z1": 0, + "z2": 0 + } + ], + "10549": [ // Ranging Guild + { + "rx1": 42, + "ry1": 49, + "rx2": 46, + "ry2": 53, + "z1": 0, + "z2": 0 + }, + { + "rx1": 57, + "ry1": 34, + "rx2": 61, + "ry2": 38, + "z1": 0, + "z2": 0 + }, + { + "rx1": 27, + "ry1": 34, + "rx2": 31, + "ry2": 38, + "z1": 0, + "z2": 0 + }, + { + "rx1": 49, + "ry1": 40, + "rx2": 49, + "ry2": 43, + "z1": 0, + "z2": 0 + }, + { + "rx1": 47, + "ry1": 44, + "rx2": 48, + "ry2": 44, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 41, + "rx2": 50, + "ry2": 42, + "z1": 0, + "z2": 0 + }, + { + "rx1": 11, + "ry1": 55, + "rx2": 16, + "ry2": 56, + "z1": 0, + "z2": 0 + } + ], + "10293": [ // Fishing Guild + { + "rx1": 57, + "ry1": 2, + "rx2": 58, + "ry2": 6, + "z1": 0, + "z2": 0 + } + ], + "9781": [ // Gnome Stronghold SE + { + "rx1": 42, + "ry1": 5, + "rx2": 45, + "ry2": 8, + "z1": 0, + "z2": 0 + }, + { + "rx1": 39, + "ry1": 14, + "rx2": 41, + "ry2": 16, + "z1": 0, + "z2": 0 + }, + { + "rx1": 45, + "ry1": 14, + "rx2": 50, + "ry2": 16, + "z1": 0, + "z2": 0 + }, + { + "rx1": 46, + "ry1": 13, + "rx2": 50, + "ry2": 13, + "z1": 0, + "z2": 0 + }, + { + "rx1": 42, + "ry1": 15, + "rx2": 44, + "ry2": 15, + "z1": 0, + "z2": 0 + }, + { + "rx1": 55, + "ry1": 16, + "rx2": 58, + "ry2": 19, + "z1": 0, + "z2": 0 + }, + { + "rx1": 26, + "ry1": 24, + "rx2": 28, + "ry2": 26, + "z1": 0, + "z2": 0 + }, + { + "rx1": 25, + "ry1": 25, + "rx2": 25, + "ry2": 25, + "z1": 0, + "z2": 0 + }, + { + "rx1": 12, + "ry1": 23, + "rx2": 15, + "ry2": 26, + "z1": 0, + "z2": 0 + }, + { + "rx1": 11, + "ry1": 30, + "rx2": 17, + "ry2": 36, + "z1": 0, + "z2": 1 + }, + { + "rx1": 12, + "ry1": 39, + "rx2": 15, + "ry2": 42, + "z1": 0, + "z2": 0 + }, + { + "rx1": 13, + "ry1": 27, + "rx2": 14, + "ry2": 38, + "z1": 0, + "z2": 0 + }, + { + "rx1": 2, + "ry1": 4, + "rx2": 4, + "ry2": 6, + "z1": 0, + "z2": 0 + }, + { + "rx1": 2, + "ry1": 10, + "rx2": 4, + "ry2": 12, + "z1": 0, + "z2": 0 + }, + { + "rx1": 7, + "ry1": 9, + "rx2": 10, + "ry2": 12, + "z1": 0, + "z2": 0 + }, + { + "rx1": 3, + "ry1": 7, + "rx2": 3, + "ry2": 9, + "z1": 0, + "z2": 0 + }, + { + "rx1": 5, + "ry1": 11, + "rx2": 6, + "ry2": 11, + "z1": 0, + "z2": 0 + }, + { + "rx1": 40, + "ry1": 26, + "rx2": 43, + "ry2": 28, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 26, + "rx2": 56, + "ry2": 29, + "z1": 0, + "z2": 0 + }, + { + "rx1": 44, + "ry1": 27, + "rx2": 44, + "ry2": 28, + "z1": 0, + "z2": 0 + }, + { + "rx1": 52, + "ry1": 27, + "rx2": 52, + "ry2": 28, + "z1": 0, + "z2": 0 + }, + { + "rx1": 45, + "ry1": 28, + "rx2": 51, + "ry2": 28, + "z1": 0, + "z2": 0 + }, + { + "rx1": 49, + "ry1": 4, + "rx2": 56, + "ry2": 11, + "z1": 0, + "z2": 1 + } + ], + "9525": [ // Gnome Stronghold SW + { + "rx1": 46, + "ry1": 22, + "rx2": 49, + "ry2": 25, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 23, + "rx2": 51, + "ry2": 25, + "z1": 0, + "z2": 0 + }, + { + "rx1": 51, + "ry1": 28, + "rx2": 56, + "ry2": 33, + "z1": 0, + "z2": 2 + }, + { + "rx1": 53, + "ry1": 30, + "rx2": 58, + "ry2": 34, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 48, + "rx2": 57, + "ry2": 49, + "z1": 0, + "z2": 0 + }, + { + "rx1": 54, + "ry1": 49, + "rx2": 58, + "ry2": 51, + "z1": 0, + "z2": 0 + }, + { + "rx1": 56, + "ry1": 35, + "rx2": 56, + "ry2": 47, + "z1": 0, + "z2": 0 + }, + { + "rx1": 46, + "ry1": 40, + "rx2": 49, + "ry2": 43, + "z1": 0, + "z2": 0 + }, + { + "rx1": 39, + "ry1": 42, + "rx2": 41, + "ry2": 44, + "z1": 0, + "z2": 0 + }, + { + "rx1": 40, + "ry1": 45, + "rx2": 41, + "ry2": 47, + "z1": 0, + "z2": 0 + }, + { + "rx1": 44, + "ry1": 53, + "rx2": 48, + "ry2": 56, + "z1": 0, + "z2": 0 + }, + { + "rx1": 20, + "ry1": 57, + "rx2": 24, + "ry2": 60, + "z1": 0, + "z2": 0 + }, + { + "rx1": 29, + "ry1": 57, + "rx2": 33, + "ry2": 60, + "z1": 0, + "z2": 0 + }, + { + "rx1": 25, + "ry1": 59, + "rx2": 28, + "ry2": 59, + "z1": 0, + "z2": 0 + }, + { + "rx1": 23, + "ry1": 55, + "rx2": 31, + "ry2": 62, + "z1": 0, + "z2": 1 + } + ], + "9526": [ // Gnome Stronghold NE + { + "rx1": 40, + "ry1": 13, + "rx2": 46, + "ry2": 15, + "z1": 0, + "z2": 0 + }, + { + "rx1": 48, + "ry1": 9, + "rx2": 52, + "ry2": 12, + "z1": 0, + "z2": 0 + }, + { + "rx1": 49, + "ry1": 16, + "rx2": 54, + "ry2": 20, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 13, + "rx2": 50, + "ry2": 15, + "z1": 0, + "z2": 0 + }, + { + "rx1": 47, + "ry1": 14, + "rx2": 49, + "ry2": 14, + "z1": 0, + "z2": 0 + }, + { + "rx1": 43, + "ry1": 15, + "rx2": 51, + "ry2": 21, + "z1": 0, + "z2": 1 + }, + { + "rx1": 48, + "ry1": 26, + "rx2": 51, + "ry2": 30, + "z1": 0, + "z2": 0 + }, + { + "rx1": 48, + "ry1": 39, + "rx2": 51, + "ry2": 43, + "z1": 0, + "z2": 0 + }, + { + "rx1": 49, + "ry1": 31, + "rx2": 50, + "ry2": 38, + "z1": 0, + "z2": 0 + }, + { + "rx1": 43, + "ry1": 29, + "rx2": 44, + "ry2": 37, + "z1": 0, + "z2": 0 + }, + { + "rx1": 24, + "ry1": 20, + "rx2": 32, + "ry2": 21, + "z1": 0, + "z2": 0 + }, + { + "rx1": 10, + "ry1": 30, + "rx2": 11, + "ry2": 37, + "z1": 0, + "z2": 0 + }, + { + "rx1": 24, + "ry1": 43, + "rx2": 32, + "ry2": 44, + "z1": 0, + "z2": 0 + }, + { + "rx1": 12, + "ry1": 48, + "rx2": 16, + "ry2": 53, + "z1": 0, + "z2": 0 + }, + { + "rx1": 19, + "ry1": 57, + "rx2": 23, + "ry2": 60, + "z1": 0, + "z2": 0 + }, + { + "rx1": 28, + "ry1": 57, + "rx2": 32, + "ry2": 60, + "z1": 0, + "z2": 0 + } + ], + "9782": [ // Gnome Stronghold NE + { + "rx1": 4, + "ry1": 7, + "rx2": 7, + "ry2": 10, + "z1": 0, + "z2": 0 + }, + { + "rx1": 10, + "ry1": 6, + "rx2": 13, + "ry2": 12, + "z1": 0, + "z2": 0 + }, + { + "rx1": 10, + "ry1": 9, + "rx2": 14, + "ry2": 13, + "z1": 0, + "z2": 1 + }, + { + "rx1": 16, + "ry1": 7, + "rx2": 19, + "ry2": 10, + "z1": 0, + "z2": 0 + }, + { + "rx1": 43, + "ry1": 6, + "rx2": 47, + "ry2": 9, + "z1": 0, + "z2": 0 + }, + { + "rx1": 48, + "ry1": 6, + "rx2": 52, + "ry2": 7, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 7, + "rx2": 56, + "ry2": 11, + "z1": 0, + "z2": 0 + }, + + { + "rx1": 16, + "ry1": 22, + "rx2": 18, + "ry2": 26, + "z1": 0, + "z2": 0 + }, + { + "rx1": 6, + "ry1": 31, + "rx2": 10, + "ry2": 33, + "z1": 0, + "z2": 0 + }, + { + "rx1": 15, + "ry1": 30, + "rx2": 19, + "ry2": 34, + "z1": 0, + "z2": 0 + }, + { + "rx1": 11, + "ry1": 32, + "rx2": 14, + "ry2": 32, + "z1": 0, + "z2": 0 + }, + { + "rx1": 17, + "ry1": 27, + "rx2": 17, + "ry2": 29, + "z1": 0, + "z2": 0 + }, + { + "rx1": 15, + "ry1": 52, + "rx2": 19, + "ry2": 56, + "z1": 0, + "z2": 0 + }, + { + "rx1": 15, + "ry1": 44, + "rx2": 19, + "ry2": 48, + "z1": 0, + "z2": 0 + }, + { + "rx1": 17, + "ry1": 49, + "rx2": 17, + "ry2": 51, + "z1": 0, + "z2": 0 + }, + { + "rx1": 12, + "ry1": 46, + "rx2": 14, + "ry2": 46, + "z1": 0, + "z2": 0 + }, + { + "rx1": 17, + "ry1": 35, + "rx2": 17, + "ry2": 43, + "z1": 0, + "z2": 0 + }, + { + "rx1": 20, + "ry1": 46, + "rx2": 25, + "ry2": 46, + "z1": 0, + "z2": 0 + }, + { + "rx1": 25, + "ry1": 33, + "rx2": 25, + "ry2": 45, + "z1": 0, + "z2": 0 + }, + { + "rx1": 20, + "ry1": 32, + "rx2": 25, + "ry2": 32, + "z1": 0, + "z2": 0 + }, + { + "rx1": 26, + "ry1": 39, + "rx2": 29, + "ry2": 39, + "z1": 0, + "z2": 0 + }, + { + "rx1": 16, + "ry1": 38, + "rx2": 18, + "ry2": 42, + "z1": 0, + "z2": 1 + }, + { + "rx1": 19, + "ry1": 40, + "rx2": 29, + "ry2": 40, + "z1": 0, + "z2": 1 + }, + { + "rx1": 15, + "ry1": 21, + "rx2": 19, + "ry2": 25, + "z1": 0, + "z2": 1 + }, + { + "rx1": 31, + "ry1": 23, + "rx2": 35, + "ry2": 26, + "z1": 0, + "z2": 1 + }, + { + "rx1": 28, + "ry1": 30, + "rx2": 30, + "ry2": 33, + "z1": 0, + "z2": 1 + }, + { + "rx1": 36, + "ry1": 30, + "rx2": 39, + "ry2": 33, + "z1": 0, + "z2": 1 + }, + { + "rx1": 33, + "ry1": 27, + "rx2": 33, + "ry2": 35, + "z1": 0, + "z2": 1 + }, + { + "rx1": 31, + "ry1": 32, + "rx2": 35, + "ry2": 32, + "z1": 0, + "z2": 1 + }, + { + "rx1": 34, + "ry1": 44, + "rx2": 34, + "ry2": 51, + "z1": 0, + "z2": 1 + }, + { + "rx1": 32, + "ry1": 52, + "rx2": 36, + "ry2": 54, + "z1": 0, + "z2": 1 + }, + { + "rx1": 37, + "ry1": 46, + "rx2": 39, + "ry2": 50, + "z1": 0, + "z2": 1 + }, + { + "rx1": 29, + "ry1": 47, + "rx2": 32, + "ry2": 49, + "z1": 0, + "z2": 1 + }, + { + "rx1": 33, + "ry1": 48, + "rx2": 36, + "ry2": 48, + "z1": 0, + "z2": 1 + }, + { + "rx1": 31, + "ry1": 43, + "rx2": 33, + "ry2": 46, + "z1": 0, + "z2": 2 + }, + { + "rx1": 31, + "ry1": 47, + "rx2": 31, + "ry2": 49, + "z1": 0, + "z2": 2 + }, + { + "rx1": 49, + "ry1": 22, + "rx2": 51, + "ry2": 26, + "z1": 0, + "z2": 0 + }, + { + "rx1": 48, + "ry1": 30, + "rx2": 52, + "ry2": 34, + "z1": 0, + "z2": 0 + }, + { + "rx1": 57, + "ry1": 31, + "rx2": 61, + "ry2": 33, + "z1": 0, + "z2": 0 + }, + { + "rx1": 49, + "ry1": 38, + "rx2": 51, + "ry2": 42, + "z1": 0, + "z2": 1 + }, + { + "rx1": 48, + "ry1": 44, + "rx2": 52, + "ry2": 48, + "z1": 0, + "z2": 0 + }, + { + "rx1": 57, + "ry1": 45, + "rx2": 61, + "ry2": 47, + "z1": 0, + "z2": 0 + }, + { + "rx1": 49, + "ry1": 52, + "rx2": 51, + "ry2": 56, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 52, + "rx2": 54, + "ry2": 56, + "z1": 0, + "z2": 1 + }, + { + "rx1": 53, + "ry1": 37, + "rx2": 57, + "ry2": 41, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 27, + "rx2": 50, + "ry2": 29, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 32, + "rx2": 56, + "ry2": 32, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 35, + "rx2": 50, + "ry2": 43, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 46, + "rx2": 56, + "ry2": 46, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 49, + "rx2": 50, + "ry2": 51, + "z1": 0, + "z2": 0 + }, + { + "rx1": 42, + "ry1": 32, + "rx2": 47, + "ry2": 32, + "z1": 0, + "z2": 0 + }, + { + "rx1": 42, + "ry1": 46, + "rx2": 47, + "ry2": 46, + "z1": 0, + "z2": 0 + }, + { + "rx1": 42, + "ry1": 33, + "rx2": 42, + "ry2": 45, + "z1": 0, + "z2": 0 + }, + { + "rx1": 38, + "ry1": 39, + "rx2": 41, + "ry2": 39, + "z1": 0, + "z2": 0 + }, + { + "rx1": 38, + "ry1": 40, + "rx2": 48, + "ry2": 40, + "z1": 0, + "z2": 1 + } + ], + "9531": [ // Jatiszo + { + "rx1": 4, + "ry1": 23, + "rx2": 6, + "ry2": 25, + "z1": 0, + "z2": 0 + } + ], + "9275": [ // Neitiznot + { + "rx1": 58, + "ry1": 22, + "rx2": 60, + "ry2": 24, + "z1": 0, + "z2": 0 + } + ], + "11575": [ // Burthorpe + { + "rx1": 25, + "ry1": 24, + "rx2": 35, + "ry2": 24, + "z1": 0, + "z2": 0 + } + ], + "11319": [ // Warrior's Guild + { + "rx1": 21, + "ry1": 15, + "rx2": 61, + "ry2": 37, + "z1": 0, + "z2": 0 + }, + { + "rx1": 32, + "ry1": 13, + "rx2": 44, + "ry2": 15, + "z1": 0, + "z2": 0 + } + ], + "11061": [ // West Catherby + { + "rx1": 55, + "ry1": 20, + "rx2": 59, + "ry2": 38, + "z1": 0, + "z2": 0 + } + ], + "11317": [ // East Catherby + { + "rx1": 5, + "ry1": 48, + "rx2": 7, + "ry2": 48, + "z1": 0, + "z2": 0 + } + ], + "5945": [ // West Shayzien Encampment + { + "rx1": 1, + "ry1": 0, + "rx2": 2, + "ry2": 3, + "z1": 0, + "z2": 1 + } + ], + "10040": [ // Lighthouse + { + "rx1": 9, + "ry1": 53, + "rx2": 16, + "ry2": 60, + "z1": 1, + "z2": 2 + }, + { // Lighthouse clockwork + "rx1": 12, + "ry1": 51, + "rx2": 13, + "ry2": 52, + "z1": 0, + "z2": 1 + } + ], + "10547": [ // SE Ardy + { + "rx1": 53, + "ry1": 1, + "rx2": 63, + "ry2": 5, + "z1": 0, + "z2": 0 + }, + { + "rx1": 34, + "ry1": 54, + "rx2": 36, + "ry2": 54, + "z1": 0, + "z2": 1 + } + ], + "11570": [ // Rimmington Dock + { + "rx1": 28, + "ry1": 19, + "rx2": 39, + "ry2": 23, + "z1": 0, + "z2": 0 + }, + { + "rx1": 17, + "ry1": 28, + "rx2": 36, + "ry2": 32, + "z1": 0, + "z2": 0 + } + ], + "11058": [ // Brimhaven Docks + { + "rx1": 22, + "ry1": 32, + "rx2": 26, + "ry2": 46, + "z1": 0, + "z2": 0 + } + ], + "10284": [ // Corsair's Cove East + { + "rx1": 7, + "ry1": 47, + "rx2": 12, + "ry2": 52, + "z1": 0, + "z2": 0 + } + ], + "10028": [ // Corsair's Cove West + { + "rx1": 47, + "ry1": 44, + "rx2": 51, + "ry2": 48, + "z1": 0, + "z2": 0 + } + ], + "10545": [ // Port Khazard + { + "rx1": 45, + "ry1": 31, + "rx2": 49, + "ry2": 42, + "z1": 0, + "z2": 0 + } + ], + "11825": [ // Musa Point Docks + { + "rx1": 1, + "ry1": 5, + "rx2": 7, + "ry2": 5, + "z1": 0, + "z2": 0 + }, + { + "rx1": 7, + "ry1": 4, + "rx2": 7, + "ry2": 6, + "z1": 0, + "z2": 0 + } + ], + "14902": [ // Bill Teach's Ship at Port Phasmatys + { + "rx1": 0, + "ry1": 33, + "rx2": 4, + "ry2": 56, + "z1": 0, + "z2": 0 + } + ], + "14646": [ // Port Phasmatys + { + "rx1": 46, + "ry1": 47, + "rx2": 50, + "ry2": 63, + "z1": 0, + "z2": 0 + } + ], + "14647": [ // Ectofuntus + { + "rx1": 46, + "ry1": 0, + "rx2": 50, + "ry2": 11, + "z1": 0, + "z2": 0 + } + ], + "14638": [ // Mos Le'Harmless Port + { + "rx1": 20, + "ry1": 2, + "rx2": 43, + "ry2": 6, + "z1": 0, + "z2": 0 + } + ], + "6968": [ // Hosidius Town + { + "rx1": 17, + "ry1": 26, + "rx2": 18, + "ry2": 38, + "z1": 0, + "z2": 0 + } + ], + "6995": [ // Ancient Cavern + { + "rx1": 42, + "ry1": 15, + "rx2": 47, + "ry2": 20, + "z1": 0, + "z2": 0 + }, + { + "rx1": 31, + "ry1": 26, + "rx2": 43, + "ry2": 41, + "z1": 0, + "z2": 0 + }, + { + "rx1": 25, + "ry1": 33, + "rx2": 30, + "ry2": 35, + "z1": 0, + "z2": 0 + }, + { + "rx1": 29, + "ry1": 27, + "rx2": 30, + "ry2": 39, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 33, + "rx2": 50, + "ry2": 33, + "z1": 0, + "z2": 0 + }, + { + "rx1": 35, + "ry1": 53, + "rx2": 41, + "ry2": 54, + "z1": 0, + "z2": 0 + } + ], + "11056": [ // North Tai Bwo Wannai + { + "rx1": 32, + "ry1": 1, + "rx2": 36, + "ry2": 5, + "z1": 0, + "z2": 0 + }, + { + "rx1": 48, + "ry1": 1, + "rx2": 52, + "ry2": 5, + "z1": 0, + "z2": 0 + } + ], + "11055": [ // South Tai Bwo Wannai + { + "rx1": 55, + "ry1": 56, + "rx2": 58, + "ry2": 59, + "z1": 0, + "z2": 0 + }, + { + "rx1": 36, + "ry1": 29, + "rx2": 39, + "ry2": 34, + "z1": 0, + "z2": 0 + }, + { + "rx1": 35, + "ry1": 30, + "rx2": 40, + "ry2": 33, + "z1": 0, + "z2": 0 + } + ], + "7749": [ // Pyramid Plunder + { + "rx1": 0, + "ry1": 0, + "rx2": 63, + "ry2": 63, + "z1": 0, + "z2": 2 + } + ], + "11310": [ // Shilo Village + { + "rx1": 26, + "ry1": 52, + "rx2": 28, + "ry2": 54, + "z1": 0, + "z2": 0 + }, + { + "rx1": 26, + "ry1": 58, + "rx2": 28, + "ry2": 60, + "z1": 0, + "z2": 0 + }, + { + "rx1": 27, + "ry1": 55, + "rx2": 27, + "ry2": 57, + "z1": 0, + "z2": 0 + }, + { + "rx1": 33, + "ry1": 52, + "rx2": 35, + "ry2": 54, + "z1": 0, + "z2": 0 + }, + { + "rx1": 29, + "ry1": 53, + "rx2": 32, + "ry2": 53, + "z1": 0, + "z2": 0 + }, + { + "rx1": 44, + "ry1": 49, + "rx2": 46, + "ry2": 57, + "z1": 0, + "z2": 0 + }, + { + "rx1": 43, + "ry1": 50, + "rx2": 47, + "ry2": 56, + "z1": 0, + "z2": 0 + }, + { + "rx1": 42, + "ry1": 51, + "rx2": 48, + "ry2": 55, + "z1": 0, + "z2": 0 + }, + { + "rx1": 41, + "ry1": 52, + "rx2": 49, + "ry2": 54, + "z1": 0, + "z2": 0 + }, + { + "rx1": 36, + "ry1": 53, + "rx2": 40, + "ry2": 53, + "z1": 0, + "z2": 0 + }, + { + "rx1": 43, + "ry1": 44, + "rx2": 47, + "ry2": 46, + "z1": 0, + "z2": 0 + }, + { + "rx1": 45, + "ry1": 43, + "rx2": 45, + "ry2": 48, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 51, + "rx2": 55, + "ry2": 55, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 53, + "rx2": 56, + "ry2": 53, + "z1": 0, + "z2": 0 + }, + { + "rx1": 52, + "ry1": 37, + "rx2": 54, + "ry2": 39, + "z1": 0, + "z2": 0 + }, + { + "rx1": 8, + "ry1": 18, + "rx2": 9, + "ry2": 19, + "z1": 0, + "z2": 0 + }, + { + "rx1": 53, + "ry1": 29, + "rx2": 53, + "ry2": 36, + "z1": 0, + "z2": 0 + } + ], + "12340": [ // Draynor Manor + { + "rx1": 30, + "ry1": 24, + "rx2": 43, + "ry2": 24, + "z1": 0, + "z2": 0 + } + ], + "9265": [ // Lletya + { + "rx1": 23, + "ry1": 34, + "rx2": 23, + "ry2": 37, + "z1": 0, + "z2": 0 + } + ], + "15148": [ // Harmony Island + { + "rx1": 30, + "ry1": 24, + "rx2": 40, + "ry2": 32, + "z1": 0, + "z2": 0 + }, + { + "rx1": 41, + "ry1": 18, + "rx2": 48, + "ry2": 36, + "z1": 0, + "z2": 0 + }, + { + "rx1": 41, + "ry1": 37, + "rx2": 45, + "ry2": 38, + "z1": 0, + "z2": 0 + }, + { + "rx1": 34, + "ry1": 57, + "rx2": 38, + "ry2": 57, + "z1": 0, + "z2": 0 + } + ], + "11423": [ // NW Keldagrim + { + "rx1": 60, + "ry1": 11, + "rx2": 63, + "ry2": 36, + "z1": 0, + "z2": 1 + } + ], + "11678": [ // SE Keldagrim + { + "rx1": 49, + "ry1": 46, + "rx2": 49, + "ry2": 51, + "z1": 0, + "z2": 0 + }, + { + "rx1": 50, + "ry1": 56, + "rx2": 51, + "ry2": 63, + "z1": 0, + "z2": 0 + } + ], + "11679": [ // NE Keldagrim + { + "rx1": 50, + "ry1": 0, + "rx2": 51, + "ry2": 1, + "z1": 0, + "z2": 0 + }, + { + "rx1": 0, + "ry1": 11, + "rx2": 3, + "ry2": 36, + "z1": 0, + "z2": 1 + } + ] +} diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_thieving.json b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_thieving.json index 92898fc17c..f23248c568 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_thieving.json +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_thieving.json @@ -162,6 +162,12 @@ "name": "Silver Stall", "xp": 54 }, + { + "level": 50, + "icon": 5560, + "name": "Wall Safe", + "xp": 70 + }, { "level": 53, "icon": 4625, diff --git a/runelite-client/src/main/scripts/CommandScript.hash b/runelite-client/src/main/scripts/CommandScript.hash index 2aac5e8d08..ff5e4cfbf5 100644 --- a/runelite-client/src/main/scripts/CommandScript.hash +++ b/runelite-client/src/main/scripts/CommandScript.hash @@ -1 +1 @@ -2FE66C1A3B63EEF10142A955C927054613F59A34C4A929C8AC79DBE0F1B06C30 \ No newline at end of file +9D5F23C8B25B79FF2B23F6AE449EDF74645E808B67ECF0E389B626966E86B1BD \ No newline at end of file diff --git a/runelite-client/src/main/scripts/CommandScript.rs2asm b/runelite-client/src/main/scripts/CommandScript.rs2asm index cb21384884..ed0caf568d 100644 --- a/runelite-client/src/main/scripts/CommandScript.rs2asm +++ b/runelite-client/src/main/scripts/CommandScript.rs2asm @@ -273,7 +273,7 @@ LABEL226: iload 6 ; prefix length iload 5 ; chat type sconst "preChatSendpublic" - runelite_callback + runelite_callback istore 5 ; chat type istore 6 ; prefix length get_varc_string 335 ; load input string @@ -565,7 +565,7 @@ LABEL441: if_icmpeq LABEL445 jump LABEL490 LABEL445: - iconst 40697935 + iconst 40697936 iconst 1 cc_find iconst 1 diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/GroundItemsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/GroundItemsPluginTest.java index 48d6296ca5..92cd6b28bc 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/GroundItemsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/GroundItemsPluginTest.java @@ -111,6 +111,8 @@ public class GroundItemsPluginTest when(client.getLocalPlayer()).thenReturn(mock(Player.class)); when(config.getHiddenItems()).thenReturn(""); + when(config.showLootbeamForHighlighted()).thenReturn(false); + when(config.showLootbeamTier()).thenReturn(HighlightTier.OFF); } @Test diff --git a/runelite-jshell/src/main/java/net/runelite/jshell/JShellAutocompleteProvider.java b/runelite-jshell/src/main/java/net/runelite/jshell/JShellAutocompleteProvider.java index 2a0a2d8418..550f606a1c 100644 --- a/runelite-jshell/src/main/java/net/runelite/jshell/JShellAutocompleteProvider.java +++ b/runelite-jshell/src/main/java/net/runelite/jshell/JShellAutocompleteProvider.java @@ -32,13 +32,11 @@ import javax.swing.text.JTextComponent; import jdk.jshell.JShell; import jdk.jshell.SourceCodeAnalysis; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.fife.ui.autocomplete.BasicCompletion; import org.fife.ui.autocomplete.Completion; import org.fife.ui.autocomplete.CompletionProviderBase; import org.fife.ui.autocomplete.ParameterizedCompletion; -@Slf4j @RequiredArgsConstructor public class JShellAutocompleteProvider extends CompletionProviderBase { diff --git a/runelite-jshell/src/main/java/net/runelite/jshell/ShellPanel.java b/runelite-jshell/src/main/java/net/runelite/jshell/ShellPanel.java index 1fd17a5711..8a5c07c1d1 100644 --- a/runelite-jshell/src/main/java/net/runelite/jshell/ShellPanel.java +++ b/runelite-jshell/src/main/java/net/runelite/jshell/ShellPanel.java @@ -55,6 +55,7 @@ import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Segment; +import jdk.jshell.DeclarationSnippet; import jdk.jshell.Diag; import jdk.jshell.JShell; import jdk.jshell.Snippet; @@ -185,7 +186,6 @@ public abstract class ShellPanel extends JPanel } console.setFont(codeFont); - console.setFocusable(false); console.setEditable(false); console.setOpaque(false); // this turns off the hover effect for some reason @@ -316,11 +316,13 @@ public abstract class ShellPanel extends JPanel { Snippet snip = ev.snippet(); offsets.put("#" + snip.id(), thisOffset); - if (ev.status() != Snippet.Status.VALID && ev.status() != Snippet.Status.RECOVERABLE_DEFINED) + if (ev.status() != Snippet.Status.VALID) { + boolean handled = false; var diags = shell.diagnostics(snip).collect(Collectors.toList()); for (var diag : diags) { + handled = true; String msg = toStringDiagnostic(src, thisOffset, diag); if (isUserCode) { @@ -332,11 +334,23 @@ public abstract class ShellPanel extends JPanel throw new RuntimeException("prelude error: " + msg); } } - if (diags.isEmpty()) + if (snip instanceof DeclarationSnippet) + { + var unresolved = shell.unresolvedDependencies((DeclarationSnippet) snip).collect(Collectors.toList()); + for (var ident : unresolved) + { + handled = true; + logToConsole("Unresolved symbol: " + ident); + } + } + if (!handled) { logToConsole("bad snippet" + ev.status()); } - break evaluation; + if (ev.status() != Snippet.Status.RECOVERABLE_DEFINED) + { + break evaluation; + } } if (ev.exception() != null) { @@ -419,18 +433,23 @@ public abstract class ShellPanel extends JPanel private void cleanup() { - for (var c : cleanup) - { - try - { - c.run(); - } - catch (Exception e) - { - shellLogger.error("Cleanup threw:", e); - } - } + var todo = new ArrayList<>(cleanup); cleanup.clear(); + + invokeOnClientThread(() -> + { + for (var c : todo) + { + try + { + c.run(); + } + catch (Exception e) + { + shellLogger.error("Cleanup threw:", e); + } + } + }); } protected abstract void invokeOnClientThread(Runnable r);