diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index ded2106f2a..b31c062c45 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -25,9 +25,9 @@ object ProjectVersions { const val launcherVersion = "2.2.0" - const val rlVersion = "1.7.3" + const val rlVersion = "1.7.3.1" - const val openosrsVersion = "4.2.1" + const val openosrsVersion = "4.3.0" const val rsversion = 194 const val cacheversion = 165 diff --git a/runelite-api/src/main/java/net/runelite/api/Scene.java b/runelite-api/src/main/java/net/runelite/api/Scene.java index 10befe0019..34983c41ad 100644 --- a/runelite-api/src/main/java/net/runelite/api/Scene.java +++ b/runelite-api/src/main/java/net/runelite/api/Scene.java @@ -51,6 +51,20 @@ public interface Scene int getDrawDistance(); void setDrawDistance(int drawDistance); + /** + * Get the minimum scene level which will be rendered + * + * @return the plane of the minimum level + */ + int getMinLevel(); + + /** + * Set the minimum scene level which will be rendered + * + * @param minLevel the plane of the minimum level + */ + void setMinLevel(int minLevel); + /** * Remove a game object from the scene * @param gameObject 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 b4d7471205..92c7606e35 100644 --- a/runelite-api/src/main/java/net/runelite/api/Varbits.java +++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java @@ -615,6 +615,15 @@ public enum Varbits */ PARASITE(10151), + /** + * Whether the vanilla wiki entity lookup is displayed under the minimap + * + * 0 = Enabled + * 1 = Disabled + * + */ + WIKI_ENTITY_LOOKUP(10113), + /** * Whether the Special Attack orb is disabled due to being in a PvP area * 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 d2cca11144..c52762382c 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 @@ -178,6 +178,7 @@ public class WidgetID public static final int DIALOG_NOTIFICATION_GROUP_ID = 229; public static final int DIALOG_SPRITE2_ID = 11; public static final int MULTISKILL_MENU_GROUP_ID = 270; + public static final int TEMPOROSS_GROUP_ID = 437; static class WorldMap { @@ -1076,6 +1077,10 @@ public class WidgetID static final int TELEPORT = 59; } + static class TemporossStatus + { + static final int STATUS_INDICATOR = 4; + } static class DialogPlayer { 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 3a50ba0862..a6a4b1af61 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 @@ -542,6 +542,8 @@ public enum WidgetInfo MULTICOMBAT_RESIZEABLE_MODERN(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID, WidgetID.ResizableViewport.MULTICOMBAT_INDICATOR), MULTICOMBAT_RESIZEABLE_CLASSIC(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID, WidgetID.ResizableViewport.MULTICOMBAT_INDICATOR), + TEMPOROSS_STATUS_INDICATOR(WidgetID.TEMPOROSS_GROUP_ID, WidgetID.TemporossStatus.STATUS_INDICATOR), + //OpenOSRS WORLD_MAP_BUTTON_BORDER(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.WORLDMAP_ORB), diff --git a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java index f653439391..a2f05f4483 100644 --- a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java +++ b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java @@ -26,9 +26,8 @@ package net.runelite.client.eventbus; import com.google.common.base.Preconditions; -import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; +import com.google.common.collect.Iterables; import java.lang.invoke.CallSite; import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandle; @@ -183,26 +182,10 @@ public class EventBus */ public synchronized void unregister(@Nonnull final Object object) { - final Multimap, Subscriber> map = HashMultimap.create(); - map.putAll(subscribers); - - for (Class clazz = object.getClass(); clazz != null; clazz = clazz.getSuperclass()) - { - for (final Method method : clazz.getDeclaredMethods()) - { - final Subscribe sub = method.getAnnotation(Subscribe.class); - - if (sub == null) - { - continue; - } - - final Class parameterClazz = method.getParameterTypes()[0]; - map.remove(parameterClazz, new Subscriber(object, method, sub.priority(), null)); - } - } - - subscribers = ImmutableMultimap.copyOf(map); + subscribers = ImmutableMultimap.copyOf(Iterables.filter( + subscribers.entries(), + e -> e.getValue().getObject() != object + )); } public synchronized void unregister(Subscriber sub) @@ -212,12 +195,10 @@ public class EventBus return; } - final Multimap, Subscriber> map = HashMultimap.create(); - map.putAll(subscribers); - - map.values().remove(sub); - - subscribers = ImmutableMultimap.copyOf(map); + subscribers = ImmutableMultimap.copyOf(Iterables.filter( + subscribers.entries(), + e -> sub != e.getValue() + )); } /** diff --git a/runelite-client/src/main/java/net/runelite/client/game/FishingSpot.java b/runelite-client/src/main/java/net/runelite/client/game/FishingSpot.java index a3de9412a2..6ab929d173 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/FishingSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/game/FishingSpot.java @@ -28,103 +28,7 @@ import com.google.common.collect.ImmutableMap; import java.util.Map; import lombok.Getter; import net.runelite.api.ItemID; -import static net.runelite.api.NpcID.FISHING_SPOT; -import static net.runelite.api.NpcID.FISHING_SPOT_10513; -import static net.runelite.api.NpcID.FISHING_SPOT_10514; -import static net.runelite.api.NpcID.FISHING_SPOT_10515; -import static net.runelite.api.NpcID.FISHING_SPOT_1497; -import static net.runelite.api.NpcID.FISHING_SPOT_1498; -import static net.runelite.api.NpcID.FISHING_SPOT_1499; -import static net.runelite.api.NpcID.FISHING_SPOT_1510; -import static net.runelite.api.NpcID.FISHING_SPOT_1511; -import static net.runelite.api.NpcID.FISHING_SPOT_1514; -import static net.runelite.api.NpcID.FISHING_SPOT_1517; -import static net.runelite.api.NpcID.FISHING_SPOT_1518; -import static net.runelite.api.NpcID.FISHING_SPOT_1519; -import static net.runelite.api.NpcID.FISHING_SPOT_1520; -import static net.runelite.api.NpcID.FISHING_SPOT_1521; -import static net.runelite.api.NpcID.FISHING_SPOT_1522; -import static net.runelite.api.NpcID.FISHING_SPOT_1523; -import static net.runelite.api.NpcID.FISHING_SPOT_1524; -import static net.runelite.api.NpcID.FISHING_SPOT_1525; -import static net.runelite.api.NpcID.FISHING_SPOT_1528; -import static net.runelite.api.NpcID.FISHING_SPOT_1530; -import static net.runelite.api.NpcID.FISHING_SPOT_1535; -import static net.runelite.api.NpcID.FISHING_SPOT_1536; -import static net.runelite.api.NpcID.FISHING_SPOT_1542; -import static net.runelite.api.NpcID.FISHING_SPOT_1544; -import static net.runelite.api.NpcID.FISHING_SPOT_2653; -import static net.runelite.api.NpcID.FISHING_SPOT_2654; -import static net.runelite.api.NpcID.FISHING_SPOT_2655; -import static net.runelite.api.NpcID.FISHING_SPOT_3317; -import static net.runelite.api.NpcID.FISHING_SPOT_3419; -import static net.runelite.api.NpcID.FISHING_SPOT_3657; -import static net.runelite.api.NpcID.FISHING_SPOT_3913; -import static net.runelite.api.NpcID.FISHING_SPOT_3914; -import static net.runelite.api.NpcID.FISHING_SPOT_3915; -import static net.runelite.api.NpcID.FISHING_SPOT_4079; -import static net.runelite.api.NpcID.FISHING_SPOT_4080; -import static net.runelite.api.NpcID.FISHING_SPOT_4081; -import static net.runelite.api.NpcID.FISHING_SPOT_4082; -import static net.runelite.api.NpcID.FISHING_SPOT_4316; -import static net.runelite.api.NpcID.FISHING_SPOT_4476; -import static net.runelite.api.NpcID.FISHING_SPOT_4477; -import static net.runelite.api.NpcID.FISHING_SPOT_4710; -import static net.runelite.api.NpcID.FISHING_SPOT_4712; -import static net.runelite.api.NpcID.FISHING_SPOT_4713; -import static net.runelite.api.NpcID.FISHING_SPOT_4714; -import static net.runelite.api.NpcID.FISHING_SPOT_5233; -import static net.runelite.api.NpcID.FISHING_SPOT_5234; -import static net.runelite.api.NpcID.FISHING_SPOT_5820; -import static net.runelite.api.NpcID.FISHING_SPOT_5821; -import static net.runelite.api.NpcID.FISHING_SPOT_6488; -import static net.runelite.api.NpcID.FISHING_SPOT_7155; -import static net.runelite.api.NpcID.FISHING_SPOT_7199; -import static net.runelite.api.NpcID.FISHING_SPOT_7200; -import static net.runelite.api.NpcID.FISHING_SPOT_7323; -import static net.runelite.api.NpcID.FISHING_SPOT_7459; -import static net.runelite.api.NpcID.FISHING_SPOT_7460; -import static net.runelite.api.NpcID.FISHING_SPOT_7461; -import static net.runelite.api.NpcID.FISHING_SPOT_7462; -import static net.runelite.api.NpcID.FISHING_SPOT_7465; -import static net.runelite.api.NpcID.FISHING_SPOT_7466; -import static net.runelite.api.NpcID.FISHING_SPOT_7467; -import static net.runelite.api.NpcID.FISHING_SPOT_7469; -import static net.runelite.api.NpcID.FISHING_SPOT_7470; -import static net.runelite.api.NpcID.FISHING_SPOT_7730; -import static net.runelite.api.NpcID.FISHING_SPOT_7731; -import static net.runelite.api.NpcID.FISHING_SPOT_7732; -import static net.runelite.api.NpcID.FISHING_SPOT_7733; -import static net.runelite.api.NpcID.FISHING_SPOT_7946; -import static net.runelite.api.NpcID.FISHING_SPOT_7947; -import static net.runelite.api.NpcID.FISHING_SPOT_8523; -import static net.runelite.api.NpcID.FISHING_SPOT_8525; -import static net.runelite.api.NpcID.FISHING_SPOT_8526; -import static net.runelite.api.NpcID.FISHING_SPOT_8527; -import static net.runelite.api.NpcID.FISHING_SPOT_9171; -import static net.runelite.api.NpcID.FISHING_SPOT_9172; -import static net.runelite.api.NpcID.FISHING_SPOT_9173; -import static net.runelite.api.NpcID.FISHING_SPOT_9174; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1506; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1507; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1508; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1509; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1513; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1515; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1516; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1526; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_1527; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_3417; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_3418; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_6825; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_7463; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_7464; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_7468; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_7676; -import static net.runelite.api.NpcID.ROD_FISHING_SPOT_8524; -import static net.runelite.api.NpcID.FISHING_SPOT_4928; -import static net.runelite.api.NpcID.FISHING_SPOT_6784; +import static net.runelite.api.NpcID.*; @Getter public enum FishingSpot @@ -142,7 +46,7 @@ public enum FishingSpot FISHING_SPOT_3914, FISHING_SPOT_5820, FISHING_SPOT_7199, FISHING_SPOT_7460, FISHING_SPOT_7465, FISHING_SPOT_7470, FISHING_SPOT_7946, FISHING_SPOT_9173, FISHING_SPOT_9174, - FISHING_SPOT_10515 + FISHING_SPOT_10515, FISHING_SPOT_10635 ), SHARK("Shark, Bass", "Shark", ItemID.RAW_SHARK, FISHING_SPOT_1511, FISHING_SPOT_1520, FISHING_SPOT_3419, @@ -175,6 +79,9 @@ public enum FishingSpot MINNOW("Minnow", ItemID.MINNOW, FISHING_SPOT_7730, FISHING_SPOT_7731, FISHING_SPOT_7732, FISHING_SPOT_7733 ), + HARPOONFISH("Harpoonfish", ItemID.RAW_HARPOONFISH, + FISHING_SPOT_10565, FISHING_SPOT_10568, FISHING_SPOT_10569 + ), INFERNAL_EEL("Infernal Eel", ItemID.INFERNAL_EEL, ROD_FISHING_SPOT_7676 ), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java index f3dfe92482..7190e70108 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java @@ -124,16 +124,17 @@ enum DiscordGameEventType CITY_LUNAR_ISLE("Lunar Isle" , DiscordAreaType.CITIES, 8253, 8252, 8509, 8508), CITY_MARIM("Marim", DiscordAreaType.REGIONS, 11051), CITY_MEIYERDITCH("Meiyerditch" , DiscordAreaType.CITIES, 14132, 14387, 14386, 14385), + CITY_MENAPHOS("Menaphos", DiscordAreaType.CITIES, 12843), CITY_MISCELLANIA("Miscellania" , DiscordAreaType.CITIES, 10044), CITY_MOR_UL_REK("Mor Ul Rek" , DiscordAreaType.CITIES, 9808, 9807, 10064, 10063), CITY_MORTTON("Mort'ton" , DiscordAreaType.CITIES, 13875), - CITY_MOS_LE_HARMLESS("Mos Le'Harmless" , DiscordAreaType.CITIES, 14638, 14639, 14894, 14895, 15151, 15406, 15407), + CITY_MOS_LE_HARMLESS("Mos Le'Harmless" , DiscordAreaType.CITIES, 14637, 14638, 14639, 14894, 14895, 15151, 15406, 15407), CITY_MOUNT_KARUULM("Mount Karuulm", DiscordAreaType.CITIES, 5179, 4923, 5180), CITY_MOUNTAIN_CAMP("Mountain Camp", DiscordAreaType.CITIES, 11065), CITY_MYNYDD("Mynydd", DiscordAreaType.CITIES, 8501), CITY_NARDAH("Nardah" , DiscordAreaType.CITIES, 13613), CITY_NEITIZNOT("Neitiznot" , DiscordAreaType.CITIES, 9275), - CITY_PISCARILIUS_HOUSE("Port Piscarilius" , DiscordAreaType.CITIES, 6971, 7227, 6970, 7226), + CITY_PISCARILIUS_HOUSE("Port Piscarilius" , DiscordAreaType.CITIES, 6969, 6971, 7227, 6970, 7225, 7226), CITY_PISCATORIS("Piscatoris" , DiscordAreaType.CITIES, 9273), CITY_POLLNIVNEACH("Pollnivneach" , DiscordAreaType.CITIES, 13358), CITY_PORT_KHAZARD("Port Khazard" , DiscordAreaType.CITIES, 10545), @@ -163,12 +164,13 @@ enum DiscordGameEventType CITY_ZULANDRA("Zul-Andra" , DiscordAreaType.CITIES, 8495, 8751), // Dungeons - DUNGEON_ABANDONED_MINE("Abandoned Mine", DiscordAreaType.DUNGEONS, 13718, 11079, 11078, 11077, 10823, 10822, 10821), + DUNGEON_ABANDONED_MINE("Abandoned Mine", DiscordAreaType.DUNGEONS, 13618, 13718, 11079, 11078, 11077, 10823, 10822, 10821), DUNGEON_AH_ZA_RHOON("Ah Za Rhoon", DiscordAreaType.DUNGEONS, 11666), DUNGEON_ANCIENT_CAVERN("Ancient Cavern", DiscordAreaType.DUNGEONS, 6483, 6995), DUNGEON_APE_ATOLL("Ape Atoll Dungeon", DiscordAreaType.DUNGEONS, 11150, 10894), DUNGEON_APE_ATOLL_BANANA_PLANTATION("Ape Atoll Banana Plantation", DiscordAreaType.DUNGEONS, 10895), - DUNGEON_ARDY_SEWERS("Ardougne Sewers", DiscordAreaType.DUNGEONS, 10136, 10647), + DUNGEON_ARDY_BASEMENT("West Ardougne Basement", DiscordAreaType.DUNGEONS, 10135), + DUNGEON_ARDY_SEWERS("Ardougne Sewers", DiscordAreaType.DUNGEONS, 10134, 10136, 10391, 10647), DUNGEON_ASGARNIAN_ICE_CAVES("Asgarnian Ice Caves", DiscordAreaType.DUNGEONS, 11925, 12181), DUNGEON_BERVIRIUS_TOMB("Tomb of Bervirius", DiscordAreaType.DUNGEONS, 11154), DUNGEON_BRIMHAVEN("Brimhaven Dungeon", DiscordAreaType.DUNGEONS, 10901, 10900, 10899, 10645, 10644, 10643), @@ -195,6 +197,7 @@ enum DiscordGameEventType DUNGEON_ECTOFUNTUS("Ectofuntus", DiscordAreaType.DUNGEONS, 14746), DUNGEON_EDGEVILLE("Edgeville Dungeon", DiscordAreaType.DUNGEONS, 12441, 12442, 12443, 12698), DUNGEON_ELEMENTAL_WORKSHOP("Elemental Workshop", DiscordAreaType.DUNGEONS, 10906, 7760), + DUNGEON_ELVEN_RABBIT_CAVE("Elven rabbit cave", DiscordAreaType.DUNGEONS, 13252), DUNGEON_ENAKHRAS_TEMPLE("Enakhra's Temple", DiscordAreaType.DUNGEONS, 12423), DUNGEON_EVIL_CHICKENS_LAIR("Evil Chicken's Lair", DiscordAreaType.DUNGEONS, 9796), DUNGEON_EXPERIMENT_CAVE("Experiment Cave", DiscordAreaType.DUNGEONS, 14235, 13979), @@ -317,7 +320,7 @@ enum DiscordGameEventType REGION_AGILITY_PYRAMID("Agility Pyramid", DiscordAreaType.REGIONS, 12105, 13356), REGION_AIR_ALTAR("Air Altar", DiscordAreaType.REGIONS, 11339), REGION_AL_KHARID_MINE("Al Kharid Mine", DiscordAreaType.REGIONS, 13107), - REGION_APE_ATOLL("Ape Atoll" , DiscordAreaType.REGIONS, 10795, 10974, 11050), + REGION_APE_ATOLL("Ape Atoll" , DiscordAreaType.REGIONS, 10794, 10795, 10974, 11050), REGION_ARANDAR("Arandar", DiscordAreaType.REGIONS, 9266, 9267, 9523), REGION_ASGARNIA("Asgarnia", DiscordAreaType.REGIONS, 11825, 11829, 11830, 12085, 12086), REGION_BATTLEFIELD("Battlefield", DiscordAreaType.REGIONS, 10034), @@ -335,6 +338,7 @@ enum DiscordGameEventType REGION_DEATH_ALTAR("Death Altar", DiscordAreaType.REGIONS, 8779), REGION_DEATH_PLATEAU("Death Plateau", DiscordAreaType.REGIONS, 11320), REGION_DENSE_ESSENCE("Dense Essence Mine", DiscordAreaType.REGIONS, 6972), + REGION_DESERT_PLATEAU("Desert Plateau", DiscordAreaType.REGIONS, 13361, 13617), REGION_DIGSITE("Digsite", DiscordAreaType.REGIONS, 13365), REGION_DRAGONTOOTH("Dragontooth Island", DiscordAreaType.REGIONS, 15159), REGION_DRAYNOR_MANOR("Draynor Manor", DiscordAreaType.REGIONS, 12340), @@ -348,6 +352,7 @@ enum DiscordGameEventType REGION_FARMING_GUILD("Farming Guild", DiscordAreaType.REGIONS, 4922), REGION_FELDIP_HILLS("Feldip Hills", DiscordAreaType.REGIONS, 9773, 9774, 10029, 10030, 10285, 10286, 10287, 10542, 10543), REGION_FENKENSTRAIN("Fenkenstrain's Castle", DiscordAreaType.REGIONS, 14135), + REGION_FIGHT_ARENA("Fight Arena", DiscordAreaType.REGIONS, 10289), REGION_FIRE_ALTAR("Fire Altar", DiscordAreaType.REGIONS, 10315), REGION_FISHER_REALM("Fisher Realm", DiscordAreaType.REGIONS, 10569), REGION_FISHING_GUILD("Fishing Guild", DiscordAreaType.REGIONS, 10293), @@ -363,6 +368,7 @@ enum DiscordGameEventType REGION_GRAND_EXCHANGE("Grand Exchange", DiscordAreaType.REGIONS, 12598), REGION_GWD("God Wars Dungeon", DiscordAreaType.REGIONS, 11578), REGION_HARMONY("Harmony Island", DiscordAreaType.REGIONS, 15148), + REGION_HAZELMERE("Hazelmere's Island", DiscordAreaType.REGIONS, 10544), REGION_ICE_PATH("Ice Path", DiscordAreaType.REGIONS, 11322, 11323), REGION_ICEBERG("Iceberg", DiscordAreaType.REGIONS, 10558, 10559), REGION_ICYENE_GRAVEYARD("Icyene Graveyard", DiscordAreaType.REGIONS, 14641, 14897, 14898), @@ -370,9 +376,9 @@ enum DiscordGameEventType REGION_ISLAND_OF_STONE("Island of Stone", DiscordAreaType.REGIONS, 9790), REGION_ISLE_OF_SOULS("Isle of Souls", DiscordAreaType.REGIONS, 8236, 8237, 8238, 8491, 8492, 8494, 8747, 8750, 9003, 9004, 9006, 9260, 9261, 9262), REGION_JIGGIG("Jiggig" , DiscordAreaType.REGIONS, 9775), - REGION_KANDARIN("Kandarin", DiscordAreaType.REGIONS, 9014, 9263, 9264, 9519, 9524, 9527, 9776, 9783, 10037, 10290, 10294, 10546, 10551, 10805), + REGION_KANDARIN("Kandarin", DiscordAreaType.REGIONS, 9268, 9269, 9014, 9263, 9264, 9519, 9524, 9527, 9776, 9783, 10037, 10290, 10294, 10546, 10551, 10805, 11062), REGION_KARAMJA("Karamja" , DiscordAreaType.REGIONS, 10801, 10802, 11054, 11311, 11312, 11313, 11566, 11567, 11568, 11569, 11822), - REGION_KEBOS_LOWLANDS("Kebos Lowlands", DiscordAreaType.REGIONS, 4665, 4666, 4921, 5178), + REGION_KEBOS_LOWLANDS("Kebos Lowlands", DiscordAreaType.REGIONS, 4665, 4666, 4667, 4921, 5178), REGION_KEBOS_SWAMP("Kebos Swamp", DiscordAreaType.REGIONS, 4664, 4920, 5174, 5175, 5176, 5430, 5431), REGION_KHARAZI_JUNGLE("Kharazi Jungle", DiscordAreaType.REGIONS, 11053, 11309, 11565, 11821), REGION_KHARIDIAN_DESERT("Kharidian Desert", DiscordAreaType.REGIONS, 12587, 12844, 12845, 12846, 12847, 12848, 13100, 13101, 13102, 13103, 13104, 13357, 13359, 13360, 13614, 13615, 13616), @@ -426,6 +432,7 @@ enum DiscordGameEventType REGION_TROLL_ARENA("Troll Arena", DiscordAreaType.REGIONS, 11576), REGION_TROLLHEIM("Trollheim", DiscordAreaType.REGIONS, 11577), REGION_TROLLWEISS_MTN("Trollweiss Mountain", DiscordAreaType.REGIONS, 11066, 11067, 11068), + REGION_TUTORIAL_ISLAND("Tutorial Island", DiscordAreaType.REGIONS, 12079, 12080, 12335, 12336, 12436, 12592), REGION_UNDERWATER("Underwater", DiscordAreaType.REGIONS, 15008, 15264), REGION_WATER_ALTAR("Water Altar", DiscordAreaType.REGIONS, 10827), REGION_WATERBIRTH_ISLAND("Waterbirth Island", DiscordAreaType.REGIONS, 10042), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java index 6e68c4270a..4aed364903 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java @@ -114,6 +114,18 @@ public interface FishingConfig extends Config return Color.GREEN; } + @Alpha + @ConfigItem( + keyName = "harpoonfishOverlayColor", + name = "Harpoonfish Overlay", + description = "Color of overlays for bubbling Harpoonfish spots", + position = 6 + ) + default Color getHarpoonfishOverlayColor() + { + return Color.GREEN; + } + @ConfigItem( position = 7, keyName = "statTimeout", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotMinimapOverlay.java index 7b995a9945..e0a62ccfe7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotMinimapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotMinimapOverlay.java @@ -32,6 +32,7 @@ import lombok.AccessLevel; import lombok.Setter; import net.runelite.api.GraphicID; import net.runelite.api.NPC; +import net.runelite.api.NpcID; import net.runelite.client.game.FishingSpot; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -79,6 +80,8 @@ class FishingSpotMinimapOverlay extends Overlay Color color = npc.getGraphic() == GraphicID.FLYING_FISH ? config.getMinnowsOverlayColor() + : npc.getId() == NpcID.FISHING_SPOT_10569 + ? config.getHarpoonfishOverlayColor() : config.getOverlayColor(); net.runelite.api.Point minimapLocation = npc.getMinimapLocation(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java index 82c710a214..a71d9faf26 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java @@ -37,6 +37,7 @@ import lombok.Setter; import net.runelite.api.Client; import net.runelite.api.GraphicID; import net.runelite.api.NPC; +import net.runelite.api.NpcID; import net.runelite.api.Perspective; import net.runelite.api.Point; import net.runelite.api.coords.LocalPoint; @@ -114,6 +115,10 @@ class FishingSpotOverlay extends Overlay { color = config.getAerialOverlayColor(); } + else if (spot == FishingSpot.HARPOONFISH && npc.getId() == NpcID.FISHING_SPOT_10569) + { + color = config.getHarpoonfishOverlayColor(); + } else { color = config.getOverlayColor(); 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 b998251ccb..096501d67b 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 @@ -32,9 +32,19 @@ import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigSection; -@ConfigGroup("itemCharge") +@ConfigGroup(ItemChargeConfig.GROUP) public interface ItemChargeConfig extends Config { + String GROUP = "itemCharge"; + + String KEY_AMULET_OF_BOUNTY = "amuletOfBounty"; + String KEY_AMULET_OF_CHEMISTRY = "amuletOfChemistry"; + String KEY_BINDING_NECKLACE = "bindingNecklace"; + String KEY_CHRONICLE = "chronicle"; + String KEY_DODGY_NECKLACE = "dodgyNecklace"; + String KEY_EXPLORERS_RING = "explorerRing"; + String KEY_RING_OF_FORGING = "ringOfForging"; + @ConfigSection( name = "Charge Settings", description = "Configuration for which charges should be displayed", @@ -129,24 +139,6 @@ public interface ItemChargeConfig extends Config return true; } - @ConfigItem( - keyName = "dodgyNecklace", - name = "", - description = "", - hidden = true - ) - default int dodgyNecklace() - { - return -1; - } - - @ConfigItem( - keyName = "dodgyNecklace", - name = "", - description = "" - ) - void dodgyNecklace(int dodgyNecklace); - @ConfigItem( keyName = "showImpCharges", name = "Imp-in-a-box charges", @@ -255,24 +247,6 @@ public interface ItemChargeConfig extends Config return true; } - @ConfigItem( - keyName = "amuletOfChemistry", - name = "", - description = "", - hidden = true - ) - default int amuletOfChemistry() - { - return -1; - } - - @ConfigItem( - keyName = "amuletOfChemistry", - name = "", - description = "" - ) - void amuletOfChemistry(int amuletOfChemistry); - @ConfigItem( keyName = "showAmuletOfBountyCharges", name = "Amulet of Bounty Charges", @@ -285,24 +259,6 @@ public interface ItemChargeConfig extends Config return true; } - @ConfigItem( - keyName = "amuletOfBounty", - name = "", - description = "", - hidden = true - ) - default int amuletOfBounty() - { - return -1; - } - - @ConfigItem( - keyName = "amuletOfBounty", - name = "", - description = "" - ) - void amuletOfBounty(int amuletOfBounty); - @ConfigItem( keyName = "recoilNotification", name = "Ring of Recoil Notification", @@ -327,24 +283,6 @@ public interface ItemChargeConfig extends Config return true; } - @ConfigItem( - keyName = "bindingNecklace", - name = "", - description = "", - hidden = true - ) - default int bindingNecklace() - { - return -1; - } - - @ConfigItem( - keyName = "bindingNecklace", - name = "", - description = "" - ) - void bindingNecklace(int bindingNecklace); - @ConfigItem( keyName = "bindingNotification", name = "Binding Necklace Notification", @@ -369,24 +307,6 @@ public interface ItemChargeConfig extends Config return true; } - @ConfigItem( - keyName = "explorerRing", - name = "", - description = "", - hidden = true - ) - default int explorerRing() - { - return -1; - } - - @ConfigItem( - keyName = "explorerRing", - name = "", - description = "" - ) - void explorerRing(int explorerRing); - @ConfigItem( keyName = "showRingOfForgingCount", name = "Ring of Forging Charges", @@ -399,24 +319,6 @@ public interface ItemChargeConfig extends Config return true; } - @ConfigItem( - keyName = "ringOfForging", - name = "", - description = "", - hidden = true - ) - default int ringOfForging() - { - return -1; - } - - @ConfigItem( - keyName = "ringOfForging", - name = "", - description = "" - ) - void ringOfForging(int ringOfForging); - @ConfigItem( keyName = "ringOfForgingNotification", name = "Ring of Forging Notification", @@ -451,22 +353,4 @@ public interface ItemChargeConfig extends Config { return false; } - - @ConfigItem( - keyName = "chronicle", - name = "", - description = "", - hidden = true - ) - default int chronicle() - { - return -1; - } - - @ConfigItem( - keyName = "chronicle", - name = "", - description = "" - ) - void chronicle(int chronicle); } 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 07e213d1d2..38f00f1892 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 @@ -69,7 +69,7 @@ class ItemChargeOverlay extends WidgetItemOverlay return; } - charges = config.dodgyNecklace(); + charges = itemChargePlugin.getItemCharges(ItemChargeConfig.KEY_DODGY_NECKLACE); } else if (itemId == ItemID.BINDING_NECKLACE) { @@ -78,7 +78,7 @@ class ItemChargeOverlay extends WidgetItemOverlay return; } - charges = config.bindingNecklace(); + charges = itemChargePlugin.getItemCharges(ItemChargeConfig.KEY_BINDING_NECKLACE); } else if (itemId >= ItemID.EXPLORERS_RING_1 && itemId <= ItemID.EXPLORERS_RING_4) { @@ -87,7 +87,7 @@ class ItemChargeOverlay extends WidgetItemOverlay return; } - charges = config.explorerRing(); + charges = itemChargePlugin.getItemCharges(ItemChargeConfig.KEY_EXPLORERS_RING); } else if (itemId == ItemID.RING_OF_FORGING) { @@ -96,7 +96,7 @@ class ItemChargeOverlay extends WidgetItemOverlay return; } - charges = config.ringOfForging(); + charges = itemChargePlugin.getItemCharges(ItemChargeConfig.KEY_RING_OF_FORGING); } else if (itemId == ItemID.AMULET_OF_CHEMISTRY) { @@ -105,7 +105,7 @@ class ItemChargeOverlay extends WidgetItemOverlay return; } - charges = config.amuletOfChemistry(); + charges = itemChargePlugin.getItemCharges(ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY); } else if (itemId == ItemID.AMULET_OF_BOUNTY) { @@ -114,7 +114,7 @@ class ItemChargeOverlay extends WidgetItemOverlay return; } - charges = config.amuletOfBounty(); + charges = itemChargePlugin.getItemCharges(ItemChargeConfig.KEY_AMULET_OF_BOUNTY); } else if (itemId == ItemID.CHRONICLE) { @@ -123,7 +123,7 @@ class ItemChargeOverlay extends WidgetItemOverlay return; } - charges = config.chronicle(); + charges = itemChargePlugin.getItemCharges(ItemChargeConfig.KEY_CHRONICLE); } else { 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 bc4ef469ef..546d049931 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 @@ -129,6 +129,9 @@ public class ItemChargePlugin extends Plugin @Inject private ClientThread clientThread; + @Inject + private ConfigManager configManager; + @Inject private OverlayManager overlayManager; @@ -173,7 +176,7 @@ public class ItemChargePlugin extends Plugin @Subscribe public void onConfigChanged(ConfigChanged event) { - if (!event.getGroup().equals("itemCharge")) + if (!event.getGroup().equals(ItemChargeConfig.GROUP)) { return; } @@ -310,7 +313,7 @@ public class ItemChargePlugin extends Plugin } else if (bindingNecklaceUsedMatcher.find()) { - updateBindingNecklaceCharges(config.bindingNecklace() - 1); + updateBindingNecklaceCharges(getItemCharges(ItemChargeConfig.KEY_BINDING_NECKLACE) - 1); } else if (bindingNecklaceCheckMatcher.find()) { @@ -347,7 +350,7 @@ public class ItemChargePlugin extends Plugin if (equipment.contains(ItemID.RING_OF_FORGING)) { - int charges = Ints.constrainToRange(config.ringOfForging() - 1, 0, MAX_RING_OF_FORGING_CHARGES); + int charges = Ints.constrainToRange(getItemCharges(ItemChargeConfig.KEY_RING_OF_FORGING) - 1, 0, MAX_RING_OF_FORGING_CHARGES); updateRingOfForgingCharges(charges); } } @@ -366,28 +369,28 @@ public class ItemChargePlugin extends Plugin if (match.equals("one")) { - config.chronicle(1); + setItemCharges(ItemChargeConfig.KEY_CHRONICLE, 1); } else { - config.chronicle(Integer.parseInt(match)); + setItemCharges(ItemChargeConfig.KEY_CHRONICLE, Integer.parseInt(match)); } } else if (chronicleUseAndCheckMatcher.find()) { - config.chronicle(Integer.parseInt(chronicleUseAndCheckMatcher.group(1))); + setItemCharges(ItemChargeConfig.KEY_CHRONICLE, Integer.parseInt(chronicleUseAndCheckMatcher.group(1))); } else if (message.equals(CHRONICLE_ONE_CHARGE_TEXT)) { - config.chronicle(1); + setItemCharges(ItemChargeConfig.KEY_CHRONICLE, 1); } else if (message.equals(CHRONICLE_EMPTY_TEXT) || message.equals(CHRONICLE_NO_CHARGES_TEXT)) { - config.chronicle(0); + setItemCharges(ItemChargeConfig.KEY_CHRONICLE, 0); } else if (message.equals(CHRONICLE_FULL_TEXT)) { - config.chronicle(1000); + setItemCharges(ItemChargeConfig.KEY_CHRONICLE, 1000); } } } @@ -501,7 +504,7 @@ public class ItemChargePlugin extends Plugin private void updateDodgyNecklaceCharges(final int value) { - config.dodgyNecklace(value); + setItemCharges(ItemChargeConfig.KEY_DODGY_NECKLACE, value); if (config.showInfoboxes() && config.showDodgyCount()) { @@ -518,7 +521,7 @@ public class ItemChargePlugin extends Plugin private void updateAmuletOfChemistryCharges(final int value) { - config.amuletOfChemistry(value); + setItemCharges(ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, value); if (config.showInfoboxes() && config.showAmuletOfChemistryCharges()) { @@ -535,7 +538,7 @@ public class ItemChargePlugin extends Plugin private void updateAmuletOfBountyCharges(final int value) { - config.amuletOfBounty(value); + setItemCharges(ItemChargeConfig.KEY_AMULET_OF_BOUNTY, value); if (config.showInfoboxes() && config.showAmuletOfBountyCharges()) { @@ -552,7 +555,7 @@ public class ItemChargePlugin extends Plugin private void updateBindingNecklaceCharges(final int value) { - config.bindingNecklace(value); + setItemCharges(ItemChargeConfig.KEY_BINDING_NECKLACE, value); if (config.showInfoboxes() && config.showBindingNecklaceCharges()) { @@ -570,7 +573,7 @@ public class ItemChargePlugin extends Plugin private void updateExplorerRingCharges(final int value) { // Note: Varbit counts upwards. We count down from the maximum charges. - config.explorerRing(MAX_EXPLORER_RING_CHARGES - value); + setItemCharges(ItemChargeConfig.KEY_EXPLORERS_RING, MAX_EXPLORER_RING_CHARGES - value); if (config.showInfoboxes() && config.showExplorerRingCharges()) { @@ -587,7 +590,7 @@ public class ItemChargePlugin extends Plugin private void updateRingOfForgingCharges(final int value) { - config.ringOfForging(value); + setItemCharges(ItemChargeConfig.KEY_RING_OF_FORGING, value); if (config.showInfoboxes() && config.showRingOfForgingCount()) { @@ -654,27 +657,27 @@ public class ItemChargePlugin extends Plugin { if (id == ItemID.DODGY_NECKLACE && type == ItemWithSlot.DODGY_NECKLACE) { - charges = config.dodgyNecklace(); + charges = getItemCharges(ItemChargeConfig.KEY_DODGY_NECKLACE); } else if (id == ItemID.BINDING_NECKLACE && type == ItemWithSlot.BINDING_NECKLACE) { - charges = config.bindingNecklace(); + charges = getItemCharges(ItemChargeConfig.KEY_BINDING_NECKLACE); } else if ((id >= ItemID.EXPLORERS_RING_1 && id <= ItemID.EXPLORERS_RING_4) && type == ItemWithSlot.EXPLORER_RING) { - charges = config.explorerRing(); + charges = getItemCharges(ItemChargeConfig.KEY_EXPLORERS_RING); } else if (id == ItemID.RING_OF_FORGING && type == ItemWithSlot.RING_OF_FORGING) { - charges = config.ringOfForging(); + charges = getItemCharges(ItemChargeConfig.KEY_RING_OF_FORGING); } else if (id == ItemID.AMULET_OF_CHEMISTRY && type == ItemWithSlot.AMULET_OF_CHEMISTY) { - charges = config.amuletOfChemistry(); + charges = getItemCharges(ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY); } else if (id == ItemID.AMULET_OF_BOUNTY && type == ItemWithSlot.AMULET_OF_BOUNTY) { - charges = config.amuletOfBounty(); + charges = getItemCharges(ItemChargeConfig.KEY_AMULET_OF_BOUNTY); } } else if (itemWithCharge.getType() == type.getType()) @@ -693,6 +696,26 @@ public class ItemChargePlugin extends Plugin infoBoxManager.addInfoBox(infobox); } + int getItemCharges(String key) + { + // Migrate old non-profile configurations + Integer i = configManager.getConfiguration(ItemChargeConfig.GROUP, key, Integer.class); + if (i != null) + { + configManager.unsetConfiguration(ItemChargeConfig.GROUP, key); + configManager.setRSProfileConfiguration(ItemChargeConfig.GROUP, key, i); + return i; + } + + i = configManager.getRSProfileConfiguration(ItemChargeConfig.GROUP, key, Integer.class); + return i == null ? -1 : i; + } + + private void setItemCharges(String key, int value) + { + configManager.setRSProfileConfiguration(ItemChargeConfig.GROUP, key, value); + } + private void removeInfobox(final ItemWithSlot item) { infoBoxManager.removeIf(t -> t instanceof ItemChargeInfobox && ((ItemChargeInfobox) t).getItem() == item); 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 46857ea2e2..ee9f307838 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 @@ -41,6 +41,7 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashSet; import java.util.List; @@ -239,6 +240,12 @@ public class LootTrackerPlugin extends Plugin private static final String SPOILS_OF_WAR_EVENT = "Spoils of war"; private static final Set SOUL_WARS_REGIONS = ImmutableSet.of(8493, 8749, 9005); + // Tempoross + private static final String TEMPOROSS_EVENT = "Reward pool (Tempoross)"; + private static final String TEMPOROSS_CASKET_EVENT = "Casket (Tempoross)"; + private static final String TEMPOROSS_LOOT_STRING = "You found some loot: "; + private static final int TEMPOROSS_REGION = 12588; + private static final Set VOWELS = ImmutableSet.of('a', 'e', 'i', 'o', 'u'); @Inject @@ -756,6 +763,12 @@ public class LootTrackerPlugin extends Plugin setEvent(LootRecordType.EVENT, type, client.getBoostedSkillLevel(Skill.HUNTER)); takeInventorySnapshot(); } + + if (regionID == TEMPOROSS_REGION && message.startsWith(TEMPOROSS_LOOT_STRING)) + { + setEvent(LootRecordType.EVENT, TEMPOROSS_EVENT, client.getBoostedSkillLevel(Skill.FISHING)); + takeInventorySnapshot(); + } } @Subscribe @@ -772,10 +785,6 @@ public class LootTrackerPlugin extends Plugin || HALLOWED_SEPULCHRE_COFFIN_EVENT.equals(eventType) || HERBIBOAR_EVENT.equals(eventType) || HESPORI_EVENT.equals(eventType) - || SEEDPACK_EVENT.equals(eventType) - || CASKET_EVENT.equals(eventType) - || BIRDNEST_EVENT.equals(eventType) - || SPOILS_OF_WAR_EVENT.equals(eventType) || eventType.endsWith("Bird House") || eventType.startsWith("H.A.M. chest") || lootRecordType == LootRecordType.PICKPOCKET) @@ -786,6 +795,17 @@ public class LootTrackerPlugin extends Plugin processInventoryLoot(eventType, lootRecordType, metadata, event.getItemContainer(), groundItems); resetEvent(); } + // Events that do not produce ground items + else if (SEEDPACK_EVENT.equals(eventType) + || CASKET_EVENT.equals(eventType) + || BIRDNEST_EVENT.equals(eventType) + || SPOILS_OF_WAR_EVENT.equals(eventType) + || TEMPOROSS_EVENT.equals(eventType) + || TEMPOROSS_CASKET_EVENT.equals(eventType)) + { + processInventoryLoot(eventType, lootRecordType, metadata, event.getItemContainer(), Collections.emptyList()); + resetEvent(); + } } @Subscribe @@ -827,6 +847,12 @@ public class LootTrackerPlugin extends Plugin setEvent(LootRecordType.EVENT, SPOILS_OF_WAR_EVENT); takeInventorySnapshot(); } + + if (event.getMenuOption().equals("Open") && event.getId() == ItemID.CASKET_25590) + { + setEvent(LootRecordType.EVENT, TEMPOROSS_CASKET_EVENT); + takeInventorySnapshot(); + } } @Schedule( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryConfig.java new file mode 100644 index 0000000000..123117c466 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryConfig.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.lowmemory; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup(LowMemoryConfig.GROUP) +public interface LowMemoryConfig extends Config +{ + String GROUP = "lowmemory"; + + @ConfigItem( + keyName = "lowDetail", + name = "Low detail", + description = "Hides ground detail and simplifies textures.", + position = 0 + ) + default boolean lowDetail() + { + return true; + } + + @ConfigItem( + keyName = "hideLowerPlanes", + name = "Hide lower planes", + description = "Only renders the current plane you are on.", + position = 1 + ) + default boolean hideLowerPlanes() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryPlugin.java index 66270da3ad..4e980af0da 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lowmemory/LowMemoryPlugin.java @@ -24,12 +24,16 @@ */ package net.runelite.client.plugins.lowmemory; +import com.google.inject.Provides; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.events.BeforeRender; import net.runelite.api.events.GameStateChanged; import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -47,12 +51,15 @@ public class LowMemoryPlugin extends Plugin @Inject private ClientThread clientThread; + @Inject + private LowMemoryConfig config; + @Override protected void startUp() { if (client.getGameState() == GameState.LOGGED_IN) { - clientThread.invoke(() -> client.changeMemoryMode(true)); + clientThread.invoke(() -> client.changeMemoryMode(config.lowDetail())); } } @@ -62,6 +69,21 @@ public class LowMemoryPlugin extends Plugin clientThread.invoke(() -> client.changeMemoryMode(false)); } + @Provides + LowMemoryConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(LowMemoryConfig.class); + } + + @Subscribe + public void onConfigChanged(ConfigChanged configChanged) + { + if (configChanged.getGroup().equals(LowMemoryConfig.GROUP)) + { + clientThread.invoke(() -> client.changeMemoryMode(config.lowDetail())); + } + } + @Subscribe public void onGameStateChanged(GameStateChanged event) { @@ -70,7 +92,16 @@ public class LowMemoryPlugin extends Plugin // which breaks the gpu plugin due to it requiring the 128x128px textures if (event.getGameState() == GameState.LOGIN_SCREEN) { - client.changeMemoryMode(true); + client.changeMemoryMode(config.lowDetail()); } } + + @Subscribe + public void onBeforeRender(BeforeRender beforeRender) + { + // This needs to be set to the current plane, but there is no event for plane change, so + // just set it each render. + client.getScene(). + setMinLevel(config.hideLowerPlanes() ? client.getPlane() : 0); + } } 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 index bf7498a25e..a794f6c157 100644 --- 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 @@ -38,6 +38,7 @@ import net.runelite.api.NPCComposition; import net.runelite.api.ObjectComposition; import net.runelite.api.ScriptID; import net.runelite.api.SpriteID; +import net.runelite.api.Varbits; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuOptionClicked; @@ -131,7 +132,7 @@ public class WikiPlugin extends Plugin children[0] = null; Widget vanilla = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER); - if (vanilla != null) + if (vanilla != null && client.getVar(Varbits.WIKI_ENTITY_LOOKUP) == 0) { vanilla.setHidden(false); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/FishingSpotLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/FishingSpotLocation.java index 4b04a4beea..f366f3dc07 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/FishingSpotLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/FishingSpotLocation.java @@ -101,6 +101,8 @@ enum FishingSpotLocation JATISZO(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER}, new WorldPoint(2400, 3780, 0), new WorldPoint(2412, 3780, 0), new WorldPoint(2419, 3789, 0)), + KHARIDIAN_DESERT_SOUTH_WEST(FishingSpot.LOBSTER, + new WorldPoint(3139, 2800, 0)), KINGSTOWN_EAST(FishingSpot.SALMON, new WorldPoint(1723, 3685, 0)), LANDS_END_EAST(FishingSpot.SHRIMP, new WorldPoint(1534, 3414, 0)), LANDS_END_WEST(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER, FishingSpot.SHRIMP}, @@ -162,6 +164,10 @@ enum FishingSpotLocation TAVERLEY_DUNGEON(FishingSpot.LAVA_EEL, new WorldPoint(2893, 9764, 0), new WorldPoint(2889, 9766, 0), new WorldPoint(2883, 9765, 0)), + TEMPOROSS(FishingSpot.HARPOONFISH, + new WorldPoint(3047, 3002, 0), new WorldPoint(3050, 2995, 0), + new WorldPoint(3036, 2996, 0), new WorldPoint(3035, 2962, 0), + new WorldPoint(3047, 2957, 0), new WorldPoint(3045, 2954, 0)), TREE_GNOME_STRONGHOLD(FishingSpot.SALMON, new WorldPoint(2389, 3422, 0), new WorldPoint(2382, 3415, 0)), TUTORIAL_ISLAND(FishingSpot.TUTORIAL_SHRIMP, new WorldPoint(3100, 3091, 0)), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java index ef4db23372..26cad92ce3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java @@ -183,6 +183,8 @@ enum MiningSiteLocation RIMMINGTON(new WorldPoint(2977, 3240, 0), new Rock(2, Ore.CLAY), new Rock(5, Ore.COPPER), new Rock(2, Ore.TIN), new Rock(6, Ore.IRON), new Rock(2, Ore.GOLD)), + RUINS_OF_UNKAH(new WorldPoint(3172, 2871, 0), + new Rock(1, Ore.COPPER), new Rock(1, Ore.TIN), new Rock(5, Ore.IRON), new Rock(2, Ore.SILVER), new Rock(1, Ore.COAL)), SALT_MINE(new WorldPoint(2835, 10334, 0), new Rock(7, Ore.BASALT), new Rock(15, Ore.TE_SALT), new Rock(12, Ore.EFH_SALT), new Rock(12, Ore.URT_SALT)), SHAYZIEN_EAST(new WorldPoint(1597, 3653, 0), new Rock(3, Ore.CLAY), new Rock(1, Ore.MITHRIL), new Rock(1, Ore.ADAMANTITE)), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPointLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPointLocation.java index 330c0738d9..140cabe81a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPointLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPointLocation.java @@ -121,6 +121,10 @@ enum TransportationPointLocation CHARTER_PRIFDDINAS("Charter Ship", new WorldPoint(2156, 3331, 0)), CHARTER_PRIFDDINAS_INSTANCE("Charter Ship", new WorldPoint(3180, 6083, 0)), + //Ferries + FERRY_AL_KHARID("Ferry to Ruins of Unkah", new WorldPoint(3269, 3142, 0), new WorldPoint(3145, 2843, 0)), + FERRY_RUINS_OF_UNKAH("Ferry to Al Kharid", new WorldPoint(3145, 2843, 0), new WorldPoint(3269, 3142, 0)), + //Minecarts/Carts MINE_CART_ARCEUUS("Lovakengj Minecart Network", new WorldPoint(1673, 3832, 0)), MINE_CART_GRANDEXCHANGE("Minecart to Keldagrim", new WorldPoint(3139, 3504, 0)), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java index 5c90e3f6c4..526d3aacbc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java @@ -268,15 +268,13 @@ public class XpGlobesOverlay extends Overlay } final int size = orbSize - config.progressArcStrokeWidth(); - final int width = (int) (size * GLOBE_ICON_RATIO); - final int height = (int) (size * GLOBE_ICON_RATIO); - - if (width <= 0 || height <= 0) + final int scaledIconSize = (int) (size * GLOBE_ICON_RATIO); + if (scaledIconSize <= 0) { return null; } - icon = ImageUtil.resizeImage(icon, width, height); + icon = ImageUtil.resizeImage(icon, scaledIconSize, scaledIconSize, true); xpGlobe.setSkillIcon(icon); xpGlobe.setSize(orbSize); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java index 7f5ba0a4c2..47272f8f17 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java @@ -66,7 +66,8 @@ public class WidgetOverlay extends Overlay new WidgetOverlay(client, WidgetInfo.VOLCANIC_MINE_STABILITY_INFOBOX_GROUP, OverlayPosition.BOTTOM_LEFT), new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_FIXED, OverlayPosition.BOTTOM_RIGHT), new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_RESIZEABLE_MODERN, OverlayPosition.CANVAS_TOP_RIGHT), - new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_RESIZEABLE_CLASSIC, OverlayPosition.CANVAS_TOP_RIGHT) + new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_RESIZEABLE_CLASSIC, OverlayPosition.CANVAS_TOP_RIGHT), + new WidgetOverlay(client, WidgetInfo.TEMPOROSS_STATUS_INDICATOR, OverlayPosition.TOP_LEFT) ); } diff --git a/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java b/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java index 219e0e2e48..6481321bc2 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/util/ImageUtil.java @@ -211,7 +211,38 @@ public class ImageUtil */ public static BufferedImage resizeImage(final BufferedImage image, final int newWidth, final int newHeight) { - final Image resized = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH); + return resizeImage(image, newWidth, newHeight, false); + } + + /** + * Re-size a BufferedImage to the given dimensions. + * + * @param image the BufferedImage. + * @param newWidth The width to set the BufferedImage to. + * @param newHeight The height to set the BufferedImage to. + * @param preserveAspectRatio Whether to preserve the original image's aspect ratio. When {@code true}, the image + * will be scaled to have a maximum of {@code newWidth} width and {@code newHeight} + * height. + * @return The BufferedImage with the specified dimensions + */ + public static BufferedImage resizeImage(final BufferedImage image, final int newWidth, final int newHeight, final boolean preserveAspectRatio) + { + final Image resized; + if (preserveAspectRatio) + { + if (image.getWidth() > image.getHeight()) + { + resized = image.getScaledInstance(newWidth, -1, Image.SCALE_SMOOTH); + } + else + { + resized = image.getScaledInstance(-1, newHeight, Image.SCALE_SMOOTH); + } + } + else + { + resized = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH); + } return ImageUtil.bufferedImageFromImage(resized); } diff --git a/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java b/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java index a2f5f7b9e0..21e7cbafc3 100644 --- a/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java +++ b/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java @@ -102,6 +102,7 @@ public class WSClient extends WebSocketListener implements AutoCloseable Request request = new Request.Builder() .url(RuneLiteAPI.getWsEndpoint()) + .header("User-Agent", RuneLiteAPI.userAgent) .build(); webSocket = okHttpClient.newWebSocket(request, this); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/itemcharges/ItemChargePluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/itemcharges/ItemChargePluginTest.java new file mode 100644 index 0000000000..a881da8f73 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/itemcharges/ItemChargePluginTest.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2018, 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.itemcharges; + +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import java.util.concurrent.ScheduledExecutorService; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; +import net.runelite.api.events.ChatMessage; +import net.runelite.client.Notifier; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.RuneLiteConfig; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class ItemChargePluginTest +{ + private static final String CHECK = "Your dodgy necklace has 10 charges left."; + private static final String PROTECT = "Your dodgy necklace protects you. It has 9 charges left."; + private static final String PROTECT_1 = "Your dodgy necklace protects you. It has 1 charge left."; + private static final String BREAK = "Your dodgy necklace protects you. It then crumbles to dust."; + + private static final String CHECK_RING_OF_FORGING_FULL = "You can smelt 140 more pieces of iron ore before a ring melts."; + private static final String CHECK_RING_OF_FORGING_ONE = "You can smelt one more piece of iron ore before a ring melts."; + private static final String USED_RING_OF_FORGING = "You retrieve a bar of iron."; + private static final String BREAK_RING_OF_FORGING = "Your Ring of Forging has melted."; + + private static final String CHECK_AMULET_OF_CHEMISTRY = "Your amulet of chemistry has 5 charges left."; + private static final String CHECK_AMULET_OF_CHEMISTRY_1 = "Your amulet of chemistry has 1 charge left."; + private static final String USED_AMULET_OF_CHEMISTRY = "Your amulet of chemistry helps you create a 4-dose potion. It has 4 charges left."; + private static final String USED_AMULET_OF_CHEMISTRY_3_DOSES = "Your amulet of chemistry helps you create a 3-dose potion. It has 2 charges left."; + private static final String USED_AMULET_OF_CHEMISTRY_2_DOSES = "Your amulet of chemistry helps you create a 2-dose potion. It has one charge left."; + private static final String BREAK_AMULET_OF_CHEMISTRY = "Your amulet of chemistry helps you create a 4-dose potion. It then crumbles to dust."; + private static final String BREAK_AMULET_OF_CHEMISTRY_3_DOSES = "Your amulet of chemistry helps you create a 3-dose potion. It then crumbles to dust."; + private static final String BREAK_AMULET_OF_CHEMISTRY_2_DOSES = "Your amulet of chemistry helps you create a 2-dose potion. It then crumbles to dust."; + + private static final String CHRONICLE_CHECK_CHARGES_FULL = "Your book has 1000 charges left."; + private static final String CHRONICLE_CHECK_CHARGES_ONE = "You have one charge left in your book."; + private static final String CHRONICLE_CHECK_CHARGES_EMPTY = "Your book has run out of charges."; + private static final String CHRONICLE_TELEPORT = "Your book has 999 charges left."; + private static final String CHRONICLE_TELEPORT_ONE = "You have one charge left in your book."; + private static final String CHRONICLE_TELEPORT_EMPTY = "Your book has run out of charges."; + private static final String CHRONICLE_TELEPORT_FAIL = "Your book does not have any charges. Purchase some Teleport Cards from Diango."; + private static final String CHRONICLE_ADD_SINGLE_CHARGE = "You add a single charge to your book. It now has one charge."; + private static final String CHRONICLE_ADD_SINGLE_CHARGE_FULL = "You add a single charge to your book. It now has 1000 charges."; + private static final String CHRONICLE_ADD_MULTIPLE_CHARGES = "You add 5 charges to your book. It now has 5 charges."; + private static final String CHRONICLE_ADD_FULL = "Your book is fully charged! It has 1,000 charges already."; + + @Mock + @Bind + private Client client; + + @Mock + @Bind + private ScheduledExecutorService scheduledExecutorService; + + @Mock + @Bind + private RuneLiteConfig runeLiteConfig; + + @Mock + @Bind + private OverlayManager overlayManager; + + @Mock + @Bind + private Notifier notifier; + + @Mock + @Bind + private InfoBoxManager infoBoxManager; + + @Mock + @Bind + private ItemChargeConfig config; + + @Mock + @Bind + private ConfigManager configManager; + + @Inject + private ItemChargePlugin itemChargePlugin; + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + } + + @Test + public void testOnChatMessage() + { + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHECK, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_DODGY_NECKLACE, 10); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", PROTECT, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_DODGY_NECKLACE, 9); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", PROTECT_1, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_DODGY_NECKLACE, 1); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", BREAK, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_DODGY_NECKLACE, 10); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHECK_RING_OF_FORGING_ONE, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_RING_OF_FORGING, 1); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHECK_RING_OF_FORGING_FULL, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_RING_OF_FORGING, 140); + reset(configManager); + + when(configManager.getRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_RING_OF_FORGING, Integer.class)).thenReturn(90); + // Create equipment inventory with ring of forging + ItemContainer equipmentItemContainer = mock(ItemContainer.class); + when(client.getItemContainer(InventoryID.EQUIPMENT)).thenReturn(equipmentItemContainer); + when(equipmentItemContainer.contains(ItemID.RING_OF_FORGING)).thenReturn(true); + // Run message + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", USED_RING_OF_FORGING, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_RING_OF_FORGING, 89); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", BREAK_RING_OF_FORGING, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_RING_OF_FORGING, 140); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHECK_AMULET_OF_CHEMISTRY, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, 5); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHECK_AMULET_OF_CHEMISTRY_1, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, 1); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", USED_AMULET_OF_CHEMISTRY, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, 4); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", USED_AMULET_OF_CHEMISTRY_3_DOSES, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, 2); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", USED_AMULET_OF_CHEMISTRY_2_DOSES, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, 1); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", BREAK_AMULET_OF_CHEMISTRY, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, 5); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", BREAK_AMULET_OF_CHEMISTRY_3_DOSES, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, 5); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", BREAK_AMULET_OF_CHEMISTRY_2_DOSES, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, 5); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_CHECK_CHARGES_FULL, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 1000); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_CHECK_CHARGES_ONE, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 1); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_CHECK_CHARGES_EMPTY, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 0); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_TELEPORT, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 999); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_TELEPORT_ONE, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 1); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_TELEPORT_EMPTY, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 0); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_TELEPORT_FAIL, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 0); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_ADD_SINGLE_CHARGE, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 1); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_ADD_SINGLE_CHARGE_FULL, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 1000); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_ADD_MULTIPLE_CHARGES, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 5); + reset(configManager); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHRONICLE_ADD_FULL, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_CHRONICLE, 1000); + reset(configManager); + } +} \ No newline at end of file diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java new file mode 100644 index 0000000000..cff8a46591 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2020, 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.loottracker; + +import com.google.common.collect.ImmutableMap; +import com.google.inject.Guice; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import javax.inject.Inject; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemComposition; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; +import net.runelite.api.IterableHashTable; +import net.runelite.api.MessageNode; +import net.runelite.api.Player; +import net.runelite.api.Skill; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.widgets.WidgetID; +import net.runelite.client.account.SessionManager; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.chat.QueuedMessage; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.ItemStack; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.http.api.item.ItemPrice; +import net.runelite.http.api.loottracker.LootRecordType; +import net.runelite.http.api.loottracker.LootTrackerClient; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; +import org.mockito.Mock; +import org.mockito.Mockito; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class LootTrackerPluginTest +{ + private static final Map HERB_IDS_TO_NAMES = ImmutableMap.builder() + .put(ItemID.GRIMY_GUAM_LEAF, "Grimy guam leaf") + .put(ItemID.GRIMY_MARRENTILL, "Grimy marrentill") + .put(ItemID.GRIMY_TARROMIN, "Grimy tarromin") + .put(ItemID.GRIMY_HARRALANDER, "Grimy harralander") + .put(ItemID.GRIMY_RANARR_WEED, "Grimy ranarr weed") + .put(ItemID.GRIMY_IRIT_LEAF, "Grimy irit leaf") + .put(ItemID.GRIMY_AVANTOE, "Grimy avantoe") + .put(ItemID.GRIMY_KWUARM, "Grimy kwuarm") + .put(ItemID.GRIMY_SNAPDRAGON, "Grimy snapdragon") + .put(ItemID.GRIMY_CADANTINE, "Grimy cadantine") + .put(ItemID.GRIMY_LANTADYME, "Grimy lantadyme") + .put(ItemID.GRIMY_DWARF_WEED, "Grimy dwarf weed") + .put(ItemID.GRIMY_TORSTOL, "Grimy torstol") + .build(); + + @Mock + @Bind + private ScheduledExecutorService scheduledExecutorService; + + @Mock + @Bind + private Client client; + + @Mock + @Bind + private SpriteManager spriteManager; + + @Mock + @Bind + private InfoBoxManager infoBoxManager; + + @Inject + private LootTrackerPlugin lootTrackerPlugin; + + @Mock + @Bind + private LootTrackerConfig lootTrackerConfig; + + @Mock + @Bind + private SessionManager sessionManager; + + @Mock + @Bind + private ItemManager itemManager; + + @Mock + @Bind + private ChatMessageManager chatMessageManager; + + @Mock + @Bind + private LootTrackerClient lootTrackerClient; + + @Before + public void setUp() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + + Player player = mock(Player.class); + when(player.getWorldLocation()).thenReturn(new WorldPoint(0, 0, 0)); + when(client.getLocalPlayer()).thenReturn(player); + } + + @Test + public void testPickPocket() + { + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You pick the hero's pocket.", "", 0); + lootTrackerPlugin.onChatMessage(chatMessage); + + assertEquals("Hero", lootTrackerPlugin.eventType); + assertEquals(LootRecordType.PICKPOCKET, lootTrackerPlugin.lootRecordType); + } + + @Test + public void testFirstClue() + { + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You have completed 1 master Treasure Trail.", "", 0); + lootTrackerPlugin.onChatMessage(chatMessage); + + assertEquals("Clue Scroll (Master)", lootTrackerPlugin.eventType); + assertEquals(LootRecordType.EVENT, lootTrackerPlugin.lootRecordType); + } + + private static ItemComposition mockItem(String name) + { + ItemComposition itemComposition = mock(ItemComposition.class); + when(itemComposition.getName()).thenReturn(name); + return itemComposition; + } + + @Test + public void testHerbiboarHerbSack() + { + when(client.getBoostedSkillLevel(Skill.HERBLORE)).thenReturn(42); + + for (Map.Entry herb : HERB_IDS_TO_NAMES.entrySet()) + { + final int id = herb.getKey(); + final String name = herb.getValue(); + final String herbMessage = String.format("You put the %s herb into your herb sack.", name); + final String herbFullMessage = String.format("Your herb sack is too full to hold the %s herb.", name); + + final ItemPrice herbPrice = new ItemPrice(); + herbPrice.setId(id); + herbPrice.setName(name); + when(itemManager.search(name)).thenReturn(Collections.singletonList(herbPrice)); + + MessageNode node = mock(MessageNode.class); + when(node.getType()).thenReturn(ChatMessageType.SPAM); + when(node.getValue()).thenReturn(herbMessage); + + MessageNode nodeFull = mock(MessageNode.class); + when(nodeFull.getType()).thenReturn(ChatMessageType.SPAM); + when(nodeFull.getValue()).thenReturn(herbFullMessage); + + IterableHashTable messageTable = mock(IterableHashTable.class); + Iterator mockIterator = mock(Iterator.class); + when(mockIterator.hasNext()).thenReturn(true, true, false); + when(mockIterator.next()).thenReturn(node).thenReturn(nodeFull); + when(messageTable.iterator()).thenReturn(mockIterator); + when(client.getMessages()).thenReturn(messageTable); + + LootTrackerPlugin lootTrackerPluginSpy = spy(this.lootTrackerPlugin); + doNothing().when(lootTrackerPluginSpy).addLoot(any(), anyInt(), any(), any(), any(Collection.class)); + + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", LootTrackerPlugin.HERBIBOAR_LOOTED_MESSAGE, "", 0); + lootTrackerPluginSpy.onChatMessage(chatMessage); + + verify(lootTrackerPluginSpy).addLoot("Herbiboar", -1, LootRecordType.EVENT, 42, Arrays.asList( + new ItemStack(id, 1, null), + new ItemStack(id, 1, null) + )); + // Check the event type is null, which means the plugin isn't waiting on an inventory change event + assertNull(lootTrackerPlugin.eventType); + } + } + + @Test + public void testCoXRaidsLootValue() + { + when(lootTrackerConfig.showRaidsLootValue()).thenReturn(true); + when(lootTrackerConfig.priceType()).thenReturn(LootTrackerPriceType.GRAND_EXCHANGE); + + LootTrackerPlugin spyPlugin = Mockito.spy(lootTrackerPlugin); + // Make sure we don't execute addLoot, so we don't have to mock LootTrackerPanel and everything else also + doNothing().when(spyPlugin).addLoot(anyString(), anyInt(), any(LootRecordType.class), isNull(), anyCollection()); + + ItemContainer itemContainer = mock(ItemContainer.class); + when(itemContainer.getItems()).thenReturn(new Item[]{ + new Item(ItemID.TWISTED_BOW, 1), + new Item(ItemID.PURE_ESSENCE, 42) + }); + when(client.getItemContainer(InventoryID.CHAMBERS_OF_XERIC_CHEST)).thenReturn(itemContainer); + + when(itemManager.getItemPrice(ItemID.TWISTED_BOW)).thenReturn(1_100_000_000); + when(itemManager.getItemPrice(ItemID.PURE_ESSENCE)).thenReturn(6); + + WidgetLoaded widgetLoaded = new WidgetLoaded(); + widgetLoaded.setGroupId(WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID); + spyPlugin.onWidgetLoaded(widgetLoaded); + + ArgumentCaptor captor = ArgumentCaptor.forClass(QueuedMessage.class); + verify(chatMessageManager).queue(captor.capture()); + + QueuedMessage queuedMessage = captor.getValue(); + assertEquals("Your loot is worth around 1,100,000,252 coins.", queuedMessage.getRuneLiteFormattedMessage()); + } + + @Test + public void testToBRaidsLootValue() + { + when(lootTrackerConfig.priceType()).thenReturn(LootTrackerPriceType.HIGH_ALCHEMY); + when(lootTrackerConfig.showRaidsLootValue()).thenReturn(true); + + LootTrackerPlugin spyPlugin = Mockito.spy(lootTrackerPlugin); + // Make sure we don't execute addLoot, so we don't have to mock LootTrackerPanel and everything else also + doNothing().when(spyPlugin).addLoot(anyString(), anyInt(), any(LootRecordType.class), isNull(), anyCollection()); + + ItemContainer itemContainer = mock(ItemContainer.class); + when(itemContainer.getItems()).thenReturn(new Item[]{ + new Item(ItemID.SCYTHE_OF_VITUR, 1), + new Item(ItemID.MAHOGANY_SEED, 10) + }); + when(client.getItemContainer(InventoryID.THEATRE_OF_BLOOD_CHEST)).thenReturn(itemContainer); + + ItemComposition compScythe = mock(ItemComposition.class); + when(itemManager.getItemComposition(ItemID.SCYTHE_OF_VITUR)).thenReturn(compScythe); + when(compScythe.getHaPrice()).thenReturn(60_000_000); + + ItemComposition compSeed = mock(ItemComposition.class); + when(itemManager.getItemComposition(ItemID.MAHOGANY_SEED)).thenReturn(compSeed); + when(compSeed.getHaPrice()).thenReturn(2_102); + + when(client.getBaseX()).thenReturn(3232); + when(client.getBaseY()).thenReturn(4320); + LocalPoint localPoint = new LocalPoint(0, 0); + when(client.getLocalPlayer().getLocalLocation()).thenReturn(localPoint); + + WidgetLoaded widgetLoaded = new WidgetLoaded(); + widgetLoaded.setGroupId(WidgetID.THEATRE_OF_BLOOD_GROUP_ID); + spyPlugin.onWidgetLoaded(widgetLoaded); + + ArgumentCaptor captor = ArgumentCaptor.forClass(QueuedMessage.class); + verify(chatMessageManager).queue(captor.capture()); + + QueuedMessage queuedMessage = captor.getValue(); + assertEquals("Your loot is worth around 60,021,020 coins.", queuedMessage.getRuneLiteFormattedMessage()); + } + + @Test + public void testBirdhouses() + { + // No bird nests + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You dismantle and discard the trap, retrieving 10 dead birds, 30 feathers and 1140 Hunter XP.", "", 0); + lootTrackerPlugin.onChatMessage(chatMessage); + + assertEquals("Magic Bird House", lootTrackerPlugin.eventType); + assertEquals(LootRecordType.EVENT, lootTrackerPlugin.lootRecordType); + + // Single bird nest + chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You dismantle and discard the trap, retrieving a nest, 10 dead birds, 50 feathers and 700 Hunter XP.", "", 0); + lootTrackerPlugin.onChatMessage(chatMessage); + + assertEquals("Teak Bird House", lootTrackerPlugin.eventType); + assertEquals(LootRecordType.EVENT, lootTrackerPlugin.lootRecordType); + + // Multiple nests + chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You dismantle and discard the trap, retrieving 2 nests, 10 dead birds, 40 feathers and 280 Hunter XP.", "", 0); + lootTrackerPlugin.onChatMessage(chatMessage); + + assertEquals("Regular Bird House", lootTrackerPlugin.eventType); + assertEquals(LootRecordType.EVENT, lootTrackerPlugin.lootRecordType); + } + + @Test + public void testGrubbyChest() + { + Player player = mock(Player.class); + when(player.getWorldLocation()).thenReturn(new WorldPoint(7323 >> 2, (7323 & 0xff) << 6, 0)); + when(client.getLocalPlayer()).thenReturn(player); + + LootTrackerPlugin lootTrackerPluginSpy = spy(this.lootTrackerPlugin); + doNothing().when(lootTrackerPluginSpy).addLoot(any(), anyInt(), any(), any(), any(Collection.class)); + + ItemContainer itemContainer = mock(ItemContainer.class); + when(itemContainer.getItems()).thenReturn(new Item[]{ + new Item(ItemID.TWISTED_BOW, 1), + new Item(ItemID.GRUBBY_KEY, 1) + }); + when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(itemContainer); + + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You unlock the chest with your key.", "", 0); + lootTrackerPluginSpy.onChatMessage(chatMessage); + + when(itemContainer.getItems()).thenReturn(new Item[]{ + new Item(ItemID.TWISTED_BOW, 1) + }); + lootTrackerPluginSpy.onItemContainerChanged(new ItemContainerChanged(InventoryID.INVENTORY.getId(), itemContainer)); + + chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You have opened the Grubby Chest 2 times.", "", 0); + lootTrackerPluginSpy.onChatMessage(chatMessage); + + when(itemContainer.getItems()).thenReturn(new Item[]{ + new Item(ItemID.TWISTED_BOW, 1), + new Item(ItemID.SHARK, 42) + }); + lootTrackerPluginSpy.onItemContainerChanged(new ItemContainerChanged(InventoryID.INVENTORY.getId(), itemContainer)); + + verify(lootTrackerPluginSpy).addLoot("Grubby Chest", -1, LootRecordType.EVENT, null, Arrays.asList( + new ItemStack(ItemID.SHARK, 42, null) + )); + } + + @Test + public void testTemporossRewardPool() + { + Player player = mock(Player.class); + when(client.getLocalPlayer()).thenReturn(player); + when(client.getLocalPlayer().getWorldLocation()).thenReturn(new WorldPoint(3153, 2833, 0)); + when(client.getBoostedSkillLevel(Skill.FISHING)).thenReturn(69); + + LootTrackerPlugin lootTrackerPluginSpy = spy(this.lootTrackerPlugin); + doNothing().when(lootTrackerPluginSpy).addLoot(any(), anyInt(), any(), any(), any(Collection.class)); + + ItemContainer itemContainer = mock(ItemContainer.class); + when(itemContainer.getItems()).thenReturn(new Item[]{ + new Item(ItemID.BUCKET_OF_WATER, 1), + new Item(ItemID.ROPE, 1) + }); + when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(itemContainer); + + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You found some loot: 30 x Raw tuna", "", 0); + lootTrackerPluginSpy.onChatMessage(chatMessage); + + when(itemContainer.getItems()).thenReturn(new Item[]{ + new Item(ItemID.BUCKET_OF_WATER, 1), + new Item(ItemID.ROPE, 1), + new Item(ItemID.RAW_TUNA, 30) + }); + lootTrackerPluginSpy.onItemContainerChanged(new ItemContainerChanged(InventoryID.INVENTORY.getId(), itemContainer)); + + verify(lootTrackerPluginSpy).addLoot("Reward pool (Tempoross)", -1, LootRecordType.EVENT, 69, Arrays.asList( + new ItemStack(ItemID.RAW_TUNA, 30, null) + )); + + chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You found some loot: Tome of water (empty)", "", 0); + lootTrackerPluginSpy.onChatMessage(chatMessage); + + when(itemContainer.getItems()).thenReturn(new Item[]{ + new Item(ItemID.BUCKET_OF_WATER, 1), + new Item(ItemID.ROPE, 1), + new Item(ItemID.RAW_TUNA, 30), + new Item(ItemID.TOME_OF_WATER_EMPTY, 1) + }); + lootTrackerPluginSpy.onItemContainerChanged(new ItemContainerChanged(InventoryID.INVENTORY.getId(), itemContainer)); + + verify(lootTrackerPluginSpy).addLoot("Reward pool (Tempoross)", -1, LootRecordType.EVENT, 69, Arrays.asList( + new ItemStack(ItemID.TOME_OF_WATER_EMPTY, 1, null) + )); + } +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSScene.java b/runescape-api/src/main/java/net/runelite/rs/api/RSScene.java index 8118b79f51..fbfd4820a0 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSScene.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSScene.java @@ -44,6 +44,9 @@ public interface RSScene extends Scene @Import("minPlane") int getMinLevel(); + @Import("minPlane") + void setMinLevel(int lvl); + @Import("newGroundItemPile") void newGroundItemPile(int plane, int x, int y, int hash, RSRenderable var5, long var6, RSRenderable var7, RSRenderable var8);