+ * 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;
+
+/**
+ * Utility class used for mapping enum IDs.
+ *
+ * Note: This class is not complete and may be missing mapped IDs.
+ */
+public final class EnumID
+{
+ public static final int MUSIC_TRACK_NAMES = 812;
+ public static final int MUSIC_TRACK_IDS = 819;
+}
diff --git a/runelite-api/src/main/java/net/runelite/api/GraphicID.java b/runelite-api/src/main/java/net/runelite/api/GraphicID.java
index 913cb9d881..b1d2c3d00f 100644
--- a/runelite-api/src/main/java/net/runelite/api/GraphicID.java
+++ b/runelite-api/src/main/java/net/runelite/api/GraphicID.java
@@ -26,6 +26,7 @@ package net.runelite.api;
public class GraphicID
{
+ public static final int SPLASH = 85;
public static final int TELEPORT = 111;
public static final int GREY_BUBBLE_TELEPORT = 86;
public static final int ENTANGLE = 179;
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 d8ce5fc04a..f272260eec 100644
--- a/runelite-api/src/main/java/net/runelite/api/ItemID.java
+++ b/runelite-api/src/main/java/net/runelite/api/ItemID.java
@@ -6494,7 +6494,7 @@ public final class ItemID
public static final int ZAMORAK_CHAPS = 10372;
public static final int ZAMORAK_COIF = 10374;
public static final int GUTHIX_BRACERS = 10376;
- public static final int GUTHIX_DRAGONHIDE = 10378;
+ public static final int GUTHIX_DHIDE = 10378;
public static final int GUTHIX_CHAPS = 10380;
public static final int GUTHIX_COIF = 10382;
public static final int SARADOMIN_BRACERS = 10384;
@@ -6801,7 +6801,7 @@ public final class ItemID
public static final int GUTHIX_ROBE_TOP_10788 = 10788;
public static final int ZAMORAK_DHIDE_10790 = 10790;
public static final int SARADOMIN_DHIDE_10792 = 10792;
- public static final int GUTHIX_DRAGONHIDE_10794 = 10794;
+ public static final int GUTHIX_DRAGONHIDE = 10794;
public static final int ROBIN_HOOD_HAT_10796 = 10796;
public static final int RUNE_PLATEBODY_G_10798 = 10798;
public static final int RUNE_PLATEBODY_T_10800 = 10800;
@@ -10637,5 +10637,17 @@ public final class ItemID
public static final int ALCHEMICAL_HYDRA_HEAD = 23081;
public static final int ANTIQUE_LAMP_23082 = 23082;
public static final int BRIMSTONE_KEY = 23083;
+ public static final int ORNATE_GLOVES = 23091;
+ public static final int ORNATE_BOOTS = 23093;
+ public static final int ORNATE_LEGS = 23095;
+ public static final int ORNATE_TOP = 23097;
+ public static final int ORNATE_CAPE = 23099;
+ public static final int ORNATE_HELM = 23101;
+ public static final int BIRTHDAY_CAKE = 23108;
+ public static final int MYSTIC_SET_LIGHT = 23110;
+ public static final int MYSTIC_SET_BLUE = 23113;
+ public static final int MYSTIC_SET_DARK = 23116;
+ public static final int MYSTIC_SET_DUSK = 23119;
+ public static final int OILY_PEARL_FISHING_ROD = 23122;
/* This file is automatically generated. Do not edit. */
}
diff --git a/runelite-api/src/main/java/net/runelite/api/NPCComposition.java b/runelite-api/src/main/java/net/runelite/api/NPCComposition.java
index 2a3a26343d..0386ba954f 100644
--- a/runelite-api/src/main/java/net/runelite/api/NPCComposition.java
+++ b/runelite-api/src/main/java/net/runelite/api/NPCComposition.java
@@ -63,14 +63,14 @@ public interface NPCComposition
*
* @return the mini-map visible state
*/
- boolean isMinimapVisable();
+ boolean isMinimapVisible();
/**
* Gets whether the NPC is visible.
*
* @return the visible state
*/
- boolean isVisable();
+ boolean isVisible();
/**
* Gets the ID of the NPC.
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 4222a45a62..3a5363de22 100644
--- a/runelite-api/src/main/java/net/runelite/api/NpcID.java
+++ b/runelite-api/src/main/java/net/runelite/api/NpcID.java
@@ -1033,8 +1033,6 @@ public final class NpcID
public static final int ANGRY_BEAR = 1060;
public static final int ANGRY_UNICORN = 1061;
public static final int ANGRY_GIANT_RAT = 1062;
- public static final int ANGRY_GIANT_RAT_1063 = 1063;
- public static final int ANGRY_GIANT_RAT_1064 = 1064;
public static final int ANGRY_GOBLIN = 1065;
public static final int FEAR_REAPER = 1066;
public static final int CONFUSION_BEAST = 1067;
@@ -2685,7 +2683,7 @@ public final class NpcID
public static final int BAT = 2827;
public static final int DRYAD = 2828;
public static final int FAIRY_2829 = 2829;
- public static final int LEPRECHAUN = 2830;
+ public static final int MYSTERIOUS_OLD_MAN = 2830;
public static final int LIZARD_MAN = 2831;
public static final int ORC = 2832;
public static final int TROLL_2833 = 2833;
@@ -6186,7 +6184,7 @@ public final class NpcID
public static final int EVIL_CHICKEN_6739 = 6739;
public static final int SHADE_6740 = 6740;
public static final int ZOMBIE_6741 = 6741;
- public static final int MYSTERIOUS_OLD_MAN = 6742;
+ public static final int MYSTERIOUS_OLD_MAN_6742 = 6742;
public static final int SERGEANT_DAMIEN_6743 = 6743;
public static final int FLIPPA_6744 = 6744;
public static final int LEO = 6745;
@@ -6209,6 +6207,7 @@ public final class NpcID
public static final int SPAWN_6768 = 6768;
public static final int OSTEN = 6769;
public static final int ARCIS = 6770;
+ public static final int DREW = 6771;
public static final int LOVADA = 6772;
public static final int DOOMSAYER = 6773;
public static final int DOOMSAYER_6774 = 6774;
@@ -6218,6 +6217,7 @@ public final class NpcID
public static final int MAZE_GUARDIAN_6779 = 6779;
public static final int PILIAR = 6780;
public static final int SHAYDA = 6781;
+ public static final int FISHING_SPOT_6784 = 6784;
public static final int HOSA = 6785;
public static final int HELLRAT_BEHEMOTH = 6793;
public static final int MONKEY_ARCHER_6794 = 6794;
@@ -7838,5 +7838,6 @@ public final class NpcID
public static final int VEOS_8630 = 8630;
public static final int SEAMAN_MORRIS = 8631;
public static final int ALCHEMICAL_HYDRA_8634 = 8634;
+ public static final int DODGY_GEEZER = 8644;
/* 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 8c4072cbe3..32141ef820 100644
--- a/runelite-api/src/main/java/net/runelite/api/NullItemID.java
+++ b/runelite-api/src/main/java/net/runelite/api/NullItemID.java
@@ -12267,5 +12267,26 @@ public final class NullItemID
public static final int NULL_23088 = 23088;
public static final int NULL_23089 = 23089;
public static final int NULL_23090 = 23090;
+ public static final int NULL_23092 = 23092;
+ public static final int NULL_23094 = 23094;
+ public static final int NULL_23096 = 23096;
+ public static final int NULL_23098 = 23098;
+ public static final int NULL_23100 = 23100;
+ public static final int NULL_23102 = 23102;
+ public static final int NULL_23103 = 23103;
+ public static final int NULL_23104 = 23104;
+ public static final int NULL_23105 = 23105;
+ public static final int NULL_23106 = 23106;
+ public static final int NULL_23107 = 23107;
+ public static final int NULL_23109 = 23109;
+ public static final int NULL_23111 = 23111;
+ public static final int NULL_23112 = 23112;
+ public static final int NULL_23114 = 23114;
+ public static final int NULL_23115 = 23115;
+ public static final int NULL_23117 = 23117;
+ public static final int NULL_23118 = 23118;
+ public static final int NULL_23120 = 23120;
+ public static final int NULL_23121 = 23121;
+ public static final int NULL_23123 = 23123;
/* 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 5371b0fdc2..c44dee1a9a 100644
--- a/runelite-api/src/main/java/net/runelite/api/NullObjectID.java
+++ b/runelite-api/src/main/java/net/runelite/api/NullObjectID.java
@@ -1184,6 +1184,7 @@ public final class NullObjectID
public static final int NULL_2566 = 2566;
public static final int NULL_2567 = 2567;
public static final int NULL_2568 = 2568;
+ public static final int NULL_2630 = 2630;
public static final int NULL_2637 = 2637;
public static final int NULL_2638 = 2638;
public static final int NULL_2639 = 2639;
@@ -4639,6 +4640,7 @@ public final class NullObjectID
public static final int NULL_11016 = 11016;
public static final int NULL_11026 = 11026;
public static final int NULL_11027 = 11027;
+ public static final int NULL_11040 = 11040;
public static final int NULL_11045 = 11045;
public static final int NULL_11046 = 11046;
public static final int NULL_11047 = 11047;
@@ -6203,6 +6205,7 @@ public final class NullObjectID
public static final int NULL_14425 = 14425;
public static final int NULL_14426 = 14426;
public static final int NULL_14427 = 14427;
+ public static final int NULL_14428 = 14428;
public static final int NULL_14429 = 14429;
public static final int NULL_14430 = 14430;
public static final int NULL_14432 = 14432;
@@ -9329,6 +9332,7 @@ public final class NullObjectID
public static final int NULL_20869 = 20869;
public static final int NULL_20874 = 20874;
public static final int NULL_20875 = 20875;
+ public static final int NULL_20877 = 20877;
public static final int NULL_20879 = 20879;
public static final int NULL_20880 = 20880;
public static final int NULL_20881 = 20881;
@@ -11438,7 +11442,6 @@ public final class NullObjectID
public static final int NULL_24552 = 24552;
public static final int NULL_24553 = 24553;
public static final int NULL_24554 = 24554;
- public static final int NULL_24558 = 24558;
public static final int NULL_24570 = 24570;
public static final int NULL_24604 = 24604;
public static final int NULL_24623 = 24623;
@@ -12310,6 +12313,8 @@ public final class NullObjectID
public static final int NULL_26195 = 26195;
public static final int NULL_26196 = 26196;
public static final int NULL_26197 = 26197;
+ public static final int NULL_26200 = 26200;
+ public static final int NULL_26204 = 26204;
public static final int NULL_26208 = 26208;
public static final int NULL_26209 = 26209;
public static final int NULL_26245 = 26245;
@@ -16101,5 +16106,13 @@ public final class NullObjectID
public static final int NULL_34651 = 34651;
public static final int NULL_34652 = 34652;
public static final int NULL_34662 = 34662;
+ public static final int NULL_34678 = 34678;
+ public static final int NULL_34679 = 34679;
+ public static final int NULL_34680 = 34680;
+ public static final int NULL_34707 = 34707;
+ public static final int NULL_34708 = 34708;
+ public static final int NULL_34709 = 34709;
+ public static final int NULL_34710 = 34710;
+ public static final int NULL_34711 = 34711;
/* 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 6679539d8f..f4c746ca3b 100644
--- a/runelite-api/src/main/java/net/runelite/api/ObjectID.java
+++ b/runelite-api/src/main/java/net/runelite/api/ObjectID.java
@@ -1452,7 +1452,6 @@ public final class ObjectID
public static final int DOOR_2627 = 2627;
public static final int DOOR_2628 = 2628;
public static final int WALL_2629 = 2629;
- public static final int FISHING_SPOT_2630 = 2630;
public static final int DOOR_2631 = 2631;
public static final int CHEST_2632 = 2632;
public static final int CHEST_2633 = 2633;
@@ -6405,7 +6404,6 @@ public final class ObjectID
public static final int WALL_11037 = 11037;
public static final int WALL_11038 = 11038;
public static final int WALL_11039 = 11039;
- public static final int RUBBLE_11040 = 11040;
public static final int LADDER_11041 = 11041;
public static final int LADDER_11042 = 11042;
public static final int STONE_LADDER = 11043;
@@ -8228,7 +8226,6 @@ public final class ObjectID
public static final int MYSTERIOUS_RUINS_14413 = 14413;
public static final int MYSTERIOUS_RUINS_14414 = 14414;
public static final int STUDY_DESK_14415 = 14415;
- public static final int FISHING_SPOT_14428 = 14428;
public static final int RIFT_14431 = 14431;
public static final int GAS_BUBBLE = 14434;
public static final int CAVE_ENTRANCE_14436 = 14436;
@@ -11551,7 +11548,6 @@ public final class ObjectID
public static final int COMPOST_BIN_20872 = 20872;
public static final int CAGE_20873 = 20873;
public static final int DUNGEON_ENTRANCE_20876 = 20876;
- public static final int DUNGEON_ENTRANCE_20877 = 20877;
public static final int EXIT_20878 = 20878;
public static final int LOG_BALANCE_20882 = 20882;
public static final int LOG_BALANCE_20884 = 20884;
@@ -13122,8 +13118,9 @@ public final class ObjectID
public static final int DISPLAY_CASE_24551 = 24551;
public static final int SPECIMEN_TABLE_24555 = 24555;
public static final int SPECIMEN_TABLE_24556 = 24556;
- public static final int ROCKS_24557 = 24557;
- public static final int DIG_SITE_SPECIMEN_ROCKS = 24559;
+ public static final int DIG_SITE_SPECIMEN_ROCKS = 24557;
+ public static final int DIG_SITE_SPECIMEN_ROCKS_24558 = 24558;
+ public static final int DIG_SITE_SPECIMEN_ROCKS_24559 = 24559;
public static final int GATE_24560 = 24560;
public static final int GATE_24561 = 24561;
public static final int GAP_24562 = 24562;
@@ -13892,14 +13889,11 @@ public final class ObjectID
public static final int CHEST_26193 = 26193;
public static final int LEVER_26194 = 26194;
public static final int BIRTHDAY_CAKE = 26198;
- public static final int BIRTHDAY_CAKE_26199 = 26199;
- public static final int BIRTHDAY_CAKE_26200 = 26200;
+ public static final int GRINDER = 26199;
public static final int TABLE_26201 = 26201;
public static final int TABLE_26202 = 26202;
public static final int TABLE_26203 = 26203;
- public static final int PRESENT = 26204;
- public static final int PRESENT_26205 = 26205;
- public static final int TABLE_26206 = 26206;
+ public static final int DOOR_26205 = 26205;
public static final int LARGE_DOOR_26207 = 26207;
public static final int WOODEN_BENCH_26210 = 26210;
public static final int OAK_BENCH_26211 = 26211;
@@ -17884,12 +17878,12 @@ public final class ObjectID
public static final int POTATO_CACTUS_33746 = 33746;
public static final int POTATO_CACTUS_33747 = 33747;
public static final int POTATO_CACTUS_33748 = 33748;
- public static final int DISEASED_POATO_CACTUS = 33749;
- public static final int DISEASED_POATO_CACTUS_33750 = 33750;
- public static final int DISEASED_POATO_CACTUS_33751 = 33751;
- public static final int DISEASED_POATO_CACTUS_33752 = 33752;
- public static final int DISEASED_POATO_CACTUS_33753 = 33753;
- public static final int DISEASED_POATO_CACTUS_33754 = 33754;
+ public static final int DISEASED_POTATO_CACTUS = 33749;
+ public static final int DISEASED_POTATO_CACTUS_33750 = 33750;
+ public static final int DISEASED_POTATO_CACTUS_33751 = 33751;
+ public static final int DISEASED_POTATO_CACTUS_33752 = 33752;
+ public static final int DISEASED_POTATO_CACTUS_33753 = 33753;
+ public static final int DISEASED_POTATO_CACTUS_33754 = 33754;
public static final int DEAD_POTATO_CACTUS = 33755;
public static final int DEAD_POTATO_CACTUS_33756 = 33756;
public static final int DEAD_POTATO_CACTUS_33757 = 33757;
@@ -18545,10 +18539,31 @@ public final class ObjectID
public static final int ALCHEMICAL_TOPIARY = 34654;
public static final int MYSTERIOUS_PIPE = 34655;
public static final int CHEMICAL_WASTE_PIPE = 34656;
- public static final int GANGPLANK_34657 = 34657;
- public static final int GANGPLANK_34658 = 34658;
public static final int THE_SHEARED_RAM = 34659;
public static final int BRIMSTONE_CHEST = 34660;
public static final int BRIMSTONE_CHEST_34661 = 34661;
+ public static final int RUBBLE_34663 = 34663;
+ public static final int RUBBLE_34664 = 34664;
+ public static final int RUBBLE_34665 = 34665;
+ public static final int RUBBLE_34666 = 34666;
+ public static final int GANGPLANK_34667 = 34667;
+ public static final int GANGPLANK_34668 = 34668;
+ public static final int GANGPLANK_34669 = 34669;
+ public static final int GANGPLANK_34670 = 34670;
+ public static final int GANGPLANK_34671 = 34671;
+ public static final int GANGPLANK_34672 = 34672;
+ public static final int VERZIK_VITUR_DISPLAY = 34677;
+ public static final int MAKING_FRIENDS_WITH_MY_ARM_DISPLAY = 34681;
+ public static final int FIRE_34682 = 34682;
+ public static final int MAGIC_MIRROR = 34683;
+ public static final int ALCHEMICAL_HYDRA_DISPLAY_34684 = 34684;
+ public static final int ATTAS_PLANT_DISPLAY = 34685;
+ public static final int LEATHER_SHIELDS = 34686;
+ public static final int BRYOPHYTA_DISPLAY = 34687;
+ public static final int BANNER_34688 = 34688;
+ public static final int BLOOMING_HESPORI_SPROUT = 34705;
+ public static final int SHRIVELLED_PLANT = 34706;
+ public static final int TWISTED_BUSH = 34712;
+ public static final int DUNGEON_ENTRANCE_34713 = 34713;
/* This file is automatically generated. Do not edit. */
}
diff --git a/runelite-api/src/main/java/net/runelite/api/Perspective.java b/runelite-api/src/main/java/net/runelite/api/Perspective.java
index 99116b7714..a0e2297ab9 100644
--- a/runelite-api/src/main/java/net/runelite/api/Perspective.java
+++ b/runelite-api/src/main/java/net/runelite/api/Perspective.java
@@ -379,7 +379,7 @@ public class Perspective
@Nullable String text,
int zOffset)
{
- if (text == null || "".equals(text))
+ if (text == null)
{
return null;
}
diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java
index 778b271036..68abc5e0f7 100644
--- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java
+++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java
@@ -45,6 +45,29 @@ public final class ScriptID
*/
public static final int CHATBOX_INPUT = 96;
+ /**
+ * Rebuilds the chatbox
+ */
+ public static final int BUILD_CHATBOX = 216;
+
+ /**
+ * Opens the Private Message chat interface
+ *
+ * Jagex refers to this script as {@code meslayer_mode6}
+ *
+ * - String Player to send private message to
+ *
+ */
+ public static final int OPEN_PRIVATE_MESSAGE_INTERFACE = 107;
+
+ /**
+ * Rebuilds the text input widget inside the chat interface
+ *
+ * - String Message Prefix. Only used inside the GE search interfaces
+ *
+ */
+ public static final int CHAT_TEXT_INPUT_REBUILD = 222;
+
/**
* Layouts the bank widgets
*
@@ -93,15 +116,6 @@ public final class ScriptID
*/
public static final int DIARY_QUEST_UPDATE_LINECOUNT = 2523;
- /**
- * Initializes the chatbox input to use RuneLite callbacks
- *
- * - String Prompt text
- * - String Default value
- *
- */
- public static final int RUNELITE_CHATBOX_INPUT_INIT = 10001;
-
/**
* Does nothing
*
diff --git a/runelite-api/src/main/java/net/runelite/api/SpriteID.java b/runelite-api/src/main/java/net/runelite/api/SpriteID.java
index 2c4ac4f878..e707854c12 100644
--- a/runelite-api/src/main/java/net/runelite/api/SpriteID.java
+++ b/runelite-api/src/main/java/net/runelite/api/SpriteID.java
@@ -1172,7 +1172,7 @@ public final class SpriteID
public static final int MINIMAP_ORB_XP_ACTIVATED = 1197;
public static final int MINIMAP_ORB_XP_HOVERED = 1198;
public static final int MINIMAP_ORB_XP_ACTIVATED_HOVERED = 1199;
- public static final int UNKNOWN_BLACK_BLOBS = 1200;
+ public static final int MINIMAP_CLICK_MASK = 1200;
public static final int OPTIONS_ZOOM_SLIDER_THUMB = 1201;
public static final int EMOTE_SIT_UP = 1202;
public static final int EMOTE_STAR_JUMP = 1203;
diff --git a/runelite-api/src/main/java/net/runelite/api/VarClientStr.java b/runelite-api/src/main/java/net/runelite/api/VarClientStr.java
index b3bf1b09b6..9667c56e74 100644
--- a/runelite-api/src/main/java/net/runelite/api/VarClientStr.java
+++ b/runelite-api/src/main/java/net/runelite/api/VarClientStr.java
@@ -34,9 +34,10 @@ import lombok.Getter;
@Getter
public enum VarClientStr
{
- CHATBOX_TYPED_TEXT(1),
- INPUT_TEXT(22),
- RECENT_CLAN_CHAT(129);
+ CHATBOX_TYPED_TEXT(335),
+ INPUT_TEXT(359),
+ PRIVATE_MESSAGE_TARGET(360),
+ RECENT_CLAN_CHAT(362);
private final int index;
}
diff --git a/runelite-api/src/main/java/net/runelite/api/VarPlayer.java b/runelite-api/src/main/java/net/runelite/api/VarPlayer.java
index c358d95da8..62489df3f0 100644
--- a/runelite-api/src/main/java/net/runelite/api/VarPlayer.java
+++ b/runelite-api/src/main/java/net/runelite/api/VarPlayer.java
@@ -37,6 +37,10 @@ public enum VarPlayer
ATTACK_STYLE(43),
QUEST_POINTS(101),
IS_POISONED(102),
+ /**
+ * Seems to start at 50(10 splash) and goes down by 1 every 30 seconds
+ */
+ DISEASE_VALUE(456),
BANK_TAB(115),
@@ -49,6 +53,14 @@ public enum VarPlayer
NMZ_REWARD_POINTS(1060),
+ /**
+ * -1 : Poison immune
+ * Normal poison damage is ceil( this / 5.0f )
+ * If this is greater than or equal to 1000000, the player is envenomed.
+ * Venom damage is (this - 999997) * 2
+ */
+ POISON(102),
+
/**
* 0 : not started
* greater than 0 : in progress
@@ -56,6 +68,11 @@ public enum VarPlayer
*/
THRONE_OF_MISCELLANIA(359),
+ /**
+ * Item currently active in the creation of a buy or sell offer
+ */
+ CURRENT_GE_ITEM(1151),
+
/**
* Experience tracker goal start.
*/
@@ -122,7 +139,30 @@ public enum VarPlayer
* Slayer unlock bitfields
*/
SLAYER_UNLOCK_1(1076),
- SLAYER_UNLOCK_2(1344);
+ SLAYER_UNLOCK_2(1344),
+
+ /**
+ * Music track unlock bitfields
+ */
+ MUSIC_TRACKS_UNLOCKED_1(20),
+ MUSIC_TRACKS_UNLOCKED_2(21),
+ MUSIC_TRACKS_UNLOCKED_3(22),
+ MUSIC_TRACKS_UNLOCKED_4(23),
+ MUSIC_TRACKS_UNLOCKED_5(24),
+ MUSIC_TRACKS_UNLOCKED_6(25),
+ MUSIC_TRACKS_UNLOCKED_7(298),
+ MUSIC_TRACKS_UNLOCKED_8(311),
+ MUSIC_TRACKS_UNLOCKED_9(346),
+ MUSIC_TRACKS_UNLOCKED_10(414),
+ MUSIC_TRACKS_UNLOCKED_11(464),
+ MUSIC_TRACKS_UNLOCKED_12(598),
+ MUSIC_TRACKS_UNLOCKED_13(662),
+ MUSIC_TRACKS_UNLOCKED_14(721),
+ MUSIC_TRACKS_UNLOCKED_15(906),
+ MUSIC_TRACKS_UNLOCKED_16(1009),
+ MUSIC_TRACKS_UNLOCKED_17(1338),
+ MUSIC_TRACKS_UNLOCKED_18(1681),
+ MUSIC_TRACKS_UNLOCKED_19(2065);
private final int id;
}
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 f3ce1e6e12..ca053bd207 100644
--- a/runelite-api/src/main/java/net/runelite/api/Varbits.java
+++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java
@@ -468,7 +468,14 @@ public enum Varbits
BANK_TAB_SIX_COUNT(4176),
BANK_TAB_SEVEN_COUNT(4177),
BANK_TAB_EIGHT_COUNT(4178),
- BANK_TAB_NINE_COUNT(4179);
+ BANK_TAB_NINE_COUNT(4179),
+
+ /**
+ * Type of GE offer currently being created
+ * 0 = buy
+ * 1 = sell
+ */
+ GE_OFFER_CREATION_TYPE(4397);
/**
* The raw varbit ID.
diff --git a/runelite-api/src/main/java/net/runelite/api/coords/WorldArea.java b/runelite-api/src/main/java/net/runelite/api/coords/WorldArea.java
index ea96884f72..9abb3aeac8 100644
--- a/runelite-api/src/main/java/net/runelite/api/coords/WorldArea.java
+++ b/runelite-api/src/main/java/net/runelite/api/coords/WorldArea.java
@@ -114,8 +114,7 @@ public class WorldArea
return Integer.MAX_VALUE;
}
- Point distances = getAxisDistances(other);
- return Math.max(distances.getX(), distances.getY());
+ return distanceTo2D(other);
}
/**
@@ -129,6 +128,29 @@ public class WorldArea
return distanceTo(new WorldArea(other, 1, 1));
}
+ /**
+ * Computes the shortest distance to another area while ignoring the plane.
+ *
+ * @param other the passed area
+ * @return the distance
+ */
+ public int distanceTo2D(WorldArea other)
+ {
+ Point distances = getAxisDistances(other);
+ return Math.max(distances.getX(), distances.getY());
+ }
+
+ /**
+ * Computes the shortest distance to a world coordinate.
+ *
+ * @param other the passed coordinate
+ * @return the distance
+ */
+ public int distanceTo2D(WorldPoint other)
+ {
+ return distanceTo2D(new WorldArea(other, 1, 1));
+ }
+
/**
* Checks whether this area is within melee distance of another.
*
diff --git a/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java b/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java
index 3f164c1845..bbacd1914a 100644
--- a/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java
+++ b/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java
@@ -25,6 +25,10 @@
*/
package net.runelite.api.coords;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import lombok.Value;
import net.runelite.api.Client;
import static net.runelite.api.Constants.CHUNK_SIZE;
@@ -150,7 +154,8 @@ public class WorldPoint
}
/**
- * Gets the coordinate of the tile that contains the passed local point.
+ * Gets the coordinate of the tile that contains the passed local point,
+ * accounting for instances.
*
* @param client the client
* @param localPoint the local coordinate
@@ -190,6 +195,46 @@ public class WorldPoint
}
}
+ /**
+ * Get occurrences of a tile on the scene, accounting for instances. There may be
+ * more than one if the same template chunk occurs more than once on the scene.
+ * @param client
+ * @param worldPoint
+ * @return
+ */
+ public static Collection toLocalInstance(Client client, WorldPoint worldPoint)
+ {
+ if (!client.isInInstancedRegion())
+ {
+ return Collections.singleton(worldPoint);
+ }
+
+ // find instance chunks using the template point. there might be more than one.
+ List worldPoints = new ArrayList<>();
+ final int z = worldPoint.getPlane();
+ int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks();
+ for (int x = 0; x < instanceTemplateChunks[z].length; ++x)
+ {
+ for (int y = 0; y < instanceTemplateChunks[z][x].length; ++y)
+ {
+ int chunkData = instanceTemplateChunks[z][x][y];
+ int rotation = chunkData >> 1 & 0x3;
+ int templateChunkY = (chunkData >> 3 & 0x7FF) * CHUNK_SIZE;
+ int templateChunkX = (chunkData >> 14 & 0x3FF) * CHUNK_SIZE;
+ if (worldPoint.getX() >= templateChunkX && worldPoint.getX() < templateChunkX + CHUNK_SIZE
+ && worldPoint.getY() >= templateChunkY && worldPoint.getY() < templateChunkY + CHUNK_SIZE)
+ {
+ WorldPoint p = new WorldPoint(client.getBaseX() + x * CHUNK_SIZE + (worldPoint.getX() & (CHUNK_SIZE - 1)),
+ client.getBaseY() + y * CHUNK_SIZE + (worldPoint.getY() & (CHUNK_SIZE - 1)),
+ worldPoint.getPlane());
+ p = rotate(p, rotation);
+ worldPoints.add(p);
+ }
+ }
+ }
+ return worldPoints;
+ }
+
/**
* Rotate the coordinates in the chunk according to chunk rotation
*
@@ -281,4 +326,36 @@ public class WorldPoint
{
return ((x >> 6) << 8) | (y >> 6);
}
+
+ /**
+ * Converts the passed region ID and coordinates to a world coordinate
+ */
+ public static WorldPoint fromRegion(int regionId, int regionX, int regionY, int plane)
+ {
+ return new WorldPoint(
+ ((regionId >>> 8) << 6) + regionX,
+ ((regionId & 0xff) << 6) + regionY,
+ plane);
+ }
+
+ /**
+ * Gets the X-axis coordinate of the region coordinate
+ */
+ public int getRegionX()
+ {
+ return getRegionOffset(x);
+ }
+
+ /**
+ * Gets the Y-axis coordinate of the region coordinate
+ */
+ public int getRegionY()
+ {
+ return getRegionOffset(y);
+ }
+
+ private static int getRegionOffset(final int position)
+ {
+ return position & 0x3f;
+ }
}
diff --git a/runelite-api/src/main/java/net/runelite/api/events/ChatMessage.java b/runelite-api/src/main/java/net/runelite/api/events/ChatMessage.java
index 9b5e12b6fd..0f5182e22b 100644
--- a/runelite-api/src/main/java/net/runelite/api/events/ChatMessage.java
+++ b/runelite-api/src/main/java/net/runelite/api/events/ChatMessage.java
@@ -26,7 +26,9 @@ package net.runelite.api.events;
import lombok.AllArgsConstructor;
import lombok.Data;
+import lombok.NoArgsConstructor;
import net.runelite.api.ChatMessageType;
+import net.runelite.api.MessageNode;
/**
* An event where a new chat message is received.
@@ -38,8 +40,13 @@ import net.runelite.api.ChatMessageType;
*/
@Data
@AllArgsConstructor
+@NoArgsConstructor
public class ChatMessage
{
+ /**
+ * The underlying MessageNode for the message.
+ */
+ private MessageNode messageNode;
/**
* The type of message received.
*/
@@ -59,4 +66,8 @@ public class ChatMessage
* current name of the clan chat the client is in.
*/
private String sender;
+ /**
+ * Timestamp of the message.
+ */
+ private int timestamp;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpSnapshotTotal.java b/runelite-api/src/main/java/net/runelite/api/events/ClanMemberJoined.java
similarity index 84%
rename from runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpSnapshotTotal.java
rename to runelite-api/src/main/java/net/runelite/api/events/ClanMemberJoined.java
index 72fcdd93d5..ff2a373c4b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpSnapshotTotal.java
+++ b/runelite-api/src/main/java/net/runelite/api/events/ClanMemberJoined.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Levi
+ * Copyright (c) 2018, trimbe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,18 +22,16 @@
* (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.xptracker;
+package net.runelite.api.events;
import lombok.Value;
+import net.runelite.api.ClanMember;
@Value
-class XpSnapshotTotal
+public class ClanMemberJoined
{
- private final int xpGainedInSession;
- private final int xpPerHour;
-
- static XpSnapshotTotal zero()
- {
- return new XpSnapshotTotal(0, 0);
- }
+ /**
+ * The ClanMember that joined
+ */
+ private ClanMember member;
}
diff --git a/runelite-api/src/main/java/net/runelite/api/events/ClanMemberLeft.java b/runelite-api/src/main/java/net/runelite/api/events/ClanMemberLeft.java
new file mode 100644
index 0000000000..24bc58f960
--- /dev/null
+++ b/runelite-api/src/main/java/net/runelite/api/events/ClanMemberLeft.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018, trimbe
+ * 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.events;
+
+import lombok.Value;
+import net.runelite.api.ClanMember;
+
+@Value
+public class ClanMemberLeft
+{
+ /**
+ * The ClanMember that left
+ */
+ private ClanMember member;
+}
diff --git a/runelite-api/src/main/java/net/runelite/api/events/OverheadTextChanged.java b/runelite-api/src/main/java/net/runelite/api/events/OverheadTextChanged.java
new file mode 100644
index 0000000000..a366eb297a
--- /dev/null
+++ b/runelite-api/src/main/java/net/runelite/api/events/OverheadTextChanged.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, Magic fTail
+ * 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.events;
+
+import lombok.Value;
+import net.runelite.api.Actor;
+
+/**
+ * Event fired when an actors overhead text is changed.
+ */
+@Value
+public class OverheadTextChanged
+{
+ private final Actor actor;
+
+ private final String overheadText;
+}
\ No newline at end of file
diff --git a/runelite-api/src/main/java/net/runelite/api/events/SetMessage.java b/runelite-api/src/main/java/net/runelite/api/events/SetMessage.java
deleted file mode 100644
index 0dde863bcc..0000000000
--- a/runelite-api/src/main/java/net/runelite/api/events/SetMessage.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package net.runelite.api.events;
-
-import lombok.Data;
-import net.runelite.api.ChatMessageType;
-import net.runelite.api.MessageNode;
-
-/**
- * An event where a {@link MessageNode} has had its message set.
- *
- * Called whenever a message is received in the chat box.
- *
- * Editing the {@link #messageNode} properties will reflect the change when
- * the message in the chat is rendered. The original values of the message
- * are held by the other fields of this event.
- */
-@Data
-public class SetMessage
-{
- /**
- * The updated message node.
- */
- private MessageNode messageNode;
- /**
- * The set message type.
- */
- private ChatMessageType type;
- /**
- * The name of the player that sent the message.
- */
- private String name;
- /**
- * The sender of the message (ie. clan name).
- */
- private String sender;
- /**
- * The new message value.
- */
- private String value;
- /**
- * Timestamp of the message.
- */
- private int timestamp;
-}
diff --git a/runelite-api/src/main/java/net/runelite/api/events/VarbitChanged.java b/runelite-api/src/main/java/net/runelite/api/events/VarbitChanged.java
index 5a6d6adc2d..9680e54ac4 100644
--- a/runelite-api/src/main/java/net/runelite/api/events/VarbitChanged.java
+++ b/runelite-api/src/main/java/net/runelite/api/events/VarbitChanged.java
@@ -29,9 +29,14 @@ package net.runelite.api.events;
import lombok.Data;
/**
- * An event where a varbit has changed.
+ * An event when a varbit or varplayer has changed.
*/
@Data
public class VarbitChanged
{
+ /**
+ * Index in the varp array that was changed.
+ * For varplayer, this is the varplayer id.
+ */
+ private int index = -1;
}
\ No newline at end of file
diff --git a/runelite-api/src/main/java/net/runelite/api/geometry/Geometry.java b/runelite-api/src/main/java/net/runelite/api/geometry/Geometry.java
new file mode 100644
index 0000000000..39efa74afa
--- /dev/null
+++ b/runelite-api/src/main/java/net/runelite/api/geometry/Geometry.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2018, Woox
+ * 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.geometry;
+
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+
+public class Geometry
+{
+ /**
+ * Find the point where two lines intersect.
+ *
+ * @param x1 X coordinate of the first endpoint of the first line.
+ * @param y1 Y coordinate of the first endpoint of the first line.
+ * @param x2 X coordinate of the second endpoint of the first line.
+ * @param y2 Y coordinate of the second endpoint of the first line.
+ * @param x3 X coordinate of the first endpoint of the second line.
+ * @param y3 Y coordinate of the first endpoint of the second line.
+ * @param x4 X coordinate of the second endpoint of the second line.
+ * @param y4 Y coordinate of the second endpoint of the second line.
+ * @return The intersection point of the lines, or null if the lines don't intersect.
+ */
+ public static Point2D.Float lineIntersectionPoint(
+ float x1, float y1, float x2, float y2,
+ float x3, float y3, float x4, float y4)
+ {
+ // https://stackoverflow.com/a/1968345
+
+ float p1x = x2 - x1;
+ float p1y = y2 - y1;
+ float p2x = x4 - x3;
+ float p2y = y4 - y3;
+
+ float s = (-p1y * (x1 - x3) + p1x * (y1 - y3)) / (-p2x * p1y + p1x * p2y);
+ float t = ( p2x * (y1 - y3) - p2y * (x1 - x3)) / (-p2x * p1y + p1x * p2y);
+
+ if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
+ {
+ float x = x1 + (t * p1x);
+ float y = y1 + (t * p1y);
+ return new Point2D.Float(x, y);
+ }
+
+ // No intersection
+ return null;
+ }
+
+ /**
+ * Find the intersection points between a Shape and a line.
+ *
+ * @param shape The shape.
+ * @param x1 X coordinate of the first endpoint of the line.
+ * @param y1 Y coordinate of the first endpoint of the line.
+ * @param x2 X coordinate of the second endpoint of the line.
+ * @param y2 Y coordinate of the second endpoint of the line.
+ * @return A list with the intersection points.
+ */
+ public static List intersectionPoints(Shape shape, float x1, float y1, float x2, float y2)
+ {
+ List intersections = new LinkedList<>();
+
+ PathIterator it = shape.getPathIterator(new AffineTransform());
+ float[] coords = new float[2];
+ float[] prevCoords = new float[2];
+ float[] start = new float[2];
+ while (!it.isDone())
+ {
+ int type = it.currentSegment(coords);
+ if (type == PathIterator.SEG_MOVETO)
+ {
+ start[0] = coords[0];
+ start[1] = coords[1];
+ prevCoords[0] = coords[0];
+ prevCoords[1] = coords[1];
+ }
+ else if (type == PathIterator.SEG_LINETO)
+ {
+ Point2D.Float intersection = lineIntersectionPoint(
+ prevCoords[0], prevCoords[1], coords[0], coords[1], x1, y1, x2, y2);
+ if (intersection != null)
+ {
+ intersections.add(intersection);
+ }
+ prevCoords[0] = coords[0];
+ prevCoords[1] = coords[1];
+ }
+ else if (type == PathIterator.SEG_CLOSE)
+ {
+ Point2D.Float intersection = lineIntersectionPoint(
+ coords[0], coords[1], start[0], start[1], x1, y1, x2, y2);
+ if (intersection != null)
+ {
+ intersections.add(intersection);
+ }
+ }
+ it.next();
+ }
+
+ return intersections;
+ }
+
+ /**
+ * Transforms the points in a path according to a method.
+ *
+ * @param it The iterator of the path to change the points on.
+ * @param method The method to use to transform the points. Takes a float[2] array with x and y coordinates as parameter.
+ * @return The transformed path.
+ */
+ public static GeneralPath transformPath(PathIterator it, Consumer method)
+ {
+ GeneralPath path = new GeneralPath();
+ float[] coords = new float[2];
+ while (!it.isDone())
+ {
+ int type = it.currentSegment(coords);
+ if (type == PathIterator.SEG_MOVETO)
+ {
+ method.accept(coords);
+ path.moveTo(coords[0], coords[1]);
+ }
+ else if (type == PathIterator.SEG_LINETO)
+ {
+ method.accept(coords);
+ path.lineTo(coords[0], coords[1]);
+ }
+ else if (type == PathIterator.SEG_CLOSE)
+ {
+ path.closePath();
+ }
+ it.next();
+ }
+
+ return path;
+ }
+
+ /**
+ * Transforms the points in a path according to a method.
+ *
+ * @param path The path to change the points on.
+ * @param method The method to use to transform the points. Takes a float[2] array with x and y coordinates as parameter.
+ * @return The transformed path.
+ */
+ public static GeneralPath transformPath(GeneralPath path, Consumer method)
+ {
+ return transformPath(path.getPathIterator(new AffineTransform()), method);
+ }
+
+ /**
+ * Splits a line into smaller segments and appends the segments to a path.
+ *
+ * @param path The path to append lines to.
+ * @param segmentLength The desired length to use for the segmented lines.
+ * @param x1 X coordinate of the first endpoint of the line.
+ * @param y1 Y coordinate of the first endpoint of the line.
+ * @param x2 X coordinate of the second endpoint of the line.
+ * @param y2 Y coordinate of the second endpoint of the line.
+ */
+ private static void appendSegmentLines(GeneralPath path, float segmentLength,
+ float x1, float y1, float x2, float y2)
+ {
+ float x = x1;
+ float y = y1;
+ float angle = (float)Math.atan2(y2 - y1, x2 - x1);
+ float dx = (float)Math.cos(angle) * segmentLength;
+ float dy = (float)Math.sin(angle) * segmentLength;
+ float length = (float)Math.hypot(x2 - x1, y2 - y1);
+ int steps = (int)((length - 1e-4) / segmentLength);
+ for (int i = 0; i < steps; i++)
+ {
+ x += dx;
+ y += dy;
+ path.lineTo(x, y);
+ }
+ }
+
+ /**
+ * Splits a path into smaller segments.
+ * For example, calling this on a path with a line of length 6, with desired
+ * segment length of 2, would split the path into 3 consecutive lines of length 2.
+ *
+ * @param it The iterator of the path to modify.
+ * @param segmentLength The desired length to use for the segments.
+ * @return The modified path.
+ */
+ public static GeneralPath splitIntoSegments(PathIterator it, float segmentLength)
+ {
+ GeneralPath newPath = new GeneralPath();
+ float[] prevCoords = new float[2];
+ float[] coords = new float[2];
+ float[] startCoords = new float[2];
+ while (!it.isDone())
+ {
+ int type = it.currentSegment(coords);
+ if (type == PathIterator.SEG_MOVETO)
+ {
+ startCoords[0] = coords[0];
+ startCoords[1] = coords[1];
+ newPath.moveTo(coords[0], coords[1]);
+ prevCoords[0] = coords[0];
+ prevCoords[1] = coords[1];
+ }
+ else if (type == PathIterator.SEG_LINETO)
+ {
+ appendSegmentLines(newPath, segmentLength, prevCoords[0], prevCoords[1], coords[0], coords[1]);
+ newPath.lineTo(coords[0], coords[1]);
+ prevCoords[0] = coords[0];
+ prevCoords[1] = coords[1];
+ }
+ else if (type == PathIterator.SEG_CLOSE)
+ {
+ appendSegmentLines(newPath, segmentLength, coords[0], coords[1], startCoords[0], startCoords[1]);
+ newPath.closePath();
+ }
+ it.next();
+ }
+
+ return newPath;
+ }
+
+ /**
+ * Splits a path into smaller segments.
+ * For example, calling this on a path with a line of length 6, with desired
+ * segment length of 2, would split the path into 3 consecutive lines of length 2.
+ *
+ * @param path The path to modify.
+ * @param segmentLength The desired length to use for the segments.
+ * @return The modified path.
+ */
+ public static GeneralPath splitIntoSegments(GeneralPath path, float segmentLength)
+ {
+ return splitIntoSegments(path.getPathIterator(new AffineTransform()), segmentLength);
+ }
+
+ /**
+ * Removes lines from a path according to a method.
+ *
+ * @param it The iterator of the path to filter.
+ * @param method The method to use to decide which lines to remove. Takes two float[2] arrays with x and y coordinates of the endpoints of the line. Lines for which the predicate returns false are removed.
+ * @return The filtered path.
+ */
+ public static GeneralPath filterPath(PathIterator it, BiPredicate method)
+ {
+ GeneralPath newPath = new GeneralPath();
+ float[] prevCoords = new float[2];
+ float[] coords = new float[2];
+ float[] start = new float[2];
+ boolean shouldMoveNext = false;
+ while (!it.isDone())
+ {
+ int type = it.currentSegment(coords);
+ if (type == PathIterator.SEG_MOVETO)
+ {
+ start[0] = coords[0];
+ start[1] = coords[1];
+ prevCoords[0] = coords[0];
+ prevCoords[1] = coords[1];
+ shouldMoveNext = true;
+ }
+ else if (type == PathIterator.SEG_LINETO)
+ {
+ if (method.test(prevCoords, coords))
+ {
+ if (shouldMoveNext)
+ {
+ newPath.moveTo(prevCoords[0], prevCoords[1]);
+ shouldMoveNext = false;
+ }
+ newPath.lineTo(coords[0], coords[1]);
+ }
+ else
+ {
+ shouldMoveNext = true;
+ }
+ prevCoords[0] = coords[0];
+ prevCoords[1] = coords[1];
+ }
+ else if (type == PathIterator.SEG_CLOSE)
+ {
+ if (shouldMoveNext)
+ {
+ newPath.moveTo(prevCoords[0], prevCoords[1]);
+ }
+ if (method.test(prevCoords, start))
+ {
+ newPath.lineTo(start[0], start[1]);
+ }
+ shouldMoveNext = false;
+ }
+ it.next();
+ }
+
+ return newPath;
+ }
+
+ /**
+ * Removes lines from a path according to a method.
+ *
+ * @param path The path to filter.
+ * @param method The method to use to decide which lines to remove. Takes two float[2] arrays with x and y coordinates of the endpoints of the line. Lines for which the predicate returns false are removed.
+ * @return The filtered path.
+ */
+ public static GeneralPath filterPath(GeneralPath path, BiPredicate method)
+ {
+ return filterPath(path.getPathIterator(new AffineTransform()), method);
+ }
+
+ /**
+ * Removes lines from a path that lie outside the clipping area and cuts
+ * lines intersecting with the clipping area so the resulting lines
+ * lie within the clipping area.
+ *
+ * @param it The iterator of the path to clip.
+ * @param shape The clipping area to clip with.
+ * @return The clipped path.
+ */
+ public static GeneralPath clipPath(PathIterator it, Shape shape)
+ {
+ GeneralPath newPath = new GeneralPath();
+ float[] prevCoords = new float[2];
+ float[] coords = new float[2];
+ float[] start = new float[2];
+ float[] nextMove = new float[2];
+ boolean shouldMove = false;
+ boolean wasInside = false;
+ while (!it.isDone())
+ {
+ int type = it.currentSegment(coords);
+ if (type == PathIterator.SEG_MOVETO)
+ {
+ start[0] = coords[0];
+ start[1] = coords[1];
+ wasInside = shape.contains(coords[0], coords[1]);
+ if (wasInside)
+ {
+ nextMove[0] = coords[0];
+ nextMove[1] = coords[1];
+ shouldMove = true;
+ }
+ prevCoords[0] = coords[0];
+ prevCoords[1] = coords[1];
+ }
+ else if (type == PathIterator.SEG_LINETO || type == PathIterator.SEG_CLOSE)
+ {
+ if (type == PathIterator.SEG_CLOSE)
+ {
+ coords[0] = start[0];
+ coords[1] = start[1];
+ }
+
+ List intersections = intersectionPoints(shape, prevCoords[0], prevCoords[1], coords[0], coords[1]);
+ intersections.sort((a, b) ->
+ {
+ double diff = a.distance(prevCoords[0], prevCoords[1]) - b.distance(prevCoords[0], prevCoords[1]);
+ if (diff < 0)
+ {
+ return -1;
+ }
+ if (diff > 0)
+ {
+ return 1;
+ }
+ return 0;
+ });
+
+ for (Point2D.Float intersection : intersections)
+ {
+ if (wasInside)
+ {
+ if (shouldMove)
+ {
+ newPath.moveTo(nextMove[0], nextMove[1]);
+ shouldMove = false;
+ }
+ newPath.lineTo(intersection.getX(), intersection.getY());
+ }
+ else
+ {
+ nextMove[0] = intersection.x;
+ nextMove[1] = intersection.y;
+ shouldMove = true;
+ }
+ wasInside = !wasInside;
+ prevCoords[0] = intersection.x;
+ prevCoords[1] = intersection.y;
+ }
+
+ wasInside = shape.contains(coords[0], coords[1]);
+ if (wasInside)
+ {
+ if (shouldMove)
+ {
+ newPath.moveTo(nextMove[0], nextMove[1]);
+ shouldMove = false;
+ }
+ newPath.lineTo(coords[0], coords[1]);
+ }
+ else
+ {
+ nextMove[0] = coords[0];
+ nextMove[1] = coords[1];
+ shouldMove = true;
+ }
+
+ prevCoords[0] = coords[0];
+ prevCoords[1] = coords[1];
+ }
+ it.next();
+ }
+ return newPath;
+ }
+
+ /**
+ * Removes lines from a path that lie outside the clipping area and cuts
+ * lines intersecting with the clipping area so the resulting lines
+ * lie within the clipping area.
+ *
+ * @param path The path to clip.
+ * @param shape The clipping area to clip with.
+ * @return The clipped path.
+ */
+ public static GeneralPath clipPath(GeneralPath path, Shape shape)
+ {
+ return clipPath(path.getPathIterator(new AffineTransform()), shape);
+ }
+}
diff --git a/runelite-api/src/main/java/net/runelite/api/vars/InputType.java b/runelite-api/src/main/java/net/runelite/api/vars/InputType.java
index db1301b281..c94ccd79ef 100644
--- a/runelite-api/src/main/java/net/runelite/api/vars/InputType.java
+++ b/runelite-api/src/main/java/net/runelite/api/vars/InputType.java
@@ -38,6 +38,7 @@ public enum InputType
RUNELITE_CHATBOX_PANEL(-3),
RUNELITE(-2),
NONE(0),
+ PRIVATE_MESSAGE(6),
SEARCH(11);
private final int type;
diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java
index 3aa6e23f13..ed4277a2a3 100644
--- a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java
+++ b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java
@@ -79,6 +79,7 @@ public interface Widget
/**
* Gets the current click configuration of the widget.
+ * @see WidgetConfig
*
* @see WidgetConfig
*/
@@ -551,6 +552,13 @@ public interface Widget
*/
void setOnMouseOverListener(Object... args);
+ /**
+ * Sets a script to be ran every frame when the mouse is in the widget bounds
+ *
+ * @param args A ScriptID, then the args for the script
+ */
+ void setOnMouseRepeatListener(Object... args);
+
/**
* Sets a script to be ran when the mouse leaves the widget bounds
*
@@ -565,6 +573,20 @@ public interface Widget
*/
void setOnTimerListener(Object... args);
+ /**
+ * Sets a script to be ran when the target mode has been activated for this widget
+ *
+ * @param args A ScriptID, then the args for the script
+ */
+ void setOnTargetEnterListener(Object... args);
+
+ /**
+ * Sets a script to be ran when the target mode has been deactivated for this widget
+ *
+ * @param args A ScriptID, then the args for the script
+ */
+ void setOnTargetLeaveListener(Object... args);
+
/**
* If this widget has any listeners on it
*/
@@ -769,4 +791,34 @@ public interface Widget
* Sets if the rectangle is filled or just stroked
*/
void setFilled(boolean filled);
+
+ /**
+ * Verb for spell targets
+ */
+ String getTargetVerb();
+
+ /**
+ * Verb for spell targets
+ */
+ void setTargetVerb(String targetVerb);
+
+ /**
+ * Can widgets under this widgets be clicked in this widgets bounding box
+ */
+ boolean getNoClickThrough();
+
+ /**
+ * Can widgets under this widgets be clicked in this widgets bounding box
+ */
+ void setNoClickThrough(boolean noClickThrough);
+
+ /**
+ * Can widgets under this widgets be scrolled in this widgets bounding box
+ */
+ boolean getNoScrollThrough();
+
+ /**
+ * Can widgets under this widgets be scrolled in this widgets bounding box
+ */
+ void setNoScrollThrough(boolean noScrollThrough);
}
diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetConfig.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetConfig.java
index 0b8f6a587d..31829b5417 100644
--- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetConfig.java
+++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetConfig.java
@@ -24,6 +24,8 @@
*/
package net.runelite.api.widgets;
+import net.runelite.api.MenuAction;
+
/**
* Utility class used for defining options to be used on the click mask
* of a {@link Widget}.
@@ -36,12 +38,61 @@ public class WidgetConfig
* Enables displaying a ninth option on a menu.
*/
public static final int SHOW_MENU_OPTION_NINE = 1 << 9;
+
+ /**
+ * Can this widget be used on a item on the floor
+ */
+ public static final int USE_GROUND_ITEM = 1 << 11;
+
+ /**
+ * Can this widget be used on a NPC
+ */
+ public static final int USE_NPC = 2 << 11;
+
+ /**
+ * Can this widget be used on a game object
+ */
+ public static final int USE_OBJECT = 4 << 11;
+
+ /**
+ * Can this widget be used on a player
+ */
+ public static final int USE_PLAYER = 8 << 11;
+
+ /**
+ * Can this widget be used on a item in your inventory
+ */
+ public static final int USE_ITEM = 16 << 11;
+
+ /**
+ * Can this widget be used on a widget with the WIDGET_USE_TARGET flag
+ */
+ public static final int USE_WIDGET = 32 << 11;
+
/**
* Controls whether or not a widget can have another dragged onto it.
*/
public static final int DRAG_ON = 1 << 17;
+
/**
* Controls whether or not a widget can be dragged around.
*/
public static final int DRAG = 1 << 20;
+
+ /**
+ * Can widgets with USE_WIDGET be used on this widget
+ */
+ public static final int WIDGET_USE_TARGET = 1 << 21;
+
+ /**
+ * Is the widget an (inventory?) item
+ */
+ public static final int ITEM = 1 << 30;
+
+ /**
+ * Add a USE option
+ *
+ * @see MenuAction#ITEM_USE
+ */
+ public static final int ITEM_USE_OP = 1 << 31;
}
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 bb9d8b6000..e6a73dc211 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
@@ -125,6 +125,8 @@ public class WidgetID
public static final int SKOTIZO_GROUP_ID = 308;
public static final int ENTERING_HOUSE_GROUP_ID = 71;
public static final int FULLSCREEN_MAP_GROUP_ID = 165;
+ public static final int QUESTLIST_GROUP_ID = 399;
+ public static final int SKILLS_GROUP_ID = 320;
static class WorldMap
{
@@ -133,7 +135,7 @@ public class WidgetID
static final int SEARCH = 24;
static final int SURFACE_SELECTOR = 32;
static final int TOOLTIP = 38;
- static final int OPTION = 42;
+ static final int OPTION = 43;
}
static class SlayerRewards
@@ -292,6 +294,7 @@ public class WidgetID
static final int TOGGLE_RUN_ORB = 22; // Has the "Toggle run" name
static final int RUN_ORB_TEXT = 23;
static final int SPEC_ORB = 28;
+ static final int WORLDMAP_ORB = 41;
}
static class LoginClickToPlayScreen
@@ -347,6 +350,7 @@ public class WidgetID
static final int ROOT_INTERFACE_CONTAINER = 62;
static final int BANK_CONTAINER = 64;
static final int INTERFACE_CONTAINER = 65;
+ static final int INVENTORY_CONTAINER = 69;
}
static class ResizableViewport
@@ -380,6 +384,7 @@ public class WidgetID
static final int PRAYER_ICON = 63;
static final int MAGIC_ICON = 64;
static final int INTERFACE_CONTAINER = 65;
+ static final int INVENTORY_CONTAINER = 71;
}
static class ResizableViewportBottomLine
@@ -412,6 +417,7 @@ public class WidgetID
static final int MUSIC_TAB = 40;
static final int MUSIC_ICON = 46;
static final int MAGIC_ICON = 63;
+ static final int INVENTORY_CONTAINER = 71;
}
static class Chatbox
@@ -513,6 +519,7 @@ public class WidgetID
static final int SPELL_BOX = 25;
static final int SPELL_ICON = 27;
static final int SPELL_TEXT = 28;
+ static final int AUTO_RETALIATE = 29;
}
static class VolcanicMine
@@ -566,7 +573,7 @@ public class WidgetID
static class Raids
{
- static final int POINTS_INFOBOX = 3;
+ static final int POINTS_INFOBOX = 6;
}
static class ExperienceDrop
@@ -685,7 +692,7 @@ public class WidgetID
static class Minigames
{
- static final int TELEPORT_BUTTON = 31;
+ static final int TELEPORT_BUTTON = 26;
}
static class StandardSpellBook
@@ -710,16 +717,11 @@ public class WidgetID
static class Pvp
{
- static final int BOUNTY_HUNTER_INFO = 6;
- static final int KILLDEATH_RATIO = 9;
- static final int BOUNTY_HUNTER_STATS = 28;
- static final int PVP_WIDGET_CONTAINER = 54;
- static final int SKULL_CONTAINER = 55;
- static final int SKULL = 56;
- static final int SAFE_ZONE = 57;
- static final int ATTACK_RANGE = 59;
- static final int WILDERNESS_LEVEL = 60; // this can also be the Deadman Mode "Protection" text
- static final int DEADMAN_PROTECTION_TIME = 61;
+ static final int BOUNTY_HUNTER_INFO = 19;
+ static final int KILLDEATH_RATIO = 15;
+ static final int SKULL_CONTAINER = 62;
+ static final int SAFE_ZONE = 64;
+ static final int WILDERNESS_LEVEL = 67; // this can also be the Deadman Mode "Protection" text
}
static class KourendFavour
@@ -746,4 +748,11 @@ public class WidgetID
{
static final int ROOT = 25;
}
+
+ static class QuestList
+ {
+ static final int FREE_CONTAINER = 6;
+ static final int MEMBERS_CONTAINER = 7;
+ static final int MINIQUEST_CONTAINER = 8;
+ }
}
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 ef02681690..fb9b005bb5 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
@@ -76,8 +76,6 @@ public enum WidgetInfo
EMOTE_WINDOW(WidgetID.EMOTES_GROUP_ID, WidgetID.Emotes.EMOTE_WINDOW),
EMOTE_CONTAINER(WidgetID.EMOTES_GROUP_ID, WidgetID.Emotes.EMOTE_CONTAINER),
- DIARY_LIST(WidgetID.DIARY_GROUP_ID, 10),
-
DIARY_QUEST_WIDGET_TITLE(WidgetID.DIARY_QUEST_GROUP_ID, WidgetID.Diary.DIARY_TITLE),
DIARY_QUEST_WIDGET_TEXT(WidgetID.DIARY_QUEST_GROUP_ID, WidgetID.Diary.DIARY_TEXT),
@@ -159,6 +157,7 @@ public enum WidgetInfo
MINIMAP_RUN_ORB_TEXT(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.RUN_ORB_TEXT),
MINIMAP_HEALTH_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.HEALTH_ORB),
MINIMAP_SPEC_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.SPEC_ORB),
+ MINIMAP_WORLDMAP_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.WORLDMAP_ORB),
LOGIN_CLICK_TO_PLAY_SCREEN(WidgetID.LOGIN_CLICK_TO_PLAY_GROUP_ID, 0),
LOGIN_CLICK_TO_PLAY_SCREEN_MESSAGE_OF_THE_DAY(WidgetID.LOGIN_CLICK_TO_PLAY_GROUP_ID, WidgetID.LoginClickToPlayScreen.MESSAGE_OF_THE_DAY),
@@ -167,6 +166,7 @@ public enum WidgetInfo
FIXED_VIEWPORT_ROOT_INTERFACE_CONTAINER(WidgetID.FIXED_VIEWPORT_GROUP_ID, WidgetID.FixedViewport.ROOT_INTERFACE_CONTAINER),
FIXED_VIEWPORT_BANK_CONTAINER(WidgetID.FIXED_VIEWPORT_GROUP_ID, WidgetID.FixedViewport.BANK_CONTAINER),
FIXED_VIEWPORT_INTERFACE_CONTAINER(WidgetID.FIXED_VIEWPORT_GROUP_ID, WidgetID.FixedViewport.INTERFACE_CONTAINER),
+ FIXED_VIEWPORT_INVENTORY_CONTAINER(WidgetID.FIXED_VIEWPORT_GROUP_ID, WidgetID.FixedViewport.INVENTORY_CONTAINER),
FIXED_VIEWPORT_COMBAT_TAB(WidgetID.FIXED_VIEWPORT_GROUP_ID, WidgetID.FixedViewport.COMBAT_TAB),
FIXED_VIEWPORT_STATS_TAB(WidgetID.FIXED_VIEWPORT_GROUP_ID, WidgetID.FixedViewport.STATS_TAB),
FIXED_VIEWPORT_QUESTS_TAB(WidgetID.FIXED_VIEWPORT_GROUP_ID, WidgetID.FixedViewport.QUESTS_TAB),
@@ -257,7 +257,9 @@ public enum WidgetInfo
RESIZABLE_VIEWPORT_BOTTOM_LINE_OPTIONS_ICON(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID, WidgetID.ResizableViewportBottomLine.SETTINGS_ICON),
RESIZABLE_VIEWPORT_BOTTOM_LINE_EMOTES_ICON(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID, WidgetID.ResizableViewportBottomLine.EMOTE_ICON),
RESIZABLE_VIEWPORT_BOTTOM_LINE_MUSIC_ICON(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID, WidgetID.ResizableViewportBottomLine.MUSIC_ICON),
+ RESIZABLE_VIEWPORT_BOTTOM_LINE_INVENTORY_CONTAINER(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID, WidgetID.ResizableViewportBottomLine.INVENTORY_CONTAINER),
RESIZABLE_VIEWPORT_INTERFACE_CONTAINER(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID, WidgetID.ResizableViewport.INTERFACE_CONTAINER),
+ RESIZABLE_VIEWPORT_INVENTORY_CONTAINER(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID, WidgetID.ResizableViewport.INVENTORY_CONTAINER),
RESIZABLE_VIEWPORT_BOTTOM_LINE_INTERFACE_CONTAINER(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID, WidgetID.ResizableViewport.INTERFACE_CONTAINER),
PRAYER_THICK_SKIN(WidgetID.PRAYER_GROUP_ID, WidgetID.Prayer.THICK_SKIN),
@@ -305,6 +307,7 @@ public enum WidgetInfo
COMBAT_SPELL_BOX(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPELL_BOX),
COMBAT_SPELL_ICON(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPELL_ICON),
COMBAT_SPELL_TEXT(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPELL_TEXT),
+ COMBAT_AUTO_RETALIATE(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.AUTO_RETALIATE),
DIALOG_OPTION(WidgetID.DIALOG_OPTION_GROUP_ID, 0),
@@ -441,19 +444,12 @@ public enum WidgetInfo
SPELL_LUNAR_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.LunarSpellBook.LUNAR_HOME_TELEPORT),
SPELL_ARCEUUS_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.ArceuusSpellBook.ARCEUUS_HOME_TELEPORT),
- PVP_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.PVP_WIDGET_CONTAINER),
PVP_SKULL_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL_CONTAINER),
- PVP_SKULL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL),
- PVP_WILDERNESS_LEVEL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.ATTACK_RANGE),
- PVP_BOUNTY_HUNTER_INFO(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.BOUNTY_HUNTER_INFO),
- PVP_BOUNTY_HUNTER_STATS(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.BOUNTY_HUNTER_STATS),
- PVP_KILLDEATH_COUNTER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.KILLDEATH_RATIO),
-
PVP_WORLD_SAFE_ZONE(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SAFE_ZONE),
- PVP_WORLD_ATTACK_RANGE(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.ATTACK_RANGE),
- DEADMAN_PROTECTION_TEXT(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.WILDERNESS_LEVEL),
- DEADMAN_PROTECTION_TIME(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.DEADMAN_PROTECTION_TIME),
+ PVP_WILDERNESS_LEVEL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.WILDERNESS_LEVEL),
+ PVP_BOUNTY_HUNTER_INFO(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.BOUNTY_HUNTER_INFO),
+ PVP_KILLDEATH_COUNTER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.KILLDEATH_RATIO),
KOUREND_FAVOUR_OVERLAY(WidgetID.KOUREND_FAVOUR_GROUP_ID, WidgetID.KourendFavour.KOUREND_FAVOUR_OVERLAY),
ZEAH_MESS_HALL_COOKING_DISPLAY(WidgetID.ZEAH_MESS_HALL_GROUP_ID, WidgetID.Zeah.MESS_HALL_COOKING_DISPLAY),
@@ -462,7 +458,11 @@ public enum WidgetInfo
SKOTIZO_CONTAINER(WidgetID.SKOTIZO_GROUP_ID, WidgetID.Skotizo.CONTAINER),
- FULLSCREEN_MAP_ROOT(WidgetID.FULLSCREEN_MAP_GROUP_ID, WidgetID.FullScreenMap.ROOT);
+ FULLSCREEN_MAP_ROOT(WidgetID.FULLSCREEN_MAP_GROUP_ID, WidgetID.FullScreenMap.ROOT),
+
+ QUESTLIST_FREE_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.FREE_CONTAINER),
+ QUESTLIST_MEMBERS_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.MEMBERS_CONTAINER),
+ QUESTLIST_MINIQUEST_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.MINIQUEST_CONTAINER);
private final int groupId;
private final int childId;
diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetType.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetType.java
index da76a7580f..9d140c3cd0 100644
--- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetType.java
+++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetType.java
@@ -27,9 +27,12 @@ package net.runelite.api.widgets;
public final class WidgetType
{
public static final int LAYER = 0;
+ public static final int INVENTORY = 2;
public static final int RECTANGLE = 3;
public static final int TEXT = 4;
public static final int GRAPHIC = 5;
public static final int MODEL = 6;
+ public static final int TEXT_INVENTORY = 7;
+ public static final int IF1_TOOLTIP = 8;
public static final int LINE = 9;
}
diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml
index 6306dc3763..9198253015 100644
--- a/runelite-client/pom.xml
+++ b/runelite-client/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.5.12-SNAPSHOT
+ 1.5.18-SNAPSHOT
client
diff --git a/runelite-client/src/main/java/net/runelite/client/Notifier.java b/runelite-client/src/main/java/net/runelite/client/Notifier.java
index 491c397202..b48a2f6e71 100644
--- a/runelite-client/src/main/java/net/runelite/client/Notifier.java
+++ b/runelite-client/src/main/java/net/runelite/client/Notifier.java
@@ -154,13 +154,13 @@ public class Notifier
public void processFlash(final Graphics2D graphics)
{
- if (flashStart == null)
+ if (flashStart == null || client.getGameCycle() % 40 >= 20)
{
return;
}
-
- if (client.getGameCycle() % 40 >= 20)
+ else if (client.getGameState() != GameState.LOGGED_IN)
{
+ flashStart = null;
return;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java
index b7fae34e2c..ecdda28103 100644
--- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java
+++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java
@@ -183,9 +183,9 @@ public class RuneLite
System.exit(0);
}
- final boolean developerMode = options.has("developer-mode");
+ final boolean developerMode = options.has("developer-mode") && RuneLiteProperties.getLauncherVersion() == null;
- if (developerMode && RuneLiteProperties.getLauncherVersion() == null)
+ if (developerMode)
{
boolean assertions = false;
assert assertions = true;
diff --git a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java
index 63f6b9b479..6ef8c82e73 100644
--- a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java
@@ -36,8 +36,8 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
-import net.runelite.api.events.SessionClose;
-import net.runelite.api.events.SessionOpen;
+import net.runelite.client.events.SessionClose;
+import net.runelite.client.events.SessionOpen;
import net.runelite.client.RuneLite;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
@@ -155,7 +155,7 @@ public class SessionManager
private void closeSession()
{
- wsClient.close();
+ wsClient.changeSession(null);
if (accountSession == null)
{
diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java
index 4cb368ace7..08cd4ea3fe 100644
--- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java
+++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java
@@ -186,8 +186,8 @@ public class Hooks implements Callbacks
* When the world map opens it loads about ~100mb of data into memory, which
* represents about half of the total memory allocated by the client.
* This gets cached and never released, which causes GC pressure which can affect
- * performance. This method reinitailzies the world map cache, which allows the
- * data to be garbage collecged, and causes the map data from disk each time
+ * performance. This method reinitializes the world map cache, which allows the
+ * data to be garbage collected, and causes the map data from disk each time
* is it opened.
*/
private void checkWorldMap()
diff --git a/runelite-client/src/main/java/net/runelite/client/chat/ChatCommand.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatCommand.java
index fb2de339a3..6b4fb9eec2 100644
--- a/runelite-client/src/main/java/net/runelite/client/chat/ChatCommand.java
+++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatCommand.java
@@ -28,7 +28,7 @@ import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import lombok.AllArgsConstructor;
import lombok.Getter;
-import net.runelite.api.events.SetMessage;
+import net.runelite.api.events.ChatMessage;
import net.runelite.client.events.ChatInput;
@AllArgsConstructor
@@ -37,6 +37,6 @@ class ChatCommand
{
private final String name;
private boolean async;
- private final BiConsumer execute;
+ private final BiConsumer execute;
private final BiPredicate input;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/chat/ChatCommandManager.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatCommandManager.java
index 4d062d5c91..415afd8d80 100644
--- a/runelite-client/src/main/java/net/runelite/client/chat/ChatCommandManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatCommandManager.java
@@ -34,7 +34,7 @@ import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
-import net.runelite.api.events.SetMessage;
+import net.runelite.api.events.ChatMessage;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ChatInput;
@@ -59,22 +59,22 @@ public class ChatCommandManager implements ChatboxInputListener
commandManager.register(this);
}
- public void registerCommand(String command, BiConsumer execute)
+ public void registerCommand(String command, BiConsumer execute)
{
registerCommand(command, execute, null);
}
- public void registerCommand(String command, BiConsumer execute, BiPredicate input)
+ public void registerCommand(String command, BiConsumer execute, BiPredicate input)
{
commands.put(command.toLowerCase(), new ChatCommand(command, false, execute, input));
}
- public void registerCommandAsync(String command, BiConsumer execute)
+ public void registerCommandAsync(String command, BiConsumer execute)
{
registerCommandAsync(command, execute, null);
}
- public void registerCommandAsync(String command, BiConsumer execute, BiPredicate input)
+ public void registerCommandAsync(String command, BiConsumer execute, BiPredicate input)
{
commands.put(command.toLowerCase(), new ChatCommand(command, true, execute, input));
}
@@ -85,14 +85,14 @@ public class ChatCommandManager implements ChatboxInputListener
}
@Subscribe
- public void onSetMessage(SetMessage setMessage)
+ public void onChatMessage(ChatMessage chatMessage)
{
if (client.getGameState() != GameState.LOGGED_IN)
{
return;
}
- switch (setMessage.getType())
+ switch (chatMessage.getType())
{
case PUBLIC:
case PUBLIC_MOD:
@@ -104,7 +104,7 @@ public class ChatCommandManager implements ChatboxInputListener
return;
}
- String message = setMessage.getValue();
+ String message = chatMessage.getMessage();
String command = extractCommand(message);
if (command == null)
@@ -120,11 +120,11 @@ public class ChatCommandManager implements ChatboxInputListener
if (chatCommand.isAsync())
{
- scheduledExecutorService.execute(() -> chatCommand.getExecute().accept(setMessage, message));
+ scheduledExecutorService.execute(() -> chatCommand.getExecute().accept(chatMessage, message));
}
else
{
- chatCommand.getExecute().accept(setMessage, message);
+ chatCommand.getExecute().accept(chatMessage, message);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java
index b563773915..0dc2d7de1d 100644
--- a/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java
@@ -42,10 +42,10 @@ import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.MessageNode;
import net.runelite.api.Varbits;
+import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ResizeableChanged;
import net.runelite.api.events.ScriptCallbackEvent;
-import net.runelite.api.events.SetMessage;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ChatColorConfig;
@@ -103,10 +103,10 @@ public class ChatMessageManager
}
@Subscribe
- public void onSetMessage(SetMessage setMessage)
+ public void onChatMessage(ChatMessage chatMessage)
{
- MessageNode messageNode = setMessage.getMessageNode();
- ChatMessageType chatMessageType = setMessage.getType();
+ MessageNode messageNode = chatMessage.getMessageNode();
+ ChatMessageType chatMessageType = chatMessage.getType();
boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1;
Color usernameColor = null;
@@ -125,7 +125,7 @@ public class ChatMessageManager
case PUBLIC:
case PUBLIC_MOD:
{
- boolean isFriend = client.isFriended(setMessage.getName(), true) && !client.getLocalPlayer().getName().equals(setMessage.getName());
+ boolean isFriend = client.isFriended(chatMessage.getName(), true) && !client.getLocalPlayer().getName().equals(chatMessage.getName());
if (isFriend)
{
@@ -149,7 +149,7 @@ public class ChatMessageManager
messageNode.setName(ColorUtil.wrapWithColorTag(messageNode.getName(), usernameColor));
}
- String sender = setMessage.getSender();
+ String sender = chatMessage.getSender();
if (senderColor != null && !Strings.isNullOrEmpty(sender))
{
messageNode.setSender(ColorUtil.wrapWithColorTag(sender, senderColor));
diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java
index 2cde4900ad..87f63d3826 100644
--- a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java
@@ -43,8 +43,12 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.nio.channels.FileLock;
import java.nio.charset.Charset;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -56,6 +60,7 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
+import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.client.RuneLite;
import net.runelite.client.account.AccountSession;
@@ -70,6 +75,7 @@ import net.runelite.http.api.config.Configuration;
public class ConfigManager
{
private static final String SETTINGS_FILE_NAME = "settings.properties";
+ private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
@Inject
EventBus eventBus;
@@ -95,6 +101,9 @@ public class ConfigManager
public final void switchSession(AccountSession session)
{
+ // Ensure existing config is saved
+ sendConfig();
+
if (session == null)
{
this.session = null;
@@ -111,12 +120,17 @@ public class ConfigManager
load(); // load profile specific config
}
+ private File getLocalPropertiesFile()
+ {
+ return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
+ }
+
private File getPropertiesFile()
{
// Sessions that aren't logged in have no username
if (session == null || session.getUsername() == null)
{
- return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
+ return getLocalPropertiesFile();
}
else
{
@@ -146,7 +160,7 @@ public class ConfigManager
return;
}
- if (configuration.getConfig().isEmpty())
+ if (configuration.getConfig() == null || configuration.getConfig().isEmpty())
{
log.debug("No configuration from client, using saved configuration on disk");
loadFromFile();
@@ -158,7 +172,13 @@ public class ConfigManager
for (ConfigEntry entry : configuration.getConfig())
{
log.debug("Loading configuration value from client {}: {}", entry.getKey(), entry.getValue());
- final String[] split = entry.getKey().split("\\.");
+ final String[] split = entry.getKey().split("\\.", 2);
+
+ if (split.length != 2)
+ {
+ continue;
+ }
+
final String groupName = split[0];
final String key = split[1];
final String value = entry.getValue();
@@ -174,7 +194,7 @@ public class ConfigManager
try
{
- saveToFile();
+ saveToFile(propertiesFile);
log.debug("Updated configuration on disk with the latest version");
}
@@ -184,6 +204,75 @@ public class ConfigManager
}
}
+ private synchronized void syncPropertiesFromFile(File propertiesFile)
+ {
+ final Properties properties = new Properties();
+ try (FileInputStream in = new FileInputStream(propertiesFile))
+ {
+ properties.load(new InputStreamReader(in, Charset.forName("UTF-8")));
+ }
+ catch (Exception e)
+ {
+ log.debug("Malformed properties, skipping update");
+ return;
+ }
+
+ final Map copy = (Map) ImmutableMap.copyOf(this.properties);
+ copy.forEach((groupAndKey, value) ->
+ {
+ if (!properties.containsKey(groupAndKey))
+ {
+ final String[] split = groupAndKey.split("\\.", 2);
+ if (split.length != 2)
+ {
+ return;
+ }
+
+ final String groupName = split[0];
+ final String key = split[1];
+ unsetConfiguration(groupName, key);
+ }
+ });
+
+ properties.forEach((objGroupAndKey, objValue) ->
+ {
+ final String groupAndKey = String.valueOf(objGroupAndKey);
+ final String[] split = groupAndKey.split("\\.", 2);
+ if (split.length != 2)
+ {
+ return;
+ }
+
+ final String groupName = split[0];
+ final String key = split[1];
+ final String value = String.valueOf(objValue);
+ setConfiguration(groupName, key, value);
+ });
+ }
+
+ public void importLocal()
+ {
+ if (session == null)
+ {
+ // No session, no import
+ return;
+ }
+
+ final File file = new File(propertiesFile.getParent(), propertiesFile.getName() + "." + TIME_FORMAT.format(new Date()));
+
+ try
+ {
+ saveToFile(file);
+ }
+ catch (IOException e)
+ {
+ log.warn("Backup failed, skipping import", e);
+ return;
+ }
+
+ syncPropertiesFromFile(getLocalPropertiesFile());
+ }
+
private synchronized void loadFromFile()
{
properties.clear();
@@ -231,7 +320,7 @@ public class ConfigManager
}
}
- private synchronized void saveToFile() throws IOException
+ private void saveToFile(final File propertiesFile) throws IOException
{
propertiesFile.getParentFile().mkdirs();
@@ -294,8 +383,6 @@ public class ConfigManager
public void setConfiguration(String groupName, String key, String value)
{
- log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
-
String oldValue = (String) properties.setProperty(groupName + "." + key, value);
if (Objects.equals(oldValue, value))
@@ -303,24 +390,13 @@ public class ConfigManager
return;
}
+ log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
+
synchronized (pendingChanges)
{
pendingChanges.put(groupName + "." + key, value);
}
- Runnable task = () ->
- {
- try
- {
- saveToFile();
- }
- catch (IOException ex)
- {
- log.warn("unable to save configuration file", ex);
- }
- };
- executor.execute(task);
-
ConfigChanged configChanged = new ConfigChanged();
configChanged.setGroup(groupName);
configChanged.setKey(key);
@@ -337,8 +413,6 @@ public class ConfigManager
public void unsetConfiguration(String groupName, String key)
{
- log.debug("Unsetting configuration value for {}.{}", groupName, key);
-
String oldValue = (String) properties.remove(groupName + "." + key);
if (oldValue == null)
@@ -346,24 +420,13 @@ public class ConfigManager
return;
}
+ log.debug("Unsetting configuration value for {}.{}", groupName, key);
+
synchronized (pendingChanges)
{
pendingChanges.put(groupName + "." + key, null);
}
- Runnable task = () ->
- {
- try
- {
- saveToFile();
- }
- catch (IOException ex)
- {
- log.warn("unable to save configuration file", ex);
- }
- };
- executor.execute(task);
-
ConfigChanged configChanged = new ConfigChanged();
configChanged.setGroup(groupName);
configChanged.setKey(key);
@@ -527,6 +590,18 @@ public class ConfigManager
}
return new Keybind(code, mods);
}
+ if (type == WorldPoint.class)
+ {
+ String[] splitStr = str.split(":");
+ int x = Integer.parseInt(splitStr[0]);
+ int y = Integer.parseInt(splitStr[1]);
+ int plane = Integer.parseInt(splitStr[2]);
+ return new WorldPoint(x, y, plane);
+ }
+ if (type == Duration.class)
+ {
+ return Duration.ofMillis(Long.parseLong(str));
+ }
return str;
}
@@ -564,11 +639,21 @@ public class ConfigManager
Keybind k = (Keybind) object;
return k.getKeyCode() + ":" + k.getModifiers();
}
+ if (object instanceof WorldPoint)
+ {
+ WorldPoint wp = (WorldPoint) object;
+ return wp.getX() + ":" + wp.getY() + ":" + wp.getPlane();
+ }
+ if (object instanceof Duration)
+ {
+ return Long.toString(((Duration) object).toMillis());
+ }
return object.toString();
}
public void sendConfig()
{
+ boolean changed;
synchronized (pendingChanges)
{
if (client != null)
@@ -588,7 +673,20 @@ public class ConfigManager
}
}
}
+ changed = !pendingChanges.isEmpty();
pendingChanges.clear();
}
+
+ if (changed)
+ {
+ try
+ {
+ saveToFile(propertiesFile);
+ }
+ catch (IOException ex)
+ {
+ log.warn("unable to save configuration file", ex);
+ }
+ }
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/discord/DiscordService.java b/runelite-client/src/main/java/net/runelite/client/discord/DiscordService.java
index 0c2739b8a2..091c479ac6 100644
--- a/runelite-client/src/main/java/net/runelite/client/discord/DiscordService.java
+++ b/runelite-client/src/main/java/net/runelite/client/discord/DiscordService.java
@@ -78,7 +78,7 @@ public class DiscordService implements AutoCloseable
discordRPC = DiscordRPC.INSTANCE;
discordEventHandlers = new DiscordEventHandlers();
}
- catch (UnsatisfiedLinkError e)
+ catch (Error e)
{
log.warn("Failed to load Discord library, Discord support will be disabled.");
}
@@ -150,9 +150,12 @@ public class DiscordService implements AutoCloseable
? "default"
: discordPresence.getLargeImageKey();
discordRichPresence.largeImageText = discordPresence.getLargeImageText();
- discordRichPresence.smallImageKey = Strings.isNullOrEmpty(discordPresence.getSmallImageKey())
- ? "default"
- : discordPresence.getSmallImageKey();
+
+ if (!Strings.isNullOrEmpty(discordPresence.getSmallImageKey()))
+ {
+ discordRichPresence.smallImageKey = discordPresence.getSmallImageKey();
+ }
+
discordRichPresence.smallImageText = discordPresence.getSmallImageText();
discordRichPresence.partyId = discordPresence.getPartyId();
discordRichPresence.partySize = discordPresence.getPartySize();
diff --git a/runelite-client/src/main/java/net/runelite/client/events/ChatboxInput.java b/runelite-client/src/main/java/net/runelite/client/events/ChatboxInput.java
index 6388c8b433..cad7d38077 100644
--- a/runelite-client/src/main/java/net/runelite/client/events/ChatboxInput.java
+++ b/runelite-client/src/main/java/net/runelite/client/events/ChatboxInput.java
@@ -25,8 +25,10 @@
package net.runelite.client.events;
import lombok.Data;
+import lombok.EqualsAndHashCode;
@Data
+@EqualsAndHashCode(callSuper = true)
public abstract class ChatboxInput extends ChatInput
{
private final String value;
diff --git a/runelite-client/src/main/java/net/runelite/client/events/PrivateMessageInput.java b/runelite-client/src/main/java/net/runelite/client/events/PrivateMessageInput.java
index fc31fae7f1..80a189f273 100644
--- a/runelite-client/src/main/java/net/runelite/client/events/PrivateMessageInput.java
+++ b/runelite-client/src/main/java/net/runelite/client/events/PrivateMessageInput.java
@@ -25,8 +25,10 @@
package net.runelite.client.events;
import lombok.Data;
+import lombok.EqualsAndHashCode;
@Data
+@EqualsAndHashCode(callSuper = true)
public abstract class PrivateMessageInput extends ChatInput
{
private final String target;
diff --git a/runelite-api/src/main/java/net/runelite/api/events/SessionClose.java b/runelite-client/src/main/java/net/runelite/client/events/SessionClose.java
similarity index 97%
rename from runelite-api/src/main/java/net/runelite/api/events/SessionClose.java
rename to runelite-client/src/main/java/net/runelite/client/events/SessionClose.java
index 7075607291..e8a2f227cb 100644
--- a/runelite-api/src/main/java/net/runelite/api/events/SessionClose.java
+++ b/runelite-client/src/main/java/net/runelite/client/events/SessionClose.java
@@ -22,7 +22,7 @@
* (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.events;
+package net.runelite.client.events;
import lombok.Data;
diff --git a/runelite-api/src/main/java/net/runelite/api/events/SessionOpen.java b/runelite-client/src/main/java/net/runelite/client/events/SessionOpen.java
similarity index 97%
rename from runelite-api/src/main/java/net/runelite/api/events/SessionOpen.java
rename to runelite-client/src/main/java/net/runelite/client/events/SessionOpen.java
index 7ff930470b..971ba7cb2e 100644
--- a/runelite-api/src/main/java/net/runelite/api/events/SessionOpen.java
+++ b/runelite-client/src/main/java/net/runelite/client/events/SessionOpen.java
@@ -22,7 +22,7 @@
* (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.events;
+package net.runelite.client.events;
import lombok.Data;
diff --git a/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java b/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java
new file mode 100644
index 0000000000..6261f1aabe
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2018, SomeoneWithAnInternetConnection
+ * Copyright (c) 2019, MrGroggle
+ * 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.game;
+
+import lombok.Getter;
+import static net.runelite.api.NullObjectID.*;
+import static net.runelite.api.ObjectID.*;
+import net.runelite.api.coords.WorldPoint;
+
+@Getter
+public enum AgilityShortcut
+{
+ GENERIC_SHORTCUT(1, "Shortcut", null,
+ // Trollheim
+ ROCKS_3790, ROCKS_3791,
+ // Fremennik Slayer Cave
+ STEPS_29993,
+ // Fossil Island
+ LADDER_30938, LADDER_30939, LADDER_30940, LADDER_30941, RUBBER_CAP_MUSHROOM,
+ // Brimhaven dungeon
+ CREVICE_30198,
+ // Lumbridge
+ STILE_12982,
+ // Gu'Tanoth Bridge
+ GAP, GAP_2831,
+ // Lumbridge Swamp Caves
+ STEPPING_STONE_5948, STEPPING_STONE_5949, ROCKS_6673,
+ // Morytania Pirate Ship
+ ROCK_16115,
+ // Lumber Yard
+ BROKEN_FENCE_2618,
+ // McGrubor's Wood
+ LOOSE_RAILING,
+ // Underwater Area Fossil Island
+ TUNNEL_30959, HOLE_30966, OBSTACLE, OBSTACLE_30767, OBSTACLE_30964, OBSTACLE_30962,
+ // Tree Gnome Village
+ LOOSE_RAILING_2186,
+ // Burgh de Rott
+ LOW_FENCE,
+ // Taverley
+ STILE,
+ // Asgarnian Ice Dungeon
+ STEPS,
+ // Fossil Island Wyvern Cave
+ STAIRS_31485),
+ BRIMHAVEN_DUNGEON_MEDIUM_PIPE_RETURN(1, "Pipe Squeeze", null, new WorldPoint(2698, 9491, 0), PIPE_21727),
+ BRIMHAVEN_DUNGEON_PIPE_RETURN(1, "Pipe Squeeze", null, new WorldPoint(2655, 9573, 0), PIPE_21728),
+ BRIMHAVEN_DUNGEON_STEPPING_STONES_RETURN(1, "Pipe Squeeze", null, STEPPING_STONE_21739),
+ BRIMHAVEN_DUNGEON_LOG_BALANCE_RETURN(1, "Log Balance", null, LOG_BALANCE_20884),
+ AGILITY_PYRAMID_ROCKS_WEST(1, "Rocks", null, CLIMBING_ROCKS_11948),
+ CAIRN_ISLE_CLIMBING_ROCKS(1, "Rocks", null, CLIMBING_ROCKS),
+ KARAMJA_GLIDER_LOG(1, "Log Balance", new WorldPoint(2906, 3050, 0), A_WOODEN_LOG ),
+ FALADOR_CRUMBLING_WALL(5, "Crumbling Wall", new WorldPoint(2936, 3357, 0), CRUMBLING_WALL_24222 ),
+ RIVER_LUM_GRAPPLE_WEST(8, "Grapple Broken Raft", new WorldPoint(3245, 3179, 0), BROKEN_RAFT),
+ RIVER_LUM_GRAPPLE_EAST(8, "Grapple Broken Raft", new WorldPoint(3258, 3179, 0), BROKEN_RAFT),
+ CORSAIR_COVE_ROCKS(10, "Rocks", new WorldPoint(2545, 2871, 0), ROCKS_31757),
+ KARAMJA_MOSS_GIANT_SWING(10, "Rope", null, ROPESWING_23568, ROPESWING_23569),
+ FALADOR_GRAPPLE_WALL(11, "Grapple Wall", new WorldPoint(3031, 3391, 0), WALL_17049, WALL_17050),
+ BRIMHAVEN_DUNGEON_STEPPING_STONES(12, "Stepping Stones", null, STEPPING_STONE_21738),
+ VARROCK_SOUTH_FENCE(13, "Fence", new WorldPoint(3239, 3334, 0), FENCE_16518),
+ GOBLIN_VILLAGE_WALL(14, "Wall", new WorldPoint(2925, 3523, 0), TIGHTGAP),
+ CORSAIR_COVE_DUNGEON_PILLAR(15, "Pillar Jump", new WorldPoint(1980, 8996, 0), PILLAR_31809),
+ EDGEVILLE_DUNGEON_MONKEYBARS(15, "Monkey Bars", null, MONKEYBARS_23566),
+ TROLLHEIM_ROCKS(15, "Rocks", null, new WorldPoint(2838, 3614, 0), ROCKS_3748), // No fixed world map location, but rocks near death plateau have a requirement of 15
+ YANILLE_UNDERWALL_TUNNEL(16, "Underwall Tunnel", new WorldPoint(2574, 3109, 0), HOLE_16520, WALL_17047),
+ YANILLE_WATCHTOWER_TRELLIS(18, "Trellis", null, TRELLIS_20056),
+ COAL_TRUCKS_LOG_BALANCE(20, "Log Balance", new WorldPoint(2598, 3475, 0), LOG_BALANCE_23274),
+ GRAND_EXCHANGE_UNDERWALL_TUNNEL(21, "Underwall Tunnel", new WorldPoint(3139, 3515, 0), UNDERWALL_TUNNEL_16529, UNDERWALL_TUNNEL_16530),
+ BRIMHAVEN_DUNGEON_PIPE(22, "Pipe Squeeze", new WorldPoint(2654, 9569, 0), PIPE_21728),
+ OBSERVATORY_SCALE_CLIFF(23, "Grapple Rocks", new WorldPoint(2447, 3155, 0), NULL_31849),
+ EAGLES_PEAK_ROCK_CLIMB(25, "Rock Climb", new WorldPoint(2320, 3499, 0), ROCKS_19849),
+ FALADOR_UNDERWALL_TUNNEL(26, "Underwall Tunnel", new WorldPoint(2947, 3313, 0), UNDERWALL_TUNNEL, UNDERWALL_TUNNEL_16528),
+ MOUNT_KARUULM_LOWER(29, "Rocks", new WorldPoint(1324, 3782, 0), ROCKS_34397),
+ CORSAIR_COVE_RESOURCE_ROCKS(30, "Rocks", new WorldPoint(2486, 2898, 0), ROCKS_31758, ROCKS_31759),
+ SOUTHEAST_KARAJMA_STEPPING_STONES(30, "Stepping Stones", new WorldPoint(2924, 2946, 0), STEPPING_STONES, STEPPING_STONES_23646, STEPPING_STONES_23647),
+ BRIMHAVEN_DUNGEON_LOG_BALANCE(30, "Log Balance", null, LOG_BALANCE_20882),
+ AGILITY_PYRAMID_ROCKS_EAST(30, "Rocks", null, CLIMBING_ROCKS_11949),
+ DRAYNOR_MANOR_STEPPING_STONES(31, "Stepping Stones", new WorldPoint(3150, 3362, 0), STEPPING_STONE_16533),
+ CATHERBY_CLIFFSIDE_GRAPPLE(32, "Grapple Rock", new WorldPoint(2868, 3429, 0), ROCKS_17042),
+ CAIRN_ISLE_ROCKS(32, "Rocks", null, ROCKS_2231),
+ ARDOUGNE_LOG_BALANCE(33, "Log Balance", new WorldPoint(2602, 3336, 0), LOG_BALANCE_16546, LOG_BALANCE_16547, LOG_BALANCE_16548),
+ BRIMHAVEN_DUNGEON_MEDIUM_PIPE(34, "Pipe Squeeze", null, new WorldPoint(2698, 9501, 0), PIPE_21727),
+ CATHERBY_OBELISK_GRAPPLE(36, "Grapple Rock", new WorldPoint(2841, 3434, 0), CROSSBOW_TREE_17062),
+ GNOME_STRONGHOLD_ROCKS(37, "Rocks", new WorldPoint(2485, 3515, 0), ROCKS_16534, ROCKS_16535),
+ AL_KHARID_MINING_PITCLIFF_SCRAMBLE(38, "Rocks", new WorldPoint(3305, 3315, 0), ROCKS_16549, ROCKS_16550),
+ YANILLE_WALL_GRAPPLE(39, "Grapple Wall", new WorldPoint(2552, 3072, 0), CASTLE_WALL),
+ NEITIZNOT_BRIDGE_REPAIR(40, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307),
+ KOUREND_LAKE_JUMP_EAST(40, "Stepping Stones", new WorldPoint(1612, 3570, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
+ KOUREND_LAKE_JUMP_WEST(40, "Stepping Stones", new WorldPoint(1604, 3572, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
+ YANILLE_DUNGEON_BALANCE(40, "Balancing Ledge", null, BALANCING_LEDGE_23548),
+ TROLLHEIM_EASY_CLIFF_SCRAMBLE(41, "Rocks", new WorldPoint(2869, 3670, 0), ROCKS_16521),
+ DWARVEN_MINE_NARROW_CREVICE(42, "Narrow Crevice", new WorldPoint(3034, 9806, 0), CREVICE_16543),
+ DRAYNOR_UNDERWALL_TUNNEL(42, "Underwall Tunnel", new WorldPoint(3068, 3261, 0), UNDERWALL_TUNNEL_19032, UNDERWALL_TUNNEL_19036),
+ TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_NORTH(43, "Rocks", new WorldPoint(2886, 3684, 0), ROCKS_3803, ROCKS_3804, ROCKS_16522),
+ TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_SOUTH(43, "Rocks", new WorldPoint(2876, 3666, 0), ROCKS_3803, ROCKS_3804, ROCKS_16522),
+ TROLLHEIM_ADVANCED_CLIFF_SCRAMBLE(44, "Rocks", new WorldPoint(2907, 3686, 0), ROCKS_16523, ROCKS_3748),
+ KOUREND_RIVER_STEPPING_STONES(45, "Stepping Stones", new WorldPoint(1721, 3509, 0), STEPPING_STONE_29728),
+ TIRANNWN_LOG_BALANCE(45, "Log Balance", null, LOG_BALANCE_3933, LOG_BALANCE_3931, LOG_BALANCE_3930, LOG_BALANCE_3929, LOG_BALANCE_3932),
+ COSMIC_ALTAR_MEDIUM_WALKWAY(46, "Narrow Walkway", new WorldPoint(2399, 4403, 0), JUTTING_WALL_17002),
+ DEEP_WILDERNESS_DUNGEON_CREVICE_NORTH(46, "Narrow Crevice", new WorldPoint(3047, 10335, 0), CREVICE_19043),
+ DEEP_WILDERNESS_DUNGEON_CREVICE_SOUTH(46, "Narrow Crevice", new WorldPoint(3045, 10327, 0), CREVICE_19043),
+ TROLLHEIM_HARD_CLIFF_SCRAMBLE(47, "Rocks", new WorldPoint(2902, 3680, 0), ROCKS_16524),
+ FREMENNIK_LOG_BALANCE(48, "Log Balance", new WorldPoint(2721, 3591, 0), LOG_BALANCE_16540, LOG_BALANCE_16541, LOG_BALANCE_16542),
+ YANILLE_DUNGEON_PIPE_SQUEEZE(49, "Pipe Squeeze", null, OBSTACLE_PIPE_23140),
+ ARCEUUS_ESSENCE_MINE_BOULDER(49, "Boulder", new WorldPoint(1774, 3888, 0), BOULDER_27990),
+ MORYTANIA_STEPPING_STONE(50, "Stepping Stone", new WorldPoint(3418, 3326, 0), STEPPING_STONE_13504),
+ VARROCK_SEWERS_PIPE_SQUEEZE(51, "Pipe Squeeze", new WorldPoint(3152, 9905, 0), OBSTACLE_PIPE_16511),
+ ARCEUUS_ESSENCE_MINE_EAST_SCRAMBLE(52, "Rock Climb", new WorldPoint(1770, 3851, 0), ROCKS_27987, ROCKS_27988),
+ KARAMJA_VOLCANO_GRAPPLE_NORTH(53, "Grapple Rock", new WorldPoint(2873, 3143, 0), STRONG_TREE_17074),
+ KARAMJA_VOLCANO_GRAPPLE_SOUTH(53, "Grapple Rock", new WorldPoint(2874, 3128, 0), STRONG_TREE_17074),
+ MOTHERLODE_MINE_WALL_EAST(54, "Wall", new WorldPoint(3124, 9703, 0), DARK_TUNNEL_10047),
+ MOTHERLODE_MINE_WALL_WEST(54, "Wall", new WorldPoint(3118, 9702, 0), DARK_TUNNEL_10047),
+ MISCELLANIA_DOCK_STEPPING_STONE(55, "Stepping Stone", new WorldPoint(2572, 3862, 0), STEPPING_STONE_11768),
+ ISAFDAR_FOREST_OBSTACLES(56, "Trap", null, DENSE_FOREST_3938, DENSE_FOREST_3939, DENSE_FOREST_3998, DENSE_FOREST_3999, DENSE_FOREST, LEAVES, LEAVES_3924, LEAVES_3925, STICKS, TRIPWIRE),
+ RELEKKA_EAST_FENCE(57, "Fence", new WorldPoint(2688, 3697, 0), BROKEN_FENCE),
+ YANILLE_DUNGEON_MONKEY_BARS(57, "Monkey Bars", null, MONKEYBARS_23567),
+ PHASMATYS_ECTOPOOL_SHORTCUT(58, "Weathered Wall", null , WEATHERED_WALL, WEATHERED_WALL_16526),
+ ELVEN_OVERPASS_CLIFF_SCRAMBLE(59, "Rocks", new WorldPoint(2345, 3300, 0), ROCKS_16514, ROCKS_16515),
+ WILDERNESS_GWD_CLIMB_EAST(60, "Rocks", new WorldPoint(2943, 3770, 0), ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406),
+ WILDERNESS_GWD_CLIMB_WEST(60, "Rocks", new WorldPoint(2928, 3760, 0), ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406),
+ MOS_LEHARMLESS_STEPPING_STONE(60, "Stepping Stone", new WorldPoint(3710, 2970, 0), STEPPING_STONE_19042),
+ WINTERTODT_GAP(60, "Gap", new WorldPoint(1629, 4023, 0), GAP_29326),
+ UNGAEL_ICE(60, "Ice Chunks", null, NULL_25337, NULL_29868, NULL_29869, NULL_29870, ICE_CHUNKS_31822, NULL_31823, ICE_CHUNKS_31990),
+ SLAYER_TOWER_MEDIUM_CHAIN_FIRST(61, "Spiked Chain (Floor 1)", new WorldPoint(3421, 3550, 0), SPIKEY_CHAIN),
+ SLAYER_TOWER_MEDIUM_CHAIN_SECOND(61, "Spiked Chain (Floor 2)", new WorldPoint(3420, 3551, 0), SPIKEY_CHAIN_16538),
+ SLAYER_DUNGEON_CREVICE(62, "Narrow Crevice", new WorldPoint(2729, 10008, 0), CREVICE_16539),
+ MOUNT_KARUULM_UPPER(62, "Rocks", new WorldPoint(1322, 3791, 0), ROCKS_34396),
+ TAVERLEY_DUNGEON_RAILING(63, "Loose Railing", new WorldPoint(2935, 9811, 0), LOOSE_RAILING_28849),
+ TROLLHEIM_WILDERNESS_ROCKS_EAST(64, "Rocks", new WorldPoint(2945, 3678, 0), ROCKS_16545),
+ TROLLHEIM_WILDERNESS_ROCKS_WEST(64, "Rocks", new WorldPoint(2917, 3672, 0), ROCKS_16545),
+ FOSSIL_ISLAND_VOLCANO(64, "Rope", new WorldPoint(3780, 3822, 0), ROPE_ANCHOR, ROPE_ANCHOR_30917),
+ MORYTANIA_TEMPLE(65, "Loose Railing", new WorldPoint(3422, 3476, 0), ROCKS_16998, ROCKS_16999, ORNATE_RAILING, ORNATE_RAILING_17000),
+ REVENANT_CAVES_GREEN_DRAGONS(65, "Jump", new WorldPoint(3220, 10086, 0), PILLAR_31561),
+ COSMIC_ALTAR_ADVANCED_WALKWAY(66, "Narrow Walkway", new WorldPoint(2408, 4401, 0), JUTTING_WALL_17002),
+ LUMBRIDGE_DESERT_STEPPING_STONE(66, "Stepping Stone", new WorldPoint(3210, 3135, 0), STEPPING_STONE_16513),
+ HEROES_GUILD_TUNNEL_EAST(67, "Crevice", new WorldPoint(2898, 9901, 0), CREVICE_9739, CREVICE_9740),
+ HEROES_GUILD_TUNNEL_WEST(67, "Crevice", new WorldPoint(2913, 9895, 0), CREVICE_9739, CREVICE_9740),
+ YANILLE_DUNGEON_RUBBLE_CLIMB(67, "Pile of Rubble", null, PILE_OF_RUBBLE_23563, PILE_OF_RUBBLE_23564),
+ ELVEN_OVERPASS_MEDIUM_CLIFF(68, "Rocks", new WorldPoint(2337, 3288, 0), ROCKS_16514, ROCKS_16515),
+ WEISS_OBSTACLES(68, "Shortcut", null, LITTLE_BOULDER, ROCKSLIDE_33184, ROCKSLIDE_33185, NULL_33327, NULL_33328, LEDGE_33190, ROCKSLIDE_33191, FALLEN_TREE_33192),
+ ARCEUUS_ESSENSE_NORTH(69, "Rock Climb", new WorldPoint(1759, 3873, 0), ROCKS_27984, ROCKS_27985),
+ TAVERLEY_DUNGEON_PIPE_BLUE_DRAGON(70, "Pipe Squeeze", new WorldPoint(2886, 9798, 0), OBSTACLE_PIPE_16509),
+ TAVERLEY_DUNGEON_ROCKS_NORTH(70, "Rocks", new WorldPoint(2887, 9823, 0), ROCKS, ROCKS_14106),
+ TAVERLEY_DUNGEON_ROCKS_SOUTH(70, "Rocks", new WorldPoint(2887, 9631, 0), ROCKS, ROCKS_14106),
+ FOSSIL_ISLAND_HARDWOOD_NORTH(70, "Hole" , new WorldPoint(3713, 3827, 0), HOLE_31481, HOLE_31482),
+ FOSSIL_ISLAND_HARDWOOD_SOUTH(70, "Hole" , new WorldPoint(3715, 3817, 0), HOLE_31481, HOLE_31482),
+ AL_KHARID_WINDOW(70, "Window", new WorldPoint(3293, 3158, 0), BROKEN_WALL_33344, BIG_WINDOW),
+ GWD_SARADOMIN_ROPE_NORTH(70, "Rope Descent", new WorldPoint(2912, 5300, 0), NULL_26371),
+ GWD_SARADOMIN_ROPE_SOUTH(70, "Rope Descent", new WorldPoint(2951, 5267, 0), NULL_26375),
+ SLAYER_TOWER_ADVANCED_CHAIN_FIRST(71, "Spiked Chain (Floor 2)", new WorldPoint(3447, 3578, 0), SPIKEY_CHAIN ),
+ SLAYER_TOWER_ADVANCED_CHAIN_SECOND(71, "Spiked Chain (Floor 3)", new WorldPoint(3446, 3576, 0), SPIKEY_CHAIN_16538),
+ STRONGHOLD_SLAYER_CAVE_TUNNEL(72, "Tunnel", new WorldPoint(2431, 9806, 0), TUNNEL_30174, TUNNEL_30175),
+ TROLL_STRONGHOLD_WALL_CLIMB(73, "Rocks", new WorldPoint(2841, 3694, 0), ROCKS_16464),
+ ARCEUUS_ESSENSE_MINE_WEST(73, "Rock Climb", new WorldPoint(1742, 3853, 0), ROCKS_27984, ROCKS_27985 ),
+ LAVA_DRAGON_ISLE_JUMP(74, "Stepping Stone", new WorldPoint(3200, 3807, 0), STEPPING_STONE_14918),
+ REVENANT_CAVES_DEMONS_JUMP(75, "Jump", new WorldPoint(3199, 10135, 0), PILLAR_31561),
+ REVENANT_CAVES_ANKOU_EAST(75, "Jump", new WorldPoint(3201, 10195, 0), PILLAR_31561),
+ REVENANT_CAVES_ANKOU_NORTH(75, "Jump", new WorldPoint(3180, 10209, 0), PILLAR_31561),
+ ZUL_ANDRA_ISLAND_CROSSING(76, "Stepping Stone", new WorldPoint(2156, 3073, 0), STEPPING_STONE_10663),
+ SHILO_VILLAGE_STEPPING_STONES( 77, "Stepping Stones", new WorldPoint(2863, 2974, 0), STEPPING_STONE_16466),
+ KHARAZI_JUNGLE_VINE_CLIMB(79, "Vine", new WorldPoint(2897, 2939, 0), NULL_26884, NULL_26886),
+ TAVERLEY_DUNGEON_SPIKED_BLADES(80, "Strange Floor", new WorldPoint(2877, 9813, 0), STRANGE_FLOOR),
+ SLAYER_DUNGEON_CHASM_JUMP(81, "Spiked Blades", new WorldPoint(2770, 10003, 0), STRANGE_FLOOR_16544),
+ LAVA_MAZE_NORTH_JUMP(82, "Stepping Stone", new WorldPoint(3092, 3880, 0), STEPPING_STONE_14917),
+ BRIMHAVEN_DUNGEON_EAST_STEPPING_STONES_NORTH(83, "Stepping Stones", new WorldPoint(2685, 9547, 0), STEPPING_STONE_19040),
+ BRIMHAVEN_DUNGEON_EAST_STEPPING_STONES_SOUTH(83, "Stepping Stones", new WorldPoint(2693, 9529, 0), STEPPING_STONE_19040),
+ ELVEN_ADVANCED_CLIFF_SCRAMBLE(85, "Rocks", new WorldPoint(2337, 3253, 0), ROCKS_16514, ROCKS_16514),
+ KALPHITE_WALL(86, "Crevice", new WorldPoint(3214, 9508, 0), CREVICE_16465),
+ BRIMHAVEN_DUNGEON_VINE_EAST(87, "Vine", new WorldPoint(2672, 9582, 0), VINE_26880, VINE_26882),
+ BRIMHAVEN_DUNGEON_VINE_WEST(87, "Vine", new WorldPoint(2606, 9584, 0), VINE_26880, VINE_26882),
+ MOUNT_KARUULM_PIPE_SOUTH(88, "Pipe", new WorldPoint(1316, 10214, 0), MYSTERIOUS_PIPE),
+ MOUNT_KARUULM_PIPE_NORTH(88, "Pipe", new WorldPoint(1346, 10231, 0), MYSTERIOUS_PIPE),
+ REVENANT_CAVES_CHAMBER_JUMP(89, "Jump", new WorldPoint(3240, 10144, 0), PILLAR_31561);
+
+ /**
+ * The agility level required to pass the shortcut
+ */
+ @Getter
+ private final int level;
+ /**
+ * Brief description of the shortcut (e.g. 'Rocks', 'Stepping Stones', 'Jump')
+ */
+ @Getter
+ private final String description;
+ /**
+ * The location of the Shortcut icon on the world map (null if there is no icon)
+ */
+ @Getter
+ private final WorldPoint worldMapLocation;
+ /**
+ * An optional location in case the location of the shortcut icon is either
+ * null or isn't close enough to the obstacle
+ */
+ @Getter
+ private final WorldPoint worldLocation;
+ /**
+ * Array of obstacles, null objects, decorations etc. that this shortcut uses.
+ * Typically an ObjectID/NullObjectID
+ */
+ @Getter
+ private final int[] obstacleIds;
+
+ AgilityShortcut(int level, String description, WorldPoint mapLocation, WorldPoint worldLocation, int... obstacleIds)
+ {
+ this.level = level;
+ this.description = description;
+ this.worldMapLocation = mapLocation;
+ this.worldLocation = worldLocation;
+ this.obstacleIds = obstacleIds;
+ }
+
+ AgilityShortcut(int level, String description, WorldPoint location, int... obstacleIds)
+ {
+ this(level, description, location, location, obstacleIds);
+ }
+
+ public String getTooltip()
+ {
+ return description + " - Level " + level;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/game/ChatboxInputManager.java b/runelite-client/src/main/java/net/runelite/client/game/ChatboxInputManager.java
deleted file mode 100644
index ec8905e380..0000000000
--- a/runelite-client/src/main/java/net/runelite/client/game/ChatboxInputManager.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2018 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.client.game;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import java.util.function.Consumer;
-import lombok.Getter;
-import net.runelite.api.Client;
-import net.runelite.api.ScriptID;
-import net.runelite.api.events.ScriptCallbackEvent;
-import net.runelite.client.callback.ClientThread;
-import net.runelite.client.eventbus.EventBus;
-import net.runelite.client.eventbus.Subscribe;
-
-@Singleton
-public class ChatboxInputManager
-{
- public static final int NO_LIMIT = Integer.MAX_VALUE;
- private final Client client;
- private final ClientThread clientThread;
-
- private Consumer done;
- private Consumer changed;
- private int characterLimit = NO_LIMIT;
-
- @Getter
- private boolean open = false;
-
- @Inject
- public ChatboxInputManager(Client client, ClientThread clientThread, EventBus eventBus)
- {
- this.client = client;
- this.clientThread = clientThread;
- eventBus.register(this);
- }
-
- /**
- * Opens a RuneScape-style chatbox input
- *
- * @param text Text to show at the top of the window
- * @param defaul Default text in the editable field
- * @param done Callback when the text box has been exited, called with "" on esc
- */
- public void openInputWindow(String text, String defaul, Consumer done)
- {
- openInputWindow(text, defaul, NO_LIMIT, done);
- }
-
- public void openInputWindow(String text, String defaul, int characterLimit, Consumer done)
- {
- openInputWindow(text, defaul, characterLimit, null, done);
- }
-
- public void openInputWindow(String text, String defaul, int characterLimit, Consumer changed, Consumer done)
- {
- this.done = done;
- this.changed = changed;
- this.characterLimit = characterLimit;
- this.open = true;
- clientThread.invoke(() -> client.runScript(
- ScriptID.RUNELITE_CHATBOX_INPUT_INIT,
- text,
- defaul
- ));
- }
-
- /**
- * Closes the RuneScape-style chatbox input
- */
- public void closeInputWindow()
- {
- if (!this.open)
- {
- return;
- }
- this.open = false;
- clientThread.invoke(() -> client.runScript(
- ScriptID.RESET_CHATBOX_INPUT,
- 1,
- 1
- ));
- }
-
- @Subscribe
- public void onScriptCallbackEvent(ScriptCallbackEvent ev)
- {
- // This replaces script 74 and most of 112
- if ("chatboxInputHandler".equals(ev.getEventName()))
- {
- int intStackSize = client.getIntStackSize();
- int stringStackSize = client.getStringStackSize();
- int typedKey = client.getIntStack()[--intStackSize];
- String str = client.getStringStack()[--stringStackSize];
- boolean isDone = false;
-
- switch (typedKey)
- {
- case 27: // Escape
- str = "";
- // fallthrough
- case '\n':
- this.open = false;
- isDone = true;
- break;
- case '\b':
- if (!str.isEmpty())
- {
- str = str.substring(0, str.length() - 1);
- }
- break;
- default:
- // If we wanted to do numbers only, we could add a limit here
- if (typedKey >= 32 && (str.length() < characterLimit))
- {
- str += Character.toString((char) typedKey);
- }
- }
-
- if (changed != null)
- {
- changed.accept(str);
- }
-
- if (isDone && done != null)
- {
- done.accept(str);
- }
-
- client.getStringStack()[stringStackSize++] = str;
- client.getIntStack()[intStackSize++] = isDone ? 1 : 0;
- client.setIntStackSize(intStackSize);
- client.setStringStackSize(stringStackSize);
- }
- }
-}
diff --git a/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java b/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java
index ad06024a7d..0f21a5b434 100644
--- a/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java
@@ -84,7 +84,7 @@ public class ItemManager
private final ItemClient itemClient = new ItemClient();
private Map itemPrices = Collections.emptyMap();
- private Map itemStats = Collections.emptyMap();
+ private Map itemStats = Collections.emptyMap();
private final LoadingCache itemImages;
private final LoadingCache itemCompositions;
private final LoadingCache itemOutlines;
@@ -226,7 +226,7 @@ public class ItemManager
{
try
{
- final Map stats = itemClient.getStats();
+ final Map stats = itemClient.getStats();
if (stats != null)
{
itemStats = ImmutableMap.copyOf(stats);
@@ -256,6 +256,15 @@ public class ItemManager
itemCompositions.put(event.getItemComposition().getId(), event.getItemComposition());
}
+ /**
+ * Invalidates internal item manager item composition cache (but not client item composition cache)
+ * @see Client#getItemCompositionCache()
+ */
+ public void invalidateItemCompositionCache()
+ {
+ itemCompositions.invalidateAll();
+ }
+
/**
* Look up an item's price
*
@@ -298,16 +307,16 @@ public class ItemManager
* @return item stats
*/
@Nullable
- public ItemStats getItemStats(int itemId)
+ public ItemStats getItemStats(int itemId, boolean allowNote)
{
ItemComposition itemComposition = getItemComposition(itemId);
- if (itemComposition == null || itemComposition.getName() == null)
+ if (itemComposition == null || itemComposition.getName() == null || (!allowNote && itemComposition.getNote() != -1))
{
return null;
}
- return itemStats.get(itemComposition.getName());
+ return itemStats.get(canonicalize(itemId));
}
/**
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 5eda167c17..f866d199ce 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
@@ -195,7 +195,7 @@ public enum ItemMapping
BLACK_MASK, BLACK_MASK_I, BLACK_MASK_1, BLACK_MASK_1_I, BLACK_MASK_2, BLACK_MASK_2_I, BLACK_MASK_3, BLACK_MASK_3_I, BLACK_MASK_4, BLACK_MASK_4_I, BLACK_MASK_5,
BLACK_MASK_5_I, BLACK_MASK_6, BLACK_MASK_6_I, BLACK_MASK_7, BLACK_MASK_7_I, BLACK_MASK_8, BLACK_MASK_8_I, BLACK_MASK_9, BLACK_MASK_9_I, BLACK_MASK_10_I,
SLAYER_HELMET, SLAYER_HELMET_I, BLACK_SLAYER_HELMET, BLACK_SLAYER_HELMET_I, PURPLE_SLAYER_HELMET, PURPLE_SLAYER_HELMET_I, RED_SLAYER_HELMET, RED_SLAYER_HELMET_I,
- GREEN_SLAYER_HELMET, GREEN_SLAYER_HELMET_I, TURQUOISE_SLAYER_HELMET, TURQUOISE_SLAYER_HELMET_I),
+ GREEN_SLAYER_HELMET, GREEN_SLAYER_HELMET_I, TURQUOISE_SLAYER_HELMET, TURQUOISE_SLAYER_HELMET_I, HYDRA_SLAYER_HELMET, HYDRA_SLAYER_HELMET_I),
// Pharaoh's Sceptres
ITEM_PHARAOHS_SCEPTRE_1(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_1),
diff --git a/runelite-client/src/main/java/net/runelite/client/game/SpriteManager.java b/runelite-client/src/main/java/net/runelite/client/game/SpriteManager.java
index f0df8286cd..f177377818 100644
--- a/runelite-client/src/main/java/net/runelite/client/game/SpriteManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/game/SpriteManager.java
@@ -28,6 +28,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.inject.Inject;
import java.awt.image.BufferedImage;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import javax.annotation.Nullable;
@@ -36,11 +37,14 @@ import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
+import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.SpritePixels;
import net.runelite.client.callback.ClientThread;
+import net.runelite.client.util.ImageUtil;
+@Slf4j
@Singleton
public class SpriteManager
{
@@ -127,4 +131,36 @@ public class SpriteManager
});
});
}
+
+ public void addSpriteOverrides(SpriteOverride[] add)
+ {
+ if (add.length <= 0)
+ {
+ return;
+ }
+
+ clientThread.invokeLater(() ->
+ {
+ Map overrides = client.getSpriteOverrides();
+ Class> owner = add[0].getClass();
+ for (SpriteOverride o : add)
+ {
+ BufferedImage image = ImageUtil.getResourceStreamFromClass(owner, o.getFileName());
+ SpritePixels sp = ImageUtil.getImageSpritePixels(image, client);
+ overrides.put(o.getSpriteId(), sp);
+ }
+ });
+ }
+
+ public void removeSpriteOverrides(SpriteOverride[] remove)
+ {
+ clientThread.invokeLater(() ->
+ {
+ Map overrides = client.getSpriteOverrides();
+ for (SpriteOverride o : remove)
+ {
+ overrides.remove(o.getSpriteId());
+ }
+ });
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/game/SpriteOverride.java b/runelite-client/src/main/java/net/runelite/client/game/SpriteOverride.java
new file mode 100644
index 0000000000..a4f894d5c0
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/game/SpriteOverride.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018 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.client.game;
+
+import net.runelite.api.SpriteID;
+
+public interface SpriteOverride
+{
+ /**
+ * An ID for a sprite. Negative numbers are used by RuneLite specific sprites
+ *
+ * @see SpriteID
+ */
+ int getSpriteId();
+
+ /**
+ * The file name for the resource to be loaded, relative to the implementing class
+ */
+ String getFileName();
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxPanelManager.java b/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxPanelManager.java
index 35e42a617e..ff23bb2cda 100644
--- a/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxPanelManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxPanelManager.java
@@ -93,6 +93,10 @@ public class ChatboxPanelManager
0,
1
);
+ if (currentInput != null)
+ {
+ killCurrentPanel();
+ }
}
private void unsafeOpenInput(ChatboxInput input)
@@ -113,6 +117,11 @@ public class ChatboxPanelManager
mouseManager.registerMouseWheelListener((MouseWheelListener) input);
}
+ if (currentInput != null)
+ {
+ killCurrentPanel();
+ }
+
currentInput = input;
client.setVar(VarClientInt.INPUT_TYPE, InputType.RUNELITE_CHATBOX_PANEL.getType());
client.getWidget(WidgetInfo.CHATBOX_TITLE).setHidden(true);
diff --git a/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxTextInput.java b/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxTextInput.java
index e340027d1a..e59e47059d 100644
--- a/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxTextInput.java
+++ b/runelite-client/src/main/java/net/runelite/client/game/chatbox/ChatboxTextInput.java
@@ -24,7 +24,10 @@
*/
package net.runelite.client.game.chatbox;
+import com.google.common.base.Strings;
+import com.google.common.primitives.Ints;
import com.google.inject.Inject;
+import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
@@ -33,21 +36,25 @@ import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Consumer;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
+import java.util.regex.Pattern;
import javax.swing.SwingUtilities;
+import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
-import net.runelite.api.FontTypeFace;
import net.runelite.api.FontID;
-import net.runelite.api.widgets.WidgetType;
+import net.runelite.api.FontTypeFace;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetSizeMode;
import net.runelite.api.widgets.WidgetTextAlignment;
+import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.MouseListener;
@@ -57,6 +64,7 @@ import net.runelite.client.util.Text;
public class ChatboxTextInput extends ChatboxInput implements KeyListener, MouseListener
{
private static final int CURSOR_FLASH_RATE_MILLIS = 1000;
+ private static final Pattern BREAK_MATCHER = Pattern.compile("[^a-zA-Z0-9']");
private final ChatboxPanelManager chatboxPanelManager;
private final ClientThread clientThread;
@@ -66,13 +74,24 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
return i -> i >= 32 && i < 127;
}
+ @AllArgsConstructor
+ private static class Line
+ {
+ private final int start;
+ private final int end;
+ private final String text;
+ }
+
@Getter
private String prompt;
+ @Getter
+ private int lines;
+
private StringBuffer value = new StringBuffer();
@Getter
- private int cursor = 0;
+ private int cursorStart = 0;
@Getter
private int cursorEnd = 0;
@@ -95,12 +114,14 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
@Getter
private int fontID = FontID.QUILL_8;
- // This is a lambda so I can have atomic updates for it's captures
- private ToIntFunction getCharOffset = null;
- private Predicate isInBounds = null;
-
+ @Getter
private boolean built = false;
+ // These are lambdas for atomic updates
+ private Predicate isInBounds = null;
+ private ToIntFunction getLineOffset = null;
+ private ToIntFunction getPointCharOffset = null;
+
@Inject
protected ChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread)
{
@@ -108,6 +129,16 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
this.clientThread = clientThread;
}
+ public ChatboxTextInput lines(int lines)
+ {
+ this.lines = lines;
+ if (built)
+ {
+ clientThread.invoke(this::update);
+ }
+ return this;
+ }
+
public ChatboxTextInput prompt(String prompt)
{
this.prompt = prompt;
@@ -157,7 +188,7 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
end = v;
}
- this.cursor = start;
+ this.cursorStart = start;
this.cursorEnd = end;
if (built)
@@ -209,7 +240,6 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
protected void update()
{
- this.built = true;
Widget container = chatboxPanelManager.getContainerWidget();
container.deleteAllChildren();
@@ -232,103 +262,209 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
protected void buildEdit(int x, int y, int w, int h)
{
+ final List editLines = new ArrayList<>();
+
Widget container = chatboxPanelManager.getContainerWidget();
- String lt = Text.escapeJagex(value.substring(0, this.cursor));
- String mt = Text.escapeJagex(value.substring(this.cursor, this.cursorEnd));
- String rt = Text.escapeJagex(value.substring(this.cursorEnd));
-
- Widget leftText = container.createChild(-1, WidgetType.TEXT);
- Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
- Widget middleText = container.createChild(-1, WidgetType.TEXT);
- Widget rightText = container.createChild(-1, WidgetType.TEXT);
-
- leftText.setFontId(fontID);
- FontTypeFace font = leftText.getFont();
+ final Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
+ long start = System.currentTimeMillis();
+ cursor.setOnTimerListener((JavaScriptCallback) ev ->
+ {
+ boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
+ cursor.setOpacity(on ? 255 : 0);
+ });
+ cursor.setTextColor(0xFFFFFF);
+ cursor.setHasListener(true);
+ cursor.setFilled(true);
+ cursor.setFontId(fontID);
+ FontTypeFace font = cursor.getFont();
if (h <= 0)
{
h = font.getBaseline();
}
- int ltw = font.getTextWidth(lt);
- int mtw = font.getTextWidth(mt);
- int rtw = font.getTextWidth(rt);
+ final int oy = y;
+ final int ox = x;
+ final int oh = h;
- int fullWidth = ltw + mtw + rtw;
-
- int ox = x;
- if (w > 0)
+ int breakIndex = -1;
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < value.length(); i++)
{
- x += (w - fullWidth) / 2;
- }
-
- int ltx = x;
- int mtx = ltx + ltw;
- int rtx = mtx + mtw;
-
- leftText.setText(lt);
- leftText.setOriginalX(ltx);
- leftText.setOriginalY(y);
- leftText.setOriginalWidth(ltw);
- leftText.setOriginalHeight(h);
- leftText.revalidate();
-
- if (!mt.isEmpty())
- {
- cursor.setTextColor(0x113399);
- }
- else
- {
- cursor.setTextColor(0xFFFFFF);
- long start = System.currentTimeMillis();
- cursor.setOnTimerListener((JavaScriptCallback) ev ->
+ int count = i - sb.length();
+ final String c = value.charAt(i) + "";
+ sb.append(c);
+ if (BREAK_MATCHER.matcher(c).matches())
{
- boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
- cursor.setOpacity(on ? 255 : 0);
- });
- cursor.setHasListener(true);
+ breakIndex = sb.length();
+ }
+
+ if (i == value.length() - 1)
+ {
+ Line line = new Line(count, count + sb.length() - 1, sb.toString());
+ editLines.add(line);
+ break;
+ }
+
+ if (font.getTextWidth(sb.toString() + value.charAt(i + 1)) < w)
+ {
+ continue;
+ }
+
+ if (editLines.size() < this.lines - 1 || this.lines == 0)
+ {
+ if (breakIndex > 1)
+ {
+ String str = sb.substring(0, breakIndex);
+ Line line = new Line(count, count + str.length() - 1, str);
+ editLines.add(line);
+
+ sb.replace(0, breakIndex, "");
+ breakIndex = -1;
+ continue;
+ }
+
+ Line line = new Line(count, count + sb.length() - 1, sb.toString());
+ editLines.add(line);
+ sb.replace(0, sb.length(), "");
+ }
}
- cursor.setFilled(true);
- cursor.setOriginalX(mtx - 1);
- cursor.setOriginalY(y);
- cursor.setOriginalWidth(2 + mtw);
- cursor.setOriginalHeight(h);
- cursor.revalidate();
- middleText.setText(mt);
- middleText.setFontId(fontID);
- middleText.setOriginalX(mtx);
- middleText.setOriginalY(y);
- middleText.setOriginalWidth(mtw);
- middleText.setOriginalHeight(h);
- middleText.setTextColor(0xFFFFFF);
- middleText.revalidate();
+ Rectangle bounds = new Rectangle(container.getCanvasLocation().getX() + container.getWidth(), y, 0, editLines.size() * oh);
+ for (int i = 0; i < editLines.size() || i == 0; i++)
+ {
+ final Line line = editLines.size() > 0 ? editLines.get(i) : new Line(0, 0, "");
+ final String text = line.text;
+ final int len = text.length();
- rightText.setText(rt);
- rightText.setFontId(fontID);
- rightText.setOriginalX(rtx);
- rightText.setOriginalY(y);
- rightText.setOriginalWidth(rtw);
- rightText.setOriginalHeight(h);
- rightText.revalidate();
+ String lt = Text.escapeJagex(text);
+ String mt = "";
+ String rt = "";
+
+ final boolean isStartLine = cursorOnLine(cursorStart, line.start, line.end)
+ || (cursorOnLine(cursorStart, line.start, line.end + 1) && i == editLines.size() - 1);
+
+ final boolean isEndLine = cursorOnLine(cursorEnd, line.start, line.end);
+
+ if (isStartLine || isEndLine || (cursorEnd > line.end && cursorStart < line.start))
+ {
+ final int cIdx = Ints.constrainToRange(cursorStart - line.start, 0, len);
+ final int ceIdx = Ints.constrainToRange(cursorEnd - line.start, 0, len);
+
+ lt = Text.escapeJagex(text.substring(0, cIdx));
+ mt = Text.escapeJagex(text.substring(cIdx, ceIdx));
+ rt = Text.escapeJagex(text.substring(ceIdx));
+ }
+
+ final int ltw = font.getTextWidth(lt);
+ final int mtw = font.getTextWidth(mt);
+ final int rtw = font.getTextWidth(rt);
+ final int fullWidth = ltw + mtw + rtw;
+
+ int ltx = ox;
+ if (w > 0)
+ {
+ ltx += (w - fullWidth) / 2;
+ }
+
+ final int mtx = ltx + ltw;
+ final int rtx = mtx + mtw;
+
+ if (ltx < bounds.x)
+ {
+ bounds.setLocation(ltx, bounds.y);
+ }
+
+ if (fullWidth > bounds.width)
+ {
+ bounds.setSize(fullWidth, bounds.height);
+ }
+
+ if (editLines.size() == 0 || isStartLine)
+ {
+ cursor.setOriginalX(mtx - 1);
+ cursor.setOriginalY(y);
+ cursor.setOriginalWidth(2);
+ cursor.setOriginalHeight(h);
+ cursor.revalidate();
+ }
+
+ if (!Strings.isNullOrEmpty(lt))
+ {
+ final Widget leftText = container.createChild(-1, WidgetType.TEXT);
+ leftText.setFontId(fontID);
+ leftText.setText(lt);
+ leftText.setOriginalX(ltx);
+ leftText.setOriginalY(y);
+ leftText.setOriginalWidth(ltw);
+ leftText.setOriginalHeight(h);
+ leftText.revalidate();
+ }
+
+ if (!Strings.isNullOrEmpty(mt))
+ {
+ final Widget background = container.createChild(-1, WidgetType.RECTANGLE);
+ background.setTextColor(0x113399);
+ background.setFilled(true);
+ background.setOriginalX(mtx - 1);
+ background.setOriginalY(y);
+ background.setOriginalWidth(2 + mtw);
+ background.setOriginalHeight(h);
+ background.revalidate();
+
+ final Widget middleText = container.createChild(-1, WidgetType.TEXT);
+ middleText.setText(mt);
+ middleText.setFontId(fontID);
+ middleText.setOriginalX(mtx);
+ middleText.setOriginalY(y);
+ middleText.setOriginalWidth(mtw);
+ middleText.setOriginalHeight(h);
+ middleText.setTextColor(0xFFFFFF);
+ middleText.revalidate();
+ }
+
+ if (!Strings.isNullOrEmpty(rt))
+ {
+ final Widget rightText = container.createChild(-1, WidgetType.TEXT);
+ rightText.setText(rt);
+ rightText.setFontId(fontID);
+ rightText.setOriginalX(rtx);
+ rightText.setOriginalY(y);
+ rightText.setOriginalWidth(rtw);
+ rightText.setOriginalHeight(h);
+ rightText.revalidate();
+ }
+
+ y += h;
+ }
net.runelite.api.Point ccl = container.getCanvasLocation();
- int canvasX = ltx + ccl.getX();
- Rectangle bounds = new Rectangle(ccl.getX() + ox, ccl.getY() + y, w > 0 ? w : fullWidth, h);
- String tsValue = value.toString();
- isInBounds = ev -> bounds.contains(ev.getPoint());
- getCharOffset = ev ->
+ isInBounds = ev -> bounds.contains(new Point(ev.getX() - ccl.getX(), ev.getY() - ccl.getY()));
+ getPointCharOffset = p ->
{
- if (fullWidth <= 0)
+ if (bounds.width <= 0)
{
return 0;
}
- int cx = ev.getX() - canvasX;
+ int cx = p.x - ccl.getX() - ox;
+ int cy = p.y - ccl.getY() - oy;
- int charIndex = (tsValue.length() * cx) / fullWidth;
+ int currentLine = Ints.constrainToRange(cy / oh, 0, editLines.size() - 1);
+
+ final Line line = editLines.get(currentLine);
+ final String tsValue = line.text;
+ int charIndex = tsValue.length();
+ int fullWidth = font.getTextWidth(tsValue);
+
+ int tx = ox;
+ if (w > 0)
+ {
+ tx += (w - fullWidth) / 2;
+ }
+ cx -= tx;
// `i` is used to track max execution time incase there is a font with ligature width data that causes this to fail
for (int i = tsValue.length(); i >= 0 && charIndex >= 0 && charIndex <= tsValue.length(); i--)
@@ -353,22 +489,72 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
break;
}
- if (charIndex < 0)
+ charIndex = Ints.constrainToRange(charIndex, 0, tsValue.length());
+ return line.start + charIndex;
+ };
+
+ getLineOffset = code ->
+ {
+ if (editLines.size() < 2)
{
- charIndex = 0;
- }
- if (charIndex > tsValue.length())
- {
- charIndex = tsValue.length();
+ return cursorStart;
}
- return charIndex;
+ int currentLine = -1;
+ for (int i = 0; i < editLines.size(); i++)
+ {
+ Line l = editLines.get(i);
+ if (cursorOnLine(cursorStart, l.start, l.end)
+ || (cursorOnLine(cursorStart, l.start, l.end + 1) && i == editLines.size() - 1))
+ {
+ currentLine = i;
+ break;
+ }
+ }
+
+ if (currentLine == -1
+ || (code == KeyEvent.VK_UP && currentLine == 0)
+ || (code == KeyEvent.VK_DOWN && currentLine == editLines.size() - 1))
+ {
+ return cursorStart;
+ }
+
+ final Line line = editLines.get(currentLine);
+ final int direction = code == KeyEvent.VK_UP ? -1 : 1;
+ final Point dest = new Point(cursor.getCanvasLocation().getX(), cursor.getCanvasLocation().getY() + (direction * oh));
+ final int charOffset = getPointCharOffset.applyAsInt(dest);
+
+ // Place cursor on right line if whitespace keep it on the same line or skip a line
+ final Line nextLine = editLines.get(currentLine + direction);
+ if ((direction == -1 && charOffset >= line.start)
+ || (direction == 1 && (charOffset > nextLine.end && (currentLine + direction != editLines.size() - 1))))
+ {
+ return nextLine.end;
+ }
+
+ return charOffset;
};
}
+ private boolean cursorOnLine(final int cursor, final int start, final int end)
+ {
+ return (cursor >= start) && (cursor <= end);
+ }
+
+ private int getCharOffset(MouseEvent ev)
+ {
+ if (getPointCharOffset == null)
+ {
+ return 0;
+ }
+
+ return getPointCharOffset.applyAsInt(ev.getPoint());
+ }
+
@Override
protected void open()
{
+ this.built = true;
update();
}
@@ -398,12 +584,12 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
char c = e.getKeyChar();
if (charValidator.test(c))
{
- if (cursor != cursorEnd)
+ if (cursorStart != cursorEnd)
{
- value.delete(cursor, cursorEnd);
+ value.delete(cursorStart, cursorEnd);
}
- value.insert(cursor, c);
- cursorAt(cursor + 1);
+ value.insert(cursorStart, c);
+ cursorAt(cursorStart + 1);
if (onChanged != null)
{
onChanged.accept(getValue());
@@ -421,13 +607,13 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
{
case KeyEvent.VK_X:
case KeyEvent.VK_C:
- if (cursor != cursorEnd)
+ if (cursorStart != cursorEnd)
{
- String s = value.substring(cursor, cursorEnd);
+ String s = value.substring(cursorStart, cursorEnd);
if (code == KeyEvent.VK_X)
{
- value.delete(cursor, cursorEnd);
- cursorAt(cursor);
+ value.delete(cursorStart, cursorEnd);
+ cursorAt(cursorStart);
}
Toolkit.getDefaultToolkit()
.getSystemClipboard()
@@ -441,20 +627,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
.getSystemClipboard()
.getData(DataFlavor.stringFlavor)
.toString();
- if (cursor != cursorEnd)
+ if (cursorStart != cursorEnd)
{
- value.delete(cursor, cursorEnd);
+ value.delete(cursorStart, cursorEnd);
}
for (int i = 0; i < s.length(); i++)
{
char ch = s.charAt(i);
if (charValidator.test(ch))
{
- value.insert(cursor, ch);
- cursor++;
+ value.insert(cursorStart, ch);
+ cursorStart++;
}
}
- cursorAt(cursor);
+ cursorAt(cursorStart);
if (onChanged != null)
{
onChanged.accept(getValue());
@@ -468,13 +654,13 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
}
return;
}
- int newPos = cursor;
+ int newPos = cursorStart;
if (ev.isShiftDown())
{
if (selectionEnd == -1 || selectionStart == -1)
{
- selectionStart = cursor;
- selectionEnd = cursor;
+ selectionStart = cursorStart;
+ selectionEnd = cursorStart;
}
newPos = selectionEnd;
}
@@ -486,20 +672,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
switch (code)
{
case KeyEvent.VK_DELETE:
- if (cursor != cursorEnd)
+ if (cursorStart != cursorEnd)
{
- value.delete(cursor, cursorEnd);
- cursorAt(cursor);
+ value.delete(cursorStart, cursorEnd);
+ cursorAt(cursorStart);
if (onChanged != null)
{
onChanged.accept(getValue());
}
return;
}
- if (cursor < value.length())
+ if (cursorStart < value.length())
{
- value.deleteCharAt(cursor);
- cursorAt(cursor);
+ value.deleteCharAt(cursorStart);
+ cursorAt(cursorStart);
if (onChanged != null)
{
onChanged.accept(getValue());
@@ -507,20 +693,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
}
return;
case KeyEvent.VK_BACK_SPACE:
- if (cursor != cursorEnd)
+ if (cursorStart != cursorEnd)
{
- value.delete(cursor, cursorEnd);
- cursorAt(cursor);
+ value.delete(cursorStart, cursorEnd);
+ cursorAt(cursorStart);
if (onChanged != null)
{
onChanged.accept(getValue());
}
return;
}
- if (cursor > 0)
+ if (cursorStart > 0)
{
- value.deleteCharAt(cursor - 1);
- cursorAt(cursor - 1);
+ value.deleteCharAt(cursorStart - 1);
+ cursorAt(cursorStart - 1);
if (onChanged != null)
{
onChanged.accept(getValue());
@@ -535,6 +721,14 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
ev.consume();
newPos++;
break;
+ case KeyEvent.VK_UP:
+ ev.consume();
+ newPos = getLineOffset.applyAsInt(code);
+ break;
+ case KeyEvent.VK_DOWN:
+ ev.consume();
+ newPos = getLineOffset.applyAsInt(code);
+ break;
case KeyEvent.VK_HOME:
ev.consume();
newPos = 0;
@@ -553,9 +747,9 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
return;
case KeyEvent.VK_ESCAPE:
ev.consume();
- if (cursor != cursorEnd)
+ if (cursorStart != cursorEnd)
{
- cursorAt(cursor);
+ cursorAt(cursorStart);
return;
}
chatboxPanelManager.close();
@@ -602,16 +796,16 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
}
if (isInBounds == null || !isInBounds.test(mouseEvent))
{
- if (cursor != cursorEnd)
+ if (cursorStart != cursorEnd)
{
selectionStart = -1;
selectionEnd = -1;
- cursorAt(getCharOffset.applyAsInt(mouseEvent));
+ cursorAt(getCharOffset(mouseEvent));
}
return mouseEvent;
}
- int nco = getCharOffset.applyAsInt(mouseEvent);
+ int nco = getCharOffset(mouseEvent);
if (mouseEvent.isShiftDown() && selectionEnd != -1)
{
@@ -653,7 +847,7 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
return mouseEvent;
}
- int nco = getCharOffset.applyAsInt(mouseEvent);
+ int nco = getCharOffset(mouseEvent);
if (selectionStart != -1)
{
selectionEnd = nco;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java
index caa116835e..73d6bf32e4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java
@@ -57,8 +57,8 @@ import javax.inject.Singleton;
import javax.swing.SwingUtilities;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
-import net.runelite.api.events.SessionClose;
-import net.runelite.api.events.SessionOpen;
+import net.runelite.client.events.SessionClose;
+import net.runelite.client.events.SessionOpen;
import net.runelite.client.RuneLite;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/account/AccountPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/account/AccountPlugin.java
index 0bef99bac0..55ab81fbe3 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/account/AccountPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/account/AccountPlugin.java
@@ -29,11 +29,11 @@ import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import javax.swing.JOptionPane;
import lombok.extern.slf4j.Slf4j;
-import net.runelite.api.events.SessionClose;
-import net.runelite.api.events.SessionOpen;
import net.runelite.client.account.AccountSession;
import net.runelite.client.account.SessionManager;
import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.events.SessionClose;
+import net.runelite.client.events.SessionOpen;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.ClientToolbar;
@@ -113,10 +113,10 @@ public class AccountPlugin extends Plugin
private void logoutClick()
{
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(null,
- "Are you sure you want to logout from RuneLite?", "Logout Confirmation",
- JOptionPane.YES_NO_OPTION))
+ "Are you sure you want to logout from RuneLite?", "Logout Confirmation",
+ JOptionPane.YES_NO_OPTION))
{
- sessionManager.logout();
+ executor.execute(sessionManager::logout);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/ArdougneDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/ArdougneDiaryRequirement.java
index 7873c2c923..85adb4db7b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/ArdougneDiaryRequirement.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/ArdougneDiaryRequirement.java
@@ -40,8 +40,10 @@ public class ArdougneDiaryRequirement extends GenericDiaryRequirement
new QuestRequirement(Quest.RUNE_MYSTERIES));
add("Steal a cake from the Ardougne market stalls.",
new SkillRequirement(Skill.THIEVING, 5));
- add("Enter the Combat Training Camp north of W. Ardougne",
+ add("Enter the Combat Training Camp north of W. Ardougne.",
new QuestRequirement(Quest.BIOHAZARD));
+ add("Go out fishing on the Fishing Trawler.",
+ new SkillRequirement(Skill.FISHING, 15));
// MEDIUM
add("Enter the Unicorn pen in Ardougne zoo using Fairy rings.",
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/FaladorDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/FaladorDiaryRequirement.java
index 3111b0d6e1..30f7843199 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/FaladorDiaryRequirement.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/FaladorDiaryRequirement.java
@@ -94,6 +94,8 @@ public class FaladorDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.AGILITY, 50));
add("Enter the mining guild wearing full prospector.",
new SkillRequirement(Skill.MINING, 60));
+ add("Kill the Blue Dragon under the Heroes' Guild.",
+ new QuestRequirement(Quest.HEROES_QUEST));
add("Crack a wall safe within Rogues Den.",
new SkillRequirement(Skill.THIEVING, 50));
add("Recharge your prayer in the Port Sarim church while wearing full Proselyte.",
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/FremennikDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/FremennikDiaryRequirement.java
index 130432035b..46c708efbb 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/FremennikDiaryRequirement.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/FremennikDiaryRequirement.java
@@ -50,9 +50,9 @@ public class FremennikDiaryRequirement extends GenericDiaryRequirement
add("Steal from the Keldagrim crafting or baker's stall.",
new SkillRequirement(Skill.THIEVING, 5),
new QuestRequirement(Quest.THE_GIANT_DWARF, true));
- add("Enter the Troll Stronghold",
+ add("Enter the Troll Stronghold.",
new QuestRequirement(Quest.DEATH_PLATEAU),
- new QuestRequirement(Quest.TROLL_STRONGHOLD));
+ new QuestRequirement(Quest.TROLL_STRONGHOLD, true));
add("Chop and burn some oak logs in the Fremennik Province.",
new SkillRequirement(Skill.WOODCUTTING, 15),
new SkillRequirement(Skill.FIREMAKING, 15));
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KandarinDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KandarinDiaryRequirement.java
index 0b775a0dba..ef9df50ce2 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KandarinDiaryRequirement.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KandarinDiaryRequirement.java
@@ -40,7 +40,7 @@ public class KandarinDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.FISHING, 16));
add("Plant some Jute seeds in the patch north of McGrubor's Wood.",
new SkillRequirement(Skill.FARMING, 13));
- add("Defeat on of each elemental in the workshop.",
+ add("Defeat one of each elemental in the workshop.",
new QuestRequirement(Quest.ELEMENTAL_WORKSHOP_I, true));
add("Cross the Coal truck log shortcut.",
new SkillRequirement(Skill.AGILITY, 20));
@@ -96,6 +96,9 @@ public class KandarinDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.MAGIC, 56));
add("Burn some Maple logs with a bow in Seers' Village.",
new SkillRequirement(Skill.FIREMAKING, 65));
+ add("Kill a Shadow Hound in the Shadow dungeon.",
+ new SkillRequirement(Skill.THIEVING, 53),
+ new QuestRequirement(Quest.DESERT_TREASURE, true));
add("Purchase and equip a granite body from Barbarian Assault.",
new SkillRequirement(Skill.STRENGTH, 50),
new SkillRequirement(Skill.DEFENCE, 50));
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java
index 951ce3a48b..182b288a3b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java
@@ -128,7 +128,6 @@ public class KourendDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.MAGIC, 90),
new SkillRequirement(Skill.MINING, 38),
new SkillRequirement(Skill.CRAFTING, 38),
- new QuestRequirement(Quest.MONKEY_MADNESS_I),
new FavourRequirement(Favour.ARCEUUS, 100));
add("Create your own Battlestaff from scratch within the Farming Guild.",
new SkillRequirement(Skill.FARMING, 85),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/MorytaniaDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/MorytaniaDiaryRequirement.java
index 9b9a861779..826b1a8410 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/MorytaniaDiaryRequirement.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/MorytaniaDiaryRequirement.java
@@ -48,6 +48,8 @@ public class MorytaniaDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.SLAYER, 15));
add("Place a Scarecrow in the Morytania flower patch.",
new SkillRequirement(Skill.FARMING, 23));
+ add("Kill a werewolf in its human form using the Wolfbane Dagger.",
+ new QuestRequirement(Quest.PRIEST_IN_PERIL));
add("Restore your prayer points at the nature altar.",
new QuestRequirement(Quest.NATURE_SPIRIT));
@@ -74,7 +76,7 @@ public class MorytaniaDiaryRequirement extends GenericDiaryRequirement
add("Use an ectophial to return to Port Phasmatys.",
new QuestRequirement(Quest.GHOSTS_AHOY));
add("Mix a Guthix Balance potion while in Morytania.",
- new SkillRequirement(Skill.HERBLORE, 36),
+ new SkillRequirement(Skill.HERBLORE, 22),
new QuestRequirement(Quest.IN_AID_OF_THE_MYREQUE, true));
// HARD
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/WesternDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/WesternDiaryRequirement.java
index be612338e8..ee67f45132 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/WesternDiaryRequirement.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/WesternDiaryRequirement.java
@@ -88,7 +88,7 @@ public class WesternDiaryRequirement extends GenericDiaryRequirement
// HARD
add("Kill an Elf with a Crystal bow.",
new SkillRequirement(Skill.RANGED, 70),
- new SkillRequirement(Skill.AGILITY, 50),
+ new SkillRequirement(Skill.AGILITY, 56),
new QuestRequirement(Quest.ROVING_ELVES));
add("Catch and cook a Monkfish in Piscatoris.",
new SkillRequirement(Skill.FISHING, 62),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityOverlay.java
index bc6e953f6d..e9c205f64f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityOverlay.java
@@ -36,6 +36,7 @@ import net.runelite.api.Client;
import net.runelite.api.Point;
import net.runelite.api.Tile;
import net.runelite.api.coords.LocalPoint;
+import net.runelite.client.game.AgilityShortcut;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
@@ -44,6 +45,7 @@ import net.runelite.client.ui.overlay.OverlayUtil;
class AgilityOverlay extends Overlay
{
private static final int MAX_DISTANCE = 2350;
+ private static final Color SHORTCUT_HIGH_LEVEL_COLOR = Color.ORANGE;
private final Client client;
private final AgilityPlugin plugin;
@@ -66,14 +68,15 @@ class AgilityOverlay extends Overlay
LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation();
Point mousePosition = client.getMouseCanvasPosition();
final List marksOfGrace = plugin.getMarksOfGrace();
- plugin.getObstacles().forEach((object, tile) ->
+ plugin.getObstacles().forEach((object, obstacle) ->
{
- if (Obstacles.SHORTCUT_OBSTACLE_IDS.contains(object.getId()) && !config.highlightShortcuts() ||
+ if (Obstacles.SHORTCUT_OBSTACLE_IDS.containsKey(object.getId()) && !config.highlightShortcuts() ||
Obstacles.TRAP_OBSTACLE_IDS.contains(object.getId()) && !config.showTrapOverlay())
{
return;
}
+ Tile tile = obstacle.getTile();
if (tile.getPlane() == client.getPlane()
&& object.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE)
{
@@ -87,11 +90,11 @@ class AgilityOverlay extends Overlay
}
return;
}
-
Area objectClickbox = object.getClickbox();
if (objectClickbox != null)
{
- Color configColor = config.getOverlayColor();
+ AgilityShortcut agilityShortcut = obstacle.getShortcut();
+ Color configColor = agilityShortcut == null || agilityShortcut.getLevel() <= plugin.getAgilityLevel() ? config.getOverlayColor() : SHORTCUT_HIGH_LEVEL_COLOR;
if (config.highlightMarks() && !marksOfGrace.isEmpty())
{
configColor = config.getMarkColor();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java
index cd60c6b940..c895a07980 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java
@@ -38,10 +38,12 @@ import net.runelite.api.Item;
import net.runelite.api.ItemID;
import static net.runelite.api.ItemID.AGILITY_ARENA_TICKET;
import net.runelite.api.Player;
+import net.runelite.api.Skill;
import static net.runelite.api.Skill.AGILITY;
import net.runelite.api.Tile;
import net.runelite.api.TileObject;
import net.runelite.api.coords.WorldPoint;
+import net.runelite.api.events.BoostedLevelChanged;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.DecorativeObjectChanged;
import net.runelite.api.events.DecorativeObjectDespawned;
@@ -63,6 +65,7 @@ import net.runelite.api.events.WallObjectSpawned;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.game.AgilityShortcut;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@@ -80,7 +83,7 @@ public class AgilityPlugin extends Plugin
private static final int AGILITY_ARENA_REGION_ID = 11157;
@Getter
- private final Map obstacles = new HashMap<>();
+ private final Map obstacles = new HashMap<>();
@Getter
private final List marksOfGrace = new ArrayList<>();
@@ -115,6 +118,9 @@ public class AgilityPlugin extends Plugin
private int lastAgilityXp;
private WorldPoint lastArenaTicketPosition;
+ @Getter
+ private int agilityLevel;
+
@Provides
AgilityConfig getConfig(ConfigManager configManager)
{
@@ -126,6 +132,7 @@ public class AgilityPlugin extends Plugin
{
overlayManager.add(agilityOverlay);
overlayManager.add(lapCounterOverlay);
+ agilityLevel = client.getBoostedSkillLevel(Skill.AGILITY);
}
@Override
@@ -136,6 +143,7 @@ public class AgilityPlugin extends Plugin
marksOfGrace.clear();
obstacles.clear();
session = null;
+ agilityLevel = 0;
}
@Subscribe
@@ -208,6 +216,17 @@ public class AgilityPlugin extends Plugin
}
}
+
+ @Subscribe
+ public void onBoostedLevelChanged(BoostedLevelChanged boostedLevelChanged)
+ {
+ Skill skill = boostedLevelChanged.getSkill();
+ if (skill == AGILITY)
+ {
+ agilityLevel = client.getBoostedSkillLevel(skill);
+ }
+ }
+
@Subscribe
public void onItemSpawned(ItemSpawned itemSpawned)
{
@@ -366,11 +385,40 @@ public class AgilityPlugin extends Plugin
}
if (Obstacles.COURSE_OBSTACLE_IDS.contains(newObject.getId()) ||
- Obstacles.SHORTCUT_OBSTACLE_IDS.contains(newObject.getId()) ||
(Obstacles.TRAP_OBSTACLE_IDS.contains(newObject.getId())
&& Obstacles.TRAP_OBSTACLE_REGIONS.contains(newObject.getWorldLocation().getRegionID())))
{
- obstacles.put(newObject, tile);
+ obstacles.put(newObject, new Obstacle(tile, null));
+ }
+
+ if (Obstacles.SHORTCUT_OBSTACLE_IDS.containsKey(newObject.getId()))
+ {
+ AgilityShortcut closestShortcut = null;
+ int distance = -1;
+
+ // Find the closest shortcut to this object
+ for (AgilityShortcut shortcut : Obstacles.SHORTCUT_OBSTACLE_IDS.get(newObject.getId()))
+ {
+ if (shortcut.getWorldLocation() == null)
+ {
+ closestShortcut = shortcut;
+ break;
+ }
+ else
+ {
+ int newDistance = shortcut.getWorldLocation().distanceTo2D(newObject.getWorldLocation());
+ if (closestShortcut == null || newDistance < distance)
+ {
+ closestShortcut = shortcut;
+ distance = newDistance;
+ }
+ }
+ }
+
+ if (closestShortcut != null)
+ {
+ obstacles.put(newObject, new Obstacle(tile, closestShortcut));
+ }
}
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacle.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacle.java
new file mode 100644
index 0000000000..6038de468b
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacle.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, MrGroggle
+ * 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 HOLDER 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.agility;
+
+import javax.annotation.Nullable;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import net.runelite.api.Tile;
+import net.runelite.client.game.AgilityShortcut;
+
+@Value
+@AllArgsConstructor
+class Obstacle
+{
+ private final Tile tile;
+ @Nullable
+ private final AgilityShortcut shortcut;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacles.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacles.java
index 43a96bd151..92df605a36 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacles.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacles.java
@@ -25,11 +25,27 @@
package net.runelite.client.plugins.agility;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
import java.util.List;
import java.util.Set;
-import static net.runelite.api.NullObjectID.*;
+import static net.runelite.api.NullObjectID.NULL_10872;
+import static net.runelite.api.NullObjectID.NULL_10873;
+import static net.runelite.api.NullObjectID.NULL_12945;
+import static net.runelite.api.NullObjectID.NULL_18083;
+import static net.runelite.api.NullObjectID.NULL_18116;
+import static net.runelite.api.NullObjectID.NULL_18122;
+import static net.runelite.api.NullObjectID.NULL_18124;
+import static net.runelite.api.NullObjectID.NULL_18129;
+import static net.runelite.api.NullObjectID.NULL_18130;
+import static net.runelite.api.NullObjectID.NULL_18132;
+import static net.runelite.api.NullObjectID.NULL_18133;
+import static net.runelite.api.NullObjectID.NULL_18135;
+import static net.runelite.api.NullObjectID.NULL_18136;
+import static net.runelite.api.NullObjectID.NULL_3550;
import static net.runelite.api.ObjectID.*;
+import net.runelite.client.game.AgilityShortcut;
class Obstacles
{
@@ -62,7 +78,7 @@ class Obstacles
STEPPING_STONE_15412, TROPICAL_TREE_15414, MONKEYBARS_15417, SKULL_SLOPE_15483, ROPE_15487, TROPICAL_TREE_16062,
// Falador
ROUGH_WALL_10833, TIGHTROPE_10834, HAND_HOLDS_10836, GAP_11161, GAP_11360, TIGHTROPE_11361,
- TIGHTROPE_11364, GAP_11365, LEDGE_11366, LEDGE_11367, LEDGE_11368, LEDGE_11370, EDGE_11371,
+ TIGHTROPE_11364, GAP_11365, LEDGE_11366, LEDGE_11367, LEDGE_11369, LEDGE_11370, EDGE_11371,
// Wilderness
OBSTACLE_PIPE_23137, ROPESWING_23132, STEPPING_STONE_23556, LOG_BALANCE_23542, ROCKS_23640,
// Seers
@@ -91,144 +107,7 @@ class Obstacles
ZIP_LINE_11645, ZIP_LINE_11646
);
- static final Set SHORTCUT_OBSTACLE_IDS = ImmutableSet.of(
- // Grand Exchange
- UNDERWALL_TUNNEL_16529, UNDERWALL_TUNNEL_16530,
- // South Varrock
- STEPPING_STONE_16533, FENCE_16518, ROCKS_16549, ROCKS_16550,
- // Falador
- WALL_17049, WALL_17050, CRUMBLING_WALL_24222, UNDERWALL_TUNNEL, UNDERWALL_TUNNEL_16528, CREVICE_16543,
- // Draynor
- UNDERWALL_TUNNEL_19032, UNDERWALL_TUNNEL_19036,
- // South Lumbridge
- BROKEN_RAFT, STEPPING_STONE_16513,
- // Trollheim
- ROCKS_3790, ROCKS_3791, ROCKS_3803, ROCKS_3804, ROCKS_16523, ROCKS_16524, ROCKS_3748, ROCKS_16545, ROCKS_16521,
- ROCKS_16522, ROCKS_16464,
- // North Camelot
- LOG_BALANCE_16540, LOG_BALANCE_16541, LOG_BALANCE_16542,
- // Rellekka
- BROKEN_FENCE,
- // Ardougne
- LOG_BALANCE_16546, LOG_BALANCE_16547, LOG_BALANCE_16548,
- // Yanille
- CASTLE_WALL, HOLE_16520, WALL_17047,
- // Observatory
- NULL_31849,
- // Gnome Stronghold
- ROCKS_16534, ROCKS_16535,
- // Karamja Volcano
- STRONG_TREE_17074,
- // Shilo Village
- STEPPING_STONE_16466,
- // Vine east of Shilo Village
- NULL_26884, NULL_26886,
- // Stepping stones east of Shilo Village
- STEPPING_STONES, STEPPING_STONES_23646, STEPPING_STONES_23647,
- // Middle of Karamja
- A_WOODEN_LOG,
- // Slayer Tower
- SPIKEY_CHAIN, SPIKEY_CHAIN_16538,
- // Fremennik Slayer Cave
- STRANGE_FLOOR_16544, CREVICE_16539, STEPS_29993,
- // Wilderness
- STEPPING_STONE_14918, STEPPING_STONE_14917, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406,
- // Godwars
- ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402,
- // Seers' Village Coal Mine
- LOG_BALANCE_23274,
- // Arceuus Essence Mine
- ROCKS_27984, ROCKS_27985, BOULDER_27990, ROCKS_27987, ROCKS_27988,
- // Wintertodt
- GAP_29326,
- // Gnome Stronghold Slayer Underground
- TUNNEL_30174, TUNNEL_30175,
- // Taverley Underground
- OBSTACLE_PIPE_16509, STRANGE_FLOOR, ROCKS, ROCKS_14106, LOOSE_RAILING_28849,
- // Heroes Guild
- CREVICE_9739, CREVICE_9740,
- // Fossil Island
- HOLE_31481, HOLE_31482, LADDER_30938, LADDER_30939, LADDER_30940, LADDER_30941, ROPE_ANCHOR, ROPE_ANCHOR_30917,
- RUBBER_CAP_MUSHROOM,
- ROCKS_31757, ROCKS_31758, ROCKS_31759, PILLAR_31809,
- // West Brimhaven
- ROPESWING_23568, ROPESWING_23569,
- // Brimhaven Dungeon
- VINE_26880, VINE_26882, PIPE_21728, STEPPING_STONE_19040, PIPE_21727, LOG_BALANCE_20882, LOG_BALANCE_20884,
- STEPPING_STONE_21738, STEPPING_STONE_21739, TIGHTGAP,
- // Lumbridge
- STILE_12982,
- // Edgeville Dungeon
- MONKEYBARS_23566, OBSTACLE_PIPE_16511,
- // Miscellania
- STEPPING_STONE_11768,
- // Kalphite
- CREVICE_16465,
- // Eagles' Peak
- ROCKS_19849,
- // Catherby
- CROSSBOW_TREE_17062, ROCKS_17042,
- // McGrubor's Woods
- LOOSE_RAILING,
- // Cairn Isle
- ROCKS_2231,
- // South Kourend
- STEPPING_STONE_29728, STEPPING_STONE_29729, STEPPING_STONE_29730,
- // Cosmic Temple
- JUTTING_WALL_17002,
- // Arandar
- ROCKS_16514, ROCKS_16515, LOG_BALANCE_3933,
- // South River Salve
- STEPPING_STONE_13504,
- DARK_TUNNEL_10047,
- // Ectofuntus
- WEATHERED_WALL, WEATHERED_WALL_16526,
- // Mos Le'Harmless
- STEPPING_STONE_19042,
- // North River Salve
- ROCKS_16998, ROCKS_16999, ORNATE_RAILING, ORNATE_RAILING_17000,
- // West Zul-Andra
- STEPPING_STONE_10663,
- // Yanille Agility Dungeon
- BALANCING_LEDGE_23548, OBSTACLE_PIPE_23140, MONKEYBARS_23567, PILE_OF_RUBBLE_23563, PILE_OF_RUBBLE_23564,
- // High Level Wilderness Dungeon
- CREVICE_19043,
- // Revenant Caves
- PILLAR_31561,
- // Elf Camp Isafdar Tirranwn
- LOG_BALANCE_3931, LOG_BALANCE_3930, LOG_BALANCE_3929, LOG_BALANCE_3932, DENSE_FOREST_3938, DENSE_FOREST_3939,
- DENSE_FOREST_3998, DENSE_FOREST_3999, DENSE_FOREST, LEAVES, LEAVES_3924, LEAVES_3925, STICKS, TRIPWIRE,
- // Gu'Tanoth bridge
- GAP, GAP_2831,
- // Lumbridge Swamp Caves
- STEPPING_STONE_5948, STEPPING_STONE_5949, ROCKS_6673,
- // Morytania Pirate Ship
- ROCK_16115,
- // Agility Pyramid Entrance
- CLIMBING_ROCKS_11948, CLIMBING_ROCKS_11949,
- // Lumber Yard
- BROKEN_FENCE_2618,
- // Ungael and Vorkath crater
- NULL_25337, NULL_29868, NULL_29869, NULL_29870, ICE_CHUNKS_31822, NULL_31823, ICE_CHUNKS_31990,
- // Underwater Area Fossil Island
- TUNNEL_30959, HOLE_30966, OBSTACLE, OBSTACLE_30767, OBSTACLE_30964, OBSTACLE_30962,
- // Tree Gnome Village
- LOOSE_RAILING_2186,
- // Weiss
- LITTLE_BOULDER, ROCKSLIDE_33184, ROCKSLIDE_33185, NULL_33327, NULL_33328, LEDGE_33190, ROCKSLIDE_33191, FALLEN_TREE_33192,
- // Al-Kharid
- BROKEN_WALL_33344, BIG_WINDOW,
- // Burgh de Rott
- LOW_FENCE,
- // Taverley
- STILE,
- // Asgarnian Ice Dungeon
- STEPS,
- // Fossil Island Wyvern Cave
- STAIRS_31485,
- // Mount Karuulm
- ROCKS_34397, ROCKS_34396
- );
+ static final Multimap SHORTCUT_OBSTACLE_IDS;
static final Set TRAP_OBSTACLE_IDS = ImmutableSet.of(
// Agility pyramid
@@ -236,4 +115,17 @@ class Obstacles
);
static final List TRAP_OBSTACLE_REGIONS = ImmutableList.of(12105, 13356);
+
+ static
+ {
+ final ImmutableMultimap.Builder builder = ImmutableMultimap.builder();
+ for (final AgilityShortcut item : AgilityShortcut.values())
+ {
+ for (int obstacle : item.getObstacleIds())
+ {
+ builder.put(obstacle, item);
+ }
+ }
+ SHORTCUT_OBSTACLE_IDS = builder.build();
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/attackstyles/AttackStylesConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/attackstyles/AttackStylesConfig.java
index 111fb9dc85..c3715481d1 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/attackstyles/AttackStylesConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/attackstyles/AttackStylesConfig.java
@@ -97,11 +97,22 @@ public interface AttackStylesConfig extends Config
return false;
}
+ @ConfigItem(
+ keyName = "hideAutoRetaliate",
+ name = "Hide auto retaliate",
+ description = "Hide auto retaliate from the combat options tab",
+ position = 7
+ )
+ default boolean hideAutoRetaliate()
+ {
+ return false;
+ }
+
@ConfigItem(
keyName = "removeWarnedStyles",
name = "Remove warned styles",
description = "Remove warned styles from the combat options tab",
- position = 7
+ position = 8
)
default boolean removeWarnedStyles()
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/attackstyles/AttackStylesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/attackstyles/AttackStylesPlugin.java
index 4b6de0ea1d..db7a9ed751 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/attackstyles/AttackStylesPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/attackstyles/AttackStylesPlugin.java
@@ -126,6 +126,7 @@ public class AttackStylesPlugin extends Plugin
overlayManager.remove(overlay);
hideWarnedStyles(false);
processWidgets();
+ hideWidget(client.getWidget(WidgetInfo.COMBAT_AUTO_RETALIATE), false);
}
public AttackStyle getAttackStyle()
@@ -174,6 +175,7 @@ public class AttackStylesPlugin extends Plugin
hideWidget(client.getWidget(widgetKey), widgetsToHide.get(equippedWeaponType, widgetKey));
}
}
+ hideWidget(client.getWidget(WidgetInfo.COMBAT_AUTO_RETALIATE), config.hideAutoRetaliate());
}
@Subscribe
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java
index 620cc586be..6a3a7f3416 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java
@@ -60,6 +60,7 @@ import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
+import net.runelite.client.game.SpriteManager;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
@@ -125,6 +126,9 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
@Inject
private KeyManager keyManager;
+ @Inject
+ private SpriteManager spriteManager;
+
private boolean shiftPressed = false;
@Provides
@@ -139,7 +143,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
keyManager.registerKeyListener(this);
mouseManager.registerMouseWheelListener(this);
clientThread.invokeLater(tabInterface::init);
- client.getSpriteOverrides().putAll(TabSprites.toMap(client));
+ spriteManager.addSpriteOverrides(TabSprites.values());
}
@Override
@@ -148,11 +152,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
keyManager.unregisterKeyListener(this);
mouseManager.unregisterMouseWheelListener(this);
clientThread.invokeLater(tabInterface::destroy);
-
- for (TabSprites value : TabSprites.values())
- {
- client.getSpriteOverrides().remove(value.getSpriteId());
- }
+ spriteManager.removeSpriteOverrides(TabSprites.values());
shiftPressed = false;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/TagManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/TagManager.java
index c20974758d..c1d5ff8c11 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/TagManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/TagManager.java
@@ -167,6 +167,20 @@ public class TagManager
}
}
+ public void renameTag(String oldTag, String newTag)
+ {
+ List items = getItemsForTag(Text.standardize(oldTag));
+ items.forEach(id ->
+ {
+ Collection tags = getTags(id, id < 0);
+
+ tags.remove(Text.standardize(oldTag));
+ tags.add(Text.standardize(newTag));
+
+ setTags(id, tags, id < 0);
+ });
+ }
+
private int getItemId(int itemId, boolean variation)
{
itemId = Math.abs(itemId);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/MenuIndexes.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/MenuIndexes.java
index afa8f6e276..51e179b143 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/MenuIndexes.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/MenuIndexes.java
@@ -39,5 +39,6 @@ class MenuIndexes
static final int CHANGE_ICON = 3;
static final int DELETE_TAB = 4;
static final int EXPORT_TAB = 5;
+ static final int RENAME_TAB = 6;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java
index 148b965043..e0b1af23eb 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java
@@ -64,7 +64,6 @@ import net.runelite.api.SpriteID;
import net.runelite.api.VarClientInt;
import net.runelite.api.VarClientStr;
import net.runelite.api.Varbits;
-import net.runelite.api.widgets.WidgetType;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.vars.InputType;
@@ -73,15 +72,14 @@ import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.api.widgets.WidgetSizeMode;
+import net.runelite.api.widgets.WidgetType;
import net.runelite.client.Notifier;
import net.runelite.client.callback.ClientThread;
-import net.runelite.client.config.ConfigManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.plugins.banktags.BankTagsConfig;
import net.runelite.client.plugins.banktags.BankTagsPlugin;
-import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP;
-import static net.runelite.client.plugins.banktags.BankTagsPlugin.ICON_SEARCH;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.TAG_SEARCH;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.VAR_TAG_SUFFIX;
import net.runelite.client.plugins.banktags.TagManager;
@@ -102,6 +100,7 @@ public class TabInterface
private static final String EXPORT_TAB = "Export tag tab";
private static final String IMPORT_TAB = "Import tag tab";
private static final String VIEW_TAB = "View tag tab";
+ private static final String RENAME_TAB = "Rename tag tab";
private static final String CHANGE_ICON = "Change icon";
private static final String REMOVE_TAG = "Remove-tag";
private static final String TAG_GEAR = "Tag-equipment";
@@ -111,11 +110,12 @@ public class TabInterface
private static final int BUTTON_HEIGHT = 20;
private static final int MARGIN = 1;
private static final int SCROLL_TICK = 500;
+ private static final int INCINERATOR_WIDTH = 48;
+ private static final int INCINERATOR_HEIGHT = 39;
private final Client client;
private final ClientThread clientThread;
private final ItemManager itemManager;
- private final ConfigManager configManager;
private final TagManager tagManager;
private final TabManager tabManager;
private final ChatboxPanelManager chatboxPanelManager;
@@ -130,6 +130,8 @@ public class TabInterface
private int currentTabIndex;
private TagTab iconToSet = null;
private Instant startScroll = Instant.now();
+ private String rememberedSearch;
+ private boolean waitSearchTick;
@Getter
private Widget upButton;
@@ -148,7 +150,6 @@ public class TabInterface
final Client client,
final ClientThread clientThread,
final ItemManager itemManager,
- final ConfigManager configManager,
final TagManager tagManager,
final TabManager tabManager,
final ChatboxPanelManager chatboxPanelManager,
@@ -159,7 +160,6 @@ public class TabInterface
this.client = client;
this.clientThread = clientThread;
this.itemManager = itemManager;
- this.configManager = configManager;
this.tagManager = tagManager;
this.tabManager = tabManager;
this.chatboxPanelManager = chatboxPanelManager;
@@ -211,7 +211,7 @@ public class TabInterface
if (config.rememberTab() && !Strings.isNullOrEmpty(config.tab()))
{
- openTag(TAG_SEARCH + config.tab());
+ openTag(config.tab());
}
}
@@ -239,7 +239,7 @@ public class TabInterface
tagManager.addTag(item, activeTab.getTag(), false);
}
- openTag(TAG_SEARCH + activeTab.getTag());
+ openTag(activeTab.getTag());
}
return;
@@ -292,7 +292,7 @@ public class TabInterface
final Iterator dataIter = Text.fromCSV(dataString).iterator();
final String name = dataIter.next();
final String icon = dataIter.next();
- configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + name, icon);
+ tabManager.setIcon(name, icon);
while (dataIter.hasNext())
{
@@ -306,7 +306,7 @@ public class TabInterface
if (activeTab != null && name.equals(activeTab.getTag()))
{
- openTag(TAG_SEARCH + activeTab.getTag());
+ openTag(activeTab.getTag());
}
notifier.notify("Tag tab " + name + " has been imported from your clipboard!");
@@ -336,7 +336,7 @@ public class TabInterface
}
else
{
- openTag(TAG_SEARCH + Text.removeTags(clicked.getName()));
+ openTag(Text.removeTags(clicked.getName()));
}
client.playSoundEffect(SoundEffectID.UI_BOOP);
@@ -373,6 +373,10 @@ public class TabInterface
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
notifier.notify("Tag tab " + tagTab.getTag() + " has been copied to your clipboard!");
break;
+ case Tab.RENAME_TAB:
+ String renameTarget = Text.standardize(event.getOpbase());
+ renameTab(renameTarget);
+ break;
}
}
@@ -382,6 +386,8 @@ public class TabInterface
currentTabIndex = 0;
maxTabs = 0;
parent = null;
+ waitSearchTick = false;
+ rememberedSearch = "";
if (upButton != null)
{
@@ -398,6 +404,8 @@ public class TabInterface
if (isHidden())
{
parent = null;
+ waitSearchTick = false;
+ rememberedSearch = "";
// If bank window was just hidden, update last active tab position
if (currentTabIndex != config.position())
@@ -462,6 +470,20 @@ public class TabInterface
activateTab(null);
}
+ if (!waitSearchTick
+ && activeTab == null
+ && !Strings.isNullOrEmpty(rememberedSearch)
+ && client.getVar(VarClientInt.INPUT_TYPE) == InputType.NONE.getType())
+ {
+ bankSearch.reset(true);
+ bankSearch.search(InputType.NONE, rememberedSearch, true);
+ rememberedSearch = "";
+ }
+ else if (waitSearchTick)
+ {
+ waitSearchTick = false;
+ }
+
updateBounds();
scrollTab(0);
}
@@ -542,6 +564,15 @@ public class TabInterface
return;
}
+ if (event.getWidgetId() == WidgetInfo.BANK_ITEM_CONTAINER.getId()
+ && event.getMenuAction() == MenuAction.EXAMINE_ITEM_BANK_EQ
+ && event.getMenuOption().equalsIgnoreCase("withdraw-x"))
+ {
+ waitSearchTick = true;
+ rememberedSearch = client.getVar(VarClientStr.INPUT_TEXT);
+ bankSearch.search(InputType.NONE, rememberedSearch, true);
+ }
+
if (iconToSet != null)
{
if (event.getMenuOption().startsWith(CHANGE_ICON + " ("))
@@ -550,7 +581,7 @@ public class TabInterface
int itemId = itemManager.canonicalize(item.getId());
iconToSet.setIconItemId(itemId);
iconToSet.getIcon().setItemId(itemId);
- configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + iconToSet.getTag(), itemId + "");
+ tabManager.setIcon(iconToSet.getTag(), itemId + "");
event.consume();
}
@@ -597,7 +628,7 @@ public class TabInterface
{
if (activeTab != null && tags.contains(activeTab.getTag()))
{
- openTag(TAG_SEARCH + activeTab.getTag());
+ openTag(activeTab.getTag());
}
}
@@ -683,6 +714,7 @@ public class TabInterface
btn.setAction(2, CHANGE_ICON);
btn.setAction(3, REMOVE_TAB);
btn.setAction(4, EXPORT_TAB);
+ btn.setAction(5, RENAME_TAB);
btn.setOnOpListener((JavaScriptCallback) this::handleTagTab);
tagTab.setBackground(btn);
}
@@ -712,13 +744,66 @@ public class TabInterface
}
tabManager.remove(tag);
- configManager.unsetConfiguration(CONFIG_GROUP, ICON_SEARCH + tag);
tabManager.save();
updateBounds();
scrollTab(0);
}
+ private void renameTab(String oldTag)
+ {
+ chatboxPanelManager.openTextInput("Enter new tag name for tag \"" + oldTag + "\":")
+ .onDone((newTag) -> clientThread.invoke(() ->
+ {
+ if (!Strings.isNullOrEmpty(newTag) && !newTag.equalsIgnoreCase(oldTag))
+ {
+ if (tabManager.find(newTag) == null)
+ {
+ TagTab tagTab = tabManager.find(oldTag);
+ tagTab.setTag(newTag);
+
+ final String coloredName = ColorUtil.wrapWithColorTag(newTag, HILIGHT_COLOR);
+ tagTab.getIcon().setName(coloredName);
+ tagTab.getBackground().setName(coloredName);
+
+ tabManager.removeIcon(oldTag);
+ tabManager.setIcon(newTag, tagTab.getIconItemId() + "");
+
+ tabManager.save();
+ tagManager.renameTag(oldTag, newTag);
+
+ if (activeTab != null && activeTab.equals(tagTab))
+ {
+ openTag(newTag);
+ }
+ }
+ else
+ {
+ chatboxPanelManager.openTextMenuInput("The specified bank tag already exists.")
+ .option("1. Merge into existing tag \"" + newTag + "\".", () ->
+ clientThread.invoke(() ->
+ {
+ tagManager.renameTag(oldTag, newTag);
+ final String activeTag = activeTab != null ? activeTab.getTag() : "";
+ deleteTab(oldTag);
+
+ if (activeTag.equals(oldTag))
+ {
+ openTag(newTag);
+ }
+ })
+ )
+ .option("2. Choose a different name.", () ->
+ clientThread.invoke(() ->
+ renameTab(oldTag))
+ )
+ .build();
+ }
+ }
+ }))
+ .build();
+ }
+
private void scrollTick(int direction)
{
// This ensures that dragging on scroll buttons do not scrolls too fast
@@ -805,17 +890,18 @@ public class TabInterface
if (incinerator != null && !incinerator.isHidden())
{
- // This is the required way to move incinerator, don't change it!
- incinerator.setOriginalHeight(39);
- incinerator.setOriginalWidth(48);
- incinerator.setRelativeY(itemContainer.getHeight());
- incinerator.revalidate();
+ incinerator.setOriginalHeight(INCINERATOR_HEIGHT);
+ incinerator.setOriginalWidth(INCINERATOR_WIDTH);
+ incinerator.setOriginalY(INCINERATOR_HEIGHT);
Widget child = incinerator.getDynamicChildren()[0];
- child.setHeight(39);
- child.setWidth(48);
+ child.setOriginalHeight(INCINERATOR_HEIGHT);
+ child.setOriginalWidth(INCINERATOR_WIDTH);
+ child.setWidthMode(WidgetSizeMode.ABSOLUTE);
+ child.setHeightMode(WidgetSizeMode.ABSOLUTE);
child.setType(WidgetType.GRAPHIC);
child.setSpriteId(TabSprites.INCINERATOR.getSpriteId());
+ incinerator.revalidate();
bounds.setSize(TAB_WIDTH + MARGIN * 2, height - incinerator.getHeight());
}
@@ -900,7 +986,6 @@ public class TabInterface
private void updateWidget(Widget t, int y)
{
t.setOriginalY(y);
- t.setRelativeY(y);
t.setHidden(y < (bounds.y + BUTTON_HEIGHT + MARGIN) || y > (bounds.y + bounds.height - TAB_HEIGHT - MARGIN - BUTTON_HEIGHT));
t.revalidate();
}
@@ -913,10 +998,10 @@ public class TabInterface
return itemManager.getItemComposition(item.getId());
}
- private void openTag(String tag)
+ private void openTag(final String tag)
{
- bankSearch.search(InputType.SEARCH, tag, true);
- activateTab(tabManager.find(tag.substring(TAG_SEARCH.length())));
+ bankSearch.search(InputType.SEARCH, TAG_SEARCH + tag, true);
+ activateTab(tabManager.find(tag));
// When tab is selected with search window open, the search window closes but the search button
// stays highlighted, this solves that issue
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabManager.java
index 3f1430dd7c..e1995a5095 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabManager.java
@@ -115,6 +115,7 @@ class TabManager
{
tagTab.setHidden(true);
tabs.remove(tagTab);
+ removeIcon(tag);
}
}
@@ -124,6 +125,16 @@ class TabManager
configManager.setConfiguration(CONFIG_GROUP, TAG_TABS_CONFIG, tags);
}
+ void removeIcon(final String tag)
+ {
+ configManager.unsetConfiguration(CONFIG_GROUP, ICON_SEARCH + Text.standardize(tag));
+ }
+
+ void setIcon(final String tag, final String icon)
+ {
+ configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + Text.standardize(tag), icon);
+ }
+
int size()
{
return tabs.size();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabSprites.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabSprites.java
index e7706679b0..20f9d0dfb6 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabSprites.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabSprites.java
@@ -25,17 +25,12 @@
*/
package net.runelite.client.plugins.banktags.tabs;
-import java.awt.image.BufferedImage;
-import java.util.HashMap;
-import java.util.Map;
import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
-import net.runelite.api.Client;
-import net.runelite.api.SpritePixels;
-import net.runelite.client.util.ImageUtil;
+import lombok.RequiredArgsConstructor;
+import net.runelite.client.game.SpriteOverride;
-@Slf4j
-public enum TabSprites
+@RequiredArgsConstructor
+public enum TabSprites implements SpriteOverride
{
INCINERATOR(-200, "incinerator.png"),
TAB_BACKGROUND(-201, "tag-tab.png"),
@@ -46,23 +41,7 @@ public enum TabSprites
@Getter
private final int spriteId;
- private final BufferedImage image;
- TabSprites(final int spriteId, final String imageName)
- {
- this.spriteId = spriteId;
- this.image = ImageUtil.getResourceStreamFromClass(this.getClass(), imageName);
- }
-
- public static Map toMap(Client client)
- {
- final Map map = new HashMap<>();
-
- for (TabSprites value : values())
- {
- map.put(value.spriteId, ImageUtil.getImageSpritePixels(value.image, client));
- }
-
- return map;
- }
+ @Getter
+ private final String fileName;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TagTab.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TagTab.java
index d3d417f465..004e5f45ed 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TagTab.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TagTab.java
@@ -33,7 +33,7 @@ import net.runelite.api.widgets.Widget;
@EqualsAndHashCode(of = "tag")
class TagTab
{
- private final String tag;
+ private String tag;
private int iconItemId;
private Widget background;
private Widget icon;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsOverlay.java
index dfd175cae7..1c480719ec 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsOverlay.java
@@ -77,7 +77,7 @@ class BarrowsOverlay extends Overlay
{
final NPCComposition composition = npc.getComposition();
- if (composition != null && !composition.isMinimapVisable())
+ if (composition != null && !composition.isMinimapVisible())
{
continue;
}
@@ -90,10 +90,16 @@ class BarrowsOverlay extends Overlay
}
// Player dots
- graphics.setColor(npcColor);
+ graphics.setColor(playerColor);
final List players = client.getPlayers();
for (Player player : players)
{
+ if (player == local)
+ {
+ // Skip local player as we draw square for it later
+ continue;
+ }
+
net.runelite.api.Point minimapLocation = player.getMinimapLocation();
if (minimapLocation != null)
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsPlugin.java
index 014f7cda98..42c1853a2f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsPlugin.java
@@ -49,7 +49,9 @@ import net.runelite.api.events.WallObjectChanged;
import net.runelite.api.events.WallObjectDespawned;
import net.runelite.api.events.WallObjectSpawned;
import net.runelite.api.events.WidgetLoaded;
+import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
+import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.chat.ChatMessageBuilder;
import net.runelite.client.chat.ChatMessageManager;
@@ -128,6 +130,19 @@ public class BarrowsPlugin extends Plugin
overlayManager.remove(brotherOverlay);
walls.clear();
ladders.clear();
+
+ // Restore widgets
+ final Widget potential = client.getWidget(WidgetInfo.BARROWS_POTENTIAL);
+ if (potential != null)
+ {
+ potential.setHidden(false);
+ }
+
+ final Widget barrowsBrothers = client.getWidget(WidgetInfo.BARROWS_BROTHERS);
+ if (barrowsBrothers != null)
+ {
+ barrowsBrothers.setHidden(false);
+ }
}
@Subscribe
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java
index a02ee25e94..bebfcee730 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java
@@ -137,7 +137,7 @@ class BoostsOverlay extends Overlay
return new Color(238, 51, 51);
}
- return boost < config.boostThreshold() ? Color.YELLOW : Color.GREEN;
+ return boost <= config.boostThreshold() ? Color.YELLOW : Color.GREEN;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonCounter.java
index 2db9d6f3e0..bd13e194be 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonCounter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonCounter.java
@@ -26,15 +26,15 @@ package net.runelite.client.plugins.cannon;
import java.awt.Color;
import java.awt.image.BufferedImage;
-import net.runelite.client.ui.overlay.infobox.Counter;
+import net.runelite.client.ui.overlay.infobox.InfoBox;
-public class CannonCounter extends Counter
+public class CannonCounter extends InfoBox
{
private final CannonPlugin plugin;
- public CannonCounter(BufferedImage img, CannonPlugin plugin)
+ CannonCounter(BufferedImage img, CannonPlugin plugin)
{
- super(img, plugin, String.valueOf(plugin.getCballsLeft()));
+ super(img, plugin);
this.plugin = plugin;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusPlugin.java
index 2087e31844..47f1adbec4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusPlugin.java
@@ -75,7 +75,8 @@ public class CerberusPlugin extends Plugin
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
- if (event.getGameState() == GameState.LOGIN_SCREEN || event.getGameState() == GameState.HOPPING)
+ GameState gameState = event.getGameState();
+ if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING || gameState == GameState.CONNECTION_LOST)
{
ghosts.clear();
}
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 a927782809..e7e22cdae3 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
@@ -43,7 +43,6 @@ import net.runelite.api.MessageNode;
import net.runelite.api.VarPlayer;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameTick;
-import net.runelite.api.events.SetMessage;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.vars.AccountType;
@@ -300,7 +299,7 @@ public class ChatCommandsPlugin extends Plugin
Widget boss = bossChildren[i];
Widget kill = killsChildren[i];
- String bossName = boss.getText();
+ String bossName = boss.getText().replace(":", "");
int kc = Integer.parseInt(kill.getText().replace(",", ""));
if (kc != getKc(bossName))
{
@@ -360,14 +359,19 @@ public class ChatCommandsPlugin extends Plugin
return true;
}
- private void killCountLookup(SetMessage setMessage, String message)
+ private void killCountLookup(ChatMessage chatMessage, String message)
{
if (!config.killcount())
{
return;
}
- ChatMessageType type = setMessage.getType();
+ if (message.length() <= KILLCOUNT_COMMAND_STRING.length())
+ {
+ return;
+ }
+
+ ChatMessageType type = chatMessage.getType();
String search = message.substring(KILLCOUNT_COMMAND_STRING.length() + 1);
final String player;
@@ -377,7 +381,7 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
- player = sanitize(setMessage.getName());
+ player = sanitize(chatMessage.getName());
}
search = longBossName(search);
@@ -403,20 +407,20 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
- final MessageNode messageNode = setMessage.getMessageNode();
+ final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
}
- private void questPointsLookup(SetMessage setMessage, String message)
+ private void questPointsLookup(ChatMessage chatMessage, String message)
{
if (!config.qp())
{
return;
}
- ChatMessageType type = setMessage.getType();
+ ChatMessageType type = chatMessage.getType();
final String player;
if (type.equals(ChatMessageType.PRIVATE_MESSAGE_SENT))
@@ -425,7 +429,7 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
- player = sanitize(setMessage.getName());
+ player = sanitize(chatMessage.getName());
}
int qp;
@@ -447,7 +451,7 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
- final MessageNode messageNode = setMessage.getMessageNode();
+ final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -477,14 +481,19 @@ public class ChatCommandsPlugin extends Plugin
return true;
}
- private void personalBestLookup(SetMessage setMessage, String message)
+ private void personalBestLookup(ChatMessage chatMessage, String message)
{
if (!config.pb())
{
return;
}
- ChatMessageType type = setMessage.getType();
+ if (message.length() <= PB_COMMAND.length())
+ {
+ return;
+ }
+
+ ChatMessageType type = chatMessage.getType();
String search = message.substring(PB_COMMAND.length() + 1);
final String player;
@@ -494,7 +503,7 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
- player = sanitize(setMessage.getName());
+ player = sanitize(chatMessage.getName());
}
search = longBossName(search);
@@ -523,7 +532,7 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
- final MessageNode messageNode = setMessage.getMessageNode();
+ final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -565,17 +574,22 @@ public class ChatCommandsPlugin extends Plugin
* Looks up the item price and changes the original message to the
* response.
*
- * @param setMessage The chat message containing the command.
+ * @param chatMessage The chat message containing the command.
* @param message The chat message
*/
- private void itemPriceLookup(SetMessage setMessage, String message)
+ private void itemPriceLookup(ChatMessage chatMessage, String message)
{
if (!config.price())
{
return;
}
- MessageNode messageNode = setMessage.getMessageNode();
+ if (message.length() <= PRICE_COMMAND_STRING.length())
+ {
+ return;
+ }
+
+ MessageNode messageNode = chatMessage.getMessageNode();
String search = message.substring(PRICE_COMMAND_STRING.length() + 1);
List results = itemManager.search(search);
@@ -621,10 +635,10 @@ public class ChatCommandsPlugin extends Plugin
* Looks up the player skill and changes the original message to the
* response.
*
- * @param setMessage The chat message containing the command.
+ * @param chatMessage The chat message containing the command.
* @param message The chat message
*/
- private void playerSkillLookup(SetMessage setMessage, String message)
+ private void playerSkillLookup(ChatMessage chatMessage, String message)
{
if (!config.lvl())
{
@@ -638,6 +652,11 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
+ if (message.length() <= LEVEL_COMMAND_STRING.length())
+ {
+ return;
+ }
+
search = message.substring(LEVEL_COMMAND_STRING.length() + 1);
}
@@ -652,7 +671,7 @@ public class ChatCommandsPlugin extends Plugin
return;
}
- final HiscoreLookup lookup = getCorrectLookupFor(setMessage);
+ final HiscoreLookup lookup = getCorrectLookupFor(chatMessage);
try
{
@@ -682,7 +701,7 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
- final MessageNode messageNode = setMessage.getMessageNode();
+ final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -693,14 +712,14 @@ public class ChatCommandsPlugin extends Plugin
}
}
- private void combatLevelLookup(SetMessage setMessage, String message)
+ private void combatLevelLookup(ChatMessage chatMessage, String message)
{
if (!config.lvl())
{
return;
}
- ChatMessageType type = setMessage.getType();
+ ChatMessageType type = chatMessage.getType();
String player;
if (type == ChatMessageType.PRIVATE_MESSAGE_SENT)
@@ -709,7 +728,7 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
- player = sanitize(setMessage.getName());
+ player = sanitize(chatMessage.getName());
}
try
@@ -767,7 +786,7 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
- final MessageNode messageNode = setMessage.getMessageNode();
+ final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -778,7 +797,7 @@ public class ChatCommandsPlugin extends Plugin
}
}
- private void clueLookup(SetMessage setMessage, String message)
+ private void clueLookup(ChatMessage chatMessage, String message)
{
if (!config.clue())
{
@@ -799,7 +818,7 @@ public class ChatCommandsPlugin extends Plugin
try
{
final Skill hiscoreSkill;
- final HiscoreLookup lookup = getCorrectLookupFor(setMessage);
+ final HiscoreLookup lookup = getCorrectLookupFor(chatMessage);
final HiscoreResult result = hiscoreClient.lookup(lookup.getName(), lookup.getEndpoint());
if (result == null)
@@ -858,7 +877,7 @@ public class ChatCommandsPlugin extends Plugin
String response = chatMessageBuilder.build();
log.debug("Setting response {}", response);
- final MessageNode messageNode = setMessage.getMessageNode();
+ final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -872,22 +891,22 @@ public class ChatCommandsPlugin extends Plugin
/**
* Gets correct lookup data for message
*
- * @param setMessage chat message
+ * @param chatMessage chat message
* @return hiscore lookup data
*/
- private HiscoreLookup getCorrectLookupFor(final SetMessage setMessage)
+ private HiscoreLookup getCorrectLookupFor(final ChatMessage chatMessage)
{
final String player;
final HiscoreEndpoint ironmanStatus;
- if (setMessage.getType().equals(ChatMessageType.PRIVATE_MESSAGE_SENT))
+ if (chatMessage.getType().equals(ChatMessageType.PRIVATE_MESSAGE_SENT))
{
player = client.getLocalPlayer().getName();
ironmanStatus = hiscoreEndpoint;
}
else
{
- player = sanitize(setMessage.getName());
+ player = sanitize(chatMessage.getName());
if (player.equals(client.getLocalPlayer().getName()))
{
@@ -897,7 +916,7 @@ public class ChatCommandsPlugin extends Plugin
else
{
// Get ironman status from their icon in chat
- ironmanStatus = getHiscoreEndpointByName(setMessage.getName());
+ ironmanStatus = getHiscoreEndpointByName(chatMessage.getName());
}
}
@@ -1090,6 +1109,7 @@ public class ChatCommandsPlugin extends Plugin
case "barrows":
return "Barrows Chests";
+ // cox
case "cox":
case "xeric":
case "chambers":
@@ -1097,6 +1117,15 @@ public class ChatCommandsPlugin extends Plugin
case "raids":
return "Chambers of Xeric";
+ // cox cm
+ case "cox cm":
+ case "xeric cm":
+ case "chambers cm":
+ case "olm cm":
+ case "raids cm":
+ return "Chambers of Xeric Challenge Mode";
+
+ // tob
case "tob":
case "theatre":
case "verzik":
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterConfig.java
new file mode 100644
index 0000000000..abc1747b4a
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterConfig.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, Magic fTail
+ * 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.chatfilter;
+
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+import net.runelite.client.config.ConfigItem;
+
+@ConfigGroup("chatfilter")
+public interface ChatFilterConfig extends Config
+{
+ @ConfigItem(
+ keyName = "filterType",
+ name = "Filter type",
+ description = "Configures how the messages are filtered",
+ position = 1
+ )
+ default ChatFilterType filterType()
+ {
+ return ChatFilterType.CENSOR_WORDS;
+ }
+
+ @ConfigItem(
+ keyName = "filteredWords",
+ name = "Filtered Words",
+ description = "List of filtered words, separated by commas",
+ position = 2
+ )
+ default String filteredWords()
+ {
+ return "";
+ }
+
+ @ConfigItem(
+ keyName = "filteredRegex",
+ name = "Filtered Regex",
+ description = "List of regular expressions to filter, one per line",
+ position = 3
+ )
+ default String filteredRegex()
+ {
+ return "";
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java
new file mode 100644
index 0000000000..355ed29b28
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2018, Magic fTail
+ * 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.chatfilter;
+
+import com.google.common.base.Splitter;
+import com.google.inject.Provides;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import javax.inject.Inject;
+import net.runelite.api.ChatMessageType;
+import net.runelite.api.Client;
+import net.runelite.api.Player;
+import net.runelite.api.events.ConfigChanged;
+import net.runelite.api.events.OverheadTextChanged;
+import net.runelite.api.events.ScriptCallbackEvent;
+import net.runelite.client.config.ConfigManager;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.util.Text;
+import org.apache.commons.lang3.StringUtils;
+
+@PluginDescriptor(
+ name = "Chat Filter",
+ description = "Censor user configurable words or patterns from chat",
+ enabledByDefault = false
+)
+public class ChatFilterPlugin extends Plugin
+{
+ private static final Splitter NEWLINE_SPLITTER = Splitter
+ .on("\n")
+ .omitEmptyStrings()
+ .trimResults();
+
+ private static final String CENSOR_MESSAGE = "Hey, everyone, I just tried to say something very silly!";
+
+ private final JagexPrintableCharMatcher jagexPrintableCharMatcher = new JagexPrintableCharMatcher();
+ private final List filteredPatterns = new ArrayList<>();
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private ChatFilterConfig config;
+
+ @Provides
+ ChatFilterConfig provideConfig(ConfigManager configManager)
+ {
+ return configManager.getConfig(ChatFilterConfig.class);
+ }
+
+ @Override
+ protected void startUp() throws Exception
+ {
+ updateFilteredPatterns();
+ }
+
+ @Override
+ protected void shutDown() throws Exception
+ {
+ filteredPatterns.clear();
+ }
+
+ @Subscribe
+ public void onScriptCallbackEvent(ScriptCallbackEvent event)
+ {
+ if (!"chatFilterCheck".equals(event.getEventName()))
+ {
+ return;
+ }
+
+ int[] intStack = client.getIntStack();
+ int intStackSize = client.getIntStackSize();
+ ChatMessageType chatMessageType = ChatMessageType.of(intStack[intStackSize - 1]);
+
+ // Only filter public chat and private messages
+ switch (chatMessageType)
+ {
+ case PUBLIC:
+ case PUBLIC_MOD:
+ case AUTOCHAT:
+ case PRIVATE_MESSAGE_RECEIVED:
+ case PRIVATE_MESSAGE_RECEIVED_MOD:
+ case CLANCHAT:
+ break;
+ default:
+ return;
+ }
+
+ String[] stringStack = client.getStringStack();
+ int stringStackSize = client.getStringStackSize();
+
+ String message = stringStack[stringStackSize - 1];
+ String censoredMessage = censorMessage(message);
+
+ if (censoredMessage == null)
+ {
+ // Block the message
+ intStack[intStackSize - 2] = 0;
+ }
+ else
+ {
+ // Replace the message
+ stringStack[stringStackSize - 1] = censoredMessage;
+ }
+ }
+
+ @Subscribe
+ public void onOverheadTextChanged(OverheadTextChanged event)
+ {
+ if (!(event.getActor() instanceof Player))
+ {
+ return;
+ }
+
+ String message = censorMessage(event.getOverheadText());
+
+ if (message == null)
+ {
+ message = " ";
+ }
+
+ event.getActor().setOverheadText(message);
+ }
+
+ String censorMessage(final String message)
+ {
+ String strippedMessage = jagexPrintableCharMatcher.retainFrom(message)
+ .replace('\u00A0', ' ');
+ boolean filtered = false;
+ for (Pattern pattern : filteredPatterns)
+ {
+ Matcher m = pattern.matcher(strippedMessage);
+
+ StringBuffer sb = new StringBuffer();
+
+ while (m.find())
+ {
+ switch (config.filterType())
+ {
+ case CENSOR_WORDS:
+ m.appendReplacement(sb, StringUtils.repeat("*", m.group(0).length()));
+ filtered = true;
+ break;
+ case CENSOR_MESSAGE:
+ return CENSOR_MESSAGE;
+ case REMOVE_MESSAGE:
+ return null;
+ }
+ }
+ m.appendTail(sb);
+
+ strippedMessage = sb.toString();
+ }
+
+ return filtered ? strippedMessage : message;
+ }
+
+ void updateFilteredPatterns()
+ {
+ filteredPatterns.clear();
+
+ Text.fromCSV(config.filteredWords()).stream()
+ .map(s -> Pattern.compile(Pattern.quote(s), Pattern.CASE_INSENSITIVE))
+ .forEach(filteredPatterns::add);
+
+ NEWLINE_SPLITTER.splitToList(config.filteredRegex()).stream()
+ .map(s ->
+ {
+ try
+ {
+ return Pattern.compile(s, Pattern.CASE_INSENSITIVE);
+ }
+ catch (PatternSyntaxException ex)
+ {
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .forEach(filteredPatterns::add);
+ }
+
+ @Subscribe
+ public void onConfigChanged(ConfigChanged event)
+ {
+ if (!"chatfilter".equals(event.getGroup()))
+ {
+ return;
+ }
+
+ updateFilteredPatterns();
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterType.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterType.java
new file mode 100644
index 0000000000..cf52fa969f
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterType.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, Magic fTail
+ * 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.chatfilter;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public enum ChatFilterType
+{
+ CENSOR_WORDS("Censor words"),
+ CENSOR_MESSAGE("Censor message"),
+ REMOVE_MESSAGE("Remove message");
+
+ private final String name;
+
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/JagexPrintableCharMatcher.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/JagexPrintableCharMatcher.java
new file mode 100644
index 0000000000..53b76cbc19
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/JagexPrintableCharMatcher.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.chatfilter;
+
+import com.google.common.base.CharMatcher;
+
+class JagexPrintableCharMatcher extends CharMatcher
+{
+ @Override
+ public boolean matches(char c)
+ {
+ // Characters which are printable
+ return (c >= 32 && c <= 126)
+ || c == 128
+ || (c >= 161 && c <= 255);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryConfig.java
new file mode 100644
index 0000000000..e30629c742
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryConfig.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, TheStonedTurtle
+ * 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.chathistory;
+
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+import net.runelite.client.config.ConfigItem;
+
+@ConfigGroup("chathistory")
+public interface ChatHistoryConfig extends Config
+{
+ @ConfigItem(
+ keyName = "retainChatHistory",
+ name = "Retain Chat History",
+ description = "Retains chat history when logging in/out or world hopping",
+ position = 0
+ )
+ default boolean retainChatHistory()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "pmTargetCycling",
+ name = "PM Target Cycling",
+ description = "Pressing Tab while sending a PM will cycle the target username based on PM history",
+ position = 1
+ )
+ default boolean pmTargetCycling()
+ {
+ return true;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java
index 4f2ae79818..43919214ea 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java
@@ -25,47 +25,74 @@
package net.runelite.client.plugins.chathistory;
import com.google.common.collect.EvictingQueue;
-import com.google.common.collect.Sets;
+import com.google.inject.Provides;
+import java.awt.event.KeyEvent;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
import java.util.Queue;
-import java.util.Set;
import javax.inject.Inject;
import net.runelite.api.ChatMessageType;
+import net.runelite.api.Client;
+import net.runelite.api.ScriptID;
+import net.runelite.api.VarClientInt;
+import net.runelite.api.VarClientStr;
+import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.MenuOptionClicked;
-import net.runelite.api.events.SetMessage;
+import net.runelite.api.vars.InputType;
+import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.QueuedMessage;
+import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.input.KeyListener;
+import net.runelite.client.input.KeyManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.util.Text;
@PluginDescriptor(
name = "Chat History",
- description = "Retain your chat history when logging in/out or world hopping"
+ description = "Retain your chat history when logging in/out or world hopping",
+ tags = {"chat", "history", "retain", "cycle", "pm"}
)
-public class ChatHistoryPlugin extends Plugin
+public class ChatHistoryPlugin extends Plugin implements KeyListener
{
private static final String WELCOME_MESSAGE = "Welcome to Old School RuneScape.";
private static final String CLEAR_HISTORY = "Clear history";
private static final String CLEAR_PRIVATE = "Private:";
- private static final Set ALLOWED_HISTORY = Sets.newHashSet(
- ChatMessageType.PUBLIC,
- ChatMessageType.PUBLIC_MOD,
- ChatMessageType.CLANCHAT,
- ChatMessageType.PRIVATE_MESSAGE_RECEIVED,
- ChatMessageType.PRIVATE_MESSAGE_SENT,
- ChatMessageType.PRIVATE_MESSAGE_RECEIVED_MOD,
- ChatMessageType.GAME
- );
+ private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB;
private Queue messageQueue;
+ private Deque friends;
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private ClientThread clientThread;
+
+ @Inject
+ private ChatHistoryConfig config;
+
+ @Inject
+ private KeyManager keyManager;
@Inject
private ChatMessageManager chatMessageManager;
+
+ @Provides
+ ChatHistoryConfig getConfig(ConfigManager configManager)
+ {
+ return configManager.getConfig(ChatHistoryConfig.class);
+ }
@Override
protected void startUp()
{
messageQueue = EvictingQueue.create(100);
+ friends = new ArrayDeque<>(5);
+ keyManager.registerKeyListener(this);
}
@Override
@@ -73,15 +100,23 @@ public class ChatHistoryPlugin extends Plugin
{
messageQueue.clear();
messageQueue = null;
+ friends.clear();
+ friends = null;
+ keyManager.unregisterKeyListener(this);
}
@Subscribe
- public void onSetMessage(SetMessage message)
+ public void onChatMessage(ChatMessage chatMessage)
{
// Start sending old messages right after the welcome message, as that is most reliable source
// of information that chat history was reset
- if (message.getValue().equals(WELCOME_MESSAGE))
+ if (chatMessage.getMessage().equals(WELCOME_MESSAGE))
{
+ if (!config.retainChatHistory())
+ {
+ return;
+ }
+
QueuedMessage queuedMessage;
while ((queuedMessage = messageQueue.poll()) != null)
@@ -92,21 +127,33 @@ public class ChatHistoryPlugin extends Plugin
return;
}
- if (ALLOWED_HISTORY.contains(message.getType()))
+ switch (chatMessage.getType())
{
- final QueuedMessage queuedMessage = QueuedMessage.builder()
- .type(message.getType())
- .name(message.getName())
- .sender(message.getSender())
- .value(nbsp(message.getValue()))
- .runeLiteFormattedMessage(nbsp(message.getMessageNode().getRuneLiteFormatMessage()))
- .timestamp(message.getTimestamp())
- .build();
+ case PRIVATE_MESSAGE_SENT:
+ case PRIVATE_MESSAGE_RECEIVED:
+ case PRIVATE_MESSAGE_RECEIVED_MOD:
+ final String name = Text.removeTags(chatMessage.getName());
+ // Remove to ensure uniqueness & its place in history
+ friends.remove(name);
+ friends.add(name);
+ // intentional fall-through
+ case PUBLIC:
+ case PUBLIC_MOD:
+ case CLANCHAT:
+ case GAME:
+ final QueuedMessage queuedMessage = QueuedMessage.builder()
+ .type(chatMessage.getType())
+ .name(chatMessage.getName())
+ .sender(chatMessage.getSender())
+ .value(nbsp(chatMessage.getMessage()))
+ .runeLiteFormattedMessage(nbsp(chatMessage.getMessageNode().getRuneLiteFormatMessage()))
+ .timestamp(chatMessage.getTimestamp())
+ .build();
- if (!messageQueue.contains(queuedMessage))
- {
- messageQueue.offer(queuedMessage);
- }
+ if (!messageQueue.contains(queuedMessage))
+ {
+ messageQueue.offer(queuedMessage);
+ }
}
}
@@ -143,4 +190,64 @@ public class ChatHistoryPlugin extends Plugin
return null;
}
+
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ if (e.getKeyCode() != CYCLE_HOTKEY || !config.pmTargetCycling())
+ {
+ return;
+ }
+
+ if (client.getVar(VarClientInt.INPUT_TYPE) != InputType.PRIVATE_MESSAGE.getType())
+ {
+ return;
+ }
+
+ clientThread.invoke(() ->
+ {
+ final String target = findPreviousFriend();
+ if (target == null)
+ {
+ return;
+ }
+
+ final String currentMessage = client.getVar(VarClientStr.INPUT_TEXT);
+
+ client.runScript(ScriptID.OPEN_PRIVATE_MESSAGE_INTERFACE, target);
+
+ client.setVar(VarClientStr.INPUT_TEXT, currentMessage);
+ client.runScript(ScriptID.CHAT_TEXT_INPUT_REBUILD, "");
+ });
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e)
+ {
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e)
+ {
+ }
+
+ private String findPreviousFriend()
+ {
+ final String currentTarget = client.getVar(VarClientStr.PRIVATE_MESSAGE_TARGET);
+ if (currentTarget == null || friends.isEmpty())
+ {
+ return null;
+ }
+
+ for (Iterator it = friends.descendingIterator(); it.hasNext(); )
+ {
+ String friend = it.next();
+ if (friend.equals(currentTarget))
+ {
+ return it.hasNext() ? it.next() : friends.getLast();
+ }
+ }
+
+ return friends.getLast();
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java
index fd148c1e90..0bfd952e01 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java
@@ -35,9 +35,9 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.MessageNode;
+import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
-import net.runelite.api.events.SetMessage;
import net.runelite.client.Notifier;
import net.runelite.client.RuneLiteProperties;
import net.runelite.client.chat.ChatColorType;
@@ -124,29 +124,29 @@ public class ChatNotificationsPlugin extends Plugin
}
@Subscribe
- public void onSetMessage(SetMessage event)
+ public void onChatMessage(ChatMessage chatMessage)
{
- MessageNode messageNode = event.getMessageNode();
+ MessageNode messageNode = chatMessage.getMessageNode();
String nodeValue = Text.removeTags(messageNode.getValue());
boolean update = false;
- switch (event.getType())
+ switch (chatMessage.getType())
{
case TRADE:
- if (event.getValue().contains("wishes to trade with you.") && config.notifyOnTrade())
+ if (chatMessage.getMessage().contains("wishes to trade with you.") && config.notifyOnTrade())
{
- notifier.notify(event.getValue());
+ notifier.notify(chatMessage.getMessage());
}
break;
case DUEL:
- if (event.getValue().contains("wishes to duel with you.") && config.notifyOnDuel())
+ if (chatMessage.getMessage().contains("wishes to duel with you.") && config.notifyOnDuel())
{
- notifier.notify(event.getValue());
+ notifier.notify(chatMessage.getMessage());
}
break;
case GAME:
// Don't notify for notification messages
- if (event.getName().equals(runeLiteProperties.getTitle()))
+ if (chatMessage.getName().equals(runeLiteProperties.getTitle()))
{
return;
}
@@ -170,7 +170,7 @@ public class ChatNotificationsPlugin extends Plugin
if (config.notifyOnOwnName())
{
- sendNotification(event);
+ sendNotification(chatMessage);
}
}
}
@@ -196,7 +196,7 @@ public class ChatNotificationsPlugin extends Plugin
if (config.notifyOnHighlight())
{
- sendNotification(event);
+ sendNotification(chatMessage);
}
}
}
@@ -208,7 +208,7 @@ public class ChatNotificationsPlugin extends Plugin
}
}
- private void sendNotification(SetMessage message)
+ private void sendNotification(ChatMessage message)
{
String name = Text.removeTags(message.getName());
String sender = message.getSender();
@@ -224,7 +224,7 @@ public class ChatNotificationsPlugin extends Plugin
stringBuilder.append(name).append(": ");
}
- stringBuilder.append(Text.removeTags(message.getValue()));
+ stringBuilder.append(Text.removeTags(message.getMessage()));
String notification = stringBuilder.toString();
notifier.notify(notification);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanActivityType.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanActivityType.java
new file mode 100644
index 0000000000..86cc5e60a5
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanActivityType.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, trimbe
+ * 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.clanchat;
+
+enum ClanActivityType
+{
+ JOINED,
+ LEFT
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatConfig.java
index 9b70ce0fca..5fdd7996be 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatConfig.java
@@ -24,6 +24,7 @@
*/
package net.runelite.client.plugins.clanchat;
+import net.runelite.api.ClanMemberRank;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@@ -31,17 +32,39 @@ import net.runelite.client.config.ConfigItem;
@ConfigGroup("clanchat")
public interface ClanChatConfig extends Config
{
+ @ConfigItem(
+ keyName = "clanChatIcons",
+ name = "Clan Chat Icons",
+ description = "Show clan chat icons next to clan members.",
+ position = 1
+ )
+ default boolean clanChatIcons()
+ {
+ return true;
+ }
+
@ConfigItem(
keyName = "recentChats",
name = "Recent Chats",
description = "Show recent clan chats.",
- position = 1
+ position = 2
)
default boolean recentChats()
{
return true;
}
+ @ConfigItem(
+ keyName = "clanCounter",
+ name = "Clan Members Counter",
+ description = "Show the amount of clan members near you.",
+ position = 3
+ )
+ default boolean showClanCounter()
+ {
+ return false;
+ }
+
@ConfigItem(
keyName = "chatsData",
name = "",
@@ -59,4 +82,48 @@ public interface ClanChatConfig extends Config
description = ""
)
void chatsData(String str);
+
+ @ConfigItem(
+ keyName = "showJoinLeave",
+ name = "Show Join/Leave",
+ description = "Adds a temporary message notifying when a member joins or leaves.",
+ position = 4
+ )
+ default boolean showJoinLeave()
+ {
+ return false;
+ }
+
+ @ConfigItem(
+ keyName = "joinLeaveRank",
+ name = "Join/Leave rank",
+ description = "Only show join/leave messages for members at or above this rank.",
+ position = 5
+ )
+ default ClanMemberRank joinLeaveRank()
+ {
+ return ClanMemberRank.UNRANKED;
+ }
+
+ @ConfigItem(
+ keyName = "privateMessageIcons",
+ name = "Private Message Icons",
+ description = "Add clan chat rank icons to private messages received from clan mates.",
+ position = 6
+ )
+ default boolean privateMessageIcons()
+ {
+ return false;
+ }
+
+ @ConfigItem(
+ keyName = "publicChatIcons",
+ name = "Public Chat Icons",
+ description = "Add clan chat rank icons to public chat messages from clan mates.",
+ position = 7
+ )
+ default boolean publicChatIcons()
+ {
+ return false;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatIndicator.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatIndicator.java
new file mode 100644
index 0000000000..e8f7542d7d
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatIndicator.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Sebastiaan
+ * 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.clanchat;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import net.runelite.client.ui.overlay.infobox.Counter;
+
+class ClanChatIndicator extends Counter
+{
+ private final ClanChatPlugin plugin;
+
+ ClanChatIndicator(BufferedImage image, ClanChatPlugin plugin)
+ {
+ super(image, plugin, plugin.getClanAmount());
+ this.plugin = plugin;
+ }
+
+ @Override
+ public int getCount()
+ {
+ return plugin.getClanAmount();
+ }
+
+ @Override
+ public String getTooltip()
+ {
+ return plugin.getClanAmount() + " clan member(s) near you";
+ }
+
+ @Override
+ public Color getTextColor()
+ {
+ return Color.WHITE;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java
index b5ee817198..73859e0271 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java
@@ -1,5 +1,7 @@
/*
* Copyright (c) 2017, Devin French
+ * Copyright (c) 2019, Adam
+ * Copyright (c) 2018, trimbe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,26 +29,55 @@ package net.runelite.client.plugins.clanchat;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.inject.Provides;
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import javax.inject.Inject;
+import net.runelite.api.ChatLineBuffer;
import net.runelite.api.ChatMessageType;
+import net.runelite.api.ClanMember;
import net.runelite.api.ClanMemberRank;
import net.runelite.api.Client;
import net.runelite.api.GameState;
+import net.runelite.api.MessageNode;
+import net.runelite.api.Player;
+import net.runelite.api.ScriptID;
+import net.runelite.api.SpriteID;
import net.runelite.api.VarClientStr;
-import net.runelite.api.widgets.WidgetType;
+import net.runelite.api.Varbits;
+import net.runelite.api.events.ChatMessage;
+import net.runelite.api.events.ClanChanged;
+import net.runelite.api.events.ClanMemberJoined;
+import net.runelite.api.events.ClanMemberLeft;
import net.runelite.api.events.ConfigChanged;
+import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
-import net.runelite.api.events.SetMessage;
+import net.runelite.api.events.PlayerDespawned;
+import net.runelite.api.events.PlayerSpawned;
import net.runelite.api.events.VarClientStrChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.api.widgets.WidgetType;
+import net.runelite.client.callback.ClientThread;
+import net.runelite.client.chat.ChatMessageBuilder;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ClanManager;
+import net.runelite.client.game.SpriteManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
+import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_OPAQUE_BACKGROUND;
+import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_TRANSPARENT_BACKGROUND;
+import static net.runelite.client.ui.JagexColors.CHAT_CLAN_TEXT_OPAQUE_BACKGROUND;
+import static net.runelite.client.ui.JagexColors.CHAT_CLAN_TEXT_TRANSPARENT_BACKGROUND;
+import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
+import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.Text;
@PluginDescriptor(
@@ -59,6 +90,8 @@ public class ClanChatPlugin extends Plugin
private static final int MAX_CHATS = 10;
private static final String CLAN_CHAT_TITLE = "Clan Chat";
private static final String RECENT_TITLE = "Recent Clan Chats";
+ private static final int JOIN_LEAVE_DURATION = 20;
+ private static final int MESSAGE_DELAY = 10;
@Inject
private Client client;
@@ -69,7 +102,24 @@ public class ClanChatPlugin extends Plugin
@Inject
private ClanChatConfig config;
+ @Inject
+ private InfoBoxManager infoBoxManager;
+
+ @Inject
+ private SpriteManager spriteManager;
+
+ @Inject
+ private ClientThread clientThread;
+
private List chats = new ArrayList<>();
+ private List clanMembers = new ArrayList<>();
+ private ClanChatIndicator clanMemberCounter;
+ /**
+ * queue of temporary messages added to the client
+ */
+ private final Deque clanJoinMessages = new ArrayDeque<>();
+ private Map activityBuffer = new HashMap<>();
+ private int clanJoinedTick;
@Provides
ClanChatConfig getConfig(ConfigManager configManager)
@@ -86,15 +136,118 @@ public class ClanChatPlugin extends Plugin
@Override
public void shutDown()
{
+ clanMembers.clear();
+ removeClanCounter();
resetClanChats();
}
@Subscribe
public void onConfigChanged(ConfigChanged configChanged)
{
- if (configChanged.getGroup().equals("clanchat") && !config.recentChats())
+ if (configChanged.getGroup().equals("clanchat"))
{
- resetClanChats();
+ if (!config.recentChats())
+ {
+ resetClanChats();
+ }
+
+ if (config.showClanCounter())
+ {
+ clientThread.invoke(this::addClanCounter);
+ }
+ else
+ {
+ removeClanCounter();
+ }
+ }
+ }
+
+ @Subscribe
+ public void onClanMemberJoined(ClanMemberJoined event)
+ {
+ final ClanMember member = event.getMember();
+
+ if (member.getWorld() == client.getWorld())
+ {
+ final String memberName = Text.toJagexName(member.getUsername());
+
+ for (final Player player : client.getPlayers())
+ {
+ if (player != null && memberName.equals(Text.toJagexName(player.getName())))
+ {
+ clanMembers.add(player);
+ addClanCounter();
+ break;
+ }
+ }
+ }
+
+ // clan members getting initialized isn't relevant
+ if (clanJoinedTick == client.getTickCount())
+ {
+ return;
+ }
+
+ if (!config.showJoinLeave() ||
+ member.getRank().getValue() < config.joinLeaveRank().getValue())
+ {
+ return;
+ }
+
+ // attempt to filter out world hopping joins
+ if (!activityBuffer.containsKey(member.getUsername()))
+ {
+ ClanMemberActivity joinActivity = new ClanMemberActivity(ClanActivityType.JOINED,
+ member, client.getTickCount());
+ activityBuffer.put(member.getUsername(), joinActivity);
+ }
+ else
+ {
+ activityBuffer.remove(member.getUsername());
+ }
+ }
+
+ @Subscribe
+ public void onClanMemberLeft(ClanMemberLeft event)
+ {
+ final ClanMember member = event.getMember();
+
+ if (member.getWorld() == client.getWorld())
+ {
+ final String memberName = Text.toJagexName(member.getUsername());
+ final Iterator each = clanMembers.iterator();
+
+ while (each.hasNext())
+ {
+ if (memberName.equals(Text.toJagexName(each.next().getName())))
+ {
+ each.remove();
+
+ if (clanMembers.isEmpty())
+ {
+ removeClanCounter();
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (!config.showJoinLeave() ||
+ member.getRank().getValue() < config.joinLeaveRank().getValue())
+ {
+ return;
+ }
+
+ if (!activityBuffer.containsKey(member.getUsername()))
+ {
+ ClanMemberActivity leaveActivity = new ClanMemberActivity(ClanActivityType.LEFT,
+ member, client.getTickCount());
+ activityBuffer.put(member.getUsername(), leaveActivity);
+ }
+ else
+ {
+ activityBuffer.remove(member.getUsername());
}
}
@@ -122,6 +275,112 @@ public class ClanChatPlugin extends Plugin
loadClanChats();
}
}
+
+ if (!config.showJoinLeave())
+ {
+ return;
+ }
+
+ timeoutClanMessages();
+
+ addClanActivityMessages();
+ }
+
+ private void timeoutClanMessages()
+ {
+ if (clanJoinMessages.isEmpty())
+ {
+ return;
+ }
+
+ boolean removed = false;
+
+ for (Iterator it = clanJoinMessages.iterator(); it.hasNext(); )
+ {
+ ClanJoinMessage clanJoinMessage = it.next();
+ MessageNode messageNode = clanJoinMessage.getMessageNode();
+ final int createdTick = clanJoinMessage.getTick();
+
+ if (client.getTickCount() > createdTick + JOIN_LEAVE_DURATION)
+ {
+ it.remove();
+
+ // If this message has been reused since, it will get a different id
+ if (clanJoinMessage.getGetMessageId() == messageNode.getId())
+ {
+ ChatLineBuffer ccInfoBuffer = client.getChatLineMap().get(ChatMessageType.CLANCHAT_INFO.getType());
+ if (ccInfoBuffer != null)
+ {
+ ccInfoBuffer.removeMessageNode(messageNode);
+ removed = true;
+ }
+ }
+ }
+ else
+ {
+ // Everything else in the deque is newer
+ break;
+ }
+ }
+
+ if (removed)
+ {
+ clientThread.invoke(() -> client.runScript(ScriptID.BUILD_CHATBOX));
+ }
+ }
+
+ private void addClanActivityMessages()
+ {
+ Iterator activityIt = activityBuffer.values().iterator();
+
+ while (activityIt.hasNext())
+ {
+ ClanMemberActivity activity = activityIt.next();
+
+ if (activity.getTick() < client.getTickCount() - MESSAGE_DELAY)
+ {
+ activityIt.remove();
+ addActivityMessage(activity.getMember(), activity.getActivityType());
+ }
+ }
+ }
+
+ private void addActivityMessage(ClanMember member, ClanActivityType activityType)
+ {
+ final String activityMessage = activityType == ClanActivityType.JOINED ? " has joined." : " has left.";
+ final ClanMemberRank rank = member.getRank();
+ String rankTag = "";
+ Color textColor = CHAT_CLAN_TEXT_OPAQUE_BACKGROUND;
+ Color channelColor = CHAT_CLAN_NAME_OPAQUE_BACKGROUND;
+
+ if (client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1)
+ {
+ textColor = CHAT_CLAN_TEXT_TRANSPARENT_BACKGROUND;
+ channelColor = CHAT_CLAN_NAME_TRANSPARENT_BACKGROUND;
+ }
+
+ if (config.clanChatIcons() && rank != null && rank != ClanMemberRank.UNRANKED)
+ {
+ int iconNumber = clanManager.getIconNumber(rank);
+ rankTag = "
";
+ }
+
+ ChatMessageBuilder message = new ChatMessageBuilder();
+ String messageString = message
+ .append("[")
+ .append(ColorUtil.wrapWithColorTag(client.getClanChatName(), channelColor) + rankTag)
+ .append("] ")
+ .append(ColorUtil.wrapWithColorTag(member.getUsername() + activityMessage, textColor))
+ .build();
+
+ client.addChatMessage(ChatMessageType.CLANCHAT_INFO, "", messageString, "");
+
+ final ChatLineBuffer chatLineBuffer = client.getChatLineMap().get(ChatMessageType.CLANCHAT_INFO.getType());
+ final MessageNode[] lines = chatLineBuffer.getLines();
+ final MessageNode line = lines[0];
+
+ ClanJoinMessage clanJoinMessage = new ClanJoinMessage(line, line.getId(), client.getTickCount());
+ clanJoinMessages.addLast(clanJoinMessage);
}
@Subscribe
@@ -134,28 +393,119 @@ public class ClanChatPlugin extends Plugin
}
@Subscribe
- public void onSetMessage(SetMessage setMessage)
+ public void onChatMessage(ChatMessage chatMessage)
{
if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN)
{
return;
}
- if (setMessage.getType() == ChatMessageType.CLANCHAT && client.getClanChatCount() > 0)
+ if (client.getClanChatCount() <= 0)
{
- insertClanRankIcon(setMessage);
+ return;
+ }
+
+ switch (chatMessage.getType())
+ {
+ case PRIVATE_MESSAGE_RECEIVED:
+ case PRIVATE_MESSAGE_RECEIVED_MOD:
+ if (!config.privateMessageIcons())
+ {
+ return;
+ }
+ break;
+ case PUBLIC:
+ case PUBLIC_MOD:
+ if (!config.publicChatIcons())
+ {
+ return;
+ }
+ break;
+ case CLANCHAT:
+ if (!config.clanChatIcons())
+ {
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+
+ insertClanRankIcon(chatMessage);
+ }
+
+ @Subscribe
+ public void onGameStateChanged(GameStateChanged state)
+ {
+ GameState gameState = state.getGameState();
+
+ if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.CONNECTION_LOST || gameState == GameState.HOPPING)
+ {
+ clanMembers.clear();
+ removeClanCounter();
+
+ clanJoinMessages.clear();
}
}
- private void insertClanRankIcon(final SetMessage message)
+ @Subscribe
+ public void onPlayerSpawned(PlayerSpawned event)
+ {
+ if (event.getPlayer().isClanMember())
+ {
+ clanMembers.add(event.getPlayer());
+ addClanCounter();
+ }
+ }
+
+ @Subscribe
+ public void onPlayerDespawned(PlayerDespawned event)
+ {
+ if (clanMembers.remove(event.getPlayer()) && clanMembers.isEmpty())
+ {
+ removeClanCounter();
+ }
+ }
+
+ @Subscribe
+ public void onClanChanged(ClanChanged event)
+ {
+ if (event.isJoined())
+ {
+ clanJoinedTick = client.getTickCount();
+ }
+ else
+ {
+ clanMembers.clear();
+ removeClanCounter();
+ }
+
+ activityBuffer.clear();
+ }
+
+ int getClanAmount()
+ {
+ return clanMembers.size();
+ }
+
+ private void insertClanRankIcon(final ChatMessage message)
{
final ClanMemberRank rank = clanManager.getRank(message.getName());
if (rank != null && rank != ClanMemberRank.UNRANKED)
{
int iconNumber = clanManager.getIconNumber(rank);
- message.getMessageNode()
- .setSender(message.getMessageNode().getSender() + "
");
+ final String img = "
";
+ if (message.getType() == ChatMessageType.CLANCHAT)
+ {
+ message.getMessageNode()
+ .setSender(message.getMessageNode().getSender() + " " + img);
+ }
+ else
+ {
+ message.getMessageNode()
+ .setName(img + message.getMessageNode().getName());
+ }
client.refreshChat();
}
}
@@ -223,4 +573,22 @@ public class ClanChatPlugin extends Plugin
config.chatsData(Text.toCSV(chats));
}
+
+ private void removeClanCounter()
+ {
+ infoBoxManager.removeInfoBox(clanMemberCounter);
+ clanMemberCounter = null;
+ }
+
+ private void addClanCounter()
+ {
+ if (!config.showClanCounter() || clanMemberCounter != null || clanMembers.isEmpty())
+ {
+ return;
+ }
+
+ final BufferedImage image = spriteManager.getSprite(SpriteID.TAB_CLAN_CHAT, 0);
+ clanMemberCounter = new ClanChatIndicator(image, this);
+ infoBoxManager.addInfoBox(clanMemberCounter);
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanJoinMessage.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanJoinMessage.java
new file mode 100644
index 0000000000..8ac0b0069b
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanJoinMessage.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.clanchat;
+
+import lombok.Value;
+import net.runelite.api.MessageNode;
+
+@Value
+class ClanJoinMessage
+{
+ private final MessageNode messageNode;
+ private final int getMessageId;
+ private final int tick;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanMemberActivity.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanMemberActivity.java
new file mode 100644
index 0000000000..1cea036a95
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanMemberActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, trimbe
+ * 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.clanchat;
+
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import net.runelite.api.ClanMember;
+
+@Value
+@AllArgsConstructor
+class ClanMemberActivity
+{
+ private ClanActivityType activityType;
+ private ClanMember member;
+ private Integer tick;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java
index 4c4d0adcd2..61b83c4c11 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java
@@ -49,7 +49,7 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc
{
private static final Set CLUES = ImmutableSet.of(
new AnagramClue("A BAKER", "Baraek", new WorldPoint(3217, 3434, 0), "Varrock square", "5"),
- new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "7"),
+ new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "6"),
new AnagramClue("A HEART", "Aretha", new WorldPoint(1814, 3851, 0), "Soul altar", "2"),
new AnagramClue("A ZEN SHE", "Zenesha", new WorldPoint(2652, 3295, 0), "Platebody Southern Ardougne centre square"),
new AnagramClue("ACE MATCH ELM", "Cam The Camel", new WorldPoint(3300, 3231, 0), "North of the glider in Al Kharid"),
@@ -257,4 +257,4 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc
{
return new int[] {objectId};
}
-}
\ No newline at end of file
+}
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 654f31e977..f352115c1e 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
@@ -24,6 +24,7 @@
*/
package net.runelite.client.plugins.cluescrolls.clues;
+import com.google.common.collect.ImmutableMap;
import java.awt.Color;
import java.awt.Graphics2D;
import lombok.AllArgsConstructor;
@@ -43,6 +44,154 @@ import net.runelite.client.ui.overlay.components.TitleComponent;
@AllArgsConstructor
public class CoordinateClue extends ClueScroll implements TextClueScroll, LocationClueScroll
{
+ private static final ImmutableMap CLUES = new ImmutableMap.Builder()
+ // Medium
+ .put(new WorldPoint(2479, 3158, 0), "South of fruit tree patch, west of Tree Gnome Village.")
+ .put(new WorldPoint(2887, 3154, 0), "West of Banana plantation on Karamja.")
+ .put(new WorldPoint(2743, 3151, 0), "Entrance of Brimhaven dungeon.")
+ .put(new WorldPoint(3184, 3150, 0), "South of Lumbridge Swamp.")
+ .put(new WorldPoint(3217, 3177, 0), "East of Lumbridge Swamp.")
+ .put(new WorldPoint(3007, 3144, 0), "Near the entrance to the Asgarnian Ice Dungeon, south of Port Sarim (AIQ).")
+ .put(new WorldPoint(2896, 3119, 0), "Near Karambwan fishing spot (DKP).")
+ .put(new WorldPoint(2697, 3207, 0), "Centre of Moss Giant Island, west of Brimhaven.")
+ .put(new WorldPoint(2679, 3110, 0), "North of Hazelmere's house (CLS).")
+ .put(new WorldPoint(3510, 3074, 0), "East of Uzer (DLQ).")
+ .put(new WorldPoint(3160, 3251, 0), "West of trapdoor leading to H.A.M Hideout.")
+ .put(new WorldPoint(2643, 3252, 0), "South of Ardougne Zoo, North of Tower of Life (DJP).")
+ .put(new WorldPoint(2322, 3061, 0), "South-west of Castle wars (BKP).")
+ .put(new WorldPoint(2875, 3046, 0), "North of nature altar, north of Shilo Village (CKR).")
+ .put(new WorldPoint(2849, 3033, 0), "West of nature altar, north of Shilo Village (CKR).")
+ .put(new WorldPoint(2848, 3296, 0), "North of Crandor island.")
+ .put(new WorldPoint(2583, 2990, 0), "Feldip Hills, south-east of Gu'Thanoth (AKS).")
+ .put(new WorldPoint(3179, 3344, 0), "South of the Champions' Guild, opposite side of the River Lum.")
+ .put(new WorldPoint(2383, 3370, 0), "South-west of Tree Gnome Stronghold.")
+ .put(new WorldPoint(3312, 3375, 0), "North-west of Exam Centre, on the hill.")
+ .put(new WorldPoint(3121, 3384, 0), "North-east of Draynor Manor, near River Lum.")
+ .put(new WorldPoint(3430, 3388, 0), "West of Mort Myre Swamp.")
+ .put(new WorldPoint(2920, 3403, 0), "South-east of Taverley, near Lady of the Lake.")
+ .put(new WorldPoint(2594, 2899, 0), "South-east of Feldip Hills, by the crimson swifts (AKS).")
+ .put(new WorldPoint(2387, 3435, 0), "West of Tree Gnome Stronghold, near the pen containing terrorbirds.")
+ .put(new WorldPoint(2512, 3467, 0), "Baxtorian Falls (Bring rope).")
+ .put(new WorldPoint(2381, 3468, 0), "West of Tree Gnome Stronghold, north of the pen with terrorbirds.")
+ .put(new WorldPoint(3005, 3475, 0), "Ice Mountain, west of Edgeville.")
+ .put(new WorldPoint(2585, 3505, 0), "By the shore line north of the Coal Trucks.")
+ .put(new WorldPoint(3443, 3515, 0), "South of Slayer Tower.")
+ .put(new WorldPoint(2416, 3516, 0), "Tree Gnome Stronghold, west of Grand Tree, near swamp.")
+ .put(new WorldPoint(3429, 3523, 0), "South of Slayer Tower.")
+ .put(new WorldPoint(2363, 3531, 0), "North-east of Eagles' Peak.")
+ .put(new WorldPoint(2919, 3535, 0), "East of Burthorpe pub.")
+ .put(new WorldPoint(3548, 3560, 0), "Inside Fenkenstrain's Castle.")
+ .put(new WorldPoint(1456, 3620, 0), "Graveyard west of Shayzien House.")
+ .put(new WorldPoint(2735, 3638, 0), "East of Rellekka, north-west of Golden Apple Tree (AJR).")
+ .put(new WorldPoint(2681, 3653, 0), "Rellekka, in the garden of the south-east house.")
+ .put(new WorldPoint(2537, 3881, 0), "Miscellania.")
+ // Hard
+ .put(new WorldPoint(2209, 3161, 0), "North-east of Tyras Camp.")
+ .put(new WorldPoint(2181, 3206, 0), "South of Elf Camp.")
+ .put(new WorldPoint(3081, 3209, 0), "Small Island (CLP).")
+ .put(new WorldPoint(3374, 3250, 0), "Duel Arena combat area.")
+ .put(new WorldPoint(2699, 3251, 0), "Little island (AIR).")
+ .put(new WorldPoint(3546, 3251, 0), "North-east of Burgh de Rott.")
+ .put(new WorldPoint(3544, 3256, 0), "North-east of Burgh de Rott.")
+ .put(new WorldPoint(2841, 3267, 0), "Crandor island.")
+ .put(new WorldPoint(3168, 3041, 0), "Bedabin Camp.")
+ .put(new WorldPoint(2542, 3031, 0), "Gu'Tanoth.")
+ .put(new WorldPoint(2581, 3030, 0), "Gu'Tanoth island, enter cave north-west of Feldip Hills (AKS).")
+ .put(new WorldPoint(2961, 3024, 0), "Ship yard (DKP).")
+ .put(new WorldPoint(2339, 3311, 0), "East of Tirannwn on Arandar mountain pass.")
+ .put(new WorldPoint(3440, 3341, 0), "Nature Spirit's grotto.")
+ .put(new WorldPoint(2763, 2974, 0), "Cairn Isle, west of Shilo Village.")
+ .put(new WorldPoint(3138, 2969, 0), "West of Bandit Camp.")
+ .put(new WorldPoint(2924, 2963, 0), "On the southern part of eastern Karamja.")
+ .put(new WorldPoint(2838, 2914, 0), "Kharazi Jungle, near water pool.")
+ .put(new WorldPoint(3441, 3419, 0), "Mort Myre Swamp.")
+ .put(new WorldPoint(2950, 2902, 0), "South-east of Kharazi Jungle.")
+ .put(new WorldPoint(2775, 2891, 0), "South-west of Kharazi Jungle.")
+ .put(new WorldPoint(3113, 3602, 0), "Wilderness. North of Edgeville (level 11).")
+ .put(new WorldPoint(2892, 3675, 0), "On the summit of Trollheim.")
+ .put(new WorldPoint(3168, 3677, 0), "Wilderness. Graveyard of Shadows.")
+ .put(new WorldPoint(2853, 3690, 0), "Entrance to the troll Stronghold.")
+ .put(new WorldPoint(3305, 3692, 0), "Wilderness. West of eastern green dragon.")
+ .put(new WorldPoint(3055, 3696, 0), "Wilderness. Bandit Camp.")
+ .put(new WorldPoint(3302, 3696, 0), "Wilderness. West of eastern green dragon.")
+ .put(new WorldPoint(1479, 3696, 0), "Lizardman Canyon.")
+ .put(new WorldPoint(2712, 3732, 0), "North-east of Rellekka.")
+ .put(new WorldPoint(2970, 3749, 0), "Wilderness. Forgotten Cemetery.")
+ .put(new WorldPoint(3094, 3764, 0), "Wilderness. Mining site north of Bandit Camp.")
+ .put(new WorldPoint(3311, 3769, 0), "Wilderness. North of Venenatis.")
+ .put(new WorldPoint(1460, 3782, 0), "Lovakengj, near burning man.")
+ .put(new WorldPoint(3244, 3792, 0), "Wilderness. South-east of Lava Dragon Isle by some Chaos Dwarves.")
+ .put(new WorldPoint(3140, 3804, 0), "Wilderness. North of Ruins.")
+ .put(new WorldPoint(2946, 3819, 0), "Wilderness. Chaos Temple (level 38).")
+ .put(new WorldPoint(3771, 3825, 0), "Fossil Island. East of Museum Camp.")
+ .put(new WorldPoint(3013, 3846, 0), "Wilderness. West of Lava Maze, before KBD's lair.")
+ .put(new WorldPoint(3058, 3884, 0), "Wilderness. Near runite ore north of Lava Maze.")
+ .put(new WorldPoint(3290, 3889, 0), "Wilderness. Demonic Ruins.")
+ .put(new WorldPoint(3770, 3897, 0), "Small Island north of Fossil Island.")
+ .put(new WorldPoint(2505, 3899, 0), "Small Island north-east of Miscellania (AJS).")
+ .put(new WorldPoint(3285, 3942, 0), "Wilderness. Rogues' Castle.")
+ .put(new WorldPoint(3159, 3959, 0), "Wilderness. North of Deserted Keep, west of Resource Area.")
+ .put(new WorldPoint(3039, 3960, 0), "Wilderness. Pirates' Hideout.")
+ .put(new WorldPoint(2987, 3963, 0), "Wilderness. West of Wilderness Agility Course.")
+ .put(new WorldPoint(3189, 3963, 0), "Wilderness. North of Resource Area, near magic axe hut.")
+ // Elite
+ .put(new WorldPoint(2357, 3151, 0), "Lletya.")
+ .put(new WorldPoint(3587, 3180, 0), "Meiyerditch.")
+ .put(new WorldPoint(2820, 3078, 0), "Tai Bwo Wannai. Hardwood Grove.")
+ .put(new WorldPoint(3811, 3060, 0), "Small island north-east of Mos Le'Harmless.")
+ .put(new WorldPoint(2180, 3282, 0), "North of Elf Camp.")
+ .put(new WorldPoint(2870, 2997, 0), "North-east of Shilo Village.")
+ .put(new WorldPoint(3302, 2988, 0), "On top of a cliff to the west of Pollnivneach.")
+ .put(new WorldPoint(2511, 2980, 0), "Just south of Gu'Tanoth, west of gnome glider.")
+ .put(new WorldPoint(2732, 3372, 0), "Legends' Guild.")
+ .put(new WorldPoint(3573, 3425, 0), "North of Dessous's tomb from Desert Treasure.")
+ .put(new WorldPoint(3828, 2848, 0), "East of Harmony Island.")
+ .put(new WorldPoint(3225, 2838, 0), "South of Desert Treasure pyramid.")
+ .put(new WorldPoint(1773, 3510, 0), "Between magic trees South of Tithe Farm.")
+ .put(new WorldPoint(3822, 3562, 0), "North-east of Dragontooth Island.")
+ .put(new WorldPoint(3603, 3564, 0), "North of the wrecked ship, outside of Port Phasmatys.")
+ .put(new WorldPoint(2936, 2721, 0), "Eastern shore of Crash Island.")
+ .put(new WorldPoint(2697, 2705, 0), "South-west of Ape Atoll.")
+ .put(new WorldPoint(2778, 3678, 0), "Mountain Camp.")
+ .put(new WorldPoint(2827, 3740, 0), "West of the entrance to the Ice Path, where the Troll child resides.")
+ .put(new WorldPoint(2359, 3799, 0), "Neitiznot.")
+ .put(new WorldPoint(2194, 3807, 0), "Pirates' Cove.")
+ .put(new WorldPoint(2700, 3808, 0), "Northwestern part of the Trollweiss and Rellekka Hunter area (DKS).")
+ .put(new WorldPoint(3215, 3835, 0), "Wilderness. Lava Dragon Isle.")
+ .put(new WorldPoint(3369, 3894, 0), "Wilderness. Fountain of Rune.")
+ .put(new WorldPoint(2065, 3923, 0), "Outside the western wall on Lunar Isle.")
+ .put(new WorldPoint(3188, 3933, 0), "Wilderness. Resource Area.")
+ .put(new WorldPoint(2997, 3953, 0), "Wilderness. Inside Agility Training Area.")
+ .put(new WorldPoint(3380, 3963, 0), "Wilderness. North of Volcano.")
+ // Master
+ .put(new WorldPoint(2178, 3209, 0), "South of Elf Camp.")
+ .put(new WorldPoint(2155, 3100, 0), "South of Port Tyras (BJS).")
+ .put(new WorldPoint(2217, 3092, 0), "Poison Waste island (DLR).")
+ .put(new WorldPoint(3830, 3060, 0), "Small island located north-east of Mos Le'Harmless.")
+ .put(new WorldPoint(2834, 3271, 0), "Crandor island.")
+ .put(new WorldPoint(2732, 3284, 0), "Witchaven.")
+ .put(new WorldPoint(3622, 3320, 0), "Meiyerditch. Outside mine.")
+ .put(new WorldPoint(2303, 3328, 0), "East of Prifddinas.")
+ .put(new WorldPoint(3570, 3405, 0), "North of Dessous's tomb from Desert Treasure.")
+ .put(new WorldPoint(2840, 3423, 0), "Water Obelisk Island.")
+ .put(new WorldPoint(3604, 3564, 0), "North of the wrecked ship, outside of Port Phasmatys (ALQ).")
+ .put(new WorldPoint(3085, 3569, 0), "Wilderness. Obelisk of Air.")
+ .put(new WorldPoint(2934, 2727, 0), "Eastern shore of Crash Island.")
+ .put(new WorldPoint(1451, 3695, 0), "West side of Lizardman Canyon with Lizardman shaman.")
+ .put(new WorldPoint(2538, 3739, 0), "Waterbirth Island.")
+ .put(new WorldPoint(1248, 3751, 0), "Farming Guild.")
+ .put(new WorldPoint(1698, 3792, 0), "Arceuus church.")
+ .put(new WorldPoint(2951, 3820, 0), "Wilderness. Chaos Temple (level 38).")
+ .put(new WorldPoint(2202, 3825, 0), "Pirates' Cove, between Lunar Isle and Rellekka.")
+ .put(new WorldPoint(1761, 3853, 0), "Arceuus essence mine.")
+ .put(new WorldPoint(2090, 3863, 0), "South of Lunar Isle, west of Astral altar.")
+ .put(new WorldPoint(1442, 3878, 0), "Sulphur Mine.")
+ .put(new WorldPoint(3380, 3929, 0), "Wilderness. Near Volcano.")
+ .put(new WorldPoint(3188, 3939, 0), "Wilderness. Resource Area.")
+ .put(new WorldPoint(3304, 3941, 0), "Wilderness. East of Rogues' Castle.")
+ .put(new WorldPoint(2994, 3961, 0), "Wilderness. Inside Agility Training Area.")
+ .build();
+
private String text;
private WorldPoint location;
private static final ItemRequirement HAS_SPADE = new SingleItemRequirement(ItemID.SPADE);
@@ -52,8 +201,18 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati
{
panelComponent.getChildren().add(TitleComponent.builder().text("Coordinate Clue").build());
+ String solution = CLUES.get(location);
+
+ if (solution != null)
+ {
+ panelComponent.getChildren().add(LineComponent.builder()
+ .left(solution)
+ .build());
+ panelComponent.getChildren().add(LineComponent.builder().build());
+ }
+
panelComponent.getChildren().add(LineComponent.builder()
- .left("Click the clue scroll along the edge of your world map to see where you should dig.")
+ .left("Click the clue scroll on your world map to see dig location.")
.build());
if (plugin.getInventoryItems() != null)
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 200a223aa3..20f0b16d9d 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
@@ -300,8 +300,9 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc
new CrypticClue("Does one really need a fire to stay warm here?", new WorldPoint(3816, 3810, 0), "Dig next to the fire near the Volcanic Mine entrance."),
new CrypticClue("Search the open crate found in a small farmhouse in Hosidius. Cabbages grow outside.", CRATE_27533, new WorldPoint(1687, 3628, 0), "The house is east of the Mess in Great Kourend."),
new CrypticClue("Dig under Ithoi's cabin.", new WorldPoint(2529, 2838, 0), "Dig under Ithoi's cabin in the Corsair Cove."),
- new CrypticClue("Search the drawers, upstairs in the bank to the East of Varrock.", new WorldPoint(3250, 3420, 1), "Search the drawers upstairs in Varrock east bank"),
- new CrypticClue("Speak to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Located upstairs in the house to the north of fairy ring CLS. Answer: 6859")
+ new CrypticClue("Search the drawers, upstairs in the bank to the East of Varrock.", DRAWERS_7194, new WorldPoint(3250, 3420, 1), "Search the drawers upstairs in Varrock east bank."),
+ new CrypticClue("Speak to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Located upstairs in the house to the north of fairy ring CLS. Answer: 6859"),
+ new CrypticClue("The effects of this fire are magnified.", new WorldPoint(1179, 3626, 0), "Dig by the fire beside Ket'sal K'uk in the westernmost part of the Kebos Swamp. ")
);
private String text;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java
index 30a33d7e50..80b97e6c24 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java
@@ -76,7 +76,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
new EmoteClue("Show your anger towards the Statue of Saradomin in Ellamaria's garden. Beware of double agents! Equip a zamorak godsword.", BY_THE_BEAR_CAGE_IN_VARROCK_PALACE_GARDENS, new WorldPoint(3230, 3478, 0), ANGRY, item(ZAMORAK_GODSWORD)),
new EmoteClue("Show your anger at the Wise old man. Beware of double agents! Equip an abyssal whip, a legend's cape and some spined chaps.", BEHIND_MISS_SCHISM_IN_DRAYNOR_VILLAGE, new WorldPoint(3088, 3254, 0), ANGRY, any("Abyssal whip", item(ABYSSAL_WHIP), item(VOLCANIC_ABYSSAL_WHIP), item(FROZEN_ABYSSAL_WHIP)), item(CAPE_OF_LEGENDS), item(SPINED_CHAPS)),
new EmoteClue("Beckon in the Digsite, near the eastern winch. Bow before you talk to me. Equip a green gnome hat, snakeskin boots and an iron pickaxe.", DIGSITE, new WorldPoint(3370, 3425, 0), BECKON, BOW, item(GREEN_HAT), item(SNAKESKIN_BOOTS), item(IRON_PICKAXE)),
- new EmoteClue("Beckon in Tai Bwo Wannai. Clap before you talk to me. Equip green dragonhide chaps, a ring of dueling and a mithril medium helmet.", SOUTH_OF_THE_SHRINE_IN_TAI_BWO_WANNAI_VILLAGE, new WorldPoint(2784, 3065, 0), BECKON, CLAP, item(GREEN_DHIDE_CHAPS), any("Ring of dueling", item(RING_OF_DUELING1), item(RING_OF_DUELING2), item(RING_OF_DUELING3), item(RING_OF_DUELING4), item(RING_OF_DUELING5), item(RING_OF_DUELING6), item(RING_OF_DUELING7), item(RING_OF_DUELING8)), item(MITHRIL_MED_HELM)),
+ new EmoteClue("Beckon in Tai Bwo Wannai. Clap before you talk to me. Equip green dragonhide chaps, a ring of dueling and a mithril medium helmet.", SOUTH_OF_THE_SHRINE_IN_TAI_BWO_WANNAI_VILLAGE, new WorldPoint(2803, 3073, 0), BECKON, CLAP, item(GREEN_DHIDE_CHAPS), any("Ring of dueling", item(RING_OF_DUELING1), item(RING_OF_DUELING2), item(RING_OF_DUELING3), item(RING_OF_DUELING4), item(RING_OF_DUELING5), item(RING_OF_DUELING6), item(RING_OF_DUELING7), item(RING_OF_DUELING8)), item(MITHRIL_MED_HELM)),
new EmoteClue("Beckon in the combat ring of Shayzien. Show your anger before you talk to me. Equip an adamant platebody, adamant full helm and adamant platelegs.", WEST_OF_THE_SHAYZIEN_COMBAT_RING, new WorldPoint(1545, 3594, 0), BECKON, ANGRY, item(ADAMANT_PLATELEGS), item(ADAMANT_PLATEBODY), item(ADAMANT_FULL_HELM)),
new EmoteClue("Bow near Lord Iorwerth. Beware of double agents! Equip a new imbued crystal bow.", TENT_IN_LORD_IORWERTHS_ENCAMPMENT, new WorldPoint(2205, 3252, 0), BOW, any("Imbued crystal bow", item(NEW_CRYSTAL_BOW_I), item(CRYSTAL_BOW_FULL_I), item(CRYSTAL_BOW_910_I), item(CRYSTAL_BOW_810_I), item(CRYSTAL_BOW_710_I), item(CRYSTAL_BOW_610_I), item(CRYSTAL_BOW_510_I), item(CRYSTAL_BOW_410_I), item(CRYSTAL_BOW_310_I), item(CRYSTAL_BOW_210_I), item(CRYSTAL_BOW_110_I))),
new EmoteClue("Bow outside the entrance to the Legends' Guild. Equip iron platelegs, an emerald amulet and an oak longbow.", OUTSIDE_THE_LEGENDS_GUILD_GATES, new WorldPoint(2729, 3349, 0), BOW, item(IRON_PLATELEGS), item(OAK_LONGBOW), item(EMERALD_AMULET)),
@@ -133,8 +133,8 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
new EmoteClue("Panic by the pilot on White Wolf Mountain. Beware of double agents! Equip mithril platelegs, a ring of life and a rune axe.", GNOME_GLIDER_ON_WHITE_WOLF_MOUNTAIN, new WorldPoint(2847, 3499, 0), PANIC, item(MITHRIL_PLATELEGS), item(RING_OF_LIFE), item(RUNE_AXE)),
new EmoteClue("Panic by the big egg where no one dare goes and the ground is burnt. Beware of double agents! Equip a dragon med helm, a TokTz-Ket-Xil, a brine sabre, rune platebody and an uncharged amulet of glory.", SOUTHEAST_CORNER_OF_LAVA_DRAGON_ISLE, new WorldPoint(3227, 3831, 0), PANIC, item(DRAGON_MED_HELM), item(TOKTZKETXIL), item(BRINE_SABRE), item(RUNE_PLATEBODY), item(AMULET_OF_GLORY)),
new EmoteClue("Panic at the area flowers meet snow. Equip Blue D'hide vambs, a dragon spear and a rune plateskirt.", HALFWAY_DOWN_TROLLWEISS_MOUNTAIN, new WorldPoint(2776, 3781, 0), PANIC, item(BLUE_DHIDE_VAMB), item(DRAGON_SPEAR), item(RUNE_PLATESKIRT), item(SLED_4084)),
- new EmoteClue("Do a push up at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), PUSH_UP, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I))),
- new EmoteClue("Blow a raspberry at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), RASPBERRY, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I))),
+ new EmoteClue("Do a push up at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), PUSH_UP, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I), item(HYDRA_SLAYER_HELMET), item(HYDRA_SLAYER_HELMET_I))),
+ new EmoteClue("Blow a raspberry at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), RASPBERRY, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I), item(HYDRA_SLAYER_HELMET), item(HYDRA_SLAYER_HELMET_I))),
new EmoteClue("Blow a raspberry at the monkey cage in Ardougne Zoo. Equip a studded leather body, bronze platelegs and a normal staff with no orb.", NEAR_THE_PARROTS_IN_ARDOUGNE_ZOO, new WorldPoint(2607, 3282, 0), RASPBERRY, item(STUDDED_BODY), item(BRONZE_PLATELEGS), item(STAFF)),
new EmoteClue("Blow raspberries outside the entrance to Keep Le Faye. Equip a coif, an iron platebody and leather gloves.", OUTSIDE_KEEP_LE_FAYE, new WorldPoint(2757, 3401, 0), RASPBERRY, item(COIF), item(IRON_PLATEBODY), item(LEATHER_GLOVES)),
new EmoteClue("Blow a raspberry in the Fishing Guild bank. Beware of double agents! Equip an elemental shield, blue dragonhide chaps and a rune warhammer.", FISHING_GUILD_BANK, new WorldPoint(2588, 3419, 0), RASPBERRY, item(ELEMENTAL_SHIELD), item(BLUE_DHIDE_CHAPS), item(RUNE_WARHAMMER)),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java
index 4f7253da7d..17fe16453b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java
@@ -170,7 +170,6 @@ public enum HotColdLocation
ZEAH_MESS_HALL(new WorldPoint(1658, 3621, 0), ZEAH, "East of Mess hall."),
ZEAH_WATSONS_HOUSE(new WorldPoint(1653, 3573, 0), ZEAH, "East of Watson's house."),
ZEAH_VANNAHS_FARM_STORE(new WorldPoint(1806, 3521, 0), ZEAH, "North of Vannah's Farm Store, between the chicken coop and willow trees."),
- ZEAH_FARMING_GUILD_SW(new WorldPoint(1227, 3712, 0), ZEAH, "South-west of the Farming Guild."),
ZEAH_FARMING_GUILD_W(new WorldPoint(1209, 3737, 0), ZEAH, "West of the Farming Guild."),
ZEAH_DAIRY_COW(new WorldPoint(1320, 3718, 0), ZEAH, "North-east of the Kebos Lowlands, east of the dairy cow."),
ZEAH_CRIMSON_SWIFTS(new WorldPoint(1186, 3583, 0), ZEAH, "South-west of the Kebos Swamp, below the crimson swifts.");
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java
index cf910192f2..cc82bcea65 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java
@@ -40,4 +40,14 @@ public interface CombatLevelConfig extends Config
{
return true;
}
+
+ @ConfigItem(
+ keyName = "wildernessAttackLevelRange",
+ name = "Show level range in wilderness",
+ description = "Displays a PVP-world-like attack level range in the wilderness"
+ )
+ default boolean wildernessAttackLevelRange()
+ {
+ return true;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java
index a72e0bf2df..bbde15c2e0 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Devin French
+ * Copyright (c) 2019, Jordan Atwood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,14 +27,20 @@ package net.runelite.client.plugins.combatlevel;
import com.google.inject.Provides;
import java.text.DecimalFormat;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.GameState;
import net.runelite.api.Skill;
+import net.runelite.api.WorldType;
+import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameTick;
+import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
@@ -42,15 +49,31 @@ import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
name = "Combat Level",
- description = "Show a more accurate combat level in Combat Options panel"
+ description = "Show a more accurate combat level in Combat Options panel and other combat level functions",
+ tags = {"wilderness", "attack", "range"}
)
public class CombatLevelPlugin extends Plugin
{
- private final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###");
+ private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###");
+ private static final String CONFIG_GROUP = "combatlevel";
+ private static final String ATTACK_RANGE_CONFIG_KEY = "wildernessAttackLevelRange";
+ private static final Pattern WILDERNESS_LEVEL_PATTERN = Pattern.compile("^Level: (\\d+)$");
+ private static final int SKULL_CONTAINER_ADJUSTED_ORIGINAL_Y = 6;
+ private static final int WILDERNESS_LEVEL_TEXT_ADJUSTED_ORIGINAL_Y = 3;
+ private static final int MIN_COMBAT_LEVEL = 3;
+
+ private int originalWildernessLevelTextPosition = -1;
+ private int originalSkullContainerPosition = -1;
@Inject
private Client client;
+ @Inject
+ private ClientThread clientThread;
+
+ @Inject
+ private CombatLevelConfig config;
+
@Inject
private CombatLevelOverlay overlay;
@@ -67,6 +90,11 @@ public class CombatLevelPlugin extends Plugin
protected void startUp() throws Exception
{
overlayManager.add(overlay);
+
+ if (config.wildernessAttackLevelRange())
+ {
+ appendAttackLevelRangeText();
+ }
}
@Override
@@ -84,6 +112,8 @@ public class CombatLevelPlugin extends Plugin
combatLevelWidget.setText(widgetText.substring(0, widgetText.indexOf(".")));
}
}
+
+ shutDownAttackLevelRange();
}
@Subscribe
@@ -112,4 +142,103 @@ public class CombatLevelPlugin extends Plugin
combatLevelWidget.setText("Combat Lvl: " + DECIMAL_FORMAT.format(combatLevelPrecise));
}
+
+ @Subscribe
+ public void onConfigChanged(ConfigChanged event)
+ {
+ if (!CONFIG_GROUP.equals(event.getGroup()) || !ATTACK_RANGE_CONFIG_KEY.equals(event.getKey()))
+ {
+ return;
+ }
+
+ if (config.wildernessAttackLevelRange())
+ {
+ appendAttackLevelRangeText();
+ }
+ else
+ {
+ shutDownAttackLevelRange();
+ }
+ }
+
+ @Subscribe
+ public void onScriptCallbackEvent(ScriptCallbackEvent event)
+ {
+ if (config.wildernessAttackLevelRange()
+ && "wildernessWidgetTextSet".equals(event.getEventName()))
+ {
+ appendAttackLevelRangeText();
+ }
+ }
+
+ private void appendAttackLevelRangeText()
+ {
+ final Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL);
+ if (wildernessLevelWidget == null)
+ {
+ return;
+ }
+
+ final String wildernessLevelText = wildernessLevelWidget.getText();
+ final Matcher m = WILDERNESS_LEVEL_PATTERN.matcher(wildernessLevelText);
+ if (!m.matches()
+ || WorldType.isPvpWorld(client.getWorldType()))
+ {
+ return;
+ }
+
+ final Widget skullContainer = client.getWidget(WidgetInfo.PVP_SKULL_CONTAINER);
+ if (originalWildernessLevelTextPosition == -1)
+ {
+ originalWildernessLevelTextPosition = wildernessLevelWidget.getOriginalY();
+ }
+ if (originalSkullContainerPosition == -1)
+ {
+ originalSkullContainerPosition = skullContainer.getRelativeY();
+ }
+
+ final int wildernessLevel = Integer.parseInt(m.group(1));
+ final int combatLevel = client.getLocalPlayer().getCombatLevel();
+
+ wildernessLevelWidget.setText(wildernessLevelText + "
" + combatAttackRange(combatLevel, wildernessLevel));
+ wildernessLevelWidget.setOriginalY(WILDERNESS_LEVEL_TEXT_ADJUSTED_ORIGINAL_Y);
+ skullContainer.setOriginalY(SKULL_CONTAINER_ADJUSTED_ORIGINAL_Y);
+
+ clientThread.invoke(wildernessLevelWidget::revalidate);
+ clientThread.invoke(skullContainer::revalidate);
+ }
+
+ private void shutDownAttackLevelRange()
+ {
+ if (WorldType.isPvpWorld(client.getWorldType()))
+ {
+ return;
+ }
+
+ final Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL);
+ if (wildernessLevelWidget != null)
+ {
+ String wildernessLevelText = wildernessLevelWidget.getText();
+ if (wildernessLevelText.contains("
"))
+ {
+ wildernessLevelWidget.setText(wildernessLevelText.substring(0, wildernessLevelText.indexOf("
")));
+ }
+ wildernessLevelWidget.setOriginalY(originalWildernessLevelTextPosition);
+ clientThread.invoke(wildernessLevelWidget::revalidate);
+ }
+ originalWildernessLevelTextPosition = -1;
+
+ final Widget skullContainer = client.getWidget(WidgetInfo.PVP_SKULL_CONTAINER);
+ if (skullContainer != null)
+ {
+ skullContainer.setOriginalY(originalSkullContainerPosition);
+ clientThread.invoke(skullContainer::revalidate);
+ }
+ originalSkullContainerPosition = -1;
+ }
+
+ private static String combatAttackRange(final int combatLevel, final int wildernessLevel)
+ {
+ return Math.max(MIN_COMBAT_LEVEL, combatLevel - wildernessLevel) + "-" + Math.min(Experience.MAX_COMBAT_LEVEL, combatLevel + wildernessLevel);
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cooking/CookingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/cooking/CookingOverlay.java
index af0a5a8b62..7e25f3ad31 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cooking/CookingOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cooking/CookingOverlay.java
@@ -78,7 +78,6 @@ class CookingOverlay extends Overlay
return null;
}
- panelComponent.setPreferredSize(new Dimension(145, 0));
panelComponent.getChildren().clear();
if (isCooking() || Duration.between(session.getLastCookingAction(), Instant.now()).getSeconds() < COOK_TIMEOUT)
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/dailytaskindicators/DailyTasksPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/dailytaskindicators/DailyTasksPlugin.java
index e44df4796a..04d6a460a3 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/dailytaskindicators/DailyTasksPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/dailytaskindicators/DailyTasksPlugin.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, Infinitay
- * Copyright (c) 2018, Shaun Dreclin
+ * Copyright (c) 2018-2019, Shaun Dreclin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -86,10 +86,15 @@ public class DailyTasksPlugin extends Plugin
}
@Override
- protected void shutDown() throws Exception
+ public void startUp()
+ {
+ loggingIn = true;
+ }
+
+ @Override
+ public void shutDown()
{
lastReset = 0L;
- loggingIn = false;
}
@Subscribe
@@ -108,7 +113,6 @@ public class DailyTasksPlugin extends Plugin
boolean dailyReset = !loggingIn && currentTime - lastReset > ONE_DAY;
if ((dailyReset || loggingIn)
- && client.getGameState() == GameState.LOGGED_IN
&& client.getVar(VarClientInt.MEMBERSHIP_STATUS) == 1)
{
// Round down to the nearest day
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java
index 636d9b923b..d68791d289 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java
@@ -31,7 +31,7 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
-import net.runelite.api.events.SessionOpen;
+import net.runelite.client.events.SessionOpen;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
@@ -43,7 +43,8 @@ import net.runelite.http.api.worlds.WorldResult;
@PluginDescriptor(
name = "Default World",
- description = "Enable a default world to be selected when launching the client"
+ description = "Enable a default world to be selected when launching the client",
+ tags = {"home"}
)
@Slf4j
public class DefaultWorldPlugin extends Plugin
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 0b9be07b7e..fd96de011c 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
@@ -347,6 +347,12 @@ class DevToolsOverlay extends Overlay
{
graphics.drawPolygon(p);
}
+
+ p = decorObject.getConvexHull2();
+ if (p != null)
+ {
+ graphics.drawPolygon(p);
+ }
}
}
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 5aae397d0f..3730a878b9 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
@@ -238,7 +238,9 @@ public class DevToolsPlugin extends Plugin
int value = Integer.parseInt(args[1]);
client.setVarpValue(client.getVarps(), varp, value);
client.addChatMessage(ChatMessageType.SERVER, "", "Set VarPlayer " + varp + " to " + value, null);
- eventBus.post(new VarbitChanged()); // fake event
+ VarbitChanged varbitChanged = new VarbitChanged();
+ varbitChanged.setIndex(varp);
+ eventBus.post(varbitChanged); // fake event
break;
}
case "getvarb":
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 dc6a6f6461..ef8454b712 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
@@ -32,6 +32,8 @@ import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.JButton;
@@ -95,8 +97,7 @@ class VarInspector extends JFrame
private int[] oldVarps2 = null;
private int numVarbits = 10000;
- private int[] oldIntVarcs = null;
- private String[] oldStrVarcs = null;
+ private Map varcs = null;
@Inject
VarInspector(Client client, EventBus eventBus, DevToolsPlugin plugin)
@@ -279,9 +280,9 @@ class VarInspector extends JFrame
public void onVarClientIntChanged(VarClientIntChanged e)
{
int idx = e.getIndex();
- int neew = client.getIntVarcs()[idx];
- int old = oldIntVarcs[idx];
- oldIntVarcs[idx] = neew;
+ int neew = (Integer) client.getVarcMap().getOrDefault(idx, 0);
+ int old = (Integer) varcs.getOrDefault(idx, 0);
+ varcs.put(idx, neew);
if (old != neew)
{
@@ -302,9 +303,9 @@ class VarInspector extends JFrame
public void onVarClientStrChanged(VarClientStrChanged e)
{
int idx = e.getIndex();
- String neew = client.getStrVarcs()[idx];
- String old = oldStrVarcs[idx];
- oldStrVarcs[idx] = neew;
+ String neew = (String) client.getVarcMap().getOrDefault(idx, "");
+ String old = (String) varcs.getOrDefault(idx, "");
+ varcs.put(idx, neew);
if (!Objects.equals(old, neew))
{
@@ -343,14 +344,11 @@ class VarInspector extends JFrame
{
oldVarps = new int[client.getVarps().length];
oldVarps2 = new int[client.getVarps().length];
- oldIntVarcs = new int[client.getIntVarcs().length];
- oldStrVarcs = new String[client.getStrVarcs().length];
}
System.arraycopy(client.getVarps(), 0, oldVarps, 0, oldVarps.length);
System.arraycopy(client.getVarps(), 0, oldVarps2, 0, oldVarps2.length);
- System.arraycopy(client.getIntVarcs(), 0, oldIntVarcs, 0, oldIntVarcs.length);
- System.arraycopy(client.getStrVarcs(), 0, oldStrVarcs, 0, oldStrVarcs.length);
+ varcs = new HashMap<>(client.getVarcMap());
eventBus.register(this);
setVisible(true);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java
index 79bb99bc5a..acd8851c0b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java
@@ -183,6 +183,9 @@ public class WidgetInfoTableModel extends AbstractTableModel
out.add(new WidgetField<>("ScrollHeight", Widget::getScrollHeight, Widget::setScrollHeight, Integer.class));
out.add(new WidgetField<>("DragDeadZone", Widget::getDragDeadZone, Widget::setDragDeadZone, Integer.class));
out.add(new WidgetField<>("DragDeadTime", Widget::getDragDeadTime, Widget::setDragDeadTime, Integer.class));
+ out.add(new WidgetField<>("NoClickThrough", Widget::getNoClickThrough, Widget::setNoClickThrough, Boolean.class));
+ out.add(new WidgetField<>("NoScrollThrough", Widget::getNoScrollThrough, Widget::setNoScrollThrough, Boolean.class));
+ out.add(new WidgetField<>("TargetVerb", Widget::getTargetVerb, Widget::setTargetVerb, String.class));
return out;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java
index 06e0369535..9598b7eff5 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java
@@ -130,6 +130,7 @@ public class DiscordPlugin extends Plugin
clientToolbar.addNavigation(discordButton);
checkForGameStateUpdate();
+ checkForAreaUpdate();
if (discordService.getCurrentUser() != null)
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordState.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordState.java
index 625aed1f08..0b57424f85 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordState.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordState.java
@@ -34,6 +34,7 @@ import java.util.Optional;
import java.util.UUID;
import javax.inject.Inject;
import lombok.Data;
+import net.runelite.client.RuneLiteProperties;
import net.runelite.client.discord.DiscordPresence;
import net.runelite.client.discord.DiscordService;
import net.runelite.client.ws.PartyService;
@@ -57,14 +58,16 @@ class DiscordState
private final DiscordService discordService;
private final DiscordConfig config;
private PartyService party;
+ private final RuneLiteProperties properties;
private DiscordPresence lastPresence;
@Inject
- private DiscordState(final DiscordService discordService, final DiscordConfig config, final PartyService party)
+ private DiscordState(final DiscordService discordService, final DiscordConfig config, final PartyService party, final RuneLiteProperties properties)
{
this.discordService = discordService;
this.config = config;
this.party = party;
+ this.properties = properties;
}
/**
@@ -90,6 +93,7 @@ class DiscordState
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
.state(lastPresence.getState())
.details(lastPresence.getDetails())
+ .largeImageText(lastPresence.getLargeImageText())
.startTimestamp(lastPresence.getStartTimestamp())
.smallImageKey(lastPresence.getSmallImageKey())
.partyMax(lastPresence.getPartyMax())
@@ -168,11 +172,15 @@ class DiscordState
}
}
+ // Replace snapshot with + to make tooltip shorter (so it will span only 1 line)
+ final String versionShortHand = properties.getVersion().replace("-SNAPSHOT", "+");
+
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
.state(MoreObjects.firstNonNull(state, ""))
.details(MoreObjects.firstNonNull(details, ""))
+ .largeImageText(properties.getTitle() + " v" + versionShortHand)
.startTimestamp(event.getStart())
- .smallImageKey(MoreObjects.firstNonNull(imageKey, "default"))
+ .smallImageKey(imageKey)
.partyMax(PARTY_MAX)
.partySize(party.getMembers().size());
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordUserInfo.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordUserInfo.java
index b358a7d01e..360d58652e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordUserInfo.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordUserInfo.java
@@ -24,10 +24,12 @@
*/
package net.runelite.client.plugins.discord;
+import lombok.EqualsAndHashCode;
import lombok.Value;
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
@Value
+@EqualsAndHashCode(callSuper = true)
class DiscordUserInfo extends PartyMemberMessage
{
private final String userId;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java
index 07977334e4..8da48d7cdc 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java
@@ -147,7 +147,8 @@ public class FishingPlugin extends Plugin
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
- if (gameStateChanged.getGameState() == GameState.LOADING)
+ GameState gameState = gameStateChanged.getGameState();
+ if (gameState == GameState.CONNECTION_LOST || gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING)
{
fishingSpots.clear();
minnowSpots.clear();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesPlugin.java
index beb56a171f..75cc26163c 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesPlugin.java
@@ -167,7 +167,7 @@ public class FriendNotesPlugin extends Plugin
if (groupId == WidgetInfo.FRIENDS_LIST.getGroupId() && event.getOption().equals("Message"))
{
// Friends have color tags
- setHoveredFriend(Text.removeTags(event.getTarget()));
+ setHoveredFriend(Text.toJagexName(Text.removeTags(event.getTarget())));
// Build "Add Note" or "Edit Note" menu entry
final MenuEntry addNote = new MenuEntry();
@@ -197,13 +197,13 @@ public class FriendNotesPlugin extends Plugin
return;
}
- //Friends have color tags
- final String sanitizedTarget = Text.removeTags(event.getMenuTarget());
-
// Handle clicks on "Add Note" or "Edit Note"
if (event.getMenuOption().equals(ADD_NOTE) || event.getMenuOption().equals(EDIT_NOTE))
{
event.consume();
+
+ //Friends have color tags
+ final String sanitizedTarget = Text.toJagexName(Text.removeTags(event.getMenuTarget()));
final String note = getFriendNote(sanitizedTarget);
// Open the new chatbox input dialog
@@ -234,7 +234,16 @@ public class FriendNotesPlugin extends Plugin
{
// Migrate a friend's note to their new display name
final Friend friend = (Friend) nameable;
- migrateFriendNote(friend.getName(), friend.getPrevName());
+ String name = friend.getName();
+ String prevName = friend.getPrevName();
+
+ if (prevName != null)
+ {
+ migrateFriendNote(
+ Text.toJagexName(name),
+ Text.toJagexName(prevName)
+ );
+ }
}
}
@@ -242,7 +251,7 @@ public class FriendNotesPlugin extends Plugin
public void onRemovedFriend(RemovedFriend event)
{
// Delete a friend's note if they are removed
- final String displayName = event.getName();
+ final String displayName = Text.toJagexName(event.getName());
log.debug("Remove friend: '{}'", displayName);
setFriendNote(displayName, null);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
index a7871f95da..7c0054ac66 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
@@ -37,7 +37,9 @@ import com.jogamp.opengl.GLException;
import com.jogamp.opengl.GLProfile;
import java.awt.Canvas;
import java.awt.Dimension;
+import java.awt.Graphics2D;
import java.awt.Image;
+import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.nio.ByteBuffer;
@@ -46,6 +48,7 @@ import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.function.Function;
import javax.inject.Inject;
+import jogamp.nativewindow.SurfaceScaleUtils;
import jogamp.nativewindow.jawt.x11.X11JAWTWindow;
import jogamp.newt.awt.NewtFactoryAWT;
import lombok.extern.slf4j.Slf4j;
@@ -71,18 +74,7 @@ import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginInstantiationException;
import net.runelite.client.plugins.PluginManager;
-import static net.runelite.client.plugins.gpu.GLUtil.glDeleteBuffer;
-import static net.runelite.client.plugins.gpu.GLUtil.glDeleteFrameBuffer;
-import static net.runelite.client.plugins.gpu.GLUtil.glDeleteRenderbuffers;
-import static net.runelite.client.plugins.gpu.GLUtil.glDeleteTexture;
-import static net.runelite.client.plugins.gpu.GLUtil.glDeleteVertexArrays;
-import static net.runelite.client.plugins.gpu.GLUtil.glGenBuffers;
-import static net.runelite.client.plugins.gpu.GLUtil.glGetInteger;
-import static net.runelite.client.plugins.gpu.GLUtil.glGenFrameBuffer;
-import static net.runelite.client.plugins.gpu.GLUtil.glGenRenderbuffer;
-import static net.runelite.client.plugins.gpu.GLUtil.glGenTexture;
-import static net.runelite.client.plugins.gpu.GLUtil.glGenVertexArrays;
-import static net.runelite.client.plugins.gpu.GLUtil.inputStreamToString;
+import static net.runelite.client.plugins.gpu.GLUtil.*;
import net.runelite.client.plugins.gpu.config.AntiAliasingMode;
import net.runelite.client.plugins.gpu.template.Template;
import net.runelite.client.ui.DrawManager;
@@ -1021,7 +1013,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
renderWidthOff = (int) Math.floor(scaleFactorX * (renderWidthOff )) - padding;
}
- gl.glViewport(renderWidthOff, renderCanvasHeight - renderViewportHeight - renderHeightOff, renderViewportWidth, renderViewportHeight);
+ glDpiAwareViewport(renderWidthOff, renderCanvasHeight - renderViewportHeight - renderHeightOff, renderViewportWidth, renderViewportHeight);
gl.glUseProgram(glProgram);
@@ -1151,16 +1143,14 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, width, height, gl.GL_BGRA, gl.GL_UNSIGNED_INT_8_8_8_8_REV, interfaceBuffer);
}
- gl.glBindTexture(gl.GL_TEXTURE_2D, interfaceTexture);
-
if (client.isStretchedEnabled())
{
Dimension dim = client.getStretchedDimensions();
- gl.glViewport(0, 0, dim.width, dim.height);
+ glDpiAwareViewport(0, 0, dim.width, dim.height);
}
else
{
- gl.glViewport(0, 0, canvasWidth, canvasHeight);
+ glDpiAwareViewport(0, 0, canvasWidth, canvasHeight);
}
// Use the texture bound in the first pass
@@ -1455,4 +1445,18 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
}
}
+ private int getScaledValue(final double scale, final int value)
+ {
+ return SurfaceScaleUtils.scale(value, (float) scale);
+ }
+
+ private void glDpiAwareViewport(final int x, final int y, final int width, final int height)
+ {
+ final AffineTransform t = ((Graphics2D) canvas.getGraphics()).getTransform();
+ gl.glViewport(
+ getScaledValue(t.getScaleX(), x),
+ getScaledValue(t.getScaleY(), y),
+ getScaledValue(t.getScaleX(), width),
+ getScaledValue(t.getScaleY(), height));
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java
index 1c28371c56..445f6c60d1 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java
@@ -300,7 +300,7 @@ class SceneUploader
int vertexCx = localX + Perspective.LOCAL_TILE_SIZE;
int vertexCy = localY;
int vertexCz = seHeight;
- final int c2 = nwColor;
+ final int c2 = seColor;
// 1,1
int vertexAx = localX + Perspective.LOCAL_TILE_SIZE;
@@ -312,7 +312,7 @@ class SceneUploader
int vertexBx = localX;
int vertexBy = localY + Perspective.LOCAL_TILE_SIZE;
int vertexBz = nwHeight;
- final int c4 = seColor;
+ final int c4 = nwColor;
vertexBuffer.put(vertexAx, vertexAz, vertexAy, c3);
vertexBuffer.put(vertexBx, vertexBz, vertexBy, c4);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java
index cd4f3f050e..5c81aca1b4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java
@@ -1,5 +1,5 @@
/*
- *
+ * Copyright (c) 2019, Adam
* Copyright (c) 2017, Robbie
* Copyright (c) 2018, SomeoneWithAnInternetConnection
* All rights reserved.
@@ -46,6 +46,7 @@ import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.GrandExchangeOffer;
+import net.runelite.api.GrandExchangeOfferState;
import net.runelite.api.ItemComposition;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
@@ -56,11 +57,15 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.GrandExchangeOfferChanged;
import net.runelite.api.events.MenuEntryAdded;
+import net.runelite.client.events.SessionClose;
+import net.runelite.client.events.SessionOpen;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.Notifier;
+import net.runelite.client.account.AccountSession;
+import net.runelite.client.account.SessionManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
@@ -73,8 +78,10 @@ import net.runelite.client.ui.NavigationButton;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.StackFormatter;
import net.runelite.client.util.Text;
-import net.runelite.http.api.osbuddy.GrandExchangeClient;
-import net.runelite.http.api.osbuddy.GrandExchangeResult;
+import net.runelite.http.api.ge.GrandExchangeClient;
+import net.runelite.http.api.ge.GrandExchangeTrade;
+import net.runelite.http.api.osbuddy.OSBGrandExchangeClient;
+import net.runelite.http.api.osbuddy.OSBGrandExchangeResult;
@PluginDescriptor(
name = "Grand Exchange",
@@ -86,7 +93,7 @@ public class GrandExchangePlugin extends Plugin
{
private static final int OFFER_CONTAINER_ITEM = 21;
private static final int OFFER_DEFAULT_ITEM_ID = 6512;
- private static final GrandExchangeClient CLIENT = new GrandExchangeClient();
+ private static final OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient();
private static final String OSB_GE_TEXT = "
OSBuddy Actively traded price: ";
private static final String BUY_LIMIT_GE_TEXT = "
Buy limit: ";
@@ -134,10 +141,38 @@ public class GrandExchangePlugin extends Plugin
@Inject
private ScheduledExecutorService executorService;
+ @Inject
+ private SessionManager sessionManager;
+
+ @Inject
+ private ConfigManager configManager;
+
private Widget grandExchangeText;
private Widget grandExchangeItem;
private Map itemGELimits;
+ private GrandExchangeClient grandExchangeClient;
+
+ private SavedOffer getOffer(int slot)
+ {
+ String offer = configManager.getConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
+ if (offer == null)
+ {
+ return null;
+ }
+ return GSON.fromJson(offer, SavedOffer.class);
+ }
+
+ private void setOffer(int slot, SavedOffer offer)
+ {
+ configManager.setConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot), GSON.toJson(offer));
+ }
+
+ private void deleteOffer(int slot)
+ {
+ configManager.unsetConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
+ }
+
@Provides
GrandExchangeConfig provideConfig(ConfigManager configManager)
{
@@ -167,6 +202,12 @@ public class GrandExchangePlugin extends Plugin
mouseManager.registerMouseListener(inputListener);
keyManager.registerKeyListener(inputListener);
}
+
+ AccountSession accountSession = sessionManager.getAccountSession();
+ if (accountSession != null)
+ {
+ grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
+ }
}
@Override
@@ -178,6 +219,27 @@ public class GrandExchangePlugin extends Plugin
grandExchangeText = null;
grandExchangeItem = null;
itemGELimits = null;
+ grandExchangeClient = null;
+ }
+
+ @Subscribe
+ public void onSessionOpen(SessionOpen sessionOpen)
+ {
+ AccountSession accountSession = sessionManager.getAccountSession();
+ if (accountSession.getUuid() != null)
+ {
+ grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
+ }
+ else
+ {
+ grandExchangeClient = null;
+ }
+ }
+
+ @Subscribe
+ public void onSessionClose(SessionClose sessionClose)
+ {
+ grandExchangeClient = null;
}
@Subscribe
@@ -204,11 +266,79 @@ public class GrandExchangePlugin extends Plugin
@Subscribe
public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent)
{
- GrandExchangeOffer offer = offerEvent.getOffer();
+ final int slot = offerEvent.getSlot();
+ final GrandExchangeOffer offer = offerEvent.getOffer();
+
ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId());
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
- SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offerEvent.getOffer(), offerEvent.getSlot()));
+ SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offer, slot));
+
+ submitTrades(slot, offer);
+
+ updateConfig(slot, offer);
+ }
+
+ private void submitTrades(int slot, GrandExchangeOffer offer)
+ {
+ if (grandExchangeClient == null)
+ {
+ return;
+ }
+
+ // Only interested in offers which are fully bought/sold
+ if (offer.getState() != GrandExchangeOfferState.BOUGHT && offer.getState() != GrandExchangeOfferState.SOLD)
+ {
+ return;
+ }
+
+ SavedOffer savedOffer = getOffer(slot);
+ if (!shouldUpdate(savedOffer, offer))
+ {
+ return;
+ }
+
+ // getPrice() is the price of the offer, not necessarily what the item bought at
+ int priceEach = offer.getSpent() / offer.getTotalQuantity();
+
+ GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
+ grandExchangeTrade.setBuy(offer.getState() == GrandExchangeOfferState.BOUGHT);
+ grandExchangeTrade.setItemId(offer.getItemId());
+ grandExchangeTrade.setQuantity(offer.getTotalQuantity());
+ grandExchangeTrade.setPrice(priceEach);
+
+ log.debug("Submitting trade: {}", grandExchangeTrade);
+ grandExchangeClient.submit(grandExchangeTrade);
+ }
+
+ private void updateConfig(int slot, GrandExchangeOffer offer)
+ {
+ if (offer.getState() == GrandExchangeOfferState.EMPTY)
+ {
+ deleteOffer(slot);
+ }
+ else
+ {
+ SavedOffer savedOffer = new SavedOffer();
+ savedOffer.setItemId(offer.getItemId());
+ savedOffer.setQuantitySold(offer.getQuantitySold());
+ savedOffer.setTotalQuantity(offer.getTotalQuantity());
+ savedOffer.setPrice(offer.getPrice());
+ savedOffer.setSpent(offer.getSpent());
+ savedOffer.setState(offer.getState());
+ setOffer(slot, savedOffer);
+ }
+ }
+
+ private boolean shouldUpdate(SavedOffer savedOffer, GrandExchangeOffer grandExchangeOffer)
+ {
+ if (savedOffer == null)
+ {
+ return false;
+ }
+
+ // Only update offer if state has changed
+ return savedOffer.getState() != grandExchangeOffer.getState();
}
@Subscribe
@@ -346,7 +476,7 @@ public class GrandExchangePlugin extends Plugin
try
{
- final GrandExchangeResult result = CLIENT.lookupItem(itemId);
+ final OSBGrandExchangeResult result = CLIENT.lookupItem(itemId);
final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average());
geText.setText(text);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/SavedOffer.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/SavedOffer.java
new file mode 100644
index 0000000000..58a4055fed
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/SavedOffer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.grandexchange;
+
+import lombok.Data;
+import net.runelite.api.GrandExchangeOfferState;
+
+@Data
+class SavedOffer
+{
+ private int itemId;
+ private int quantitySold;
+ private int totalQuantity;
+ private int price;
+ private int spent;
+ private GrandExchangeOfferState state;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/ColorTileMarker.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/ColorTileMarker.java
new file mode 100644
index 0000000000..6a6a30a065
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/ColorTileMarker.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019, Jordan Atwood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.groundmarkers;
+
+import java.awt.Color;
+import lombok.Value;
+import net.runelite.api.coords.WorldPoint;
+
+/**
+ * Used to denote marked tiles and their colors.
+ * Note: This is not used for serialization of ground markers; see {@link GroundMarkerPoint}
+ */
+@Value
+class ColorTileMarker
+{
+ private WorldPoint worldPoint;
+ private Color color;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerConfig.java
index d77f3ab9f5..ba8cb98e14 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerConfig.java
@@ -23,7 +23,6 @@
* (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.groundmarkers;
import java.awt.Color;
@@ -45,4 +44,14 @@ public interface GroundMarkerConfig extends Config
{
return Color.YELLOW;
}
+
+ @ConfigItem(
+ keyName = "rememberTileColors",
+ name = "Remember color per tile",
+ description = "Color tiles using the color from time of placement"
+ )
+ default boolean rememberTileColors()
+ {
+ return false;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerInputListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerInputListener.java
index 3b87dd1802..a097d47d29 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerInputListener.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerInputListener.java
@@ -64,4 +64,4 @@ public class GroundMarkerInputListener implements KeyListener
plugin.setHotKeyPressed(false);
}
}
-}
\ No newline at end of file
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerOverlay.java
index ccd6fd7483..768d90b51b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerOverlay.java
@@ -25,10 +25,11 @@
*/
package net.runelite.client.plugins.groundmarkers;
+import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
-import java.util.List;
+import java.util.Collection;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Perspective;
@@ -42,6 +43,8 @@ import net.runelite.client.ui.overlay.OverlayUtil;
public class GroundMarkerOverlay extends Overlay
{
+ private static final int MAX_DRAW_DISTANCE = 32;
+
private final Client client;
private final GroundMarkerConfig config;
private final GroundMarkerPlugin plugin;
@@ -60,25 +63,33 @@ public class GroundMarkerOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
- List points = plugin.getPoints();
- for (WorldPoint point : points)
+ final Collection points = plugin.getPoints();
+ for (final ColorTileMarker point : points)
{
- if (point.getPlane() != client.getPlane())
+ WorldPoint worldPoint = point.getWorldPoint();
+ if (worldPoint.getPlane() != client.getPlane())
{
continue;
}
- drawTile(graphics, point);
+ Color tileColor = point.getColor();
+ if (tileColor == null || !config.rememberTileColors())
+ {
+ // If this is an old tile which has no color, or rememberTileColors is off, use marker color
+ tileColor = config.markerColor();
+ }
+
+ drawTile(graphics, worldPoint, tileColor);
}
return null;
}
- private void drawTile(Graphics2D graphics, WorldPoint point)
+ private void drawTile(Graphics2D graphics, WorldPoint point, Color color)
{
WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation();
- if (point.distanceTo(playerLocation) >= 32)
+ if (point.distanceTo(playerLocation) >= MAX_DRAW_DISTANCE)
{
return;
}
@@ -95,6 +106,6 @@ public class GroundMarkerOverlay extends Overlay
return;
}
- OverlayUtil.renderPolygon(graphics, poly, config.markerColor());
+ OverlayUtil.renderPolygon(graphics, poly, color);
}
-}
\ No newline at end of file
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java
index 12ceda382a..40e7ff72cf 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java
@@ -34,13 +34,13 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
-import static net.runelite.api.Constants.CHUNK_SIZE;
import net.runelite.api.GameState;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
@@ -69,19 +69,23 @@ public class GroundMarkerPlugin extends Plugin
private static final String CONFIG_GROUP = "groundMarker";
private static final String MARK = "Mark tile";
private static final String WALK_HERE = "Walk here";
+ private static final String REGION_PREFIX = "region_";
- private static final Gson gson = new Gson();
+ private static final Gson GSON = new Gson();
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
private boolean hotKeyPressed;
@Getter(AccessLevel.PACKAGE)
- private final List points = new ArrayList<>();
+ private final List points = new ArrayList<>();
@Inject
private Client client;
+ @Inject
+ private GroundMarkerConfig config;
+
@Inject
private GroundMarkerInputListener inputListener;
@@ -101,24 +105,25 @@ public class GroundMarkerPlugin extends Plugin
{
if (points == null || points.isEmpty())
{
- configManager.unsetConfiguration(CONFIG_GROUP, "region_" + regionId);
+ configManager.unsetConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId);
return;
}
- String json = gson.toJson(points);
- configManager.setConfiguration(CONFIG_GROUP, "region_" + regionId, json);
+ String json = GSON.toJson(points);
+ configManager.setConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId, json);
}
private Collection getPoints(int regionId)
{
- String json = configManager.getConfiguration(CONFIG_GROUP, "region_" + regionId);
+ String json = configManager.getConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId);
if (Strings.isNullOrEmpty(json))
{
- return Collections.EMPTY_LIST;
+ return Collections.emptyList();
}
- return gson.fromJson(json, new TypeToken>()
- {
- }.getType());
+
+ // CHECKSTYLE:OFF
+ return GSON.fromJson(json, new TypeToken>(){}.getType());
+ // CHECKSTYLE:ON
}
@Provides
@@ -132,110 +137,46 @@ public class GroundMarkerPlugin extends Plugin
points.clear();
int[] regions = client.getMapRegions();
+
+ if (regions == null)
+ {
+ return;
+ }
+
for (int regionId : regions)
{
// load points for region
log.debug("Loading points for region {}", regionId);
Collection regionPoints = getPoints(regionId);
- Collection worldPoints = translateToWorld(regionPoints);
- points.addAll(worldPoints);
+ Collection colorTileMarkers = translateToColorTileMarker(regionPoints);
+ points.addAll(colorTileMarkers);
}
}
/**
- * Translate a collection of ground marker points to world points, accounting for instances
+ * Translate a collection of ground marker points to color tile markers, accounting for instances
*
- * @param points
- * @return
+ * @param points {@link GroundMarkerPoint}s to be converted to {@link ColorTileMarker}s
+ * @return A collection of color tile markers, converted from the passed ground marker points, accounting for local
+ * instance points. See {@link WorldPoint#toLocalInstance(Client, WorldPoint)}
*/
- private Collection translateToWorld(Collection points)
+ private Collection translateToColorTileMarker(Collection points)
{
if (points.isEmpty())
{
- return Collections.EMPTY_LIST;
+ return Collections.emptyList();
}
- List worldPoints = new ArrayList<>();
- for (GroundMarkerPoint point : points)
- {
- int regionId = point.getRegionId();
- int regionX = point.getRegionX();
- int regionY = point.getRegionY();
- int z = point.getZ();
-
- // world point of the tile marker
- WorldPoint worldPoint = new WorldPoint(
- ((regionId >>> 8) << 6) + regionX,
- ((regionId & 0xff) << 6) + regionY,
- z
- );
-
- if (!client.isInInstancedRegion())
+ return points.stream()
+ .map(point -> new ColorTileMarker(
+ WorldPoint.fromRegion(point.getRegionId(), point.getRegionX(), point.getRegionY(), point.getZ()),
+ point.getColor()))
+ .flatMap(colorTile ->
{
- worldPoints.add(worldPoint);
- continue;
- }
-
- // find instance chunks using the template point. there might be more than one.
- int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks();
- for (int x = 0; x < instanceTemplateChunks[z].length; ++x)
- {
- for (int y = 0; y < instanceTemplateChunks[z][x].length; ++y)
- {
- int chunkData = instanceTemplateChunks[z][x][y];
- int rotation = chunkData >> 1 & 0x3;
- int templateChunkY = (chunkData >> 3 & 0x7FF) * CHUNK_SIZE;
- int templateChunkX = (chunkData >> 14 & 0x3FF) * CHUNK_SIZE;
- if (worldPoint.getX() >= templateChunkX && worldPoint.getX() < templateChunkX + CHUNK_SIZE
- && worldPoint.getY() >= templateChunkY && worldPoint.getY() < templateChunkY + CHUNK_SIZE)
- {
- WorldPoint p = new WorldPoint(client.getBaseX() + x * CHUNK_SIZE + (worldPoint.getX() & (CHUNK_SIZE - 1)),
- client.getBaseY() + y * CHUNK_SIZE + (worldPoint.getY() & (CHUNK_SIZE - 1)),
- worldPoint.getPlane());
- p = rotate(p, rotation);
- worldPoints.add(p);
- }
- }
- }
- }
- return worldPoints;
- }
-
- /**
- * Rotate the chunk containing the given point to rotation 0
- *
- * @param point point
- * @param rotation rotation
- * @return world point
- */
- private static WorldPoint rotateInverse(WorldPoint point, int rotation)
- {
- return rotate(point, 4 - rotation);
- }
-
- /**
- * Rotate the coordinates in the chunk according to chunk rotation
- *
- * @param point point
- * @param rotation rotation
- * @return world point
- */
- private static WorldPoint rotate(WorldPoint point, int rotation)
- {
- int chunkX = point.getX() & ~(CHUNK_SIZE - 1);
- int chunkY = point.getY() & ~(CHUNK_SIZE - 1);
- int x = point.getX() & (CHUNK_SIZE - 1);
- int y = point.getY() & (CHUNK_SIZE - 1);
- switch (rotation)
- {
- case 1:
- return new WorldPoint(chunkX + y, chunkY + (CHUNK_SIZE - 1 - x), point.getPlane());
- case 2:
- return new WorldPoint(chunkX + (CHUNK_SIZE - 1 - x), chunkY + (CHUNK_SIZE - 1 - y), point.getPlane());
- case 3:
- return new WorldPoint(chunkX + (CHUNK_SIZE - 1 - y), chunkY + x, point.getPlane());
- }
- return point;
+ final Collection localWorldPoints = WorldPoint.toLocalInstance(client, colorTile.getWorldPoint());
+ return localWorldPoints.stream().map(wp -> new ColorTileMarker(wp, colorTile.getColor()));
+ })
+ .collect(Collectors.toList());
}
@Subscribe
@@ -298,6 +239,7 @@ public class GroundMarkerPlugin extends Plugin
{
overlayManager.add(overlay);
keyManager.registerKeyListener(inputListener);
+ loadPoints();
}
@Override
@@ -305,10 +247,10 @@ public class GroundMarkerPlugin extends Plugin
{
overlayManager.remove(overlay);
keyManager.unregisterKeyListener(inputListener);
+ points.clear();
}
-
- protected void markTile(LocalPoint localPoint)
+ private void markTile(LocalPoint localPoint)
{
if (localPoint == null)
{
@@ -318,21 +260,21 @@ public class GroundMarkerPlugin extends Plugin
WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, localPoint);
int regionId = worldPoint.getRegionID();
- GroundMarkerPoint point = new GroundMarkerPoint(regionId, worldPoint.getX() & 0x3f, worldPoint.getY() & 0x3f, client.getPlane());
+ GroundMarkerPoint point = new GroundMarkerPoint(regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), client.getPlane(), config.markerColor());
log.debug("Updating point: {} - {}", point, worldPoint);
- List points = new ArrayList<>(getPoints(regionId));
- if (points.contains(point))
+ List groundMarkerPoints = new ArrayList<>(getPoints(regionId));
+ if (groundMarkerPoints.contains(point))
{
- points.remove(point);
+ groundMarkerPoints.remove(point);
}
else
{
- points.add(point);
+ groundMarkerPoints.add(point);
}
- savePoints(regionId, points);
+ savePoints(regionId, groundMarkerPoints);
loadPoints();
}
-}
\ No newline at end of file
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java
index b31db32222..3e10a654c0 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java
@@ -23,16 +23,22 @@
* (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.groundmarkers;
+import java.awt.Color;
+import lombok.EqualsAndHashCode;
import lombok.Value;
+/**
+ * Used for serialization of ground marker points.
+ */
@Value
-public class GroundMarkerPoint
+@EqualsAndHashCode(exclude = { "color" })
+class GroundMarkerPoint
{
private int regionId;
private int regionX;
private int regionY;
private int z;
-}
\ No newline at end of file
+ private Color color;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java
index 9a47e57de0..c49eb37f8f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java
@@ -47,6 +47,7 @@ import net.runelite.api.Varbits;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
+import net.runelite.api.events.GraphicChanged;
import net.runelite.api.events.HitsplatApplied;
import net.runelite.api.events.InteractingChanged;
import net.runelite.client.Notifier;
@@ -196,12 +197,14 @@ public class IdleNotifierPlugin extends Plugin
case MINING_MOTHERLODE_INFERNAL:
case MINING_MOTHERLODE_3A:
/* Herblore */
+ case HERBLORE_PESTLE_AND_MORTAR:
case HERBLORE_POTIONMAKING:
case HERBLORE_MAKE_TAR:
/* Magic */
case MAGIC_CHARGING_ORBS:
case MAGIC_LUNAR_STRING_JEWELRY:
case MAGIC_MAKE_TABLET:
+ case MAGIC_ENCHANTING_JEWELRY:
/* Prayer */
case USING_GILDED_ALTAR:
/* Farming */
@@ -329,6 +332,22 @@ public class IdleNotifierPlugin extends Plugin
}
}
+ @Subscribe
+ public void onGraphicChanged(GraphicChanged event)
+ {
+ Actor actor = event.getActor();
+
+ if (actor != client.getLocalPlayer())
+ {
+ return;
+ }
+
+ if (actor.getGraphic() == GraphicID.SPLASH)
+ {
+ lastCombatCountdown = HIGHEST_MONSTER_ATTACK_SPEED;
+ }
+ }
+
@Subscribe
public void onGameTick(GameTick event)
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java
index 2edb250135..f9dc12f4e7 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java
@@ -40,14 +40,16 @@ import javax.inject.Singleton;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.HyperlinkEvent;
import net.runelite.api.Client;
-import net.runelite.api.events.SessionClose;
-import net.runelite.api.events.SessionOpen;
+import net.runelite.client.events.SessionClose;
+import net.runelite.client.events.SessionOpen;
import net.runelite.client.RuneLiteProperties;
import net.runelite.client.account.SessionManager;
+import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.ui.ColorScheme;
@@ -66,9 +68,12 @@ public class InfoPanel extends PluginPanel
private static final ImageIcon DISCORD_ICON;
private static final ImageIcon PATREON_ICON;
private static final ImageIcon WIKI_ICON;
+ private static final ImageIcon IMPORT_ICON;
private final JLabel loggedLabel = new JLabel();
private final JRichTextPane emailLabel = new JRichTextPane();
+ private JPanel syncPanel;
+ private JPanel actionsContainer;
@Inject
@Nullable
@@ -86,6 +91,9 @@ public class InfoPanel extends PluginPanel
@Inject
private ScheduledExecutorService executor;
+ @Inject
+ private ConfigManager configManager;
+
static
{
ARROW_RIGHT_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "/util/arrow_right.png"));
@@ -93,6 +101,7 @@ public class InfoPanel extends PluginPanel
DISCORD_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "discord_icon.png"));
PATREON_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "patreon_icon.png"));
WIKI_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "wiki_icon.png"));
+ IMPORT_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "import_icon.png"));
}
void init()
@@ -150,11 +159,22 @@ public class InfoPanel extends PluginPanel
versionPanel.add(loggedLabel);
versionPanel.add(emailLabel);
- updateLoggedIn();
-
- JPanel actionsContainer = new JPanel();
+ actionsContainer = new JPanel();
actionsContainer.setBorder(new EmptyBorder(10, 0, 0, 0));
- actionsContainer.setLayout(new GridLayout(4, 1, 0, 10));
+ actionsContainer.setLayout(new GridLayout(0, 1, 0, 10));
+
+ syncPanel = buildLinkPanel(IMPORT_ICON, "Import local settings", "to remote RuneLite account", () ->
+ {
+ final int result = JOptionPane.showOptionDialog(syncPanel,
+ "This will replace your current RuneLite account settings with settings from your local profile.",
+ "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, new String[]{"Yes", "No"}, "No");
+
+ if (result == JOptionPane.YES_OPTION)
+ {
+ configManager.importLocal();
+ }
+ });
actionsContainer.add(buildLinkPanel(GITHUB_ICON, "Report an issue or", "make a suggestion", runeLiteProperties.getGithubLink()));
actionsContainer.add(buildLinkPanel(DISCORD_ICON, "Talk to us on our", "discord server", runeLiteProperties.getDiscordInvite()));
@@ -164,6 +184,7 @@ public class InfoPanel extends PluginPanel
add(versionPanel, BorderLayout.NORTH);
add(actionsContainer, BorderLayout.CENTER);
+ updateLoggedIn();
eventBus.register(this);
}
@@ -171,6 +192,14 @@ public class InfoPanel extends PluginPanel
* Builds a link panel with a given icon, text and url to redirect to.
*/
private static JPanel buildLinkPanel(ImageIcon icon, String topText, String bottomText, String url)
+ {
+ return buildLinkPanel(icon, topText, bottomText, () -> LinkBrowser.browse(url));
+ }
+
+ /**
+ * Builds a link panel with a given icon, text and callable to call.
+ */
+ private static JPanel buildLinkPanel(ImageIcon icon, String topText, String bottomText, Runnable callback)
{
JPanel container = new JPanel();
container.setBackground(ColorScheme.DARKER_GRAY_COLOR);
@@ -193,7 +222,6 @@ public class InfoPanel extends PluginPanel
@Override
public void mousePressed(MouseEvent mouseEvent)
{
- LinkBrowser.browse(url);
container.setBackground(pressedColor);
textContainer.setBackground(pressedColor);
}
@@ -201,6 +229,7 @@ public class InfoPanel extends PluginPanel
@Override
public void mouseReleased(MouseEvent e)
{
+ callback.run();
container.setBackground(hoverColor);
textContainer.setBackground(hoverColor);
}
@@ -252,12 +281,14 @@ public class InfoPanel extends PluginPanel
emailLabel.setContentType("text/plain");
emailLabel.setText(name);
loggedLabel.setText("Logged in as");
+ actionsContainer.add(syncPanel, 0);
}
else
{
emailLabel.setContentType("text/html");
emailLabel.setText("Login to sync settings to the cloud.");
loggedLabel.setText("Not logged in");
+ actionsContainer.remove(syncPanel);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java
index 40488c5137..28c503b20a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java
@@ -203,4 +203,15 @@ public interface ItemChargeConfig extends Config
{
return false;
}
+
+ @ConfigItem(
+ keyName = "showInfoboxes",
+ name = "Show Infoboxes",
+ description = "Configures whether to show an infobox equipped charge items",
+ position = 15
+ )
+ default boolean showInfoboxes()
+ {
+ return false;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeInfobox.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeInfobox.java
new file mode 100644
index 0000000000..7ee70d44b5
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeInfobox.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018, 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.itemcharges;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import lombok.Getter;
+import net.runelite.api.EquipmentInventorySlot;
+import net.runelite.client.ui.overlay.infobox.Counter;
+
+@Getter
+class ItemChargeInfobox extends Counter
+{
+ private final ItemChargePlugin plugin;
+ private final ItemWithSlot item;
+ private final EquipmentInventorySlot slot;
+
+ ItemChargeInfobox(
+ ItemChargePlugin plugin,
+ BufferedImage image,
+ String name,
+ int charges,
+ ItemWithSlot item,
+ EquipmentInventorySlot slot)
+ {
+ super(image, plugin, charges);
+ setTooltip(name);
+ this.plugin = plugin;
+ this.item = item;
+ this.slot = slot;
+ }
+
+ @Override
+ public Color getTextColor()
+ {
+ return getPlugin().getColor(getCount());
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java
index 7730d46ffd..27bb35b21d 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java
@@ -24,7 +24,6 @@
*/
package net.runelite.client.plugins.itemcharges;
-import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
@@ -83,7 +82,7 @@ class ItemChargeOverlay extends Overlay
continue;
}
- charges = itemChargePlugin.getDodgyCharges();
+ charges = config.dodgyNecklace();
}
else
{
@@ -112,7 +111,7 @@ class ItemChargeOverlay extends Overlay
final TextComponent textComponent = new TextComponent();
textComponent.setPosition(new Point(bounds.x, bounds.y + 16));
textComponent.setText(charges < 0 ? "?" : String.valueOf(charges));
- textComponent.setColor(getColor(charges));
+ textComponent.setColor(itemChargePlugin.getColor(charges));
textComponent.render(graphics);
}
return null;
@@ -137,20 +136,6 @@ class ItemChargeOverlay extends Overlay
return jewellery;
}
- private Color getColor(int charges)
- {
- Color color = Color.WHITE;
- if (charges <= config.veryLowWarning())
- {
- color = config.veryLowWarningColor();
- }
- else if (charges <= config.lowWarning())
- {
- color = config.lowWarningolor();
- }
- return color;
- }
-
private boolean displayOverlay()
{
return config.showTeleportCharges() || config.showDodgyCount() || config.showFungicideCharges()
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java
index c545e9a5bb..e295efd9e5 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Seth
+ * Copyright (c) 2018, Hydrox6
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,19 +26,29 @@
package net.runelite.client.plugins.itemcharges;
import com.google.inject.Provides;
+import java.awt.Color;
+import java.awt.image.BufferedImage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
-import lombok.AccessLevel;
-import lombok.Getter;
import net.runelite.api.ChatMessageType;
+import net.runelite.api.Client;
+import net.runelite.api.EquipmentInventorySlot;
+import net.runelite.api.InventoryID;
+import net.runelite.api.Item;
+import net.runelite.api.ItemContainer;
+import net.runelite.api.ItemID;
import net.runelite.api.events.ChatMessage;
+import net.runelite.api.events.ConfigChanged;
+import net.runelite.api.events.ItemContainerChanged;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
+import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
@PluginDescriptor(
name = "Item Charges",
@@ -56,21 +67,27 @@ public class ItemChargePlugin extends Plugin
private static final int MAX_DODGY_CHARGES = 10;
+ @Inject
+ private Client client;
+
@Inject
private OverlayManager overlayManager;
@Inject
private ItemChargeOverlay overlay;
+ @Inject
+ private ItemManager itemManager;
+
+ @Inject
+ private InfoBoxManager infoBoxManager;
+
@Inject
private Notifier notifier;
@Inject
private ItemChargeConfig config;
- @Getter(AccessLevel.PACKAGE)
- private int dodgyCharges;
-
@Provides
ItemChargeConfig getConfig(ConfigManager configManager)
{
@@ -81,13 +98,43 @@ public class ItemChargePlugin extends Plugin
protected void startUp()
{
overlayManager.add(overlay);
- dodgyCharges = config.dodgyNecklace();
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
+ infoBoxManager.removeIf(ItemChargeInfobox.class::isInstance);
+ }
+
+ @Subscribe
+ public void onConfigChanged(ConfigChanged event)
+ {
+ if (!event.getGroup().equals("itemCharge"))
+ {
+ return;
+ }
+
+ if (!config.showInfoboxes())
+ {
+ infoBoxManager.removeIf(ItemChargeInfobox.class::isInstance);
+ return;
+ }
+
+ if (!config.showTeleportCharges())
+ {
+ removeInfobox(ItemWithSlot.TELEPORT);
+ }
+
+ if (!config.showAbyssalBraceletCharges())
+ {
+ removeInfobox(ItemWithSlot.ABYSSAL_BRACELET);
+ }
+
+ if (!config.showDodgyCount())
+ {
+ removeInfobox(ItemWithSlot.DODGY_NECKLACE);
+ }
}
@Subscribe
@@ -110,22 +157,141 @@ public class ItemChargePlugin extends Plugin
notifier.notify("Your dodgy necklace has crumbled to dust.");
}
- setDodgyCharges(MAX_DODGY_CHARGES);
+ updateDodgyNecklaceCharges(MAX_DODGY_CHARGES);
}
else if (dodgyCheckMatcher.find())
{
- setDodgyCharges(Integer.parseInt(dodgyCheckMatcher.group(1)));
+ updateDodgyNecklaceCharges(Integer.parseInt(dodgyCheckMatcher.group(1)));
}
else if (dodgyProtectMatcher.find())
{
- setDodgyCharges(Integer.parseInt(dodgyProtectMatcher.group(1)));
+ updateDodgyNecklaceCharges(Integer.parseInt(dodgyProtectMatcher.group(1)));
}
}
}
- private void setDodgyCharges(int dodgyCharges)
+ @Subscribe
+ public void onItemContainerChanged(ItemContainerChanged event)
{
- this.dodgyCharges = dodgyCharges;
- config.dodgyNecklace(dodgyCharges);
+ if (event.getItemContainer() != client.getItemContainer(InventoryID.EQUIPMENT) || !config.showInfoboxes())
+ {
+ return;
+ }
+
+ final Item[] items = event.getItemContainer().getItems();
+
+ if (config.showTeleportCharges())
+ {
+ updateJewelleryInfobox(ItemWithSlot.TELEPORT, items);
+ }
+
+ if (config.showDodgyCount())
+ {
+ updateJewelleryInfobox(ItemWithSlot.DODGY_NECKLACE, items);
+ }
+
+ if (config.showAbyssalBraceletCharges())
+ {
+ updateJewelleryInfobox(ItemWithSlot.ABYSSAL_BRACELET, items);
+ }
+ }
+
+ private void updateDodgyNecklaceCharges(final int value)
+ {
+ config.dodgyNecklace(value);
+
+ if (config.showInfoboxes() && config.showDodgyCount())
+ {
+ final ItemContainer itemContainer = client.getItemContainer(InventoryID.EQUIPMENT);
+
+ if (itemContainer == null)
+ {
+ return;
+ }
+
+ updateJewelleryInfobox(ItemWithSlot.DODGY_NECKLACE, itemContainer.getItems());
+ }
+ }
+
+ private void updateJewelleryInfobox(ItemWithSlot item, Item[] items)
+ {
+ for (final EquipmentInventorySlot equipmentInventorySlot : item.getSlots())
+ {
+ updateJewelleryInfobox(item, items, equipmentInventorySlot);
+ }
+ }
+
+ private void updateJewelleryInfobox(ItemWithSlot type, Item[] items, EquipmentInventorySlot slot)
+ {
+ removeInfobox(type, slot);
+
+ if (slot.getSlotIdx() >= items.length)
+ {
+ return;
+ }
+
+ final int id = items[slot.getSlotIdx()].getId();
+ if (id < 0)
+ {
+ return;
+ }
+
+ final ItemWithCharge itemWithCharge = ItemWithCharge.findItem(id);
+ int charges = -1;
+
+ if (itemWithCharge == null)
+ {
+ if (id == ItemID.DODGY_NECKLACE && type == ItemWithSlot.DODGY_NECKLACE)
+ {
+ charges = config.dodgyNecklace();
+ }
+ }
+ else if (itemWithCharge.getType() == type.getType())
+ {
+ charges = itemWithCharge.getCharges();
+ }
+
+ if (charges <= 0)
+ {
+ return;
+ }
+
+ final String name = itemManager.getItemComposition(id).getName();
+ final BufferedImage image = itemManager.getImage(id);
+ final ItemChargeInfobox infobox = new ItemChargeInfobox(this, image, name, charges, type, slot);
+ infoBoxManager.addInfoBox(infobox);
+ }
+
+ private void removeInfobox(final ItemWithSlot item)
+ {
+ infoBoxManager.removeIf(t -> t instanceof ItemChargeInfobox && ((ItemChargeInfobox) t).getItem() == item);
+ }
+
+ private void removeInfobox(final ItemWithSlot item, final EquipmentInventorySlot slot)
+ {
+ infoBoxManager.removeIf(t ->
+ {
+ if (!(t instanceof ItemChargeInfobox))
+ {
+ return false;
+ }
+
+ final ItemChargeInfobox i = (ItemChargeInfobox)t;
+ return i.getItem() == item && i.getSlot() == slot;
+ });
+ }
+
+ Color getColor(int charges)
+ {
+ Color color = Color.WHITE;
+ if (charges <= config.veryLowWarning())
+ {
+ color = config.veryLowWarningColor();
+ }
+ else if (charges <= config.lowWarning())
+ {
+ color = config.lowWarningolor();
+ }
+ return color;
}
}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java
index 2f25c12164..cbe5d20ff3 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java
@@ -32,5 +32,6 @@ enum ItemChargeType
IMPBOX,
TELEPORT,
WATERCAN,
- WATERSKIN
+ WATERSKIN,
+ DODGY_NECKLACE
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithSlot.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithSlot.java
new file mode 100644
index 0000000000..3fbd2bac66
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithSlot.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019, Tomas Slusny
+ * 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.itemcharges;
+
+import com.google.common.collect.Sets;
+import java.util.Set;
+import lombok.Getter;
+import net.runelite.api.EquipmentInventorySlot;
+
+@Getter
+enum ItemWithSlot
+{
+ ABYSSAL_BRACELET(ItemChargeType.ABYSSAL_BRACELET, EquipmentInventorySlot.GLOVES),
+ DODGY_NECKLACE(ItemChargeType.DODGY_NECKLACE, EquipmentInventorySlot.AMULET),
+ TELEPORT(ItemChargeType.TELEPORT, EquipmentInventorySlot.WEAPON, EquipmentInventorySlot.AMULET, EquipmentInventorySlot.GLOVES, EquipmentInventorySlot.RING);
+
+ private final ItemChargeType type;
+ private final Set slots;
+
+ ItemWithSlot(final ItemChargeType type, final EquipmentInventorySlot... slots)
+ {
+ this.type = type;
+ this.slots = Sets.newHashSet(slots);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesConfig.java
index ed69408341..a7b62e52b3 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesConfig.java
@@ -74,4 +74,16 @@ public interface ItemPricesConfig extends Config
{
return true;
}
+
+ @ConfigItem(
+ keyName = "showAlchProfit",
+ name = "Show High Alchemy Profit",
+ description = "Show the profit from casting high alchemy on items",
+ position = 5
+ )
+ default boolean showAlchProfit()
+ {
+ return false;
+ }
+
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java
index 7e170db214..7c748a7702 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java
@@ -196,6 +196,7 @@ class ItemPricesOverlay extends Overlay
int gePrice = 0;
int haPrice = 0;
+ int haProfit = 0;
if (config.showGEPrice())
{
@@ -205,16 +206,20 @@ class ItemPricesOverlay extends Overlay
{
haPrice = Math.round(itemDef.getPrice() * HIGH_ALCHEMY_CONSTANT);
}
+ if (gePrice > 0 && haPrice > 0 && config.showAlchProfit())
+ {
+ haProfit = calculateHAProfit(haPrice, gePrice);
+ }
if (gePrice > 0 || haPrice > 0)
{
- return stackValueText(qty, gePrice, haPrice);
+ return stackValueText(qty, gePrice, haPrice, haProfit);
}
return null;
}
- private String stackValueText(int qty, int gePrice, int haValue)
+ private String stackValueText(int qty, int gePrice, int haValue, int haProfit)
{
if (gePrice > 0)
{
@@ -246,9 +251,36 @@ class ItemPricesOverlay extends Overlay
}
}
+ if (haProfit != 0)
+ {
+ Color haColor = haProfitColor(haProfit);
+
+ itemStringBuilder.append("");
+ itemStringBuilder.append("HA Profit: ")
+ .append(ColorUtil.wrapWithColorTag(String.valueOf(haProfit * qty), haColor))
+ .append(" gp");
+ if (config.showEA() && qty > 1)
+ {
+ itemStringBuilder.append(" (")
+ .append(ColorUtil.wrapWithColorTag(String.valueOf(haProfit), haColor))
+ .append(" ea)");
+ }
+ }
+
// Build string and reset builder
final String text = itemStringBuilder.toString();
itemStringBuilder.setLength(0);
return text;
}
+
+ private int calculateHAProfit(int haPrice, int gePrice)
+ {
+ int natureRunePrice = itemManager.getItemPrice(ItemID.NATURE_RUNE);
+ return haPrice - gePrice - natureRunePrice;
+ }
+
+ private static Color haProfitColor(int haProfit)
+ {
+ return haProfit >= 0 ? Color.GREEN : Color.RED;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java
index 6b66cf57e0..099b5a16a7 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java
@@ -36,6 +36,7 @@ import net.runelite.client.plugins.itemstats.food.Anglerfish;
import net.runelite.client.plugins.itemstats.potions.PrayerPotion;
import net.runelite.client.plugins.itemstats.potions.SaradominBrew;
import net.runelite.client.plugins.itemstats.potions.SuperRestore;
+import net.runelite.client.plugins.itemstats.special.CastleWarsBandage;
import net.runelite.client.plugins.itemstats.special.SpicyStew;
import static net.runelite.client.plugins.itemstats.stats.Stats.*;
@@ -137,6 +138,9 @@ public class ItemStatChanges
// Regular overload (NMZ)
add(combo(5, boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5)), boost(RANGED, perc(.15, 5)), boost(MAGIC, perc(.15, 5)), heal(HITPOINTS, -50)), OVERLOAD_1, OVERLOAD_2, OVERLOAD_3, OVERLOAD_4);
+ // Bandages (Castle Wars)
+ add(new CastleWarsBandage(), BANDAGES);
+
// Recovery potions
add(combo(5, heal(ATTACK, perc(.30, 10)), heal(STRENGTH, perc(.30, 10)), heal(DEFENCE, perc(.30, 10)), heal(RANGED, perc(.30, 10)), heal(MAGIC, perc(.30, 10))), RESTORE_POTION1, RESTORE_POTION2, RESTORE_POTION3, RESTORE_POTION4);
add(heal(RUN_ENERGY, 10), ENERGY_POTION1, ENERGY_POTION2, ENERGY_POTION3, ENERGY_POTION4);
@@ -174,7 +178,7 @@ public class ItemStatChanges
// Misc/run energy
add(heal(RUN_ENERGY, 10), WHITE_TREE_FRUIT);
- add(heal(RUN_ENERGY, 30), STRANGE_FRUIT, BANDAGES);
+ add(heal(RUN_ENERGY, 30), STRANGE_FRUIT);
add(heal(RUN_ENERGY, 50), MINT_CAKE);
add(combo(food(12), heal(RUN_ENERGY, 50)), GOUT_TUBER);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java
index c9fa8af82b..3c7d586a86 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java
@@ -52,6 +52,16 @@ public interface ItemStatConfig extends Config
return true;
}
+ @ConfigItem(
+ keyName = "geStats",
+ name = "Enable GE item information",
+ description = "Shows an item information panel when buying items in the GE"
+ )
+ default boolean geStats()
+ {
+ return true;
+ }
+
@ConfigItem(
keyName = "relative",
name = "Show Relative",
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java
index 986321e966..206ab6fc13 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java
@@ -139,7 +139,7 @@ public class ItemStatOverlay extends Overlay
if (config.equipmentStats())
{
- final ItemStats stats = itemManager.getItemStats(itemId);
+ final ItemStats stats = itemManager.getItemStats(itemId, false);
if (stats != null)
{
@@ -205,7 +205,7 @@ public class ItemStatOverlay extends Overlay
final Item item = items[slot];
if (item != null)
{
- other = itemManager.getItemStats(item.getId());
+ other = itemManager.getItemStats(item.getId(), false);
}
}
@@ -258,7 +258,7 @@ public class ItemStatOverlay extends Overlay
if (config.relative())
{
- b.append(c.getRelative());
+ b.append(c.getFormattedRelative());
}
if (config.theoretical())
@@ -267,7 +267,7 @@ public class ItemStatOverlay extends Overlay
{
b.append("/");
}
- b.append(c.getTheoretical());
+ b.append(c.getFormattedTheoretical());
}
if (config.absolute() && (config.relative() || config.theoretical()))
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatPlugin.java
index 250a6410cd..d8facce32a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatPlugin.java
@@ -24,13 +24,46 @@
*/
package net.runelite.client.plugins.itemstats;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Inject;
import com.google.inject.Provides;
+import java.awt.FontMetrics;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import net.runelite.api.Client;
+import net.runelite.api.FontID;
+import net.runelite.api.InventoryID;
+import net.runelite.api.Item;
+import net.runelite.api.ItemContainer;
+import net.runelite.api.ItemID;
+import net.runelite.api.SpriteID;
+import net.runelite.api.VarPlayer;
+import net.runelite.api.Varbits;
+import net.runelite.api.events.ConfigChanged;
+import net.runelite.api.events.GameTick;
+import net.runelite.api.events.ScriptCallbackEvent;
+import net.runelite.api.events.VarbitChanged;
+import net.runelite.api.widgets.JavaScriptCallback;
+import net.runelite.api.widgets.Widget;
+import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.api.widgets.WidgetTextAlignment;
+import net.runelite.api.widgets.WidgetType;
+import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.ui.FontManager;
+import net.runelite.client.ui.JagexColors;
import net.runelite.client.ui.overlay.OverlayManager;
+import net.runelite.client.util.StackFormatter;
+import net.runelite.http.api.item.ItemEquipmentStats;
+import net.runelite.http.api.item.ItemStats;
@PluginDescriptor(
name = "Item Stats",
@@ -39,12 +72,30 @@ import net.runelite.client.ui.overlay.OverlayManager;
)
public class ItemStatPlugin extends Plugin
{
+ private static final int ORANGE_TEXT = JagexColors.DARK_ORANGE_INTERFACE_TEXT.getRGB();
+ private static final int YELLOW_TEXT = JagexColors.YELLOW_INTERFACE_TEXT.getRGB();
+ private static final int TEXT_HEIGHT = 11;
+
@Inject
private OverlayManager overlayManager;
@Inject
private ItemStatOverlay overlay;
+ @Inject
+ private Client client;
+
+ @Inject
+ private ItemManager itemManager;
+
+ @Inject
+ private ItemStatConfig config;
+
+ @Inject
+ private ClientThread clientThread;
+
+ private Widget itemInformationTitle;
+
@Provides
ItemStatConfig getConfig(ConfigManager configManager)
{
@@ -67,5 +118,320 @@ public class ItemStatPlugin extends Plugin
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
+ clientThread.invokeLater(this::resetGEInventory);
+ }
+
+ @Subscribe
+ public void onConfigChanged(ConfigChanged event)
+ {
+ if (event.getKey().equals("geStats"))
+ {
+ clientThread.invokeLater(this::resetGEInventory);
+ }
+ }
+
+ @Subscribe
+ public void onGameTick(GameTick event)
+ {
+ if (itemInformationTitle != null && config.geStats()
+ && (client.getWidget(WidgetInfo.GRAND_EXCHANGE_WINDOW_CONTAINER) == null
+ || client.getWidget(WidgetInfo.GRAND_EXCHANGE_WINDOW_CONTAINER).isHidden()))
+ {
+ resetGEInventory();
+ }
+ }
+
+ @Subscribe
+ public void onVarbitChanged(VarbitChanged event)
+ {
+ if (client.getVar(VarPlayer.CURRENT_GE_ITEM) == -1 && config.geStats())
+ {
+ resetGEInventory();
+ }
+ }
+
+ @Subscribe
+ public void onScriptCallbackEvent(ScriptCallbackEvent event)
+ {
+ if (event.getEventName().equals("geBuilt") && config.geStats())
+ {
+ int currentGeItem = client.getVar(VarPlayer.CURRENT_GE_ITEM);
+ if (currentGeItem != -1 && client.getVar(Varbits.GE_OFFER_CREATION_TYPE) == 0)
+ {
+ createItemInformation(currentGeItem);
+ }
+ }
+ }
+
+ private void createItemInformation(int id)
+ {
+ final ItemStats itemStats = itemManager.getItemStats(id, false);
+
+ if (itemStats == null || !itemStats.isEquipable())
+ {
+ return;
+ }
+
+ final ItemEquipmentStats equipmentStats = itemStats.getEquipment();
+
+ if (equipmentStats == null)
+ {
+ return;
+ }
+
+ final Widget geInv = client.getWidget(WidgetInfo.GRAND_EXCHANGE_INVENTORY_ITEMS_CONTAINER);
+
+ if (geInv == null)
+ {
+ return;
+ }
+
+ final Widget invContainer = getInventoryContainer();
+
+ if (invContainer == null)
+ {
+ return;
+ }
+
+ invContainer.deleteAllChildren();
+ geInv.setHidden(true);
+
+ int yPos = 0;
+
+ final FontMetrics smallFM = client.getCanvas().getFontMetrics(FontManager.getRunescapeSmallFont());
+
+ // HEADER
+
+ itemInformationTitle = createText(invContainer, "Item Information", FontID.BOLD_12, ORANGE_TEXT,
+ 8, 8, invContainer.getWidth(), 16);
+ itemInformationTitle.setYTextAlignment(WidgetTextAlignment.CENTER);
+
+ Widget closeButton = invContainer.createChild(-1, WidgetType.GRAPHIC);
+ closeButton.setOriginalY(8);
+ closeButton.setOriginalX(invContainer.getWidth() - 24);
+ closeButton.setOriginalHeight(16);
+ closeButton.setOriginalWidth(16);
+ closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL);
+ closeButton.setAction(0, "Close");
+ closeButton.setOnMouseOverListener((JavaScriptCallback) (ev) ->
+ {
+ closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL_HOVERED);
+ });
+ closeButton.setOnMouseLeaveListener((JavaScriptCallback) (ev) ->
+ {
+ closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL);
+ });
+ closeButton.setOnOpListener((JavaScriptCallback) (ev) -> resetGEInventory());
+ closeButton.setHasListener(true);
+ closeButton.revalidate();
+
+ yPos += 15;
+
+ createSeparator(invContainer, yPos);
+
+ // ICON AND TITLE
+
+ yPos += 25;
+
+ Widget icon = invContainer.createChild(-1, WidgetType.GRAPHIC);
+ icon.setOriginalX(8);
+ icon.setOriginalY(yPos);
+ icon.setOriginalWidth(36);
+ icon.setOriginalHeight(32);
+ icon.setItemId(id);
+ icon.setItemQuantityMode(0);
+ icon.setBorderType(1);
+ icon.revalidate();
+
+ Widget itemName = createText(invContainer, itemManager.getItemComposition(id).getName(), FontID.PLAIN_12, ORANGE_TEXT,
+ 50, yPos, invContainer.getWidth() - 40, 30);
+ itemName.setYTextAlignment(WidgetTextAlignment.CENTER);
+
+ yPos += 20;
+
+ createSeparator(invContainer, yPos);
+
+ // STATS HEADER
+
+ yPos += 25;
+
+ createText(invContainer, "Attack", FontID.PLAIN_11, ORANGE_TEXT, 5, yPos, 50, -1);
+
+ int defenceXPos = invContainer.getWidth() - (smallFM.stringWidth("Defence") + 5);
+ createText(invContainer, "Defence", FontID.PLAIN_11, ORANGE_TEXT, defenceXPos, yPos, 50, -1);
+
+ // STYLE BONUSES
+
+ final Set stats = ImmutableSet.of(
+ "Stab",
+ "Slash",
+ "Crush",
+ "Magic",
+ "Ranged"
+ );
+
+ final List attackStats = ImmutableList.of(
+ equipmentStats.getAstab(),
+ equipmentStats.getAslash(),
+ equipmentStats.getAcrush(),
+ equipmentStats.getAmagic(),
+ equipmentStats.getArange()
+ );
+
+ final List defenceStats = ImmutableList.of(
+ equipmentStats.getDstab(),
+ equipmentStats.getDslash(),
+ equipmentStats.getDcrush(),
+ equipmentStats.getDmagic(),
+ equipmentStats.getDrange()
+ );
+
+ int index = 0;
+
+ for (final String stat : stats)
+ {
+ yPos += TEXT_HEIGHT + 2;
+
+ // Style label
+ final Widget styleText = createText(invContainer, stat, FontID.PLAIN_11, ORANGE_TEXT,
+ 0, yPos, invContainer.getWidth(), -1);
+ styleText.setXTextAlignment(WidgetTextAlignment.CENTER);
+
+ // Attack bonus
+ createText(invContainer, attackStats.get(index).toString(), FontID.PLAIN_11, YELLOW_TEXT,
+ 5, yPos, 50, -1);
+
+ // Defence bonus
+ final int defenceX = invContainer.getWidth() - (smallFM.stringWidth(defenceStats.get(index).toString()) + 5);
+ createText(invContainer, defenceStats.get(index).toString(), FontID.PLAIN_11, YELLOW_TEXT,
+ defenceX, yPos, 50, -1);
+
+ index++;
+ }
+
+ // MISC BONUSES
+
+ yPos += TEXT_HEIGHT + 8;
+
+ final Map miscStats = ImmutableMap.of(
+ "Strength", equipmentStats.getStr(),
+ "Ranged Strength", equipmentStats.getRstr(),
+ "Magic Damage", equipmentStats.getMdmg(),
+ "Prayer Bonus", equipmentStats.getPrayer()
+ );
+
+ for (final Map.Entry miscStat : miscStats.entrySet())
+ {
+ final String name = miscStat.getKey();
+ final String value = miscStat.getValue().toString();
+
+ // Stat label
+ createText(invContainer, name, FontID.PLAIN_11, ORANGE_TEXT, 5, yPos, 50, -1);
+
+ // Stat bonus
+ int valueXPos = invContainer.getWidth() - (smallFM.stringWidth(value) + 5);
+ createText(invContainer, value, FontID.PLAIN_11, YELLOW_TEXT, valueXPos, yPos, 50, -1);
+
+ yPos += TEXT_HEIGHT + 2;
+ }
+
+ // COINS
+
+ createSeparator(invContainer, invContainer.getHeight() - 40);
+
+ final String coinText = "You have " + StackFormatter.quantityToRSStackSize(getCurrentGP())
+ + (getCurrentGP() == 1 ? " coin." : " coins.");
+
+ final Widget coinWidget = createText(invContainer, coinText, FontID.PLAIN_12, ORANGE_TEXT,
+ 0, invContainer.getHeight() - 18, invContainer.getWidth(), -1);
+
+ coinWidget.setXTextAlignment(WidgetTextAlignment.CENTER);
+ }
+
+ private static Widget createText(Widget parent, String text, int fontId, int textColor,
+ int x, int y, int width, int height)
+ {
+ final Widget widget = parent.createChild(-1, WidgetType.TEXT);
+ widget.setText(text);
+ widget.setFontId(fontId);
+ widget.setTextColor(textColor);
+ widget.setTextShadowed(true);
+ widget.setOriginalHeight(height == -1 ? TEXT_HEIGHT : height);
+ widget.setOriginalWidth(width);
+ widget.setOriginalY(y);
+ widget.setOriginalX(x);
+ widget.revalidate();
+ return widget;
+ }
+
+ private static void createSeparator(Widget parent, int y)
+ {
+ Widget separator = parent.createChild(-1, WidgetType.GRAPHIC);
+ separator.setOriginalWidth(parent.getWidth());
+ separator.setOriginalY(y);
+ separator.setOriginalHeight(32);
+ separator.setSpriteId(SpriteID.UNKNOWN_BORDER_EDGE_HORIZONTAL_995);
+ separator.revalidate();
+ }
+
+ private void resetGEInventory()
+ {
+ final Widget invContainer = getInventoryContainer();
+
+ if (invContainer == null)
+ {
+ return;
+ }
+
+ if (itemInformationTitle != null && invContainer.getChild(0) == itemInformationTitle)
+ {
+ invContainer.deleteAllChildren();
+ itemInformationTitle = null;
+ }
+
+ final Widget geInv = client.getWidget(WidgetInfo.GRAND_EXCHANGE_INVENTORY_ITEMS_CONTAINER);
+ if (geInv != null)
+ {
+ geInv.setHidden(false);
+ }
+ }
+
+ private int getCurrentGP()
+ {
+ final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY);
+
+ if (inventory == null)
+ {
+ return 0;
+ }
+
+ for (final Item item : inventory.getItems())
+ {
+ if (item.getId() == ItemID.COINS_995)
+ {
+ return item.getQuantity();
+ }
+ }
+
+ return 0;
+ }
+
+ private Widget getInventoryContainer()
+ {
+ if (client.isResized())
+ {
+ if (client.getVar(Varbits.SIDE_PANELS) == 1)
+ {
+ return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_INVENTORY_CONTAINER);
+ }
+ else
+ {
+ return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_INVENTORY_CONTAINER);
+ }
+ }
+ else
+ {
+ return client.getWidget(WidgetInfo.FIXED_VIEWPORT_INVENTORY_CONTAINER);
+ }
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/RangeStatBoost.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/RangeStatBoost.java
index abe47cea1c..13011b9f6a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/RangeStatBoost.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/RangeStatBoost.java
@@ -42,33 +42,21 @@ public class RangeStatBoost extends SingleEffect
@Override
public StatChange effect(Client client)
{
- final StatChange a = this.a.effect(client);
- final StatChange b = this.b.effect(client);
+ final StatChange changeA = this.a.effect(client);
+ final StatChange changeB = this.b.effect(client);
- final StatChange r = new StatChange();
- r.setAbsolute(concat(a.getAbsolute(), b.getAbsolute()));
- r.setRelative(concat(a.getRelative(), b.getRelative()));
- r.setTheoretical(concat(a.getTheoretical(), b.getTheoretical()));
- r.setStat(a.getStat());
+ final RangeStatChange r = new RangeStatChange();
+ r.setMinAbsolute(Math.min(changeA.getAbsolute(), changeB.getAbsolute()));
+ r.setAbsolute(Math.max(changeA.getAbsolute(), changeB.getAbsolute()));
+ r.setMinRelative(Math.min(changeA.getRelative(), changeB.getRelative()));
+ r.setRelative(Math.max(changeA.getRelative(), changeB.getRelative()));
+ r.setMinTheoretical(Math.min(changeA.getTheoretical(), changeB.getTheoretical()));
+ r.setTheoretical(Math.max(changeA.getTheoretical(), changeB.getTheoretical()));
+ r.setStat(changeA.getStat());
- final int avg = (a.getPositivity().ordinal() + b.getPositivity().ordinal()) / 2;
+ final int avg = (changeA.getPositivity().ordinal() + changeB.getPositivity().ordinal()) / 2;
r.setPositivity(Positivity.values()[avg]);
return r;
}
-
- private String concat(String a, String b)
- {
- // If they share a operator, strip b's duplicate
- if (a.length() > 1 && b.length() > 1)
- {
- final char a0 = a.charAt(0);
- if ((a0 == '+' || a0 == '-' || a0 == '±') && b.charAt(0) == a0)
- {
- b = b.substring(1);
- }
- }
-
- return a + "~" + b;
- }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/RangeStatChange.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/RangeStatChange.java
new file mode 100644
index 0000000000..90b614bf10
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/RangeStatChange.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016-2019, Jordan Atwood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.itemstats;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * A stat change which can result in different magnitudes of change to the stat
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class RangeStatChange extends StatChange
+{
+ /**
+ * Minimum relative change that will occur if the stat boost is applied now.
+ * In this class, {@code relative} is representative of the maximum relative change that will
+ * occur.
+ */
+ private int minRelative;
+
+ /**
+ * Minimum theoretical change that can occur before boost cap is enforced.
+ * In this class, {@code theoretical} is representative of the maximum theoretical change that
+ * will occur.
+ */
+ private int minTheoretical;
+
+ /**
+ * Minimum absolute total of the stat after applying the boost.
+ * In this class, {@code absolute} is representative of the maximum absolute change that will
+ * occur.
+ */
+ private int minAbsolute;
+
+ /**
+ * Returns a human-readable formatted relative boost.
+ * Should be the boost range in the format "±N" (for minimum -N and maximum +N values),
+ * "+MIN~MAX" (for minimum and maximum values of the same sign),
+ * "-MIN~+MAX" (for negative minimum and positive maximum values), or
+ * "+MAX" (for equal minimum and maximum values).
+ *
+ * @return The formatted relative boost amount
+ */
+ @Override
+ public String getFormattedRelative()
+ {
+ return concat(minRelative, getRelative());
+ }
+
+ /**
+ * Returns a human-readable formatted theoretical boost.
+ * Should be the boost range in the format "±N" (for minimum -N and maximum +N values),
+ * "+MIN~MAX" (for minimum and maximum values of the same sign),
+ * "-MIN~+MAX" (for negative minimum and positive maximum values), or
+ * "+MAX" (for equal minimum and maximum values).
+ *
+ * @return The formatted theoretical boost amount
+ */
+ @Override
+ public String getFormattedTheoretical()
+ {
+ return concat(minTheoretical, getTheoretical());
+ }
+
+ private static String concat(int changeA, int changeB)
+ {
+ if (changeA == changeB)
+ {
+ return formatBoost(changeA);
+ }
+ else if (changeA * -1 == changeB)
+ {
+ return "±" + Math.abs(changeA);
+ }
+
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append(String.format("%+d", changeA));
+ sb.append('~');
+
+ // If they share a operator, strip b's duplicate
+ if (changeA < 0 && changeB < 0
+ || changeA >= 0 && changeB >= 0)
+ {
+ sb.append(Math.abs(changeB));
+ }
+ else
+ {
+ sb.append(String.format("%+d", changeB));
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatBoost.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatBoost.java
index 1bc59d7412..cc5f7797f2 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatBoost.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatBoost.java
@@ -88,10 +88,9 @@ public abstract class StatBoost extends SingleEffect
{
out.setPositivity(Positivity.WORSE);
}
- out.setAbsolute(Integer.toString(newValue));
- out.setRelative(String.format("%+d", delta));
- out.setTheoretical(String.format("%+d", calcedDelta));
+ out.setAbsolute(newValue);
+ out.setRelative(delta);
+ out.setTheoretical(calcedDelta);
return out;
}
-
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatChange.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatChange.java
index 3157748083..e9453984f4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatChange.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatChange.java
@@ -40,23 +40,48 @@ public class StatChange
/**
* Relative change that will occur if the stat boost is applied now.
- * Should be a number prefixed by "+" or "-".
*/
- private String relative;
+ private int relative;
/**
* Theoretical change that can occur before boost cap is enforced.
- * Should be a number prefixed by "+" or "-".
*/
- private String theoretical;
+ private int theoretical;
/**
* Absolute total of the stat after applying the boost.
*/
- private String absolute;
+ private int absolute;
/**
* How beneficial this stat boost will be to the player.
*/
private Positivity positivity;
+
+ /**
+ * Returns a human-readable formatted relative boost.
+ * Should be the boost amount prefixed by "+" or "-".
+ *
+ * @return The formatted relative boost amount
+ */
+ public String getFormattedRelative()
+ {
+ return formatBoost(relative);
+ }
+
+ /**
+ * Returns a human-readable formatted theoretical boost.
+ * Should be the boost amount prefixed by "+" or "-".
+ *
+ * @return The formatted theoretical boost amount
+ */
+ public String getFormattedTheoretical()
+ {
+ return formatBoost(theoretical);
+ }
+
+ static String formatBoost(int boost)
+ {
+ return String.format("%+d", boost);
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/CastleWarsBandage.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/CastleWarsBandage.java
new file mode 100644
index 0000000000..e66f9ed709
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/CastleWarsBandage.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019, Giovds
+ * 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.itemstats.special;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Comparator;
+import java.util.stream.Stream;
+import net.runelite.api.Client;
+import net.runelite.api.EquipmentInventorySlot;
+import net.runelite.api.InventoryID;
+import net.runelite.api.Item;
+import net.runelite.api.ItemContainer;
+import net.runelite.api.ItemID;
+import static net.runelite.client.plugins.itemstats.Builders.heal;
+import static net.runelite.client.plugins.itemstats.Builders.perc;
+import net.runelite.client.plugins.itemstats.Effect;
+import net.runelite.client.plugins.itemstats.StatChange;
+import net.runelite.client.plugins.itemstats.StatsChanges;
+import static net.runelite.client.plugins.itemstats.stats.Stats.HITPOINTS;
+import static net.runelite.client.plugins.itemstats.stats.Stats.RUN_ENERGY;
+
+public class CastleWarsBandage implements Effect
+{
+ private static final ImmutableSet BRACELETS = ImmutableSet.of(
+ ItemID.CASTLE_WARS_BRACELET1, ItemID.CASTLE_WARS_BRACELET2, ItemID.CASTLE_WARS_BRACELET3
+ );
+
+ private static final double BASE_HP_PERC = .10;
+ private static final double BRACELET_HP_PERC = .50;
+
+ @Override
+ public StatsChanges calculate(Client client)
+ {
+ final ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT);
+ final double percH = hasBracelet(equipmentContainer) ? BRACELET_HP_PERC : BASE_HP_PERC;
+ final StatChange hitPoints = heal(HITPOINTS, perc(percH, 0)).effect(client);
+ final StatChange runEnergy = heal(RUN_ENERGY, 30).effect(client);
+ final StatsChanges changes = new StatsChanges(2);
+ changes.setStatChanges(new StatChange[]{hitPoints, runEnergy});
+ changes.setPositivity(Stream.of(changes.getStatChanges())
+ .map(StatChange::getPositivity)
+ .max(Comparator.comparing(Enum::ordinal)).get());
+
+ return changes;
+ }
+
+ private boolean hasBracelet(ItemContainer equipmentContainer)
+ {
+ if (equipmentContainer == null)
+ {
+ return false;
+ }
+
+ final Item[] equipment = equipmentContainer.getItems();
+
+ if (equipment.length > EquipmentInventorySlot.GLOVES.getSlotIdx())
+ {
+ return BRACELETS.contains(equipment[EquipmentInventorySlot.GLOVES.getSlotIdx()].getId());
+ }
+
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java
index 8dab7fd601..7eee548751 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java
@@ -132,11 +132,14 @@ public class SpicyStew implements Effect
int currentBoost = currentValue - currentBase; // Can be negative
int spiceBoostCapped = (currentBoost <= 0) ? spiceBoost : Math.max(0, spiceBoost - currentBoost);
- StatChange change = new StatChange();
+ final RangeStatChange change = new RangeStatChange();
change.setStat(stat);
- change.setRelative("±" + spiceBoostCapped);
- change.setTheoretical("±" + spiceBoost);
- change.setAbsolute(String.valueOf(stat.getValue(client) + spiceBoostCapped));
+ change.setMinRelative(-spiceBoost);
+ change.setRelative(spiceBoostCapped);
+ change.setMinTheoretical(-spiceBoost);
+ change.setTheoretical(spiceBoost);
+ change.setMinAbsolute(Math.max(-spiceBoost, -currentValue));
+ change.setAbsolute(stat.getValue(client) + spiceBoostCapped);
Positivity positivity;
if (spiceBoostCapped == 0)
@@ -155,5 +158,4 @@ public class SpicyStew implements Effect
return change;
}
-
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kingdomofmiscellania/KingdomCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/kingdomofmiscellania/KingdomCounter.java
index 7dc6aabf35..8a2871125f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/kingdomofmiscellania/KingdomCounter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/kingdomofmiscellania/KingdomCounter.java
@@ -32,9 +32,9 @@ public class KingdomCounter extends Counter
{
private final KingdomPlugin plugin;
- public KingdomCounter(BufferedImage image, KingdomPlugin plugin)
+ KingdomCounter(BufferedImage image, KingdomPlugin plugin)
{
- super(image, plugin, String.valueOf(plugin.getFavor()));
+ super(image, plugin, plugin.getFavor());
this.plugin = plugin;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Book.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Book.java
index 974ef66f78..49f6ccf7f9 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Book.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Book.java
@@ -59,7 +59,7 @@ enum Book
TRISTESSAS_TRAGEDY(ItemID.TRISTESSAS_TRAGEDY, "Tristessa's Tragedy", "The Tragedy of Tristessa."),
TREACHERY_OF_ROYALTY(ItemID.TREACHERY_OF_ROYALTY, "The Treachery of Royalty", "The Treachery of Royalty, by Professor Answith."),
TRANSPORTATION_INCANTATIONS(ItemID.TRANSPORTATION_INCANTATIONS, "Transportation Incantations", "Transportation Incantations, by Amon Ducot."),
- SOUL_JORUNEY(ItemID.SOUL_JOURNEY, "Soul Journey", "The Journey of Souls, by Aretha."),
+ SOUL_JOURNEY(ItemID.SOUL_JOURNEY, "Soul Journey", "The Journey of Souls, by Aretha."),
VARLAMORE_ENVOY(ItemID.VARLAMORE_ENVOY, "Varlamore Envoy", "The Envoy to Varlamore, by Deryk Paulson.");
private static final Map BY_ID = buildById();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryConfig.java
index b61a24c139..6ec40a00fd 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryConfig.java
@@ -42,4 +42,14 @@ public interface KourendLibraryConfig extends Config
{
return true;
}
+
+ @ConfigItem(
+ keyName = "hideDuplicateBook",
+ name = "Hide duplicate book",
+ description = "Don't show the duplicate book locations in the library"
+ )
+ default boolean hideDuplicateBook()
+ {
+ return true;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryOverlay.java
index 3c6863af3a..5cf7910ee6 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryOverlay.java
@@ -35,6 +35,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
+import javax.annotation.Nullable;
import lombok.AccessLevel;
import lombok.Setter;
import net.runelite.api.Client;
@@ -54,15 +55,19 @@ class KourendLibraryOverlay extends Overlay
private final static int MAXIMUM_DISTANCE = 24;
private final Library library;
private final Client client;
+ private final KourendLibraryConfig config;
+ private final KourendLibraryPlugin plugin;
@Setter(AccessLevel.PACKAGE)
private boolean hidden;
@Inject
- private KourendLibraryOverlay(Library library, Client client)
+ private KourendLibraryOverlay(Library library, Client client, KourendLibraryConfig config, KourendLibraryPlugin plugin)
{
this.library = library;
this.client = client;
+ this.config = config;
+ this.plugin = plugin;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
@@ -133,7 +138,7 @@ class KourendLibraryOverlay extends Overlay
Color color = bookIsKnown ? Color.ORANGE : Color.WHITE;
// Render the poly on the floor
- if (!(bookIsKnown && book == null) && (library.getState() == SolvedState.NO_DATA || book != null || !possible.isEmpty()))
+ if (!(bookIsKnown && book == null) && (library.getState() == SolvedState.NO_DATA || book != null || !possible.isEmpty()) && !shouldHideOverlayIfDuplicateBook(book))
{
Polygon poly = getCanvasTilePoly(client, localBookcase);
if (poly != null)
@@ -146,7 +151,7 @@ class KourendLibraryOverlay extends Overlay
// If the book is singled out, render the text and the book's icon
if (bookIsKnown)
{
- if (book != null)
+ if (book != null && !shouldHideOverlayIfDuplicateBook(book))
{
FontMetrics fm = g.getFontMetrics();
Rectangle2D bounds = fm.getStringBounds(book.getShortName(), g);
@@ -216,9 +221,10 @@ class KourendLibraryOverlay extends Overlay
.forEach(n ->
{
Book b = library.getCustomerBook();
+ boolean doesPlayerContainBook = b != null && plugin.doesPlayerContainBook(b);
LocalPoint local = n.getLocalLocation();
Polygon poly = getCanvasTilePoly(client, local);
- OverlayUtil.renderPolygon(g, poly, Color.WHITE);
+ OverlayUtil.renderPolygon(g, poly, doesPlayerContainBook ? Color.GREEN : Color.WHITE);
Point screen = Perspective.localToCanvas(client, local, client.getPlane(), n.getLogicalHeight());
if (screen != null)
{
@@ -229,4 +235,12 @@ class KourendLibraryOverlay extends Overlay
return null;
}
+
+ private boolean shouldHideOverlayIfDuplicateBook(@Nullable Book book)
+ {
+ return config.hideDuplicateBook()
+ && book != null
+ && !book.isDarkManuscript()
+ && plugin.doesPlayerContainBook(book);
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPlugin.java
index 73602299f4..649189fc47 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/KourendLibraryPlugin.java
@@ -26,6 +26,7 @@ package net.runelite.client.plugins.kourendlibrary;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
+import java.util.EnumSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
@@ -34,6 +35,9 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.api.AnimationID;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
+import net.runelite.api.InventoryID;
+import net.runelite.api.Item;
+import net.runelite.api.ItemContainer;
import net.runelite.api.MenuAction;
import net.runelite.api.Player;
import net.runelite.api.coords.WorldPoint;
@@ -41,6 +45,7 @@ import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameTick;
+import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
@@ -94,6 +99,7 @@ public class KourendLibraryPlugin extends Plugin
private boolean buttonAttached = false;
private WorldPoint lastBookcaseClick = null;
private WorldPoint lastBookcaseAnimatedOn = null;
+ private EnumSet playerBooks = null;
@Provides
KourendLibraryConfig provideConfig(ConfigManager configManager)
@@ -120,6 +126,8 @@ public class KourendLibraryPlugin extends Plugin
overlayManager.add(overlay);
+ updatePlayerBooks();
+
if (!config.hideButton())
{
clientToolbar.addNavigation(navButton);
@@ -135,6 +143,7 @@ public class KourendLibraryPlugin extends Plugin
buttonAttached = false;
lastBookcaseClick = null;
lastBookcaseAnimatedOn = null;
+ playerBooks = null;
}
@Subscribe
@@ -271,4 +280,37 @@ public class KourendLibraryPlugin extends Plugin
}
}
}
+
+ @Subscribe
+ public void onItemContainerChanged(ItemContainerChanged itemContainerChangedEvent)
+ {
+ updatePlayerBooks();
+ }
+
+ boolean doesPlayerContainBook(Book book)
+ {
+ return playerBooks.contains(book);
+ }
+
+ private void updatePlayerBooks()
+ {
+ ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY);
+
+ if (itemContainer != null)
+ {
+ EnumSet books = EnumSet.noneOf(Book.class);
+
+ for (Item item : itemContainer.getItems())
+ {
+ Book book = Book.byId(item.getId());
+
+ if (book != null)
+ {
+ books.add(book);
+ }
+ }
+
+ playerBooks = books;
+ }
+ }
}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java
index 62ebba956f..02618031db 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java
@@ -299,7 +299,7 @@ class Library
DARK_MANUSCRIPT_13515,
BYRNES_CORONATION_SPEECH,
DARK_MANUSCRIPT_13517,
- SOUL_JORUNEY,
+ SOUL_JOURNEY,
DARK_MANUSCRIPT_13518,
TRANSPORTATION_INCANTATIONS
),
@@ -322,7 +322,7 @@ class Library
DARK_MANUSCRIPT_13514,
EATHRAM_RADA_EXTRACT,
DARK_MANUSCRIPT_13522,
- SOUL_JORUNEY,
+ SOUL_JOURNEY,
WINTERTODT_PARABLE,
TWILL_ACCORD,
DARK_MANUSCRIPT_13515,
@@ -348,7 +348,7 @@ class Library
DARK_MANUSCRIPT_13519,
BYRNES_CORONATION_SPEECH,
DARK_MANUSCRIPT_13517,
- SOUL_JORUNEY,
+ SOUL_JOURNEY,
DARK_MANUSCRIPT_13522,
WINTERTODT_PARABLE,
TWILL_ACCORD,
@@ -384,7 +384,7 @@ class Library
TREACHERY_OF_ROYALTY,
DARK_MANUSCRIPT_13518,
TRANSPORTATION_INCANTATIONS,
- SOUL_JORUNEY,
+ SOUL_JOURNEY,
VARLAMORE_ENVOY
),
Arrays.asList(
@@ -409,7 +409,7 @@ class Library
IDEOLOGY_OF_DARKNESS,
WINTERTODT_PARABLE,
TWILL_ACCORD,
- SOUL_JORUNEY,
+ SOUL_JOURNEY,
DARK_MANUSCRIPT_13515,
EATHRAM_RADA_EXTRACT,
DARK_MANUSCRIPT_13518,
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java
index 279251e1c9..4da52e1492 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java
@@ -36,7 +36,7 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
-import net.runelite.api.events.SessionOpen;
+import net.runelite.client.events.SessionOpen;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyListener;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java
index 98b7053117..bba5994d89 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java
@@ -51,11 +51,23 @@ public interface LootTrackerConfig extends Config
@ConfigItem(
keyName = "saveLoot",
- name = "Save loot",
- description = "Save loot between client sessions (requires being logged in)"
+ name = "Submit loot tracker data",
+ description = "Submit loot tracker data (requires being logged in)"
)
default boolean saveLoot()
{
return true;
}
+
+ @ConfigItem(
+ keyName = "syncPanel",
+ name = "Synchronize panel contents",
+ description = "Synchronize you local loot tracker with your online (requires being logged in). This means" +
+ " that panel is filled with portion of your remote data on startup and deleting data in panel deletes them" +
+ " also on server."
+ )
+ default boolean syncPanel()
+ {
+ return true;
+ }
}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java
index 4aaa7e0c7a..ed850cdcbb 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java
@@ -99,6 +99,7 @@ class LootTrackerPanel extends PluginPanel
private final ItemManager itemManager;
private final LootTrackerPlugin plugin;
+ private final LootTrackerConfig config;
private boolean groupLoot;
private boolean hideIgnoredItems;
@@ -130,10 +131,11 @@ class LootTrackerPanel extends PluginPanel
INVISIBLE_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(invisibleImg, -220));
}
- LootTrackerPanel(final LootTrackerPlugin plugin, final ItemManager itemManager)
+ LootTrackerPanel(final LootTrackerPlugin plugin, final ItemManager itemManager, final LootTrackerConfig config)
{
this.itemManager = itemManager;
this.plugin = plugin;
+ this.config = config;
this.hideIgnoredItems = true;
setBorder(new EmptyBorder(6, 6, 6, 6));
@@ -297,7 +299,7 @@ class LootTrackerPanel extends PluginPanel
// Delete all loot, or loot matching the current view
LootTrackerClient client = plugin.getLootTrackerClient();
- if (client != null)
+ if (client != null && config.syncPanel())
{
client.delete(currentView);
}
@@ -472,7 +474,7 @@ class LootTrackerPanel extends PluginPanel
LootTrackerClient client = plugin.getLootTrackerClient();
// Without loot being grouped we have no way to identify single kills to be deleted
- if (client != null && groupLoot)
+ if (client != null && groupLoot && config.syncPanel())
{
client.delete(box.getId());
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java
index acb725db64..ec2bf74aad 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java
@@ -25,9 +25,13 @@
*/
package net.runelite.client.plugins.loottracker;
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.Multisets;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.io.IOException;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -54,8 +58,7 @@ import net.runelite.api.SpriteID;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
-import net.runelite.api.events.SessionClose;
-import net.runelite.api.events.SessionOpen;
+import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.WidgetID;
import net.runelite.client.account.AccountSession;
@@ -65,6 +68,8 @@ import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.NpcLootReceived;
import net.runelite.client.events.PlayerLootReceived;
+import net.runelite.client.events.SessionClose;
+import net.runelite.client.events.SessionOpen;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.ItemStack;
import net.runelite.client.game.SpriteManager;
@@ -92,6 +97,10 @@ public class LootTrackerPlugin extends Plugin
private static final Pattern CLUE_SCROLL_PATTERN = Pattern.compile("You have completed [0-9]+ ([a-z]+) Treasure Trails.");
private static final int THEATRE_OF_BLOOD_REGION = 12867;
+ // Brimstone loot handling
+ private static final String BRIMSTONE_CHEST_MESSAGE = "You find some treasure in the chest!";
+ private static final String BRIMSTONE_CHEST_EVENT_TYPE = "Brimstone Chest";
+
@Inject
private ClientToolbar clientToolbar;
@@ -122,6 +131,8 @@ public class LootTrackerPlugin extends Plugin
private List ignoredItems = new ArrayList<>();
+ private Multiset inventorySnapshot;
+
@Getter(AccessLevel.PACKAGE)
private LootTrackerClient lootTrackerClient;
@@ -194,7 +205,7 @@ public class LootTrackerPlugin extends Plugin
protected void startUp() throws Exception
{
ignoredItems = Text.fromCSV(config.getIgnoredItems());
- panel = new LootTrackerPanel(this, itemManager);
+ panel = new LootTrackerPanel(this, itemManager, config);
spriteManager.getSpriteAsync(SpriteID.TAB_INVENTORY, 0, panel::loadHeaderIcon);
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png");
@@ -226,9 +237,8 @@ public class LootTrackerPlugin extends Plugin
{
Collection lootRecords;
- if (!config.saveLoot())
+ if (!config.syncPanel())
{
- // don't load loot if we're not saving loot
return;
}
@@ -274,7 +284,7 @@ public class LootTrackerPlugin extends Plugin
if (lootTrackerClient != null && config.saveLoot())
{
- LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items));
+ LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items), Instant.now());
lootTrackerClient.submit(lootRecord);
}
}
@@ -291,7 +301,7 @@ public class LootTrackerPlugin extends Plugin
if (lootTrackerClient != null && config.saveLoot())
{
- LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items));
+ LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items), Instant.now());
lootTrackerClient.submit(lootRecord);
}
}
@@ -350,7 +360,7 @@ public class LootTrackerPlugin extends Plugin
if (lootTrackerClient != null && config.saveLoot())
{
- LootRecord lootRecord = new LootRecord(eventType, LootRecordType.EVENT, toGameItems(items));
+ LootRecord lootRecord = new LootRecord(eventType, LootRecordType.EVENT, toGameItems(items), Instant.now());
lootTrackerClient.submit(lootRecord);
}
}
@@ -363,8 +373,25 @@ public class LootTrackerPlugin extends Plugin
return;
}
+ final String message = event.getMessage();
+
+ if (message.equals(BRIMSTONE_CHEST_MESSAGE))
+ {
+ eventType = BRIMSTONE_CHEST_EVENT_TYPE;
+
+ final ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY);
+ if (itemContainer != null)
+ {
+ inventorySnapshot = HashMultiset.create();
+ Arrays.stream(itemContainer.getItems())
+ .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity()));
+ }
+
+ return;
+ }
+
// Check if message is for a clue scroll reward
- final Matcher m = CLUE_SCROLL_PATTERN.matcher(Text.removeTags(event.getMessage()));
+ final Matcher m = CLUE_SCROLL_PATTERN.matcher(Text.removeTags(message));
if (m.find())
{
final String type = m.group(1).toLowerCase();
@@ -389,6 +416,50 @@ public class LootTrackerPlugin extends Plugin
}
}
+ @Subscribe
+ public void onItemContainerChanged(ItemContainerChanged event)
+ {
+ if (eventType == null || !eventType.equals(BRIMSTONE_CHEST_EVENT_TYPE))
+ {
+ return;
+ }
+
+ if (event.getItemContainer() != client.getItemContainer(InventoryID.INVENTORY))
+ {
+ return;
+ }
+
+ processBrimstoneChestLoot(event.getItemContainer());
+ eventType = null;
+ }
+
+ private void processBrimstoneChestLoot(ItemContainer inventoryContainer)
+ {
+ if (inventorySnapshot != null)
+ {
+ Multiset currentInventory = HashMultiset.create();
+ Arrays.stream(inventoryContainer.getItems())
+ .forEach(item -> currentInventory.add(item.getId(), item.getQuantity()));
+
+ final Multiset diff = Multisets.difference(currentInventory, inventorySnapshot);
+
+ List items = diff.entrySet().stream()
+ .map(e -> new ItemStack(e.getElement(), e.getCount(), client.getLocalPlayer().getLocalLocation()))
+ .collect(Collectors.toList());
+
+ final LootTrackerItem[] entries = buildEntries(stack(items));
+ SwingUtilities.invokeLater(() -> panel.add(BRIMSTONE_CHEST_EVENT_TYPE, -1, entries));
+
+ if (lootTrackerClient != null && config.saveLoot())
+ {
+ LootRecord lootRecord = new LootRecord(BRIMSTONE_CHEST_EVENT_TYPE, LootRecordType.EVENT, toGameItems(items), Instant.now());
+ lootTrackerClient.submit(lootRecord);
+ }
+
+ inventorySnapshot = null;
+ }
+ }
+
void toggleItem(String name, boolean ignore)
{
final Set ignoredItemSet = new HashSet<>(ignoredItems);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java
index f2030bd47d..23ab63df16 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java
@@ -92,6 +92,16 @@ public interface MenuEntrySwapperConfig extends Config
return false;
}
+ @ConfigItem(
+ keyName = "swapContract",
+ name = "Contract",
+ description = "Swap Talk-to with Contract on Guildmaster Jane"
+ )
+ default boolean swapContract()
+ {
+ return true;
+ }
+
@ConfigItem(
keyName = "swapChase",
name = "Chase",
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 e6420bdc99..b164d10b86 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
@@ -45,8 +45,10 @@ import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.PostItemComposition;
import net.runelite.api.events.WidgetMenuOptionClicked;
import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.game.ItemManager;
import net.runelite.client.game.ItemVariationMapping;
import net.runelite.client.input.KeyManager;
import net.runelite.client.menus.MenuManager;
@@ -101,6 +103,9 @@ public class MenuEntrySwapperPlugin extends Plugin
@Inject
private Client client;
+ @Inject
+ private ClientThread clientThread;
+
@Inject
private MenuEntrySwapperConfig config;
@@ -116,6 +121,9 @@ public class MenuEntrySwapperPlugin extends Plugin
@Inject
private MenuManager menuManager;
+ @Inject
+ private ItemManager itemManager;
+
@Getter
private boolean configuringShiftClick = false;
@@ -146,6 +154,11 @@ public class MenuEntrySwapperPlugin extends Plugin
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
+ if (!CONFIG_GROUP.equals(event.getGroup()))
+ {
+ return;
+ }
+
if (event.getKey().equals("shiftClickCustomization"))
{
if (config.shiftClickCustomization())
@@ -157,6 +170,16 @@ public class MenuEntrySwapperPlugin extends Plugin
disableCustomization();
}
}
+ else if (event.getKey().startsWith(ITEM_KEY_PREFIX))
+ {
+ clientThread.invoke(this::resetItemCompositionCache);
+ }
+ }
+
+ private void resetItemCompositionCache()
+ {
+ itemManager.invalidateItemCompositionCache();
+ client.getItemCompositionCache().reset();
}
private Integer getSwapConfig(int itemId)
@@ -179,6 +202,7 @@ public class MenuEntrySwapperPlugin extends Plugin
private void unsetSwapConfig(int itemId)
{
+ itemId = ItemVariationMapping.map(itemId);
configManager.unsetConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId);
}
@@ -186,6 +210,7 @@ public class MenuEntrySwapperPlugin extends Plugin
{
keyManager.registerKeyListener(inputListener);
refreshShiftClickCustomizationMenus();
+ clientThread.invoke(this::resetItemCompositionCache);
}
private void disableCustomization()
@@ -193,6 +218,7 @@ public class MenuEntrySwapperPlugin extends Plugin
keyManager.unregisterKeyListener(inputListener);
removeShiftClickCustomizationMenus();
configuringShiftClick = false;
+ clientThread.invoke(this::resetItemCompositionCache);
}
@Subscribe
@@ -290,7 +316,6 @@ public class MenuEntrySwapperPlugin extends Plugin
if (option.equals(RESET) && target.equals(MENU_TARGET))
{
unsetSwapConfig(itemId);
- itemComposition.resetShiftClickActionIndex();
return;
}
@@ -323,7 +348,6 @@ public class MenuEntrySwapperPlugin extends Plugin
if (valid)
{
setSwapConfig(itemId, index);
- itemComposition.setShiftClickActionIndex(index);
}
}
@@ -364,6 +388,11 @@ public class MenuEntrySwapperPlugin extends Plugin
swap("bank", option, target, true);
}
+ if (config.swapContract())
+ {
+ swap("contract", option, target, true);
+ }
+
if (config.swapExchange())
{
swap("exchange", option, target, true);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mta/graveyard/GraveyardCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/mta/graveyard/GraveyardCounter.java
index 83e74cc6d6..ecfbafd544 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/mta/graveyard/GraveyardCounter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/mta/graveyard/GraveyardCounter.java
@@ -31,22 +31,15 @@ import net.runelite.client.ui.overlay.infobox.Counter;
public class GraveyardCounter extends Counter
{
- private int count;
-
- public GraveyardCounter(BufferedImage image, Plugin plugin)
+ GraveyardCounter(BufferedImage image, Plugin plugin)
{
- super(image, plugin, "0");
- }
-
- public void setCount(int count)
- {
- this.count = count;
- this.setText(String.valueOf(count));
+ super(image, plugin, 0);
}
@Override
public Color getTextColor()
{
+ int count = getCount();
if (count >= GraveyardRoom.MIN_SCORE)
{
return Color.GREEN;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/musicindicator/MusicIndicatorPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/musicindicator/MusicIndicatorPlugin.java
new file mode 100644
index 0000000000..ecef015bd7
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/musicindicator/MusicIndicatorPlugin.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2019, Shaun Dreclin
+ * 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.musicindicator;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import javax.inject.Inject;
+import net.runelite.api.ChatMessageType;
+import net.runelite.api.Client;
+import net.runelite.api.EnumComposition;
+import net.runelite.api.EnumID;
+import net.runelite.api.VarPlayer;
+import net.runelite.api.events.GameStateChanged;
+import net.runelite.api.events.GameTick;
+import net.runelite.api.events.VarbitChanged;
+import net.runelite.client.chat.ChatColorType;
+import net.runelite.client.chat.ChatMessageBuilder;
+import net.runelite.client.chat.ChatMessageManager;
+import net.runelite.client.chat.QueuedMessage;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+
+@PluginDescriptor(
+ name = "Music Track Indicator",
+ description = "Show chat notifications when unlocking music tracks"
+)
+public class MusicIndicatorPlugin extends Plugin
+{
+ private static final List MUSIC_TRACK_VARPS = ImmutableList.of(
+ VarPlayer.MUSIC_TRACKS_UNLOCKED_1, VarPlayer.MUSIC_TRACKS_UNLOCKED_2, VarPlayer.MUSIC_TRACKS_UNLOCKED_3,
+ VarPlayer.MUSIC_TRACKS_UNLOCKED_4, VarPlayer.MUSIC_TRACKS_UNLOCKED_5, VarPlayer.MUSIC_TRACKS_UNLOCKED_6,
+ VarPlayer.MUSIC_TRACKS_UNLOCKED_7, VarPlayer.MUSIC_TRACKS_UNLOCKED_8, VarPlayer.MUSIC_TRACKS_UNLOCKED_9,
+ VarPlayer.MUSIC_TRACKS_UNLOCKED_10, VarPlayer.MUSIC_TRACKS_UNLOCKED_11, VarPlayer.MUSIC_TRACKS_UNLOCKED_12,
+ VarPlayer.MUSIC_TRACKS_UNLOCKED_13, VarPlayer.MUSIC_TRACKS_UNLOCKED_14, VarPlayer.MUSIC_TRACKS_UNLOCKED_15,
+ VarPlayer.MUSIC_TRACKS_UNLOCKED_16, VarPlayer.MUSIC_TRACKS_UNLOCKED_17, VarPlayer.MUSIC_TRACKS_UNLOCKED_18,
+ VarPlayer.MUSIC_TRACKS_UNLOCKED_19
+ );
+
+ private static final Map VARP_INDEX_TO_VARPLAYER = MUSIC_TRACK_VARPS.stream()
+ .collect(Collectors.collectingAndThen(Collectors.toMap(VarPlayer::getId, Function.identity()),
+ ImmutableMap::copyOf));
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private ChatMessageManager chatMessageManager;
+
+ // Mapping of relevant varps to their values, used to compare against new values
+ private final Map musicTrackVarpValues = new HashMap<>();
+
+ private boolean loggingIn;
+
+ @Override
+ public void startUp()
+ {
+ loggingIn = true;
+ }
+
+ @Override
+ public void shutDown()
+ {
+ musicTrackVarpValues.clear();
+ }
+
+ @Subscribe
+ public void onGameStateChanged(GameStateChanged event)
+ {
+ switch (event.getGameState())
+ {
+ case LOGGING_IN:
+ case CONNECTION_LOST:
+ case HOPPING:
+ musicTrackVarpValues.clear();
+ loggingIn = true;
+ }
+ }
+
+ @Subscribe
+ public void onGameTick(GameTick event)
+ {
+ if (!loggingIn)
+ {
+ return;
+ }
+
+ loggingIn = false;
+
+ for (VarPlayer musicTrackVarp : MUSIC_TRACK_VARPS)
+ {
+ int value = client.getVar(musicTrackVarp);
+ musicTrackVarpValues.put(musicTrackVarp, value);
+ }
+ }
+
+ @Subscribe
+ public void onVarbitChanged(VarbitChanged event)
+ {
+ int idx = event.getIndex();
+
+ VarPlayer varPlayer = VARP_INDEX_TO_VARPLAYER.get(idx);
+ if (varPlayer == null)
+ {
+ return;
+ }
+
+ // Old varplayer values have not been initialized yet
+ if (musicTrackVarpValues.isEmpty())
+ {
+ return;
+ }
+
+ assert musicTrackVarpValues.containsKey(varPlayer);
+
+ int newValue = client.getVar(varPlayer);
+ int oldValue = musicTrackVarpValues.put(varPlayer, newValue);
+ int musicTracksUnlocked = ~oldValue & newValue;
+
+ if (musicTracksUnlocked == 0)
+ {
+ return;
+ }
+
+ final EnumComposition names = client.getEnum(EnumID.MUSIC_TRACK_NAMES);
+ final int varpId = MUSIC_TRACK_VARPS.indexOf(varPlayer) + 1;
+
+ for (int bit = 0; bit < Integer.SIZE; ++bit)
+ {
+ if ((musicTracksUnlocked & (1 << bit)) == 0)
+ {
+ continue;
+ }
+
+ int musicTrackId = getTrackId(varpId, bit);
+ String musicTrackName = names.getStringValue(musicTrackId);
+
+ sendChatMessage("You have unlocked a new music track: " + musicTrackName + ".");
+ }
+ }
+
+ /**
+ * Get the id for a track identified by the given varp and a bit index
+ * @param variableId
+ * @param bit
+ * @return
+ */
+ private int getTrackId(int variableId, int bit)
+ {
+ // values are packed into a coordgrid
+ int packed = (variableId << 14) | bit;
+ EnumComposition ids = client.getEnum(EnumID.MUSIC_TRACK_IDS);
+ for (int key : ids.getKeys())
+ {
+ int value = ids.getIntValue(key);
+ if (value == packed)
+ {
+ return key;
+ }
+ }
+ return -1;
+ }
+
+ private void sendChatMessage(String chatMessage)
+ {
+ final String message = new ChatMessageBuilder()
+ .append(ChatColorType.HIGHLIGHT)
+ .append(chatMessage)
+ .build();
+
+ chatMessageManager.queue(
+ QueuedMessage.builder()
+ .type(ChatMessageType.GAME)
+ .runeLiteFormattedMessage(message)
+ .build());
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/AbsorptionCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/AbsorptionCounter.java
index 05d1498312..4671edde12 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/AbsorptionCounter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/AbsorptionCounter.java
@@ -26,43 +26,27 @@ package net.runelite.client.plugins.nightmarezone;
import java.awt.Color;
import java.awt.image.BufferedImage;
-import lombok.Getter;
import lombok.Setter;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.overlay.infobox.Counter;
+@Setter
public class AbsorptionCounter extends Counter
{
- private int absorption;
-
- @Getter
- @Setter
private int threshold;
-
- @Getter
- @Setter
private Color aboveThresholdColor = Color.GREEN;
-
- @Getter
- @Setter
private Color belowThresholdColor = Color.RED;
- public AbsorptionCounter(BufferedImage image, Plugin plugin, int absorption, int threshold)
+ AbsorptionCounter(BufferedImage image, Plugin plugin, int absorption, int threshold)
{
- super(image, plugin, "");
+ super(image, plugin, absorption);
this.threshold = threshold;
- setAbsorption(absorption);
- }
-
- public void setAbsorption(int absorption)
- {
- this.absorption = absorption;
- setText(String.valueOf(absorption));
}
@Override
public Color getTextColor()
{
+ int absorption = getCount();
if (absorption >= threshold)
{
return aboveThresholdColor;
@@ -76,6 +60,7 @@ public class AbsorptionCounter extends Counter
@Override
public String getTooltip()
{
+ int absorption = getCount();
return "Absorption: " + absorption;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneOverlay.java
index e2a123b1af..71ae196d3e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneOverlay.java
@@ -129,7 +129,7 @@ class NightmareZoneOverlay extends Overlay
}
else
{
- absorptionCounter.setAbsorption(absorptionPoints);
+ absorptionCounter.setCount(absorptionPoints);
}
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java
index 69fa0b7164..3c409987af 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java
@@ -33,6 +33,8 @@ import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameTick;
+import net.runelite.api.widgets.Widget;
+import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
@@ -81,6 +83,13 @@ public class NightmareZonePlugin extends Plugin
{
overlayManager.remove(overlay);
overlay.removeAbsorptionCounter();
+
+ Widget nmzWidget = client.getWidget(WidgetInfo.NIGHTMARE_ZONE);
+
+ if (nmzWidget != null)
+ {
+ nmzWidget.setHidden(false);
+ }
}
@Subscribe
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java
index fe0f7e65d3..0b23ac8eb2 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java
@@ -27,7 +27,7 @@ package net.runelite.client.plugins.notes;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import javax.inject.Inject;
-import net.runelite.api.events.SessionOpen;
+import net.runelite.client.events.SessionOpen;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java
index d4c8c356ec..6c41b2f24d 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java
@@ -46,6 +46,7 @@ import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayUtil;
+import net.runelite.client.util.Text;
public class NpcSceneOverlay extends Overlay
{
@@ -87,7 +88,7 @@ public class NpcSceneOverlay extends Overlay
for (NPC npc : plugin.getHighlightedNpcs())
{
- renderNpcOverlay(graphics, npc, npc.getName(), config.getHighlightColor());
+ renderNpcOverlay(graphics, npc, config.getHighlightColor());
}
return null;
@@ -143,7 +144,7 @@ public class NpcSceneOverlay extends Overlay
}
}
- private void renderNpcOverlay(Graphics2D graphics, NPC actor, String name, Color color)
+ private void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color)
{
switch (config.renderStyle())
{
@@ -176,11 +177,12 @@ public class NpcSceneOverlay extends Overlay
if (config.drawNames())
{
- Point textLocation = actor.getCanvasTextLocation(graphics, name, actor.getLogicalHeight() + 40);
+ String npcName = Text.removeTags(actor.getName());
+ Point textLocation = actor.getCanvasTextLocation(graphics, npcName, actor.getLogicalHeight() + 40);
if (textLocation != null)
{
- OverlayUtil.renderTextLocation(graphics, textLocation, name, color);
+ OverlayUtil.renderTextLocation(graphics, textLocation, npcName, color);
}
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/AggressionTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/AggressionTimer.java
new file mode 100644
index 0000000000..7194d2ddd6
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/AggressionTimer.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018, Woox
+ * 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.npcunaggroarea;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import lombok.Getter;
+import lombok.Setter;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.ui.overlay.infobox.Timer;
+
+class AggressionTimer extends Timer
+{
+ @Getter
+ @Setter
+ private boolean visible;
+
+ AggressionTimer(Duration duration, BufferedImage image, Plugin plugin, boolean visible)
+ {
+ super(duration.toMillis(), ChronoUnit.MILLIS, image, plugin);
+ setTooltip("Time until NPCs become unaggressive");
+ this.visible = visible;
+ }
+
+ @Override
+ public Color getTextColor()
+ {
+ Duration timeLeft = Duration.between(Instant.now(), getEndTime());
+
+ if (timeLeft.getSeconds() < 60)
+ {
+ return Color.RED.brighter();
+ }
+
+ return Color.WHITE;
+ }
+
+ @Override
+ public boolean render()
+ {
+ return visible && super.render();
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaConfig.java
new file mode 100644
index 0000000000..a0e4992e31
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaConfig.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018, Woox
+ * 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.npcunaggroarea;
+
+import java.awt.Color;
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+import net.runelite.client.config.ConfigItem;
+
+@ConfigGroup("npcUnaggroArea")
+public interface NpcAggroAreaConfig extends Config
+{
+ String CONFIG_GROUP = "npcUnaggroArea";
+ String CONFIG_CENTER1 = "center1";
+ String CONFIG_CENTER2 = "center2";
+ String CONFIG_LOCATION = "location";
+ String CONFIG_DURATION = "duration";
+
+ @ConfigItem(
+ keyName = "npcUnaggroAlwaysActive",
+ name = "Always active",
+ description = "Always show this plugins overlays
Otherwise, they will only be shown when any NPC name matches the list",
+ position = 1
+ )
+ default boolean alwaysActive()
+ {
+ return false;
+ }
+
+ @ConfigItem(
+ keyName = "npcUnaggroNames",
+ name = "NPC names",
+ description = "Enter names of NPCs where you wish to use this plugin",
+ position = 2
+ )
+ default String npcNamePatterns()
+ {
+ return "";
+ }
+
+ @ConfigItem(
+ keyName = "npcUnaggroShowTimer",
+ name = "Show timer",
+ description = "Display a timer until NPCs become unaggressive",
+ position = 3
+ )
+ default boolean showTimer()
+ {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "npcUnaggroShowAreaLines",
+ name = "Show area lines",
+ description = "Display lines, when walked past, the unaggressive timer resets",
+ position = 4
+ )
+ default boolean showAreaLines()
+ {
+ return false;
+ }
+
+ @ConfigItem(
+ keyName = "npcUnaggroAreaColor",
+ name = "Area lines colour",
+ description = "Choose colour to use for marking NPC unaggressive area",
+ position = 5
+ )
+ default Color aggroAreaColor()
+ {
+ return Color.YELLOW;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPointsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaNotWorkingOverlay.java
similarity index 53%
rename from runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPointsOverlay.java
rename to runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaNotWorkingOverlay.java
index 5e66876bce..0a9dedb357 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPointsOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaNotWorkingOverlay.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Kamiel
+ * Copyright (c) 2018, Woox
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,73 +22,45 @@
* (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.raids;
+package net.runelite.client.plugins.npcunaggroarea;
+import com.google.inject.Inject;
import java.awt.Dimension;
import java.awt.Graphics2D;
-import javax.inject.Inject;
-import net.runelite.api.Client;
-import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG;
-import net.runelite.api.Varbits;
-import static net.runelite.client.plugins.raids.RaidsPlugin.POINTS_FORMAT;
import net.runelite.client.ui.overlay.Overlay;
-import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
-import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.components.LineComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
-public class RaidsPointsOverlay extends Overlay
+class NpcAggroAreaNotWorkingOverlay extends Overlay
{
- @Inject
- private Client client;
+ private final NpcAggroAreaPlugin plugin;
+ private final PanelComponent panelComponent;
@Inject
- private RaidsPlugin plugin;
-
- private final PanelComponent panel = new PanelComponent();
-
- @Inject
- private RaidsPointsOverlay(RaidsPlugin plugin)
+ private NpcAggroAreaNotWorkingOverlay(NpcAggroAreaPlugin plugin)
{
- super(plugin);
- setPosition(OverlayPosition.TOP_RIGHT);
- setPriority(OverlayPriority.HIGH);
- getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Raids overlay"));
+ this.plugin = plugin;
+
+ panelComponent = new PanelComponent();
+ panelComponent.setPreferredSize(new Dimension(150, 0));
+ panelComponent.getChildren().add(LineComponent.builder()
+ .left("Unaggressive NPC timers will start working when you teleport far away or enter a dungeon.")
+ .build());
+
+ setPriority(OverlayPriority.LOW);
+ setPosition(OverlayPosition.TOP_LEFT);
}
@Override
public Dimension render(Graphics2D graphics)
{
- if (!plugin.isInRaidChambers())
+ if (!plugin.isActive() || plugin.getSafeCenters()[1] != null)
{
return null;
}
- int totalPoints = client.getVar(Varbits.TOTAL_POINTS);
- int personalPoints = client.getVar(Varbits.PERSONAL_POINTS);
- int partySize = client.getVar(Varbits.RAID_PARTY_SIZE);
-
- panel.getChildren().clear();
- panel.getChildren().add(LineComponent.builder()
- .left("Total:")
- .right(POINTS_FORMAT.format(totalPoints))
- .build());
-
- panel.getChildren().add(LineComponent.builder()
- .left(client.getLocalPlayer().getName() + ":")
- .right(POINTS_FORMAT.format(personalPoints))
- .build());
-
- if (partySize > 1)
- {
- panel.getChildren().add(LineComponent.builder()
- .left("Party size:")
- .right(String.valueOf(partySize))
- .build());
- }
-
- return panel.render(graphics);
+ return panelComponent.render(graphics);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaOverlay.java
new file mode 100644
index 0000000000..811952de57
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaOverlay.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018, Woox
+ * 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.npcunaggroarea;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.geom.GeneralPath;
+import java.time.Instant;
+import javax.inject.Inject;
+import net.runelite.api.Client;
+import net.runelite.api.Perspective;
+import net.runelite.api.Point;
+import net.runelite.api.coords.LocalPoint;
+import net.runelite.api.geometry.Geometry;
+import net.runelite.client.ui.overlay.Overlay;
+import net.runelite.client.ui.overlay.OverlayLayer;
+import net.runelite.client.ui.overlay.OverlayPosition;
+import net.runelite.client.ui.overlay.OverlayPriority;
+
+class NpcAggroAreaOverlay extends Overlay
+{
+ private static final int MAX_LOCAL_DRAW_LENGTH = 20 * Perspective.LOCAL_TILE_SIZE;
+
+ private final Client client;
+ private final NpcAggroAreaConfig config;
+ private final NpcAggroAreaPlugin plugin;
+
+ @Inject
+ private NpcAggroAreaOverlay(Client client, NpcAggroAreaConfig config, NpcAggroAreaPlugin plugin)
+ {
+ this.client = client;
+ this.config = config;
+ this.plugin = plugin;
+
+ setLayer(OverlayLayer.ABOVE_SCENE);
+ setPriority(OverlayPriority.LOW);
+ setPosition(OverlayPosition.DYNAMIC);
+ }
+
+ @Override
+ public Dimension render(Graphics2D graphics)
+ {
+ if (!plugin.isActive() || plugin.getSafeCenters()[1] == null)
+ {
+ return null;
+ }
+
+ GeneralPath lines = plugin.getLinesToDisplay()[client.getPlane()];
+ if (lines == null)
+ {
+ return null;
+ }
+
+ Color outlineColor = config.aggroAreaColor();
+ AggressionTimer timer = plugin.getCurrentTimer();
+ if (timer == null || Instant.now().compareTo(timer.getEndTime()) < 0)
+ {
+ outlineColor = new Color(
+ outlineColor.getRed(),
+ outlineColor.getGreen(),
+ outlineColor.getBlue(),
+ 100);
+ }
+
+ renderPath(graphics, lines, outlineColor);
+ return null;
+ }
+
+ private void renderPath(Graphics2D graphics, GeneralPath path, Color color)
+ {
+ LocalPoint playerLp = client.getLocalPlayer().getLocalLocation();
+ Rectangle viewArea = new Rectangle(
+ playerLp.getX() - MAX_LOCAL_DRAW_LENGTH,
+ playerLp.getY() - MAX_LOCAL_DRAW_LENGTH,
+ MAX_LOCAL_DRAW_LENGTH * 2,
+ MAX_LOCAL_DRAW_LENGTH * 2);
+
+ graphics.setColor(color);
+ graphics.setStroke(new BasicStroke(1));
+
+ path = Geometry.clipPath(path, viewArea);
+ path = Geometry.filterPath(path, (p1, p2) ->
+ Perspective.localToCanvas(client, new LocalPoint((int)p1[0], (int)p1[1]), client.getPlane()) != null &&
+ Perspective.localToCanvas(client, new LocalPoint((int)p2[0], (int)p2[1]), client.getPlane()) != null);
+ path = Geometry.transformPath(path, coords ->
+ {
+ Point point = Perspective.localToCanvas(client, new LocalPoint((int)coords[0], (int)coords[1]), client.getPlane());
+ coords[0] = point.getX();
+ coords[1] = point.getY();
+ });
+
+ graphics.draw(path);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java
new file mode 100644
index 0000000000..e1c1704762
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2018, Woox
+ * 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.npcunaggroarea;
+
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.inject.Provides;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.image.BufferedImage;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.List;
+import javax.inject.Inject;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.api.Client;
+import net.runelite.api.Constants;
+import net.runelite.api.ItemID;
+import net.runelite.api.NPC;
+import net.runelite.api.NPCComposition;
+import net.runelite.api.Perspective;
+import net.runelite.api.coords.LocalPoint;
+import net.runelite.api.coords.WorldArea;
+import net.runelite.api.coords.WorldPoint;
+import net.runelite.api.events.ConfigChanged;
+import net.runelite.api.events.GameStateChanged;
+import net.runelite.api.events.GameTick;
+import net.runelite.api.events.NpcSpawned;
+import net.runelite.api.geometry.Geometry;
+import net.runelite.client.config.ConfigManager;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.game.ItemManager;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.ui.overlay.OverlayManager;
+import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
+import net.runelite.client.util.WildcardMatcher;
+
+@Slf4j
+@PluginDescriptor(
+ name = "NPC Aggression Timer",
+ description = "Highlights the unaggressive area of NPCs nearby and timer until it becomes active",
+ tags = {"highlight", "lines", "unaggro", "aggro", "aggressive", "npcs", "area", "slayer"},
+ enabledByDefault = false
+)
+public class NpcAggroAreaPlugin extends Plugin
+{
+ /*
+ How it works: The game remembers 2 tiles. When the player goes >10 steps
+ away from both tiles, the oldest one is moved to under the player and the
+ NPC aggression timer resets.
+ So to first figure out where the 2 tiles are, we wait until the player teleports
+ a long enough distance. At that point it's very likely that the player
+ moved out of the radius of both tiles, which resets one of them. The other
+ should reset shortly after as the player starts moving around.
+ */
+
+ private static final int SAFE_AREA_RADIUS = 10;
+ private static final int UNKNOWN_AREA_RADIUS = SAFE_AREA_RADIUS * 2;
+ private static final int AGGRESSIVE_TIME_SECONDS = 600;
+ private static final Splitter NAME_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
+ private static final WorldArea WILDERNESS_ABOVE_GROUND = new WorldArea(2944, 3523, 448, 448, 0);
+ private static final WorldArea WILDERNESS_UNDERGROUND = new WorldArea(2944, 9918, 320, 442, 0);
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private NpcAggroAreaConfig config;
+
+ @Inject
+ private NpcAggroAreaOverlay overlay;
+
+ @Inject
+ private NpcAggroAreaNotWorkingOverlay notWorkingOverlay;
+
+ @Inject
+ private OverlayManager overlayManager;
+
+ @Inject
+ private ItemManager itemManager;
+
+ @Inject
+ private InfoBoxManager infoBoxManager;
+
+ @Inject
+ private ConfigManager configManager;
+
+ @Getter
+ private final WorldPoint[] safeCenters = new WorldPoint[2];
+
+ @Getter
+ private final GeneralPath[] linesToDisplay = new GeneralPath[Constants.MAX_Z];
+
+ @Getter
+ private boolean active;
+
+ @Getter
+ private AggressionTimer currentTimer;
+
+ private WorldPoint lastPlayerLocation;
+ private WorldPoint previousUnknownCenter;
+ private boolean loggingIn;
+ private List npcNamePatterns;
+
+ @Provides
+ NpcAggroAreaConfig provideConfig(ConfigManager configManager)
+ {
+ return configManager.getConfig(NpcAggroAreaConfig.class);
+ }
+
+ @Override
+ protected void startUp() throws Exception
+ {
+ overlayManager.add(overlay);
+ overlayManager.add(notWorkingOverlay);
+ npcNamePatterns = NAME_SPLITTER.splitToList(config.npcNamePatterns());
+ }
+
+ @Override
+ protected void shutDown() throws Exception
+ {
+ removeTimer();
+ overlayManager.remove(overlay);
+ overlayManager.remove(notWorkingOverlay);
+ Arrays.fill(safeCenters, null);
+ lastPlayerLocation = null;
+ currentTimer = null;
+ loggingIn = false;
+ npcNamePatterns = null;
+ active = false;
+
+ Arrays.fill(linesToDisplay, null);
+ }
+
+ private Area generateSafeArea()
+ {
+ final Area area = new Area();
+
+ for (WorldPoint wp : safeCenters)
+ {
+ if (wp == null)
+ {
+ continue;
+ }
+
+ Polygon poly = new Polygon();
+ poly.addPoint(wp.getX() - SAFE_AREA_RADIUS, wp.getY() - SAFE_AREA_RADIUS);
+ poly.addPoint(wp.getX() - SAFE_AREA_RADIUS, wp.getY() + SAFE_AREA_RADIUS + 1);
+ poly.addPoint(wp.getX() + SAFE_AREA_RADIUS + 1, wp.getY() + SAFE_AREA_RADIUS + 1);
+ poly.addPoint(wp.getX() + SAFE_AREA_RADIUS + 1, wp.getY() - SAFE_AREA_RADIUS);
+ area.add(new Area(poly));
+ }
+
+ return area;
+ }
+
+ private void transformWorldToLocal(float[] coords)
+ {
+ final LocalPoint lp = LocalPoint.fromWorld(client, (int)coords[0], (int)coords[1]);
+ coords[0] = lp.getX() - Perspective.LOCAL_TILE_SIZE / 2f;
+ coords[1] = lp.getY() - Perspective.LOCAL_TILE_SIZE / 2f;
+ }
+
+ private void reevaluateActive()
+ {
+ if (currentTimer != null)
+ {
+ currentTimer.setVisible(active && config.showTimer());
+ }
+
+ calculateLinesToDisplay();
+ }
+
+ private void calculateLinesToDisplay()
+ {
+ if (!active || !config.showAreaLines())
+ {
+ Arrays.fill(linesToDisplay, null);
+ return;
+ }
+
+ Rectangle sceneRect = new Rectangle(
+ client.getBaseX() + 1, client.getBaseY() + 1,
+ Constants.SCENE_SIZE - 2, Constants.SCENE_SIZE - 2);
+
+ for (int i = 0; i < linesToDisplay.length; i++)
+ {
+ GeneralPath lines = new GeneralPath(generateSafeArea());
+ lines = Geometry.clipPath(lines, sceneRect);
+ lines = Geometry.splitIntoSegments(lines, 1);
+ lines = Geometry.transformPath(lines, this::transformWorldToLocal);
+ linesToDisplay[i] = lines;
+ }
+ }
+
+ private void removeTimer()
+ {
+ infoBoxManager.removeInfoBox(currentTimer);
+ currentTimer = null;
+ }
+
+ private void createTimer(Duration duration)
+ {
+ removeTimer();
+ BufferedImage image = itemManager.getImage(ItemID.ENSOULED_DEMON_HEAD);
+ currentTimer = new AggressionTimer(duration, image, this, active && config.showTimer());
+ infoBoxManager.addInfoBox(currentTimer);
+ }
+
+ private void resetTimer()
+ {
+ createTimer(Duration.ofSeconds(AGGRESSIVE_TIME_SECONDS));
+ }
+
+ private static boolean isInWilderness(WorldPoint location)
+ {
+ return WILDERNESS_ABOVE_GROUND.distanceTo2D(location) == 0 || WILDERNESS_UNDERGROUND.distanceTo2D(location) == 0;
+ }
+
+ private boolean isNpcMatch(NPC npc)
+ {
+ NPCComposition composition = npc.getTransformedComposition();
+ if (composition == null)
+ {
+ return false;
+ }
+
+ if (Strings.isNullOrEmpty(composition.getName()))
+ {
+ return false;
+ }
+
+ // Most NPCs stop aggroing when the player has more than double
+ // its combat level.
+ int playerLvl = client.getLocalPlayer().getCombatLevel();
+ int npcLvl = composition.getCombatLevel();
+ String npcName = composition.getName().toLowerCase();
+ if (npcLvl > 0 && playerLvl > npcLvl * 2 && !isInWilderness(npc.getWorldLocation()))
+ {
+ return false;
+ }
+
+ for (String pattern : npcNamePatterns)
+ {
+ if (WildcardMatcher.matches(pattern, npcName))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void checkAreaNpcs(final NPC... npcs)
+ {
+ for (NPC npc : npcs)
+ {
+ if (npc == null)
+ {
+ continue;
+ }
+
+ if (isNpcMatch(npc))
+ {
+ active = true;
+ break;
+ }
+ }
+
+ reevaluateActive();
+ }
+
+ private void recheckActive()
+ {
+ active = config.alwaysActive();
+ checkAreaNpcs(client.getCachedNPCs());
+ }
+
+ @Subscribe
+ public void onNpcSpawned(NpcSpawned event)
+ {
+ if (config.alwaysActive())
+ {
+ return;
+ }
+
+ checkAreaNpcs(event.getNpc());
+ }
+
+ @Subscribe
+ public void onGameTick(GameTick event)
+ {
+ WorldPoint newLocation = client.getLocalPlayer().getWorldLocation();
+ if (lastPlayerLocation != null)
+ {
+ if (safeCenters[1] == null && newLocation.distanceTo2D(lastPlayerLocation) > SAFE_AREA_RADIUS * 4)
+ {
+ safeCenters[0] = null;
+ safeCenters[1] = newLocation;
+ resetTimer();
+ calculateLinesToDisplay();
+
+ // We don't know where the previous area was, so if the player e.g.
+ // entered a dungeon and then goes back out, he/she may enter the previous
+ // area which is unknown and would make the plugin inaccurate
+ previousUnknownCenter = lastPlayerLocation;
+ }
+ }
+
+ if (safeCenters[0] == null && previousUnknownCenter != null &&
+ previousUnknownCenter.distanceTo2D(newLocation) <= UNKNOWN_AREA_RADIUS)
+ {
+ // Player went back to their previous unknown area before the 2nd
+ // center point was found, which means we don't know where it is again.
+ safeCenters[1] = null;
+ removeTimer();
+ calculateLinesToDisplay();
+ }
+
+ if (safeCenters[1] != null)
+ {
+ if (Arrays.stream(safeCenters).noneMatch(
+ x -> x != null && x.distanceTo2D(newLocation) <= SAFE_AREA_RADIUS))
+ {
+ safeCenters[0] = safeCenters[1];
+ safeCenters[1] = newLocation;
+ resetTimer();
+ calculateLinesToDisplay();
+ previousUnknownCenter = null;
+ }
+ }
+
+ lastPlayerLocation = newLocation;
+ }
+
+ @Subscribe
+ public void onConfigChanged(ConfigChanged event)
+ {
+ String key = event.getKey();
+ switch (key)
+ {
+ case "npcUnaggroAlwaysActive":
+ recheckActive();
+ break;
+ case "npcUnaggroShowTimer":
+ if (currentTimer != null)
+ {
+ currentTimer.setVisible(active && config.showTimer());
+ }
+ break;
+ case "npcUnaggroCollisionDetection":
+ case "npcUnaggroShowAreaLines":
+ calculateLinesToDisplay();
+ break;
+ case "npcUnaggroNames":
+ npcNamePatterns = NAME_SPLITTER.splitToList(config.npcNamePatterns());
+ recheckActive();
+ break;
+ }
+ }
+
+ private void loadConfig()
+ {
+ safeCenters[0] = configManager.getConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_CENTER1, WorldPoint.class);
+ safeCenters[1] = configManager.getConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_CENTER2, WorldPoint.class);
+ lastPlayerLocation = configManager.getConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_LOCATION, WorldPoint.class);
+
+ Duration timeLeft = configManager.getConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_DURATION, Duration.class);
+ if (timeLeft != null)
+ {
+ createTimer(timeLeft);
+ }
+ }
+
+ private void resetConfig()
+ {
+ configManager.unsetConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_CENTER1);
+ configManager.unsetConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_CENTER2);
+ configManager.unsetConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_LOCATION);
+ configManager.unsetConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_DURATION);
+ }
+
+ private void saveConfig()
+ {
+ if (safeCenters[0] == null || safeCenters[1] == null || lastPlayerLocation == null || currentTimer == null)
+ {
+ resetConfig();
+ }
+ else
+ {
+ configManager.setConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_CENTER1, safeCenters[0]);
+ configManager.setConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_CENTER2, safeCenters[1]);
+ configManager.setConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_LOCATION, lastPlayerLocation);
+ configManager.setConfiguration(NpcAggroAreaConfig.CONFIG_GROUP, NpcAggroAreaConfig.CONFIG_DURATION, Duration.between(Instant.now(), currentTimer.getEndTime()));
+ }
+ }
+
+ private void onLogin()
+ {
+ loadConfig();
+ resetConfig();
+
+ WorldPoint newLocation = client.getLocalPlayer().getWorldLocation();
+ assert newLocation != null;
+
+ // If the player isn't at the location he/she logged out at,
+ // the safe unaggro area probably changed, and should be disposed.
+ if (lastPlayerLocation == null || newLocation.distanceTo(lastPlayerLocation) != 0)
+ {
+ safeCenters[0] = null;
+ safeCenters[1] = null;
+ lastPlayerLocation = newLocation;
+ }
+ }
+
+ @Subscribe
+ public void onGameStateChanged(GameStateChanged event)
+ {
+ switch (event.getGameState())
+ {
+ case LOGGED_IN:
+ if (loggingIn)
+ {
+ loggingIn = false;
+ onLogin();
+ }
+
+ recheckActive();
+ break;
+
+ case LOGGING_IN:
+ loggingIn = true;
+ break;
+
+ case LOGIN_SCREEN:
+ if (lastPlayerLocation != null)
+ {
+ saveConfig();
+ }
+
+ safeCenters[0] = null;
+ safeCenters[1] = null;
+ lastPlayerLocation = null;
+ break;
+ }
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsOverlay.java
index af9431038e..f111a6f94f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsOverlay.java
@@ -29,6 +29,7 @@ import java.awt.Graphics2D;
import java.awt.Polygon;
import javax.inject.Inject;
import net.runelite.api.Client;
+import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.TileObject;
import net.runelite.client.ui.overlay.Overlay;
@@ -65,22 +66,31 @@ class ObjectIndicatorsOverlay extends Overlay
}
final Polygon polygon;
+ Polygon polygon2 = null;
if (object instanceof GameObject)
{
polygon = ((GameObject) object).getConvexHull();
}
+ else if (object instanceof DecorativeObject)
+ {
+ polygon = ((DecorativeObject) object).getConvexHull();
+ polygon2 = ((DecorativeObject) object).getConvexHull2();
+ }
else
{
polygon = object.getCanvasTilePoly();
}
- if (polygon == null)
+ if (polygon != null)
{
- continue;
+ OverlayUtil.renderPolygon(graphics, polygon, config.markerColor());
}
- OverlayUtil.renderPolygon(graphics, polygon, config.markerColor());
+ if (polygon2 != null)
+ {
+ OverlayUtil.renderPolygon(graphics, polygon2, config.markerColor());
+ }
}
return null;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java
index a352d728db..05fd84d0d8 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java
@@ -43,6 +43,7 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import static net.runelite.api.Constants.REGION_SIZE;
+import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import net.runelite.api.MenuAction;
@@ -58,6 +59,8 @@ import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
+import net.runelite.api.events.DecorativeObjectSpawned;
+import net.runelite.api.events.DecorativeObjectDespawned;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyListener;
@@ -158,26 +161,15 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
@Subscribe
public void onGameObjectSpawned(GameObjectSpawned event)
{
- final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, event.getGameObject().getLocalLocation());
- final Set objectPoints = points.get(worldPoint.getRegionID());
+ final GameObject eventObject = event.getGameObject();
+ checkObjectPoints(eventObject);
+ }
- if (objectPoints == null)
- {
- return;
- }
-
- for (ObjectPoint objectPoint : objectPoints)
- {
- if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX()
- && (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY())
- {
- if (objectPoint.getName().equals(client.getObjectDefinition(event.getGameObject().getId()).getName()))
- {
- objects.add(event.getGameObject());
- break;
- }
- }
- }
+ @Subscribe
+ public void onDecorativeObjectSpawned(DecorativeObjectSpawned event)
+ {
+ final DecorativeObject eventObject = event.getDecorativeObject();
+ checkObjectPoints(eventObject);
}
@Subscribe
@@ -186,6 +178,12 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
objects.remove(event.getGameObject());
}
+ @Subscribe
+ public void onDecorativeObjectDespawned(DecorativeObjectDespawned event)
+ {
+ objects.remove(event.getDecorativeObject());
+ }
+
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
@@ -263,6 +261,30 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
markObject(name, object);
}
+ private void checkObjectPoints(TileObject object)
+ {
+ final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation());
+ final Set objectPoints = points.get(worldPoint.getRegionID());
+
+ if (objectPoints == null)
+ {
+ return;
+ }
+
+ for (ObjectPoint objectPoint : objectPoints)
+ {
+ if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX()
+ && (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY())
+ {
+ if (objectPoint.getName().equals(client.getObjectDefinition(object.getId()).getName()))
+ {
+ objects.add(object);
+ break;
+ }
+ }
+ }
+ }
+
private TileObject findTileObject(Tile tile, int id)
{
if (tile == null)
@@ -271,6 +293,12 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
}
final GameObject[] tileGameObjects = tile.getGameObjects();
+ final DecorativeObject tileDecorativeObject = tile.getDecorativeObject();
+
+ if (tileDecorativeObject != null && tileDecorativeObject.getId() == id)
+ {
+ return tileDecorativeObject;
+ }
for (GameObject object : tileGameObjects)
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java
index 03110fe35c..0e910ff338 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java
@@ -128,6 +128,7 @@ public class PartyPlugin extends Plugin implements KeyListener
private int lastHp, lastPray;
private boolean hotkeyDown, doSync;
+ private boolean sendAlert;
@Override
public void configure(Binder binder)
@@ -161,6 +162,7 @@ public class PartyPlugin extends Plugin implements KeyListener
keyManager.unregisterKeyListener(this);
hotkeyDown = false;
doSync = false;
+ sendAlert = false;
}
@Provides
@@ -189,7 +191,7 @@ public class PartyPlugin extends Plugin implements KeyListener
.build();
chatMessageManager.queue(QueuedMessage.builder()
- .type(ChatMessageType.GAME)
+ .type(ChatMessageType.CLANCHAT_INFO)
.runeLiteFormattedMessage(leaveMessage)
.build());
}
@@ -284,6 +286,12 @@ public class PartyPlugin extends Plugin implements KeyListener
@Subscribe
public void onGameTick(final GameTick event)
{
+ if (sendAlert && client.getGameState() == GameState.LOGGED_IN)
+ {
+ sendAlert = false;
+ sendInstructionMessage();
+ }
+
if (doSync && !party.getMembers().isEmpty())
{
// Request sync
@@ -373,7 +381,7 @@ public class PartyPlugin extends Plugin implements KeyListener
.build();
chatMessageManager.queue(QueuedMessage.builder()
- .type(ChatMessageType.GAME)
+ .type(ChatMessageType.CLANCHAT_INFO)
.runeLiteFormattedMessage(joinMessage)
.build());
@@ -381,15 +389,7 @@ public class PartyPlugin extends Plugin implements KeyListener
if (localMember != null && partyData.getMemberId().equals(localMember.getMemberId()))
{
- final String helpMessage = new ChatMessageBuilder()
- .append(ChatColorType.HIGHLIGHT)
- .append("To leave party hold SHIFT and right click party stats overlay.")
- .build();
-
- chatMessageManager.queue(QueuedMessage.builder()
- .type(ChatMessageType.GAME)
- .runeLiteFormattedMessage(helpMessage)
- .build());
+ sendAlert = true;
}
}
@@ -430,7 +430,7 @@ public class PartyPlugin extends Plugin implements KeyListener
.build();
chatMessageManager.queue(QueuedMessage.builder()
- .type(ChatMessageType.GAME)
+ .type(ChatMessageType.CLANCHAT_INFO)
.runeLiteFormattedMessage(joinMessage)
.build());
}
@@ -510,4 +510,17 @@ public class PartyPlugin extends Plugin implements KeyListener
hotkeyDown = false;
}
}
+
+ private void sendInstructionMessage()
+ {
+ final String helpMessage = new ChatMessageBuilder()
+ .append(ChatColorType.HIGHLIGHT)
+ .append("To leave party hold SHIFT and right click party stats overlay.")
+ .build();
+
+ chatMessageManager.queue(QueuedMessage.builder()
+ .type(ChatMessageType.CLANCHAT_INFO)
+ .runeLiteFormattedMessage(helpMessage)
+ .build());
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java
index 2b9e1820f3..693b23cb89 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java
@@ -27,6 +27,8 @@ package net.runelite.client.plugins.party;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Rectangle;
import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
@@ -34,6 +36,7 @@ import net.runelite.api.MenuAction;
import net.runelite.client.plugins.party.data.PartyData;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
+import net.runelite.client.ui.overlay.components.ComponentConstants;
import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.components.ProgressBarComponent;
import net.runelite.client.ui.overlay.components.TitleComponent;
@@ -58,6 +61,8 @@ public class PartyStatsOverlay extends Overlay
this.plugin = plugin;
this.party = party;
this.config = config;
+ body.setBorder(new Rectangle());
+ body.setGap(new Point(0, ComponentConstants.STANDARD_BORDER / 2));
getMenuEntries().add(new OverlayMenuEntry(MenuAction.RUNELITE_OVERLAY, "Leave", "Party"));
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/LocationUpdate.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/LocationUpdate.java
index 0ff6569379..f5bf7131ce 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/LocationUpdate.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/LocationUpdate.java
@@ -24,11 +24,13 @@
*/
package net.runelite.client.plugins.party.messages;
+import lombok.EqualsAndHashCode;
import lombok.Value;
import net.runelite.api.coords.WorldPoint;
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
@Value
+@EqualsAndHashCode(callSuper = true)
public class LocationUpdate extends PartyMemberMessage
{
private final WorldPoint worldPoint;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/TilePing.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/TilePing.java
index 1378403333..fb4f812a81 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/TilePing.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/TilePing.java
@@ -24,11 +24,13 @@
*/
package net.runelite.client.plugins.party.messages;
+import lombok.EqualsAndHashCode;
import lombok.Value;
import net.runelite.api.coords.WorldPoint;
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
@Value
+@EqualsAndHashCode(callSuper = true)
public class TilePing extends PartyMemberMessage
{
private final WorldPoint point;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PestControlPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PestControlPlugin.java
index 360e56f40d..7e711e66a0 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PestControlPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PestControlPlugin.java
@@ -92,7 +92,8 @@ public class PestControlPlugin extends Plugin
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
- if (event.getGameState() == GameState.LOADING)
+ GameState gameState = event.getGameState();
+ if (gameState == GameState.CONNECTION_LOST || gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING)
{
spinners.clear();
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java
index c40d4a9020..6b032bc8ee 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java
@@ -155,13 +155,13 @@ public interface PlayerIndicatorsConfig extends Config
@ConfigItem(
position = 11,
- keyName = "drawOverheadPlayerNames",
- name = "Draw names above players",
- description = "Configures whether or not player names should be drawn above players"
+ keyName = "playerNamePosition",
+ name = "Name position",
+ description = "Configures the position of drawn player names, or if they should be disabled"
)
- default boolean drawOverheadPlayerNames()
+ default PlayerNameLocation playerNamePosition()
{
- return true;
+ return PlayerNameLocation.ABOVE_HEAD;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java
index 3795b89f1c..5373fc1eb4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018, Tomas Slusny
+ * Copyright (c) 2019, Jordan Atwood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,10 +39,14 @@ import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.OverlayUtil;
+import net.runelite.client.util.Text;
@Singleton
public class PlayerIndicatorsOverlay extends Overlay
{
+ private static final int ACTOR_OVERHEAD_TEXT_MARGIN = 40;
+ private static final int ACTOR_HORIZONTAL_TEXT_MARGIN = 10;
+
private final PlayerIndicatorsService playerIndicatorsService;
private final PlayerIndicatorsConfig config;
private final ClanManager clanManager;
@@ -66,39 +71,78 @@ public class PlayerIndicatorsOverlay extends Overlay
private void renderPlayerOverlay(Graphics2D graphics, Player actor, Color color)
{
- if (!config.drawOverheadPlayerNames())
+ final PlayerNameLocation drawPlayerNamesConfig = config.playerNamePosition();
+ if (drawPlayerNamesConfig == PlayerNameLocation.DISABLED)
{
return;
}
- String name = actor.getName().replace('\u00A0', ' ');
- int offset = actor.getLogicalHeight() + 40;
- Point textLocation = actor.getCanvasTextLocation(graphics, name, offset);
-
- if (textLocation != null)
+ final int zOffset;
+ switch (drawPlayerNamesConfig)
{
- if (config.showClanRanks() && actor.isClanMember())
+ case MODEL_CENTER:
+ case MODEL_RIGHT:
+ zOffset = actor.getLogicalHeight() / 2;
+ break;
+ default:
+ zOffset = actor.getLogicalHeight() + ACTOR_OVERHEAD_TEXT_MARGIN;
+ }
+
+ final String name = Text.sanitize(actor.getName());
+ Point textLocation = actor.getCanvasTextLocation(graphics, name, zOffset);
+
+ if (drawPlayerNamesConfig == PlayerNameLocation.MODEL_RIGHT)
+ {
+ textLocation = actor.getCanvasTextLocation(graphics, "", zOffset);
+
+ if (textLocation == null)
{
- ClanMemberRank rank = clanManager.getRank(name);
-
- if (rank != ClanMemberRank.UNRANKED)
- {
- BufferedImage clanchatImage = clanManager.getClanImage(rank);
-
- if (clanchatImage != null)
- {
- int width = clanchatImage.getWidth();
- int textHeight = graphics.getFontMetrics().getHeight() - graphics.getFontMetrics().getMaxDescent();
- Point imageLocation = new Point(textLocation.getX() - width / 2 - 1, textLocation.getY() - textHeight / 2 - clanchatImage.getHeight() / 2);
- OverlayUtil.renderImageLocation(graphics, imageLocation, clanchatImage);
-
- // move text
- textLocation = new Point(textLocation.getX() + width / 2, textLocation.getY());
- }
- }
+ return;
}
- OverlayUtil.renderTextLocation(graphics, textLocation, name, color);
+ textLocation = new Point(textLocation.getX() + ACTOR_HORIZONTAL_TEXT_MARGIN, textLocation.getY());
}
+
+ if (textLocation == null)
+ {
+ return;
+ }
+
+ if (config.showClanRanks() && actor.isClanMember())
+ {
+ final ClanMemberRank rank = clanManager.getRank(name);
+
+ if (rank != ClanMemberRank.UNRANKED)
+ {
+ final BufferedImage clanchatImage = clanManager.getClanImage(rank);
+
+ if (clanchatImage != null)
+ {
+ final int clanImageWidth = clanchatImage.getWidth();
+ final int clanImageTextMargin;
+ final int clanImageNegativeMargin;
+
+ if (drawPlayerNamesConfig == PlayerNameLocation.MODEL_RIGHT)
+ {
+ clanImageTextMargin = clanImageWidth;
+ clanImageNegativeMargin = 0;
+ }
+ else
+ {
+ clanImageTextMargin = clanImageWidth / 2;
+ clanImageNegativeMargin = clanImageWidth / 2;
+ }
+
+ final int textHeight = graphics.getFontMetrics().getHeight() - graphics.getFontMetrics().getMaxDescent();
+ final Point imageLocation = new Point(textLocation.getX() - clanImageNegativeMargin - 1, textLocation.getY() - textHeight / 2 - clanchatImage.getHeight() / 2);
+ OverlayUtil.renderImageLocation(graphics, imageLocation, clanchatImage);
+
+ // move text
+ textLocation = new Point(textLocation.getX() + clanImageTextMargin, textLocation.getY());
+ }
+ }
+ }
+
+ OverlayUtil.renderTextLocation(graphics, textLocation, name, color);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerNameLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerNameLocation.java
new file mode 100644
index 0000000000..14a4eff208
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerNameLocation.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019, Jordan Atwood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.playerindicators;
+
+import lombok.AllArgsConstructor;
+
+@AllArgsConstructor
+public enum PlayerNameLocation
+{
+
+ DISABLED("Disabled"),
+ ABOVE_HEAD("Above head"),
+ MODEL_CENTER("Center of model"),
+ MODEL_RIGHT("Right of model");
+
+ private final String name;
+
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonConfig.java
new file mode 100644
index 0000000000..6c723d4f71
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonConfig.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018 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.poison;
+
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+import net.runelite.client.config.ConfigItem;
+
+@ConfigGroup(PoisonConfig.GROUP)
+public interface PoisonConfig extends Config
+{
+ String GROUP = "poison";
+
+ @ConfigItem(
+ keyName = "showInfoboxes",
+ name = "Show Infoboxes",
+ description = "Configures whether to show the infoboxes"
+ )
+ default boolean showInfoboxes()
+ {
+ return false;
+ }
+
+ @ConfigItem(
+ keyName = "changeHealthIcon",
+ name = "Change HP Orb Icon",
+ description = "Configures whether the hp orb icon should change color to match poison/disease"
+ )
+ default boolean changeHealthIcon()
+ {
+ return true;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonInfobox.java b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonInfobox.java
new file mode 100644
index 0000000000..44d7746781
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonInfobox.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 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.poison;
+
+import java.awt.Color;
+import java.time.temporal.ChronoUnit;
+import java.awt.image.BufferedImage;
+import net.runelite.client.ui.overlay.infobox.Timer;
+
+class PoisonInfobox extends Timer
+{
+ private final PoisonPlugin plugin;
+
+ PoisonInfobox(BufferedImage image, PoisonPlugin plugin)
+ {
+ super(PoisonPlugin.POISON_TICK_MILLIS, ChronoUnit.MILLIS, image, plugin);
+ this.plugin = plugin;
+ }
+
+ @Override
+ public String getTooltip()
+ {
+ return plugin.createTooltip();
+ }
+
+ @Override
+ public Color getTextColor()
+ {
+ return Color.RED.brighter();
+ }
+}
+
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonOverlay.java
new file mode 100644
index 0000000000..758811f292
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonOverlay.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018 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.poison;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import javax.inject.Inject;
+import net.runelite.api.Client;
+import net.runelite.api.Point;
+import net.runelite.api.widgets.Widget;
+import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.client.ui.overlay.Overlay;
+import net.runelite.client.ui.overlay.OverlayLayer;
+import net.runelite.client.ui.overlay.OverlayPosition;
+import net.runelite.client.ui.overlay.tooltip.Tooltip;
+import net.runelite.client.ui.overlay.tooltip.TooltipManager;
+
+class PoisonOverlay extends Overlay
+{
+ private final PoisonPlugin plugin;
+ private final Client client;
+ private final TooltipManager tooltipManager;
+
+ @Inject
+ private PoisonOverlay(final PoisonPlugin plugin, final Client client, final TooltipManager tooltipManager)
+ {
+ this.plugin = plugin;
+ this.client = client;
+ this.tooltipManager = tooltipManager;
+ setPosition(OverlayPosition.DYNAMIC);
+ setLayer(OverlayLayer.ABOVE_WIDGETS);
+ }
+
+ @Override
+ public Dimension render(Graphics2D graphics)
+ {
+ if (plugin.getLastDamage() <= 0)
+ {
+ return null;
+ }
+
+ final Widget healthOrb = client.getWidget(WidgetInfo.MINIMAP_HEALTH_ORB);
+
+ if (healthOrb == null || healthOrb.isHidden())
+ {
+ return null;
+ }
+
+ final Rectangle bounds = healthOrb.getBounds();
+
+ if (bounds.getX() <= 0)
+ {
+ return null;
+ }
+
+ final Point mousePosition = client.getMouseCanvasPosition();
+
+ if (bounds.contains(mousePosition.getX(), mousePosition.getY()))
+ {
+ tooltipManager.add(new Tooltip(plugin.createTooltip()));
+ }
+
+ return null;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonPlugin.java
new file mode 100644
index 0000000000..84a4c5e3d6
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonPlugin.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2018 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.poison;
+
+import com.google.inject.Provides;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.text.MessageFormat;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import javax.inject.Inject;
+import lombok.Getter;
+import net.runelite.api.Client;
+import net.runelite.api.GameState;
+import net.runelite.api.SpriteID;
+import net.runelite.api.VarPlayer;
+import net.runelite.api.events.ConfigChanged;
+import net.runelite.api.events.VarbitChanged;
+import net.runelite.client.callback.ClientThread;
+import net.runelite.client.config.ConfigManager;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.game.SpriteManager;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.ui.FontManager;
+import net.runelite.client.ui.overlay.OverlayManager;
+import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
+import net.runelite.client.util.ColorUtil;
+import net.runelite.client.util.ImageUtil;
+
+@PluginDescriptor(
+ name = "Poison",
+ description = "Tracks current damage values for Poison and Venom",
+ tags = {"combat", "poison", "venom", "heart", "hp"}
+)
+public class PoisonPlugin extends Plugin
+{
+ static final int POISON_TICK_MILLIS = 18200;
+ private static final int VENOM_THRESHOLD = 1000000;
+ private static final int VENOM_MAXIUMUM_DAMAGE = 20;
+
+ private static final BufferedImage HEART_DISEASE;
+ private static final BufferedImage HEART_POISON;
+ private static final BufferedImage HEART_VENOM;
+
+ static
+ {
+ HEART_DISEASE = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-DISEASE.png"), 26, 26);
+ HEART_POISON = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-POISON.png"), 26, 26);
+ HEART_VENOM = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-VENOM.png"), 26, 26);
+ }
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private ClientThread clientThread;
+
+ @Inject
+ private PoisonOverlay poisonOverlay;
+
+ @Inject
+ private OverlayManager overlayManager;
+
+ @Inject
+ private InfoBoxManager infoBoxManager;
+
+ @Inject
+ private SpriteManager spriteManager;
+
+ @Inject
+ private PoisonConfig config;
+
+ @Getter
+ private int lastDamage;
+ private boolean envenomed;
+ private PoisonInfobox infobox;
+ private Instant poisonNaturalCure;
+ private Instant nextPoisonTick;
+ private int lastValue = -1;
+ private int lastDiseaseValue = -1;
+ private BufferedImage heart;
+
+ @Provides
+ PoisonConfig getConfig(ConfigManager configManager)
+ {
+ return configManager.getConfig(PoisonConfig.class);
+ }
+
+ @Override
+ protected void startUp() throws Exception
+ {
+ overlayManager.add(poisonOverlay);
+
+ if (client.getGameState() == GameState.LOGGED_IN)
+ {
+ clientThread.invoke(this::checkHealthIcon);
+ }
+ }
+
+ @Override
+ protected void shutDown() throws Exception
+ {
+ overlayManager.remove(poisonOverlay);
+
+ if (infobox != null)
+ {
+ infoBoxManager.removeInfoBox(infobox);
+ infobox = null;
+ }
+
+ envenomed = false;
+ lastDamage = 0;
+ poisonNaturalCure = null;
+ nextPoisonTick = null;
+ lastValue = -1;
+ lastDiseaseValue = -1;
+
+ clientThread.invoke(this::resetHealthIcon);
+ }
+
+ @Subscribe
+ public void onVarbitChanged(VarbitChanged event)
+ {
+ final int poisonValue = client.getVar(VarPlayer.POISON);
+ if (poisonValue != lastValue)
+ {
+ lastValue = poisonValue;
+ nextPoisonTick = Instant.now().plus(Duration.of(POISON_TICK_MILLIS, ChronoUnit.MILLIS));
+
+ final int damage = nextDamage(poisonValue);
+ this.lastDamage = damage;
+
+ envenomed = poisonValue >= VENOM_THRESHOLD;
+
+ if (poisonValue < VENOM_THRESHOLD)
+ {
+ poisonNaturalCure = Instant.now().plus(Duration.of(POISON_TICK_MILLIS * poisonValue, ChronoUnit.MILLIS));
+ }
+ else
+ {
+ poisonNaturalCure = null;
+ }
+
+ if (config.showInfoboxes())
+ {
+ if (infobox != null)
+ {
+ infoBoxManager.removeInfoBox(infobox);
+ infobox = null;
+ }
+
+ if (damage > 0)
+ {
+ final BufferedImage image = getSplat(envenomed ? SpriteID.HITSPLAT_DARK_GREEN_VENOM : SpriteID.HITSPLAT_GREEN_POISON, damage);
+
+ if (image != null)
+ {
+ infobox = new PoisonInfobox(image, this);
+ infoBoxManager.addInfoBox(infobox);
+ }
+ }
+ }
+
+ checkHealthIcon();
+ }
+
+ final int diseaseValue = client.getVar(VarPlayer.DISEASE_VALUE);
+ if (diseaseValue != lastDiseaseValue)
+ {
+ lastDiseaseValue = diseaseValue;
+ checkHealthIcon();
+ }
+ }
+
+ @Subscribe
+ public void onConfigChanged(ConfigChanged event)
+ {
+ if (!event.getGroup().equals(PoisonConfig.GROUP))
+ {
+ return;
+ }
+
+ if (!config.showInfoboxes() && infobox != null)
+ {
+ infoBoxManager.removeInfoBox(infobox);
+ infobox = null;
+ }
+
+ if (config.changeHealthIcon())
+ {
+ clientThread.invoke(this::checkHealthIcon);
+ }
+ else
+ {
+ clientThread.invoke(this::resetHealthIcon);
+ }
+ }
+
+ private static int nextDamage(int poisonValue)
+ {
+ int damage;
+
+ if (poisonValue >= VENOM_THRESHOLD)
+ {
+ //Venom Damage starts at 6, and increments in twos;
+ //The VarPlayer increments in values of 1, however.
+ poisonValue -= VENOM_THRESHOLD - 3;
+ damage = poisonValue * 2;
+ //Venom Damage caps at 20, but the VarPlayer keeps increasing
+ if (damage > VENOM_MAXIUMUM_DAMAGE)
+ {
+ damage = VENOM_MAXIUMUM_DAMAGE;
+ }
+ }
+ else
+ {
+ damage = (int) Math.ceil(poisonValue / 5.0f);
+ }
+
+ return damage;
+ }
+
+ private BufferedImage getSplat(int id, int damage)
+ {
+ //Get a copy of the hitsplat to get a clean one each time
+ final BufferedImage rawSplat = spriteManager.getSprite(id, 0);
+ if (rawSplat == null)
+ {
+ return null;
+ }
+
+ final BufferedImage splat = new BufferedImage(
+ rawSplat.getColorModel(),
+ rawSplat.copyData(null),
+ rawSplat.getColorModel().isAlphaPremultiplied(),
+ null);
+
+ final Graphics g = splat.getGraphics();
+ g.setFont(FontManager.getRunescapeSmallFont());
+
+ // Align the text in the centre of the hitsplat
+ final FontMetrics metrics = g.getFontMetrics();
+ final String text = String.valueOf(damage);
+ final int x = (splat.getWidth() - metrics.stringWidth(text)) / 2;
+ final int y = (splat.getHeight() - metrics.getHeight()) / 2 + metrics.getAscent();
+
+ g.setColor(Color.BLACK);
+ g.drawString(String.valueOf(damage), x + 1, y + 1);
+ g.setColor(Color.WHITE);
+ g.drawString(String.valueOf(damage), x, y);
+ return splat;
+ }
+
+ private static String getFormattedTime(Instant endTime)
+ {
+ final Duration timeLeft = Duration.between(Instant.now(), endTime);
+ int seconds = (int) (timeLeft.toMillis() / 1000L);
+ int minutes = seconds / 60;
+ int secs = seconds % 60;
+
+ return String.format("%d:%02d", minutes, secs);
+ }
+
+ String createTooltip()
+ {
+ String line1 = MessageFormat.format("Next {0} damage: {1}Time until damage: {2}",
+ envenomed ? "venom" : "poison", ColorUtil.wrapWithColorTag(String.valueOf(lastDamage), Color.RED), getFormattedTime(nextPoisonTick));
+ String line2 = envenomed ? "" : MessageFormat.format("Time until cure: {0}", getFormattedTime(poisonNaturalCure));
+
+ return line1 + line2;
+ }
+
+ private void checkHealthIcon()
+ {
+ if (!config.changeHealthIcon())
+ {
+ return;
+ }
+
+ final BufferedImage newHeart;
+ final int poison = client.getVar(VarPlayer.IS_POISONED);
+
+ if (poison >= VENOM_THRESHOLD)
+ {
+ newHeart = HEART_VENOM;
+ }
+ else if (poison > 0)
+ {
+ newHeart = HEART_POISON;
+ }
+ else if (client.getVar(VarPlayer.DISEASE_VALUE) > 0)
+ {
+ newHeart = HEART_DISEASE;
+ }
+ else
+ {
+ resetHealthIcon();
+ return;
+ }
+
+ // Only update sprites when the heart icon actually changes
+ if (newHeart != heart)
+ {
+ heart = newHeart;
+ client.getWidgetSpriteCache().reset();
+ client.getSpriteOverrides().put(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, ImageUtil.getImageSpritePixels(heart, client));
+ }
+ }
+
+ private void resetHealthIcon()
+ {
+ if (heart == null)
+ {
+ return;
+ }
+
+ client.getWidgetSpriteCache().reset();
+ client.getSpriteOverrides().remove(SpriteID.MINIMAP_ORB_HITPOINTS_ICON);
+ heart = null;
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerCounter.java
index 546c9f98a8..c510dab82e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerCounter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerCounter.java
@@ -24,25 +24,32 @@
*/
package net.runelite.client.plugins.prayer;
+import java.awt.Color;
import lombok.Getter;
import net.runelite.client.plugins.Plugin;
-import net.runelite.client.ui.overlay.infobox.Counter;
+import net.runelite.client.ui.overlay.infobox.InfoBox;
-class PrayerCounter extends Counter
+class PrayerCounter extends InfoBox
{
@Getter
private final PrayerType prayerType;
PrayerCounter(Plugin plugin, PrayerType prayerType)
{
- super(null, plugin, "");
+ super(null, plugin);
this.prayerType = prayerType;
}
@Override
- public String toString()
+ public String getText()
{
- return "Counter{" + "prayer=" + prayerType.getName() + '}';
+ return null;
+ }
+
+ @Override
+ public Color getTextColor()
+ {
+ return null;
}
@Override
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerItems.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerItems.java
index df12b4f247..24ffbc5a56 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerItems.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerItems.java
@@ -41,6 +41,9 @@ enum PrayerItems
ANCIENT_BLESSING(ItemID.ANCIENT_BLESSING, 1),
HONOURABLE_BLESSING(ItemID.HONOURABLE_BLESSING, 1),
WAR_BLESSING(ItemID.WAR_BLESSING, 1),
+ RADAS_BLESSING_2(ItemID.RADAS_BLESSING_2, 1),
+ RADAS_BLESSING_3(ItemID.RADAS_BLESSING_3, 1),
+ RADAS_BLESSING_4(ItemID.RADAS_BLESSING_4, 2),
// Rings
EXPLORERS_RING(ItemID.EXPLORERS_RING, 1),
@@ -145,8 +148,8 @@ enum PrayerItems
ANCIENT_DHIDE(ItemID.ANCIENT_DHIDE, 1),
ARMADYL_DHIDE(ItemID.ARMADYL_DHIDE, 1),
BANDOS_DHIDE(ItemID.BANDOS_DHIDE, 1),
- GUTHIX_DRAGONHIDE(ItemID.GUTHIX_DRAGONHIDE, 1),
- GUTHIX_DRAGONHIDE_10794(ItemID.GUTHIX_DRAGONHIDE_10794, 1),
+ GUTHIX_DRAGONHIDE(ItemID.GUTHIX_DHIDE, 1),
+ GUTHIX_DRAGONHIDE_10794(ItemID.GUTHIX_DRAGONHIDE, 1),
SARADOMIN_DHIDE(ItemID.SARADOMIN_DHIDE, 1),
SARADOMIN_DHIDE_10792(ItemID.SARADOMIN_DHIDE_10792, 1),
ZAMORAK_DHIDE(ItemID.ZAMORAK_DHIDE, 1),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java
index 0d4633fe94..46570b3b5a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java
@@ -49,9 +49,6 @@ import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.VarbitChanged;
-import net.runelite.api.events.WidgetHiddenChanged;
-import net.runelite.api.widgets.Widget;
-import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.chat.ChatMessageBuilder;
@@ -104,9 +101,6 @@ public class RaidsPlugin extends Plugin
@Inject
private RaidsOverlay overlay;
- @Inject
- private RaidsPointsOverlay pointsOverlay;
-
@Inject
private LayoutSolver layoutSolver;
@@ -152,7 +146,6 @@ public class RaidsPlugin extends Plugin
protected void startUp() throws Exception
{
overlayManager.add(overlay);
- overlayManager.add(pointsOverlay);
updateLists();
clientThread.invokeLater(() -> checkRaidPresence(true));
}
@@ -161,7 +154,6 @@ public class RaidsPlugin extends Plugin
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
- overlayManager.remove(pointsOverlay);
infoBoxManager.removeInfoBox(timer);
inRaidChambers = false;
raid = null;
@@ -186,22 +178,6 @@ public class RaidsPlugin extends Plugin
clientThread.invokeLater(() -> checkRaidPresence(true));
}
- @Subscribe
- public void onWidgetHiddenChanged(WidgetHiddenChanged event)
- {
- if (!inRaidChambers || event.isHidden())
- {
- return;
- }
-
- Widget widget = event.getWidget();
-
- if (widget == client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX))
- {
- widget.setHidden(true);
- }
- }
-
@Subscribe
public void onVarbitChanged(VarbitChanged event)
{
@@ -230,7 +206,7 @@ public class RaidsPlugin extends Plugin
{
if (timer != null)
{
- timer.timeFloor();
+ timer.timeOlm();
timer.setStopped(true);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsTimer.java
index 8b40b09e10..8df3087054 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsTimer.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsTimer.java
@@ -41,6 +41,7 @@ public class RaidsTimer extends InfoBox
private LocalTime time;
private LocalTime firstFloorTime;
private LocalTime secondFloorTime;
+ private LocalTime thirdFloorTime;
private LocalTime olmTime;
@Setter
@@ -66,14 +67,20 @@ public class RaidsTimer extends InfoBox
{
secondFloorTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
}
- else if (olmTime == null)
+ else if (thirdFloorTime == null)
{
- olmTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
+ thirdFloorTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
}
floorTime = Instant.now();
}
+ public void timeOlm()
+ {
+ Duration elapsed = Duration.between(floorTime, Instant.now());
+ olmTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
+ }
+
@Override
public String getText()
{
@@ -126,6 +133,12 @@ public class RaidsTimer extends InfoBox
builder.append(secondFloorTime.format(DateTimeFormatter.ofPattern("mm:ss")));
}
+ if (thirdFloorTime != null)
+ {
+ builder.append("Third floor: ");
+ builder.append(thirdFloorTime.format(DateTimeFormatter.ofPattern("mm:ss")));
+ }
+
if (olmTime != null)
{
builder.append("Olm: ");
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenPlugin.java
index b7e8b682b0..9a3908f7d3 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenPlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Shaun Dreclin
+ * Copyright (c) 2018-2019, Shaun Dreclin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,7 +24,6 @@
*/
package net.runelite.client.plugins.roguesden;
-import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import javax.inject.Inject;
import lombok.AccessLevel;
@@ -33,8 +32,7 @@ import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
-import net.runelite.api.ItemContainer;
-import static net.runelite.api.ItemID.MYSTIC_JEWEL;
+import net.runelite.api.ItemID;
import net.runelite.api.Tile;
import net.runelite.api.TileObject;
import net.runelite.api.events.GameObjectChanged;
@@ -44,10 +42,10 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GroundObjectChanged;
import net.runelite.api.events.GroundObjectDespawned;
import net.runelite.api.events.GroundObjectSpawned;
+import net.runelite.api.events.ItemContainerChanged;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
-import net.runelite.client.task.Schedule;
import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
@@ -90,29 +88,24 @@ public class RoguesDenPlugin extends Plugin
hasGem = false;
}
- @Schedule(period = 600, unit = ChronoUnit.MILLIS)
- public void checkGem()
+ @Subscribe
+ public void onItemContainerChanged(ItemContainerChanged event)
{
- hasGem = hasGem();
- }
-
- private boolean hasGem()
- {
- ItemContainer container = client.getItemContainer(InventoryID.INVENTORY);
- if (container == null)
+ if (event.getItemContainer() != client.getItemContainer(InventoryID.INVENTORY))
{
- return false;
+ return;
}
- for (Item item : container.getItems())
+ for (Item item : event.getItemContainer().getItems())
{
- if (item.getId() == MYSTIC_JEWEL)
+ if (item.getId() == ItemID.MYSTIC_JEWEL)
{
- return true;
+ hasGem = true;
+ return;
}
}
- return false;
+ hasGem = false;
}
@Subscribe
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java
index 14b53f9995..4662b95d5a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java
@@ -229,10 +229,17 @@ public class RunecraftPlugin extends Plugin
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
- if (event.getGameState() == GameState.LOADING)
+ GameState gameState = event.getGameState();
+ switch (gameState)
{
- abyssObjects.clear();
- darkMage = null;
+ case LOADING:
+ abyssObjects.clear();
+ break;
+ case CONNECTION_LOST:
+ case HOPPING:
+ case LOGIN_SCREEN:
+ darkMage = null;
+ break;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerRenderable.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerRenderable.java
index 0d44e01345..95b2da1207 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerRenderable.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerRenderable.java
@@ -28,6 +28,7 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
+import java.awt.Rectangle;
import java.awt.Stroke;
import lombok.AccessLevel;
import lombok.Getter;
@@ -55,6 +56,9 @@ public class ScreenMarkerRenderable implements LayoutableRenderableEntity
@Setter(AccessLevel.PACKAGE)
private Stroke stroke;
+ @Getter
+ private final Rectangle bounds = new Rectangle();
+
@Override
public Dimension render(Graphics2D graphics)
{
@@ -72,6 +76,7 @@ public class ScreenMarkerRenderable implements LayoutableRenderableEntity
graphics.setColor(color);
graphics.setStroke(stroke);
graphics.drawRect(offset, offset, width - thickness, height - thickness);
+ bounds.setSize(preferredSize);
return preferredSize;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java
index e4c6fd2ec9..ee78f3cc22 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java
@@ -145,6 +145,8 @@ public class ScreenshotPlugin extends Plugin
private Integer chambersOfXericNumber;
+ private Integer chambersOfXericChallengeNumber;
+
private Integer theatreOfBloodNumber;
private boolean shouldTakeScreenshot;
@@ -347,6 +349,16 @@ public class ScreenshotPlugin extends Plugin
}
}
+ if (chatMessage.startsWith("Your completed Chambers of Xeric Challenge Mode count is:"))
+ {
+ Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage));
+ if (m.find())
+ {
+ chambersOfXericChallengeNumber = Integer.valueOf(m.group());
+ return;
+ }
+ }
+
if (chatMessage.startsWith("Your completed Theatre of Blood count is:"))
{
Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage));
@@ -453,14 +465,22 @@ public class ScreenshotPlugin extends Plugin
}
case CHAMBERS_OF_XERIC_REWARD_GROUP_ID:
{
- if (chambersOfXericNumber == null)
+ if (chambersOfXericNumber != null)
+ {
+ fileName = "Chambers of Xeric(" + chambersOfXericNumber + ")";
+ chambersOfXericNumber = null;
+ break;
+ }
+ else if (chambersOfXericChallengeNumber != null)
+ {
+ fileName = "Chambers of Xeric Challenge Mode(" + chambersOfXericChallengeNumber + ")";
+ chambersOfXericChallengeNumber = null;
+ break;
+ }
+ else
{
return;
}
-
- fileName = "Chambers of Xeric(" + chambersOfXericNumber + ")";
- chambersOfXericNumber = null;
- break;
}
case THEATRE_OF_BLOOD_REWARD_GROUP_ID:
{
@@ -720,6 +740,12 @@ public class ScreenshotPlugin extends Plugin
return chambersOfXericNumber;
}
+ @VisibleForTesting
+ int getChambersOfXericChallengeNumber()
+ {
+ return chambersOfXericChallengeNumber;
+ }
+
@VisibleForTesting
int gettheatreOfBloodNumber()
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java
index f0edfc1928..675381b1fb 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java
@@ -73,6 +73,8 @@ class SlayerOverlay extends Overlay
ItemID.RED_SLAYER_HELMET_I,
ItemID.TURQUOISE_SLAYER_HELMET,
ItemID.TURQUOISE_SLAYER_HELMET_I,
+ ItemID.HYDRA_SLAYER_HELMET,
+ ItemID.HYDRA_SLAYER_HELMET_I,
ItemID.SLAYER_RING_ETERNAL,
ItemID.ENCHANTED_GEM,
ItemID.ETERNAL_GEM,
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 3d3d64b25b..875f1f009d 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
@@ -60,7 +60,6 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
-import net.runelite.api.events.SetMessage;
import net.runelite.api.vars.SlayerUnlock;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
@@ -581,7 +580,7 @@ public class SlayerPlugin extends Plugin
// add and update counter, set timer
addCounter();
- counter.setText(String.valueOf(amount));
+ counter.setCount(amount);
infoTimer = Instant.now();
}
@@ -724,14 +723,14 @@ public class SlayerPlugin extends Plugin
counter = null;
}
- void taskLookup(SetMessage setMessage, String message)
+ void taskLookup(ChatMessage chatMessage, String message)
{
if (!config.taskCommand())
{
return;
}
- ChatMessageType type = setMessage.getType();
+ ChatMessageType type = chatMessage.getType();
final String player;
if (type.equals(ChatMessageType.PRIVATE_MESSAGE_SENT))
@@ -740,7 +739,7 @@ public class SlayerPlugin extends Plugin
}
else
{
- player = Text.removeTags(setMessage.getName())
+ player = Text.removeTags(chatMessage.getName())
.replace('\u00A0', ' ');
}
@@ -787,7 +786,7 @@ public class SlayerPlugin extends Plugin
.append(sb.toString())
.build();
- final MessageNode messageNode = setMessage.getMessageNode();
+ final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java
index 5521380e57..ada3f3a727 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java
@@ -59,7 +59,7 @@ class TargetWeaknessOverlay extends Overlay
this.itemManager = itemManager;
this.npcManager = npcManager;
setPosition(OverlayPosition.DYNAMIC);
- setLayer(OverlayLayer.ABOVE_SCENE);
+ setLayer(OverlayLayer.UNDER_WIDGETS);
}
@Override
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 594038aa27..d3663a7def 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
@@ -65,11 +65,11 @@ enum Task
CAVE_SLIMES("Cave slimes", ItemID.SWAMP_CAVE_SLIME),
CERBERUS("Cerberus", ItemID.HELLPUPPY),
CHAOS_ELEMENTAL("Chaos Elemental", ItemID.PET_CHAOS_ELEMENTAL),
- CHAOS_FANATIC("Chaos Fanatic", ItemID.PET_CHAOS_ELEMENTAL),
+ CHAOS_FANATIC("Chaos Fanatic", ItemID.ANCIENT_STAFF),
COCKATRICE("Cockatrice", ItemID.COCKATRICE, "Cockathrice"),
COWS("Cows", ItemID.COW_MASK),
CRAWLING_HANDS("Crawling hands", ItemID.CRAWLING_HAND, "Crushing hand"),
- CRAZY_ARCHAEOLOGIST("Crazy Archaeologist", ItemID.FEDORA),
+ CRAZY_ARCHAEOLOGIST("Crazy Archaeologists", ItemID.FEDORA, "Crazy Archaeologist"),
CROCODILES("Crocodiles", ItemID.SWAMP_LIZARD),
DAGANNOTH("Dagannoth", ItemID.DAGANNOTH),
DAGANNOTH_KINGS("Dagannoth Kings", ItemID.PET_DAGANNOTH_PRIME),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TaskCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TaskCounter.java
index f4ac0045b9..0d4274c063 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TaskCounter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TaskCounter.java
@@ -29,10 +29,10 @@ import net.runelite.client.ui.overlay.infobox.Counter;
import java.awt.image.BufferedImage;
-public class TaskCounter extends Counter
+class TaskCounter extends Counter
{
- public TaskCounter(BufferedImage img, Plugin plugin, int amount)
+ TaskCounter(BufferedImage img, Plugin plugin, int amount)
{
- super(img, plugin, String.valueOf(amount));
+ super(img, plugin, amount);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounter.java
index 083ef5bba6..425c781b45 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounter.java
@@ -25,33 +25,52 @@
package net.runelite.client.plugins.specialcounter;
import java.awt.image.BufferedImage;
+import java.util.Map;
import net.runelite.client.ui.overlay.infobox.Counter;
class SpecialCounter extends Counter
{
- private int hitValue;
+ private final SpecialCounterPlugin plugin;
private SpecialWeapon weapon;
SpecialCounter(BufferedImage image, SpecialCounterPlugin plugin, int hitValue, SpecialWeapon weapon)
{
- super(image, plugin, null);
+ super(image, plugin, hitValue);
+ this.plugin = plugin;
this.weapon = weapon;
- this.hitValue = hitValue;
}
void addHits(double hit)
{
- this.hitValue += hit;
- }
-
- @Override
- public String getText()
- {
- return Integer.toString(hitValue);
+ int count = getCount();
+ setCount(count + (int) hit);
}
@Override
public String getTooltip()
+ {
+ Map partySpecs = plugin.getPartySpecs();
+ int hitValue = getCount();
+
+ if (partySpecs.isEmpty())
+ {
+ return buildTooltip(hitValue);
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(buildTooltip(hitValue));
+
+ for (Map.Entry entry : partySpecs.entrySet())
+ {
+ stringBuilder.append("")
+ .append(entry.getKey() == null ? "You" : entry.getKey()).append(": ")
+ .append(buildTooltip(entry.getValue()));
+ }
+
+ return stringBuilder.toString();
+ }
+
+ private String buildTooltip(int hitValue)
{
if (!weapon.isDamage())
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
index 40a50e7c53..4ff5b8ae6f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
@@ -24,9 +24,13 @@
*/
package net.runelite.client.plugins.specialcounter;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
+import lombok.AccessLevel;
+import lombok.Getter;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.EquipmentInventorySlot;
@@ -42,11 +46,14 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.VarbitChanged;
+import net.runelite.client.callback.ClientThread;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
+import net.runelite.client.ws.PartyService;
+import net.runelite.client.ws.WSClient;
@PluginDescriptor(
name = "Special Attack Counter",
@@ -65,20 +72,38 @@ public class SpecialCounterPlugin extends Plugin
private SpecialWeapon specialWeapon;
private final Set interactedNpcIds = new HashSet<>();
private final SpecialCounter[] specialCounter = new SpecialCounter[SpecialWeapon.values().length];
+ @Getter(AccessLevel.PACKAGE)
+ private final Map partySpecs = new HashMap<>();
@Inject
private Client client;
+ @Inject
+ private ClientThread clientThread;
+
+ @Inject
+ private WSClient wsClient;
+
+ @Inject
+ private PartyService party;
+
@Inject
private InfoBoxManager infoBoxManager;
@Inject
private ItemManager itemManager;
+ @Override
+ protected void startUp()
+ {
+ wsClient.registerMessage(SpecialCounterUpdate.class);
+ }
+
@Override
protected void shutDown()
{
removeCounters();
+ wsClient.unregisterMessage(SpecialCounterUpdate.class);
}
@Subscribe
@@ -126,9 +151,9 @@ public class SpecialCounterPlugin extends Plugin
return;
}
- checkInteracting();
+ int interactingId = checkInteracting();
- if (specialHitpointsExperience != -1 && specialUsed)
+ if (interactingId > -1 && specialHitpointsExperience != -1 && specialUsed)
{
specialUsed = false;
int hpXp = client.getSkillExperience(Skill.HITPOINTS);
@@ -139,13 +164,22 @@ public class SpecialCounterPlugin extends Plugin
{
if (specialWeapon != null)
{
- updateCounter(specialWeapon, deltaExperience);
+ int hit = getHit(specialWeapon, deltaExperience);
+
+ updateCounter(specialWeapon, null, hit);
+
+ if (!party.getMembers().isEmpty())
+ {
+ final SpecialCounterUpdate specialCounterUpdate = new SpecialCounterUpdate(interactingId, specialWeapon, hit);
+ specialCounterUpdate.setMemberId(party.getLocalMember().getMemberId());
+ wsClient.send(specialCounterUpdate);
+ }
}
}
}
}
- private void checkInteracting()
+ private int checkInteracting()
{
Player localPlayer = client.getLocalPlayer();
Actor interacting = localPlayer.getInteracting();
@@ -157,17 +191,26 @@ public class SpecialCounterPlugin extends Plugin
if (!interactedNpcIds.contains(interactingId))
{
removeCounters();
- modifier = 1d;
- interactedNpcIds.add(interactingId);
-
- final Boss boss = Boss.getBoss(interactingId);
- if (boss != null)
- {
- modifier = boss.getModifier();
- interactedNpcIds.addAll(boss.getIds());
- }
-
+ addInteracting(interactingId);
}
+
+ return interactingId;
+ }
+
+ return -1;
+ }
+
+ private void addInteracting(int npcId)
+ {
+ modifier = 1d;
+ interactedNpcIds.add(npcId);
+
+ // Add alternate forms of bosses
+ final Boss boss = Boss.getBoss(npcId);
+ if (boss != null)
+ {
+ modifier = boss.getModifier();
+ interactedNpcIds.addAll(boss.getIds());
}
}
@@ -182,6 +225,36 @@ public class SpecialCounterPlugin extends Plugin
}
}
+ @Subscribe
+ public void onSpecialCounterUpdate(SpecialCounterUpdate event)
+ {
+ if (party.getLocalMember().getMemberId().equals(event.getMemberId()))
+ {
+ return;
+ }
+
+ String name = party.getMemberById(event.getMemberId()).getName();
+ if (name == null)
+ {
+ return;
+ }
+
+ clientThread.invoke(() ->
+ {
+ // If not interacting with any npcs currently, add to interacting list
+ if (interactedNpcIds.isEmpty())
+ {
+ addInteracting(event.getNpcId());
+ }
+
+ // Otherwise we only add the count if it is against a npc we are already tracking
+ if (interactedNpcIds.contains(event.getNpcId()))
+ {
+ updateCounter(event.getWeapon(), name, event.getHit());
+ }
+ });
+ }
+
private SpecialWeapon usedSpecialWeapon()
{
ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
@@ -210,10 +283,9 @@ public class SpecialCounterPlugin extends Plugin
return null;
}
- private void updateCounter(SpecialWeapon specialWeapon, int deltaExperience)
+ private void updateCounter(SpecialWeapon specialWeapon, String name, int hit)
{
SpecialCounter counter = specialCounter[specialWeapon.ordinal()];
- int hit = getHit(specialWeapon, deltaExperience);
if (counter == null)
{
@@ -226,11 +298,25 @@ public class SpecialCounterPlugin extends Plugin
{
counter.addHits(hit);
}
+
+ // If in a party, add hit to partySpecs for the infobox tooltip
+ if (!party.getMembers().isEmpty())
+ {
+ if (partySpecs.containsKey(name))
+ {
+ partySpecs.put(name, hit + partySpecs.get(name));
+ }
+ else
+ {
+ partySpecs.put(name, hit);
+ }
+ }
}
private void removeCounters()
{
interactedNpcIds.clear();
+ partySpecs.clear();
for (int i = 0; i < specialCounter.length; ++i)
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java
new file mode 100644
index 0000000000..16eff1af25
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, 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.specialcounter;
+
+import lombok.EqualsAndHashCode;
+import lombok.Value;
+import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
+
+@Value
+@EqualsAndHashCode(callSuper = true)
+public class SpecialCounterUpdate extends PartyMemberMessage
+{
+ private final int npcId;
+ private final SpecialWeapon weapon;
+ private final int hit;
+}
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 0deb55c2ab..ada42169ad 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
@@ -24,8 +24,6 @@
*/
package net.runelite.client.plugins.statusbars;
-import com.google.common.base.Strings;
-import com.google.common.primitives.Ints;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
@@ -196,28 +194,16 @@ class StatusBarsOverlay extends Overlay
for (final StatChange c : statsChanges.getStatChanges())
{
- final String strVar = c.getTheoretical();
-
- if (Strings.isNullOrEmpty(strVar))
- {
- continue;
- }
-
- final Integer value = Ints.tryParse(strVar.startsWith("+") ? strVar.substring(1) : strVar);
-
- if (value == null)
- {
- continue;
- }
+ final int theoreticalBoost = c.getTheoretical();
if (c.getStat().getName().equals(Skill.HITPOINTS.getName()))
{
- foodHealValue = value;
+ foodHealValue = theoreticalBoost;
}
if (c.getStat().getName().equals(Skill.PRAYER.getName()))
{
- prayerHealValue = value;
+ prayerHealValue = theoreticalBoost;
}
if (foodHealValue != 0 && prayerHealValue != 0)
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tileindicators/TileIndicatorsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/tileindicators/TileIndicatorsConfig.java
index fcff77c540..d8d9fd7d36 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/tileindicators/TileIndicatorsConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/tileindicators/TileIndicatorsConfig.java
@@ -58,7 +58,7 @@ public interface TileIndicatorsConfig extends Config
@ConfigItem(
keyName = "highlightCurrentColor",
name = "Color of current tile highlighting",
- description = "Configures the highlight color of current destination"
+ description = "Configures the highlight color of current tile position"
)
default Color highlightCurrentColor()
{
@@ -74,6 +74,17 @@ public interface TileIndicatorsConfig extends Config
{
return false;
}
+
+ @Alpha
+ @ConfigItem(
+ keyName = "highlightHoveredColor",
+ name = "Color of current hovered highlighting",
+ description = "Configures the highlight color of hovered tile"
+ )
+ default Color highlightHoveredColor()
+ {
+ return new Color(0, 0, 0, 0);
+ }
@ConfigItem(
keyName = "highlightHoveredTile",
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tileindicators/TileIndicatorsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/tileindicators/TileIndicatorsOverlay.java
index b4c546ccc9..c45f147ddc 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/tileindicators/TileIndicatorsOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/tileindicators/TileIndicatorsOverlay.java
@@ -42,7 +42,6 @@ import net.runelite.client.ui.overlay.OverlayUtil;
public class TileIndicatorsOverlay extends Overlay
{
- private static final Color EMPTY = new Color(0, 0, 0, 0);
private final Client client;
private final TileIndicatorsConfig config;
@@ -76,7 +75,7 @@ public class TileIndicatorsOverlay extends Overlay
// If we have tile "selected" render it
if (client.getSelectedSceneTile() != null)
{
- renderTile(graphics, client.getSelectedSceneTile().getLocalLocation(), EMPTY);
+ renderTile(graphics, client.getSelectedSceneTile().getLocalLocation(), config.highlightHoveredColor());
}
}
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 1a039c008f..2a76b949be 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
@@ -59,6 +59,7 @@ import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.events.WidgetHiddenChanged;
import net.runelite.api.widgets.Widget;
+import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE;
import net.runelite.client.config.ConfigManager;
@@ -217,7 +218,7 @@ public class TimersPlugin extends Plugin
{
Widget widget = event.getWidget();
if (WorldType.isPvpWorld(client.getWorldType())
- && WidgetInfo.TO_GROUP(widget.getId()) == WidgetInfo.PVP_CONTAINER.getGroupId())
+ && WidgetInfo.TO_GROUP(widget.getId()) == WidgetID.PVP_GROUP_ID)
{
widgetHiddenChangedOnPvpWorld = true;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/Produce.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/Produce.java
index 6be6414259..66883eedba 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/Produce.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/Produce.java
@@ -93,8 +93,8 @@ public enum Produce
// Tree crops
OAK("Oak", ItemID.OAK_LOGS, 40, 5),
WILLOW("Willow", ItemID.WILLOW_LOGS, 40, 7),
- MAPLE("Maple", ItemID.MAPLE_TREE, 40, 9),
- YEW("Yew", ItemID.YEW_TREE, 40, 11),
+ MAPLE("Maple", ItemID.MAPLE_LOGS, 40, 9),
+ YEW("Yew", ItemID.YEW_LOGS, 40, 11),
MAGIC("Magic", ItemID.MAGIC_LOGS, 40, 13),
// Fruit tree crops
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/twitch/TwitchPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/twitch/TwitchPlugin.java
index c87ca1ad32..275eea5d54 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/twitch/TwitchPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/twitch/TwitchPlugin.java
@@ -24,6 +24,7 @@
*/
package net.runelite.client.plugins.twitch;
+import com.google.common.base.Strings;
import com.google.inject.Provides;
import java.time.temporal.ChronoUnit;
import java.util.Map;
@@ -96,11 +97,18 @@ public class TwitchPlugin extends Plugin implements TwitchListener, ChatboxInput
return configManager.getConfig(TwitchConfig.class);
}
- private void connect()
+ private synchronized void connect()
{
- if (twitchConfig.username() != null
- && twitchConfig.oauthToken() != null
- && twitchConfig.channel() != null)
+ if (twitchIRCClient != null)
+ {
+ log.debug("Terminating Twitch client {}", twitchIRCClient);
+ twitchIRCClient.close();
+ twitchIRCClient = null;
+ }
+
+ if (!Strings.isNullOrEmpty(twitchConfig.username())
+ && !Strings.isNullOrEmpty(twitchConfig.oauthToken())
+ && !Strings.isNullOrEmpty(twitchConfig.channel()))
{
String channel = twitchConfig.channel().toLowerCase();
if (!channel.startsWith("#"))
@@ -108,6 +116,8 @@ public class TwitchPlugin extends Plugin implements TwitchListener, ChatboxInput
channel = "#" + channel;
}
+ log.debug("Connecting to Twitch as {}", twitchConfig.username());
+
twitchIRCClient = new TwitchIRCClient(
this,
twitchConfig.username(),
@@ -145,12 +155,6 @@ public class TwitchPlugin extends Plugin implements TwitchListener, ChatboxInput
return;
}
- if (twitchIRCClient != null)
- {
- twitchIRCClient.close();
- twitchIRCClient = null;
- }
-
connect();
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java
new file mode 100644
index 0000000000..afbc30b766
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2018 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.client.plugins.wiki;
+
+import com.google.common.primitives.Ints;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.api.Client;
+import net.runelite.api.MenuAction;
+import net.runelite.api.MenuEntry;
+import net.runelite.api.NPC;
+import net.runelite.api.NPCComposition;
+import net.runelite.api.ObjectComposition;
+import net.runelite.api.coords.WorldPoint;
+import net.runelite.api.events.MenuEntryAdded;
+import net.runelite.api.events.MenuOptionClicked;
+import net.runelite.api.events.WidgetLoaded;
+import net.runelite.api.widgets.JavaScriptCallback;
+import net.runelite.api.widgets.Widget;
+import net.runelite.api.widgets.WidgetConfig;
+import net.runelite.api.widgets.WidgetID;
+import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.api.widgets.WidgetPositionMode;
+import net.runelite.api.widgets.WidgetType;
+import net.runelite.client.callback.ClientThread;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.game.ItemManager;
+import net.runelite.client.game.SpriteManager;
+import net.runelite.client.game.chatbox.ChatboxPanelManager;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.util.LinkBrowser;
+import net.runelite.client.util.Text;
+import okhttp3.HttpUrl;
+
+@Slf4j
+@PluginDescriptor(
+ name = "Wiki",
+ description = "Adds a Wiki button that takes you to the OSRS Wiki"
+)
+public class WikiPlugin extends Plugin
+{
+ private static final int[] QUESTLIST_WIDGET_IDS = new int[]
+ {
+ WidgetInfo.QUESTLIST_FREE_CONTAINER.getId(),
+ WidgetInfo.QUESTLIST_MEMBERS_CONTAINER.getId(),
+ WidgetInfo.QUESTLIST_MINIQUEST_CONTAINER.getId(),
+ };
+
+ static final HttpUrl WIKI_BASE = HttpUrl.parse("https://oldschool.runescape.wiki");
+ static final HttpUrl WIKI_API = WIKI_BASE.newBuilder().addPathSegments("api.php").build();
+ static final String UTM_SORUCE_KEY = "utm_source";
+ static final String UTM_SORUCE_VALUE = "runelite";
+
+ private static final String MENUOP_GUIDE = "Guide";
+ private static final String MENUOP_QUICKGUIDE = "Quick Guide";
+ private static final String MENUOP_WIKI = "Wiki";
+
+ private static final Pattern SKILL_REGEX = Pattern.compile("([A-Za-z]+) guide");
+ private static final Pattern DIARY_REGEX = Pattern.compile("([A-Za-z &]+) Journal");
+
+ @Inject
+ private SpriteManager spriteManager;
+
+ @Inject
+ private ClientThread clientThread;
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private ChatboxPanelManager chatboxPanelManager;
+
+ @Inject
+ private ItemManager itemManager;
+
+ @Inject
+ private Provider wikiSearchChatboxTextInputProvider;
+
+ private Widget icon;
+
+ private boolean wikiSelected = false;
+
+ @Override
+ public void startUp()
+ {
+ spriteManager.addSpriteOverrides(WikiSprite.values());
+ clientThread.invokeLater(this::addWidgets);
+ }
+
+ @Override
+ public void shutDown()
+ {
+ spriteManager.removeSpriteOverrides(WikiSprite.values());
+ clientThread.invokeLater(() ->
+ {
+ Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS);
+ if (minimapOrbs == null)
+ {
+ return;
+ }
+ Widget[] children = minimapOrbs.getChildren();
+ if (children == null || children.length < 1)
+ {
+ return;
+ }
+ children[0] = null;
+
+ onDeselect();
+ client.setSpellSelected(false);
+ });
+ }
+
+ @Subscribe
+ private void onWidgetLoaded(WidgetLoaded l)
+ {
+ if (l.getGroupId() == WidgetID.MINIMAP_GROUP_ID)
+ {
+ addWidgets();
+ }
+ }
+
+ private void addWidgets()
+ {
+ Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS);
+ if (minimapOrbs == null)
+ {
+ return;
+ }
+
+ icon = minimapOrbs.createChild(0, WidgetType.GRAPHIC);
+ icon.setSpriteId(WikiSprite.WIKI_ICON.getSpriteId());
+ icon.setOriginalX(0);
+ icon.setOriginalY(2);
+ icon.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT);
+ icon.setYPositionMode(WidgetPositionMode.ABSOLUTE_BOTTOM);
+ icon.setOriginalWidth(42);
+ icon.setOriginalHeight(16);
+ icon.setTargetVerb("Lookup");
+ icon.setName("Wiki");
+ icon.setClickMask(WidgetConfig.USE_GROUND_ITEM | WidgetConfig.USE_ITEM | WidgetConfig.USE_NPC | WidgetConfig.USE_OBJECT);
+ icon.setNoClickThrough(true);
+ icon.setOnTargetEnterListener((JavaScriptCallback) ev ->
+ {
+ wikiSelected = true;
+ icon.setSpriteId(WikiSprite.WIKI_SELECTED_ICON.getSpriteId());
+ });
+ icon.setAction(5, "Search"); // Start at option 5 so the target op is ontop
+ icon.setOnOpListener((JavaScriptCallback) ev ->
+ {
+ switch (ev.getOp())
+ {
+ case 6:
+ openSearchInput();
+ break;
+ }
+ });
+ // This doesn't always run because we cancel the menuop
+ icon.setOnTargetLeaveListener((JavaScriptCallback) ev -> onDeselect());
+ icon.revalidate();
+ }
+
+ private void onDeselect()
+ {
+ wikiSelected = false;
+ if (icon != null)
+ {
+ icon.setSpriteId(WikiSprite.WIKI_ICON.getSpriteId());
+ }
+ }
+
+ @Subscribe
+ private void onMenuOptionClicked(MenuOptionClicked ev)
+ {
+ if (wikiSelected)
+ {
+ onDeselect();
+ client.setSpellSelected(false);
+ ev.consume();
+
+ String type;
+ int id;
+ String name;
+ WorldPoint location;
+
+ switch (ev.getMenuAction())
+ {
+ case CANCEL:
+ return;
+ case ITEM_USE_ON_WIDGET:
+ case SPELL_CAST_ON_GROUND_ITEM:
+ {
+ type = "item";
+ id = itemManager.canonicalize(ev.getId());
+ name = itemManager.getItemComposition(id).getName();
+ location = null;
+ break;
+ }
+ case SPELL_CAST_ON_NPC:
+ {
+ type = "npc";
+ NPC npc = client.getCachedNPCs()[ev.getId()];
+ NPCComposition nc = npc.getTransformedComposition();
+ id = nc.getId();
+ name = nc.getName();
+ location = npc.getWorldLocation();
+ break;
+ }
+ case SPELL_CAST_ON_GAME_OBJECT:
+ {
+ type = "object";
+ ObjectComposition lc = client.getObjectDefinition(ev.getId());
+ if (lc.getImpostorIds() != null)
+ {
+ lc = lc.getImpostor();
+ }
+ id = lc.getId();
+ name = lc.getName();
+ location = WorldPoint.fromScene(client, ev.getActionParam(), ev.getWidgetId(), client.getPlane());
+ break;
+ }
+ default:
+ log.info("Unknown menu option: {} {} {}", ev, ev.getMenuAction(), ev.getMenuAction() == MenuAction.CANCEL);
+ return;
+ }
+
+ name = Text.removeTags(name);
+ HttpUrl.Builder urlBuilder = WIKI_BASE.newBuilder();
+ urlBuilder.addPathSegments("w/Special:Lookup")
+ .addQueryParameter("type", type)
+ .addQueryParameter("id", "" + id)
+ .addQueryParameter("name", name)
+ .addQueryParameter(UTM_SORUCE_KEY, UTM_SORUCE_VALUE);
+
+ if (location != null)
+ {
+ urlBuilder.addQueryParameter("x", "" + location.getX())
+ .addQueryParameter("y", "" + location.getY())
+ .addQueryParameter("plane", "" + location.getPlane());
+ }
+
+ HttpUrl url = urlBuilder.build();
+
+ LinkBrowser.browse(url.toString());
+ return;
+ }
+
+ if (ev.getMenuAction() == MenuAction.RUNELITE)
+ {
+ boolean quickguide = false;
+ switch (ev.getMenuOption())
+ {
+ case MENUOP_QUICKGUIDE:
+ quickguide = true;
+ //fallthrough;
+ case MENUOP_GUIDE:
+ ev.consume();
+ String quest = Text.removeTags(ev.getMenuTarget());
+ HttpUrl.Builder ub = WIKI_BASE.newBuilder()
+ .addPathSegment("w")
+ .addPathSegment(quest)
+ .addQueryParameter(UTM_SORUCE_KEY, UTM_SORUCE_VALUE);
+ if (quickguide)
+ {
+ ub.addPathSegment("Quick_guide");
+ }
+ LinkBrowser.browse(ub.build().toString());
+ break;
+ case MENUOP_WIKI:
+ Matcher skillRegex = WikiPlugin.SKILL_REGEX.matcher(Text.removeTags(ev.getMenuTarget()));
+ Matcher diaryRegex = WikiPlugin.DIARY_REGEX.matcher(Text.removeTags(ev.getMenuTarget()));
+
+ if (skillRegex.find())
+ {
+ LinkBrowser.browse(WIKI_BASE.newBuilder()
+ .addPathSegment("w")
+ .addPathSegment(skillRegex.group(1))
+ .addQueryParameter(UTM_SORUCE_KEY, UTM_SORUCE_VALUE)
+ .build().toString());
+ }
+ else if (diaryRegex.find())
+ {
+ LinkBrowser.browse(WIKI_BASE.newBuilder()
+ .addPathSegment("w")
+ .addPathSegment(diaryRegex.group(1) + " Diary")
+ .addQueryParameter(UTM_SORUCE_KEY, UTM_SORUCE_VALUE)
+ .build().toString());
+ }
+ }
+ }
+ }
+
+ private void openSearchInput()
+ {
+ wikiSearchChatboxTextInputProvider.get()
+ .build();
+ }
+
+ @Subscribe
+ public void onMenuEntryAdded(MenuEntryAdded event)
+ {
+ int widgetIndex = event.getActionParam0();
+ int widgetID = event.getActionParam1();
+ MenuEntry[] menuEntries = client.getMenuEntries();
+
+ if (Ints.contains(QUESTLIST_WIDGET_IDS, widgetID) && "Read Journal:".equals(event.getOption()))
+ {
+ menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 2);
+
+ MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
+ menuEntry.setTarget(event.getTarget());
+ menuEntry.setOption(MENUOP_GUIDE);
+ menuEntry.setParam0(widgetIndex);
+ menuEntry.setParam1(widgetID);
+ menuEntry.setType(MenuAction.RUNELITE.getId());
+
+ menuEntry = menuEntries[menuEntries.length - 2] = new MenuEntry();
+ menuEntry.setTarget(event.getTarget());
+ menuEntry.setOption(MENUOP_QUICKGUIDE);
+ menuEntry.setParam0(widgetIndex);
+ menuEntry.setParam1(widgetID);
+ menuEntry.setType(MenuAction.RUNELITE.getId());
+
+ client.setMenuEntries(menuEntries);
+ }
+
+ if ((WidgetInfo.TO_GROUP(widgetID) == WidgetID.SKILLS_GROUP_ID && event.getOption().startsWith("View"))
+ || (WidgetInfo.TO_GROUP(widgetID) == WidgetID.DIARY_GROUP_ID && event.getOption().startsWith("Open")))
+ {
+ menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1);
+
+ MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
+ menuEntry.setTarget(event.getOption().replace("View ", "").replace("Open ", ""));
+ menuEntry.setOption(MENUOP_WIKI);
+ menuEntry.setParam0(widgetIndex);
+ menuEntry.setParam1(widgetID);
+ menuEntry.setIdentifier(event.getIdentifier());
+ menuEntry.setType(MenuAction.RUNELITE.getId());
+
+ client.setMenuEntries(menuEntries);
+ }
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java
new file mode 100644
index 0000000000..ef3b91f9a0
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2018 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.client.plugins.wiki;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import com.google.inject.Inject;
+import java.awt.event.KeyEvent;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.inject.Named;
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.api.widgets.JavaScriptCallback;
+import net.runelite.api.widgets.Widget;
+import net.runelite.api.widgets.WidgetPositionMode;
+import net.runelite.api.widgets.WidgetSizeMode;
+import net.runelite.api.widgets.WidgetTextAlignment;
+import net.runelite.api.widgets.WidgetType;
+import net.runelite.client.callback.ClientThread;
+import net.runelite.client.game.chatbox.ChatboxPanelManager;
+import net.runelite.client.game.chatbox.ChatboxTextInput;
+import net.runelite.client.util.LinkBrowser;
+import net.runelite.http.api.RuneLiteAPI;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.HttpUrl;
+import okhttp3.Request;
+import okhttp3.Response;
+
+@Slf4j
+public class WikiSearchChatboxTextInput extends ChatboxTextInput
+{
+ private static final int LINE_HEIGHT = 20;
+ private static final int CHATBOX_HEIGHT = 120;
+ private static final int MAX_NUM_PREDICTIONS = (CHATBOX_HEIGHT / LINE_HEIGHT) - 2; // 1 title, 1 edit
+
+ private static final int PREDICTION_DEBOUNCE_DELAY_MS = 200;
+
+ private final ChatboxPanelManager chatboxPanelManager;
+ private final Gson gson = new Gson();
+
+ private Future> runningRequest = null;
+ private List predictions = ImmutableList.of();
+
+ private int selectedPrediction = -1;
+ private String offPrediction = null;
+
+ @Inject
+ public WikiSearchChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread,
+ ScheduledExecutorService scheduledExecutorService, @Named("developerMode") final boolean developerMode)
+ {
+ super(chatboxPanelManager, clientThread);
+ this.chatboxPanelManager = chatboxPanelManager;
+
+ lines(1);
+ prompt("OSRS Wiki Search");
+ onDone(string ->
+ {
+ if (string != null && string.length() > 0)
+ {
+ search(string);
+ }
+ });
+ onChanged(searchString ->
+ {
+ selectedPrediction = -1;
+ Future> rr = runningRequest;
+ if (rr != null)
+ {
+ rr.cancel(false);
+ }
+ if (searchString.length() <= 1)
+ {
+ runningRequest = null;
+ clientThread.invokeLater(() ->
+ {
+ predictions = ImmutableList.of();
+ update();
+ });
+ return;
+ }
+ runningRequest = scheduledExecutorService.schedule(() ->
+ {
+ HttpUrl url = WikiPlugin.WIKI_API.newBuilder()
+ .addQueryParameter("action", "opensearch")
+ .addQueryParameter("search", searchString)
+ .addQueryParameter("redirects", "resolve")
+ .addQueryParameter("format", "json")
+ .addQueryParameter("warningsaserror", Boolean.toString(developerMode))
+ .build();
+
+ Request req = new Request.Builder()
+ .url(url)
+ .build();
+
+ RuneLiteAPI.CLIENT.newCall(req).enqueue(new Callback()
+ {
+ @Override
+ public void onFailure(Call call, IOException e)
+ {
+ log.warn("error searching wiki", e);
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException
+ {
+ String body = response.body().string();
+ try
+ {
+ JsonArray jar = new JsonParser().parse(body).getAsJsonArray();
+ List apredictions = gson.fromJson(jar.get(1), new TypeToken>()
+ {
+ }.getType());
+
+ if (apredictions.size() > MAX_NUM_PREDICTIONS)
+ {
+ apredictions = apredictions.subList(0, MAX_NUM_PREDICTIONS);
+ }
+
+ final List bpredictions = apredictions;
+
+ clientThread.invokeLater(() ->
+ {
+ predictions = bpredictions;
+ update();
+ });
+ }
+ catch (JsonParseException | IllegalStateException | IndexOutOfBoundsException e)
+ {
+ log.warn("error parsing wiki response {}", body, e);
+ }
+ finally
+ {
+ response.close();
+ }
+ }
+ });
+
+ runningRequest = null;
+ }, PREDICTION_DEBOUNCE_DELAY_MS, TimeUnit.MILLISECONDS);
+ });
+ }
+
+ @Override
+ protected void update()
+ {
+ Widget container = chatboxPanelManager.getContainerWidget();
+ container.deleteAllChildren();
+
+ Widget promptWidget = container.createChild(-1, WidgetType.TEXT);
+ promptWidget.setText(getPrompt());
+ promptWidget.setTextColor(0x800000);
+ promptWidget.setFontId(getFontID());
+ promptWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
+ promptWidget.setOriginalX(0);
+ promptWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
+ promptWidget.setOriginalY(5);
+ promptWidget.setOriginalHeight(LINE_HEIGHT);
+ promptWidget.setXTextAlignment(WidgetTextAlignment.CENTER);
+ promptWidget.setYTextAlignment(WidgetTextAlignment.CENTER);
+ promptWidget.setWidthMode(WidgetSizeMode.MINUS);
+ promptWidget.revalidate();
+
+ buildEdit(0, 5 + LINE_HEIGHT, container.getWidth(), LINE_HEIGHT);
+
+ Widget separator = container.createChild(-1, WidgetType.LINE);
+ separator.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
+ separator.setOriginalX(0);
+ separator.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
+ separator.setOriginalY(4 + (LINE_HEIGHT * 2));
+ separator.setOriginalHeight(0);
+ separator.setOriginalWidth(16);
+ separator.setWidthMode(WidgetSizeMode.MINUS);
+ separator.revalidate();
+
+ for (int i = 0; i < predictions.size(); i++)
+ {
+ String pred = predictions.get(i);
+ int y = 6 + (LINE_HEIGHT * (2 + i));
+
+ Widget bg = container.createChild(-1, WidgetType.RECTANGLE);
+ bg.setTextColor(0x4444DD);
+ bg.setFilled(true);
+ bg.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
+ bg.setOriginalX(1);
+ bg.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
+ bg.setOriginalY(y);
+ bg.setOriginalHeight(LINE_HEIGHT);
+ bg.setOriginalWidth(16);
+ bg.setWidthMode(WidgetSizeMode.MINUS);
+ bg.revalidate();
+ bg.setName("" + pred);
+ bg.setAction(0, "Open");
+ bg.setHasListener(true);
+ bg.setOnOpListener((JavaScriptCallback) ev -> search(pred));
+
+ Widget text = container.createChild(-1, WidgetType.TEXT);
+ text.setText(pred);
+ text.setFontId(getFontID());
+ text.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
+ text.setOriginalX(0);
+ text.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
+ text.setOriginalY(y);
+ text.setOriginalHeight(LINE_HEIGHT);
+ text.setXTextAlignment(WidgetTextAlignment.CENTER);
+ text.setYTextAlignment(WidgetTextAlignment.CENTER);
+ text.setWidthMode(WidgetSizeMode.MINUS);
+ text.revalidate();
+
+ if (i == selectedPrediction)
+ {
+ text.setTextColor(0xFFFFFF);
+ }
+ else
+ {
+ bg.setOpacity(255);
+ text.setTextColor(0x000000);
+ bg.setOnMouseRepeatListener((JavaScriptCallback) ev -> text.setTextColor(0xFFFFFF));
+ bg.setOnMouseLeaveListener((JavaScriptCallback) ev -> text.setTextColor(0x000000));
+ }
+ }
+ }
+
+ @Override
+ public void keyPressed(KeyEvent ev)
+ {
+ switch (ev.getKeyCode())
+ {
+ case KeyEvent.VK_UP:
+ ev.consume();
+ if (selectedPrediction > -1)
+ {
+ selectedPrediction--;
+ if (selectedPrediction == -1)
+ {
+ value(offPrediction);
+ }
+ else
+ {
+ value(predictions.get(selectedPrediction));
+ }
+ }
+ break;
+ case KeyEvent.VK_DOWN:
+ ev.consume();
+
+ if (selectedPrediction == -1)
+ {
+ offPrediction = getValue();
+ }
+
+ selectedPrediction++;
+ if (selectedPrediction >= predictions.size())
+ {
+ selectedPrediction = predictions.size() - 1;
+ }
+
+ if (selectedPrediction != -1)
+ {
+ value(predictions.get(selectedPrediction));
+ }
+ break;
+ default:
+ super.keyPressed(ev);
+ }
+ }
+
+ private void search(String search)
+ {
+ LinkBrowser.browse(WikiPlugin.WIKI_BASE.newBuilder()
+ .addQueryParameter("search", search)
+ .addQueryParameter(WikiPlugin.UTM_SORUCE_KEY, WikiPlugin.UTM_SORUCE_VALUE)
+ .build()
+ .toString());
+ chatboxPanelManager.close();
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSprite.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSprite.java
new file mode 100644
index 0000000000..188d54837b
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSprite.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 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.client.plugins.wiki;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import net.runelite.api.SpriteID;
+import net.runelite.client.game.SpriteOverride;
+
+@RequiredArgsConstructor
+public enum WikiSprite implements SpriteOverride
+{
+ WIKI_ICON(-300, "wiki.png"),
+ WIKI_SELECTED_ICON(-301, "wiki_selected.png"),
+ FIXED_MODE_MINIMAP_CLICKMASK(SpriteID.MINIMAP_CLICK_MASK, "fixed_mode_minimap_clickmask.png");
+
+ @Getter
+ private final int spriteId;
+
+ @Getter
+ private final String fileName;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java
index 32605d4ed0..67ac3ec635 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java
@@ -32,7 +32,21 @@ import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
-import static net.runelite.api.AnimationID.*;
+import static net.runelite.api.AnimationID.CONSTRUCTION;
+import static net.runelite.api.AnimationID.FIREMAKING;
+import static net.runelite.api.AnimationID.FLETCHING_BOW_CUTTING;
+import static net.runelite.api.AnimationID.IDLE;
+import static net.runelite.api.AnimationID.LOOKING_INTO;
+import static net.runelite.api.AnimationID.WOODCUTTING_3A_AXE;
+import static net.runelite.api.AnimationID.WOODCUTTING_ADAMANT;
+import static net.runelite.api.AnimationID.WOODCUTTING_BLACK;
+import static net.runelite.api.AnimationID.WOODCUTTING_BRONZE;
+import static net.runelite.api.AnimationID.WOODCUTTING_DRAGON;
+import static net.runelite.api.AnimationID.WOODCUTTING_INFERNAL;
+import static net.runelite.api.AnimationID.WOODCUTTING_IRON;
+import static net.runelite.api.AnimationID.WOODCUTTING_MITHRIL;
+import static net.runelite.api.AnimationID.WOODCUTTING_RUNE;
+import static net.runelite.api.AnimationID.WOODCUTTING_STEEL;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
@@ -43,9 +57,9 @@ import static net.runelite.api.ItemID.BRUMA_ROOT;
import net.runelite.api.MessageNode;
import net.runelite.api.Player;
import net.runelite.api.events.AnimationChanged;
+import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ItemContainerChanged;
-import net.runelite.api.events.SetMessage;
import net.runelite.client.Notifier;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.config.ConfigManager;
@@ -192,21 +206,21 @@ public class WintertodtPlugin extends Plugin
}
@Subscribe
- public void onSetMessage(SetMessage setMessage)
+ public void onChatMessage(ChatMessage chatMessage)
{
if (!isInWintertodt)
{
return;
}
- ChatMessageType chatMessageType = setMessage.getType();
+ ChatMessageType chatMessageType = chatMessage.getType();
if (chatMessageType != ChatMessageType.SERVER && chatMessageType != ChatMessageType.FILTERED)
{
return;
}
- MessageNode messageNode = setMessage.getMessageNode();
+ MessageNode messageNode = chatMessage.getMessageNode();
final WintertodtInterruptType interruptType;
if (messageNode.getValue().startsWith("The cold of"))
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java
index 07f4d727a5..b545939202 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java
@@ -131,7 +131,7 @@ public class WorldHopperPlugin extends Plugin
@Inject
private WorldHopperConfig config;
- private final ScheduledExecutorService hopperExecutorService = new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor());
+ private ScheduledExecutorService hopperExecutorService;
private NavigationButton navButton;
private WorldSwitcherPanel panel;
@@ -201,6 +201,8 @@ public class WorldHopperPlugin extends Plugin
}
worldResultFuture = executorService.scheduleAtFixedRate(this::tick, 0, WORLD_FETCH_TIMER, TimeUnit.MINUTES);
+
+ hopperExecutorService = new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor());
pingFuture = hopperExecutorService.scheduleAtFixedRate(this::pingWorlds, WORLD_PING_TIMER, WORLD_PING_TIMER, TimeUnit.MINUTES);
}
@@ -221,6 +223,7 @@ public class WorldHopperPlugin extends Plugin
clientToolbar.removeNavigation(navButton);
hopperExecutorService.shutdown();
+ hopperExecutorService = null;
}
@Subscribe
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutLocation.java
deleted file mode 100644
index dd2e3771b6..0000000000
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutLocation.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2018, Morgan Lewis
- * 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 HOLDER 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.worldmap;
-
-import lombok.Getter;
-import net.runelite.api.coords.WorldPoint;
-
-@Getter
-enum AgilityShortcutLocation
-{
- KARAMJA_GLIDER_LOG("Log Balance", 1, new WorldPoint(2906, 3050, 0)),
- FALADOR_CRUMBLING_WALL("Crumbling Wall", 5, new WorldPoint(2936, 3357, 0)),
- RIVER_LUM_GRAPPLE_WEST("Grapple Broken Raft", 8, new WorldPoint(3245, 3179, 0)),
- RIVER_LUM_GRAPPLE_EAST("Grapple Broken Raft", 8, new WorldPoint(3258, 3179, 0)),
- CORSAIR_COVE_ROCKS("Rocks", 10, new WorldPoint(2545, 2871, 0)),
- FALADOR_GRAPPLE_WALL("Grapple Wall", 11, new WorldPoint(3031, 3391, 0)),
- VARROCK_SOUTH_FENCE("Fence", 13, new WorldPoint(3239, 3334, 0)),
- GOBLIN_VILLAGE_WALL("Wall", 14, new WorldPoint(2925, 3523, 0)),
- CORSAIR_COVE_DUNGEON_PILLAR("Pillar Jump", 15, new WorldPoint(1980, 8996, 0)),
- YANILLE_UNDERWALL_TUNNEL("Underwall Tunnel", 16, new WorldPoint(2574, 3109, 0)),
- COAL_TRUCKS_LOG_BALANCE("Log Balance", 20, new WorldPoint(2598, 3475, 0)),
- GRAND_EXCHANGE_UNDERWALL_TUNNEL("Underwall Tunnel", 21, new WorldPoint(3139, 3515, 0)),
- BRIMHAVEN_DUNGEON_PIPE("Pipe Squeeze", 22, new WorldPoint(2654, 9569, 0)),
- OBSERVATORY_SCALE_CLIFF("Grapple Rocks", 23, new WorldPoint(2447, 3155, 0)),
- EAGLES_PEAK_ROCK_CLIMB("Rock Climb", 25, new WorldPoint(2320, 3499, 0)),
- FALADOR_UNDERWALL_TUNNEL("Underwall Tunnel", 26, new WorldPoint(2947, 3313, 0)),
- MOUNT_KARUULM_LOWER("Rocks", 29, new WorldPoint(1324, 3782, 0)),
- CORSAIR_COVE_RESOURCE_ROCKS("Rocks", 30, new WorldPoint(2545, 2871, 0)),
- SOUTHEAST_KARAJMA_STEPPING_STONES("Stepping Stones", 30, new WorldPoint(2924, 2946, 0)),
- DRAYNOR_MANOR_STEPPING_STONES("Stepping Stones", 31, new WorldPoint(3150, 3362, 0)),
- CATHERBY_CLIFFSIDE_GRAPPLE("Grapple Rock", 32, new WorldPoint(2868, 3429, 0)),
- ARDOUGNE_LOG_BALANCE("Log Balance", 33, new WorldPoint(2602, 3336, 0)),
- GNOME_STRONGHOLD_ROCKS("Rocks", 37, new WorldPoint(2485, 3515, 0)),
- AL_KHARID_MINING_PITCLIFF_SCRAMBLE("Rocks", 38, new WorldPoint(3305, 3315, 0)),
- YANILLE_WALL_GRAPPLE("Grapple Wall", 39, new WorldPoint(2552, 3072, 0)),
- NEITIZNOT_BRIDGE_REPAIR("Bridge Repair - Quest", 40, new WorldPoint(2315, 3828, 0)),
- KOUREND_LAKE_JUMP_WEST("Stepping Stones", 40, new WorldPoint(1604, 3572, 0)),
- KOUREND_LAKE_JUMP_EAST("Stepping Stones", 40, new WorldPoint(1612, 3570, 0)),
- TROLLHEIM_EASY_CLIFF_SCRAMBLE("Rocks", 41, new WorldPoint(2869, 3670, 0)),
- DWARVEN_MINE_NARROW_CREVICE("Narrow Crevice", 42, new WorldPoint(3034, 9806, 0)),
- DRAYNOR_UNDERWALL_TUNNEL("Underwall Tunnel", 42, new WorldPoint(3068, 3261, 0)),
- TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_NORTH("Rocks", 43, new WorldPoint(2886, 3684, 0)),
- TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_SOUTH("Rocks", 43, new WorldPoint(2876, 3666, 0)),
- TROLLHEIM_ADVANCED_CLIFF_SCRAMBLE("Rocks", 44, new WorldPoint(2907, 3686, 0)),
- KOUREND_RIVER_STEPPING_STONES("Stepping Stones", 45, new WorldPoint(1721, 3509, 0)),
- COSMIC_ALTAR_MEDIUM_WALKWAY("Narrow Walkway", 46, new WorldPoint(2399, 4403, 0)),
- DEEP_WILDERNESS_DUNGEON_CREVICE_NORTH("Narrow Crevice", 46, new WorldPoint(3047, 10335, 0)),
- DEEP_WILDERNESS_DUNGEON_CREVICE_SOUTH("Narrow Crevice", 46, new WorldPoint(3045, 10327, 0)),
- TROLLHEIM_HARD_CLIFF_SCRAMBLE("Rocks", 47, new WorldPoint(2902, 3680, 0)),
- FREMENNIK_LOG_BALANCE("Log Balance", 48, new WorldPoint(2721, 3591, 0)),
- ARCEUUS_ESSENCE_MINE_BOULDER("Boulder", 49, new WorldPoint(1774, 3888, 0)),
- MORYTANIA_STEPPING_STONE("Stepping Stone", 50, new WorldPoint(3418, 3326, 0)),
- VARROCK_SEWERS_PIPE_SQUEEZE("Pipe Squeeze", 51, new WorldPoint(3152, 9905, 0)),
- ARCEUUS_ESSENCE_MINE_EAST_SCRAMBLE("Rock Climb", 52, new WorldPoint(1770, 3851, 0)),
- KARAMJA_VOLCANO_GRAPPLE_NORTH("Grapple Rock", 53, new WorldPoint(2873, 3143, 0)),
- KARAMJA_VOLCANO_GRAPPLE_SOUTH("Grapple Rock", 53, new WorldPoint(2874, 3128, 0)),
- MOTHERLODE_MINE_WALL_WEST("Wall", 54, new WorldPoint(3118, 9702, 0)),
- MOTHERLODE_MINE_WALL_EAST("Wall", 54, new WorldPoint(3124, 9703, 0)),
- MISCELLANIA_DOCK_STEPPING_STONE("Stepping Stone", 55, new WorldPoint(2572, 3862, 0)),
- RELEKKA_EAST_FENCE("Fence", 57, new WorldPoint(2688, 3697, 0)),
- ELVEN_OVERPASS_CLIFF_SCRAMBLE("Rocks", 59, new WorldPoint(2345, 3300, 0)),
- WILDERNESS_GWD_CLIMB_WEST("Rocks", 60, new WorldPoint(2928, 3760, 0)),
- WILDERNESS_GWD_CLIMB_EAST("Rocks", 60, new WorldPoint(2943, 3770, 0)),
- MOS_LEHARMLESS_STEPPING_STONE("Stepping Stone", 60, new WorldPoint(3710, 2970, 0)),
- WINTERTODT_GAP("Gap", 60, new WorldPoint(1629, 4023, 0)),
- SLAYER_TOWER_MEDIUM_CHAIN_FIRST("Spiked Chain (Floor 1)", 61, new WorldPoint(3421, 3550, 0)),
- SLAYER_TOWER_MEDIUM_CHAIN_SECOND("Spiked Chain (Floor 2)", 61, new WorldPoint(3420, 3551, 0)),
- SLAYER_DUNGEON_CREVICE("Narrow Crevice", 62, new WorldPoint(2729, 10008, 0)),
- MOUNT_KARUULM_UPPER("Rocks", 62, new WorldPoint(1322, 3791, 0)),
- TAVERLEY_DUNGEON_RAILING("Loose Railing", 63, new WorldPoint(2935, 9811, 0)),
- TROLLHEIM_WILDERNESS_ROCKS("Rocks", 64, new WorldPoint(2945, 3678, 0)),
- FOSSIL_ISLAND_VOLCANO("Rope", 64, new WorldPoint(3780, 3822, 0)),
- MORYTANIA_TEMPLE("Loose Railing", 65, new WorldPoint(3422, 3476, 0)),
- REVENANT_CAVES_GREEN_DRAGONS("Jump", 65, new WorldPoint(3220, 10086, 0)),
- COSMIC_ALTAR_ADVANCED_WALKWAY("Narrow Walkway", 66, new WorldPoint(2408, 4401, 0)),
- LUMBRIDGE_DESERT_STEPPING_STONE("Stepping Stone", 66, new WorldPoint(3210, 3135, 0)),
- HEROS_GUILD_TUNNEL_WEST("Crevice", 67, new WorldPoint(2898, 9901, 0)),
- HEROS_GUILD_TUNNEL_EAST("Crevice", 67, new WorldPoint(2913, 9895, 0)),
- ELVEN_OVERPASS_MEDIUM_CLIFF("Rocks", 68, new WorldPoint(2337, 3288, 0)),
- ARCEUUS_ESSENSE_NORTH("Rock Climb", 69, new WorldPoint(1759, 3873, 0)),
- TAVERLEY_DUNGEON_PIPE_BLUE_DRAGON("Pipe Squeeze", 70, new WorldPoint(2886, 9798, 0)),
- FOSSIL_ISLAND_HARDWOOD("Hole", 70, new WorldPoint(3663, 3810, 0)),
- GWD_SARADOMIN_ROPE_FIRST("Rope Descent", 70, new WorldPoint(2912, 5300, 0)),
- GWD_SARADOMIN_ROPE_SECOND("Rope Descent", 70, new WorldPoint(2951, 5267, 0)),
- SLAYER_TOWER_ADVANCED_CHAIN_FIRST("Spiked Chain (Floor 2)", 71, new WorldPoint(3447, 3578, 0)),
- SLAYER_TOWER_ADVANCED_CHAIN_SECOND("Spiked Chain (Floor 3)", 71, new WorldPoint(3446, 3576, 0)),
- SLAYER_CAVE_WALL_CLIMB("Tunnel", 72, new WorldPoint(2431, 9806, 0)),
- TROLL_STRONGHOLD_WALL_CLIMB("Rocks", 73, new WorldPoint(2841, 3694, 0)),
- ARCEUUS_ESSENSE_MINE_WEST("Rock Climb", 73, new WorldPoint(1742, 3853, 0)),
- LAVA_DRAGON_ISLE_JUMP("Stepping Stone", 74, new WorldPoint(3200, 3807, 0)),
- REVENANT_CAVES_DEMONS_JUMP("Jump", 75, new WorldPoint(3199, 10135, 0)),
- REVENANT_CAVES_ANKOU_EAST("Jump", 75, new WorldPoint(3201, 10195, 0)),
- REVENANT_CAVES_ANKOU_NORTH("Jump", 75, new WorldPoint(3180, 10209, 0)),
- ZUL_ANDRA_ISLAND_CROSSING("Stepping Stone", 76, new WorldPoint(2156, 3073, 0)),
- SHILO_VILLAGE_STEPPING_STONES("Stepping Stones", 77, new WorldPoint(2863, 2974, 0)),
- KHARAZI_JUNGLE_VINE_CLIMB("Vine", 79, new WorldPoint(2897, 2939, 0)),
- TAVERLEY_DUNGEON_SPIKED_BLADES("Strange Floor", 80, new WorldPoint(2877, 9813, 0)),
- SLAYER_DUNGEON_CHASM_JUMP("Spiked Blades", 81, new WorldPoint(2770, 10003, 0)),
- LAVA_MAZE_NORTH_JUMP("Stepping Stone", 82, new WorldPoint(3092, 3880, 0)),
- BRIMHAVEN_DUNGEON_EAST_STEPPING_NORTH("Stepping Stones", 83, new WorldPoint(2685, 9547, 0)),
- BRIMHAVEN_DUNGEON_EAST_STEPPING_SOUTH("Stepping Stones", 83, new WorldPoint(2693, 9529, 0)),
- ELVEN_ADVANCED_CLIFF_SCRAMBLE("Rocks", 85, new WorldPoint(2337, 3253, 0)),
- KALPHITE_WALL("Crevice", 86, new WorldPoint(3214, 9508, 0)),
- BRIMHAVEN_DUNGEON_VINE_EAST("Vine", 87, new WorldPoint(2672, 9582, 0)),
- BRIMHAVEN_DUNGEON_VINE_WEST("Vine", 87, new WorldPoint(2606, 9584, 0)),
- RENEVANT_CAVES("Jump", 89, new WorldPoint(3240, 10144, 0));
-
- private final String tooltip;
- private final WorldPoint location;
- private final int levelReq;
-
- AgilityShortcutLocation(String description, int level, WorldPoint location)
- {
- this.tooltip = description + " - Level " + level;
- this.location = location;
- this.levelReq = level;
- }
-}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutPoint.java
index 74f4673c85..c99979f103 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutPoint.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutPoint.java
@@ -27,12 +27,13 @@ package net.runelite.client.plugins.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
+import net.runelite.client.game.AgilityShortcut;
class AgilityShortcutPoint extends WorldMapPoint
{
- AgilityShortcutPoint(AgilityShortcutLocation data, BufferedImage icon, boolean showTooltip)
+ AgilityShortcutPoint(AgilityShortcut data, BufferedImage icon, boolean showTooltip)
{
- super(data.getLocation(), icon);
+ super(data.getWorldMapLocation(), icon);
if (showTooltip)
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartLocation.java
index 66dde6666b..c1d9e9fb88 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartLocation.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartLocation.java
@@ -30,6 +30,7 @@ import net.runelite.api.coords.WorldPoint;
enum QuestStartLocation
{
+ //Free Quests
COOKS_ASSISTANT_RFD("Cook's Assistant", new WorldPoint(3211, 3216, 0)),
THE_CORSAIR_CURSE("The Corsair Curse", new WorldPoint(3029, 3273, 0)),
DEMON_SLAYER("Demon Slayer", new WorldPoint(3204, 3424, 0)),
@@ -48,8 +49,12 @@ enum QuestStartLocation
SHIELD_OF_ARRAV("Shield of Arrav", new WorldPoint(3208, 3495, 0)),
VAMPIRE_SLAYER("Vampire Slayer", new WorldPoint(3096, 3266, 0)),
WITCHS_POTION("Witch's Potion", new WorldPoint(2967, 3203, 0)),
+ X_MARKS_THE_SPOT("X Marks the Spot", new WorldPoint(3227, 3242, 0)),
+
+ //Members' Quests
ANIMAL_MAGNETISM("Animal Magnetism", new WorldPoint(3094, 3360, 0)),
ANOTHER_SLICE_OF_HAM("Another Slice of H.A.M.", new WorldPoint(2799, 5428, 0)),
+ THE_ASCENT_OF_ARCEUUS("The Ascent of Arceuus", new WorldPoint(1700, 3742, 0)),
BETWEEN_A_ROCK("Between a Rock...", new WorldPoint(2823, 10168, 0)),
BIG_CHOMPY_BIRD_HUNTING("Big Chompy Bird Hunting", new WorldPoint(2629, 2981, 0)),
BIOHAZARD("Biohazard", new WorldPoint(2591, 3335, 0)),
@@ -84,6 +89,7 @@ enum QuestStartLocation
FISHING_CONTEST_1("Fishing Contest", new WorldPoint(2875, 3483, 0)),
FISHING_CONTEST_2("Fishing Contest", new WorldPoint(2820, 3487, 0)),
FORGETTABLE_TALE("Forgettable Tale...", new WorldPoint(2826, 10215, 0)),
+ THE_FORSAKEN_TOWER("The Forsaken Tower", new WorldPoint(1484, 3747, 0)),
THE_FREMENNIK_ISLES("The Fremennik Isles", new WorldPoint(2645, 3711, 0)),
THE_FREMENNIK_TRIALS("The Fremennik Trials", new WorldPoint(2657, 3669, 0)),
GARDEN_OF_TRANQUILLITY("Garden of Tranquillity", new WorldPoint(3227, 3477, 0)),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreeLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreeLocation.java
index 69eaedcddc..d32dee4c32 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreeLocation.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreeLocation.java
@@ -38,7 +38,6 @@ enum RareTreeLocation
TEAK("Teak tree", 35,
// Ape Atoll
new WorldPoint(2774, 2697, 0),
- new WorldPoint(2716, 2710, 0),
// Desert
new WorldPoint(3510, 3073, 0),
@@ -85,6 +84,7 @@ enum RareTreeLocation
new WorldPoint(1237, 3770, 0),
// Ape Atoll
+ new WorldPoint(2716, 2710, 0),
new WorldPoint(2725, 2735, 0),
// Mos Le'Harmless
@@ -140,7 +140,7 @@ enum RareTreeLocation
new WorldPoint(3018, 3316, 0),
new WorldPoint(3041, 3320, 0),
new WorldPoint(3052, 3272, 0),
- new WorldPoint(2933, 3234, 0),
+ new WorldPoint(2931, 3231, 0),
// Misthalin
new WorldPoint(3085, 3481, 0),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java
index fea186927b..276e2083e4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java
@@ -36,6 +36,7 @@ import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ExperienceChanged;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.game.AgilityShortcut;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager;
@@ -167,9 +168,10 @@ public class WorldMapPlugin extends Plugin
if (config.agilityShortcutLevelIcon() || config.agilityShortcutTooltips())
{
- Arrays.stream(AgilityShortcutLocation.values())
+ Arrays.stream(AgilityShortcut.values())
+ .filter(value -> value.getWorldMapLocation() != null)
.map(value -> new AgilityShortcutPoint(value,
- agilityLevel > 0 && config.agilityShortcutLevelIcon() && value.getLevelReq() > agilityLevel ? NOPE_ICON : BLANK_ICON,
+ agilityLevel > 0 && config.agilityShortcutLevelIcon() && value.getLevel() > agilityLevel ? NOPE_ICON : BLANK_ICON,
config.agilityShortcutTooltips()))
.forEach(worldMapPointManager::add);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java
index f5987290eb..512be6d12e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java
@@ -28,7 +28,6 @@ package net.runelite.client.plugins.xptracker;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
-import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
@@ -95,7 +94,7 @@ class XpInfoBox extends JPanel
private boolean paused = false;
- XpInfoBox(XpTrackerPlugin xpTrackerPlugin, XpTrackerConfig xpTrackerConfig, Client client, JPanel panel, Skill skill, SkillIconManager iconManager) throws IOException
+ XpInfoBox(XpTrackerPlugin xpTrackerPlugin, XpTrackerConfig xpTrackerConfig, Client client, JPanel panel, Skill skill, SkillIconManager iconManager)
{
this.xpTrackerConfig = xpTrackerConfig;
this.panel = panel;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPanel.java
index e98f4da4f7..c7bf7c3876 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPanel.java
@@ -27,7 +27,6 @@ package net.runelite.client.plugins.xptracker;
import java.awt.BorderLayout;
import java.awt.GridLayout;
-import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.swing.BoxLayout;
@@ -129,20 +128,13 @@ class XpPanel extends PluginPanel
layoutPanel.add(overallPanel);
layoutPanel.add(infoBoxPanel);
- try
+ for (Skill skill : Skill.values())
{
- for (Skill skill : Skill.values())
+ if (skill == Skill.OVERALL)
{
- if (skill == Skill.OVERALL)
- {
- break;
- }
- infoBoxes.put(skill, new XpInfoBox(xpTrackerPlugin, xpTrackerConfig, client, infoBoxPanel, skill, iconManager));
+ break;
}
- }
- catch (IOException e)
- {
- log.warn(null, e);
+ infoBoxes.put(skill, new XpInfoBox(xpTrackerPlugin, xpTrackerConfig, client, infoBoxPanel, skill, iconManager));
}
errorPanel.setContent("Exp trackers", "You have not gained experience yet.");
@@ -193,7 +185,7 @@ class XpPanel extends PluginPanel
}
}
- void updateTotal(XpSnapshotTotal xpSnapshotTotal)
+ void updateTotal(XpSnapshotSingle xpSnapshotTotal)
{
// if player has gained exp and hasn't switched displays yet, hide error panel and show overall info
if (xpSnapshotTotal.getXpGainedInSession() > 0 && !overallPanel.isVisible())
@@ -201,11 +193,16 @@ class XpPanel extends PluginPanel
overallPanel.setVisible(true);
remove(errorPanel);
}
+ else if (xpSnapshotTotal.getXpGainedInSession() == 0 && overallPanel.isVisible())
+ {
+ overallPanel.setVisible(false);
+ add(errorPanel);
+ }
SwingUtilities.invokeLater(() -> rebuildAsync(xpSnapshotTotal));
}
- private void rebuildAsync(XpSnapshotTotal xpSnapshotTotal)
+ private void rebuildAsync(XpSnapshotSingle xpSnapshotTotal)
{
overallExpGained.setText(XpInfoBox.htmlLabel("Gained: ", xpSnapshotTotal.getXpGainedInSession()));
overallExpHour.setText(XpInfoBox.htmlLabel("Per hour: ", xpSnapshotTotal.getXpPerHour()));
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseState.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseState.java
index 9f57de71c3..194c890c42 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseState.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseState.java
@@ -49,7 +49,7 @@ class XpPauseState
return findPauseState(skill).isPaused();
}
- void tickXp(Skill skill, int currentXp, int pauseAfterMinutes)
+ void tickXp(Skill skill, long currentXp, int pauseAfterMinutes)
{
final XpPauseStateSingle state = findPauseState(skill);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseStateSingle.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseStateSingle.java
index d74d498bd1..9e5cc55622 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseStateSingle.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpPauseStateSingle.java
@@ -39,7 +39,7 @@ class XpPauseStateSingle
@Getter
private long lastChangeMillis;
@Getter
- private int xp;
+ private long xp;
boolean isPaused()
{
@@ -66,7 +66,7 @@ class XpPauseStateSingle
return pauseReasons.add(XpPauseReason.PAUSE_MANUAL);
}
- boolean xpChanged(int xp)
+ boolean xpChanged(long xp)
{
this.xp = xp;
this.lastChangeMillis = System.currentTimeMillis();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java
index a0ebb02341..16602b0cb4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java
@@ -40,7 +40,6 @@ class XpState
{
private static final double DEFAULT_XP_MODIFIER = 4.0;
private static final double SHARED_XP_MODIFIER = DEFAULT_XP_MODIFIER / 3.0;
- private final XpStateTotal xpTotal = new XpStateTotal();
private final Map