From 5a96398b34d73ded195f4738a9a540845e5209af Mon Sep 17 00:00:00 2001 From: Rice Boxer Date: Thu, 27 Jun 2019 21:15:18 -0700 Subject: [PATCH 01/10] Fix Father Jean's coordinates in easy cryptic clue --- .../runelite/client/plugins/cluescrolls/clues/CrypticClue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ca75bf4ca8..125ed56687 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 @@ -80,7 +80,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Speak to the bartender of the Blue Moon Inn in Varrock.", "Bartender", new WorldPoint(3226, 3399, 0), "Talk to the bartender in Blue Moon Inn in Varrock."), new CrypticClue("This aviator is at the peak of his profession.", "Captain Bleemadge", new WorldPoint(2846, 1749, 0), "Captain Bleemadge, the gnome glider pilot, is found at the top of White Wolf Mountain."), new CrypticClue("Search the crates in the shed just north of East Ardougne.", CRATE_355, new WorldPoint(2617, 3347, 0), "The crates in the shed north of the northern Ardougne bank."), - new CrypticClue("I wouldn't wear this jean on my legs.", "Father Jean", new WorldPoint(1697, 3574, 0), "Talk to father Jean in the Hosidius church"), + new CrypticClue("I wouldn't wear this jean on my legs.", "Father Jean", new WorldPoint(1734, 3576, 0), "Talk to father Jean in the Hosidius church"), new CrypticClue("Search the crate in the Toad and Chicken pub.", CRATE_354, new WorldPoint(2913, 3536, 0), "The Toad and Chicken pub is located in Burthorpe."), new CrypticClue("Search chests found in the upstairs of shops in Port Sarim.", CLOSED_CHEST_375, new WorldPoint(3016, 3205, 1), "Search the chest in the upstairs of Wydin's Food Store, on the east wall."), new CrypticClue("Right on the blessed border, cursed by the evil ones. On the spot inaccessible by both; I will be waiting. The bugs' imminent possession holds the answer.", new WorldPoint(3410, 3324, 0), "B I P. Dig right under the fairy ring."), From bb4da0b822ea82a04b428755af2072f80ab250fd Mon Sep 17 00:00:00 2001 From: psikoi Date: Sat, 29 Jun 2019 11:47:00 +0100 Subject: [PATCH 02/10] Add ENTER/ESC key events for screenmarker saving --- .../screenmarkers/ui/ScreenMarkerPanel.java | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java index d225410209..b0270ba49d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java @@ -29,6 +29,8 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; @@ -169,12 +171,7 @@ class ScreenMarkerPanel extends JPanel @Override public void mousePressed(MouseEvent mouseEvent) { - marker.getMarker().setName(nameInput.getText()); - plugin.updateConfig(); - - nameInput.setEditable(false); - updateNameActions(false); - requestFocusInWindow(); + save(); } @Override @@ -198,10 +195,7 @@ class ScreenMarkerPanel extends JPanel @Override public void mousePressed(MouseEvent mouseEvent) { - nameInput.setEditable(false); - nameInput.setText(marker.getMarker().getName()); - updateNameActions(false); - requestFocusInWindow(); + cancel(); } @Override @@ -252,6 +246,21 @@ class ScreenMarkerPanel extends JPanel nameInput.setPreferredSize(new Dimension(0, 24)); nameInput.getTextField().setForeground(Color.WHITE); nameInput.getTextField().setBorder(new EmptyBorder(0, 8, 0, 0)); + nameInput.addKeyListener(new KeyAdapter() + { + @Override + public void keyPressed(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_ENTER) + { + save(); + } + else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) + { + cancel(); + } + } + }); nameWrapper.add(nameInput, BorderLayout.CENTER); nameWrapper.add(nameActions, BorderLayout.EAST); @@ -424,6 +433,24 @@ class ScreenMarkerPanel extends JPanel } + private void save() + { + marker.getMarker().setName(nameInput.getText()); + plugin.updateConfig(); + + nameInput.setEditable(false); + updateNameActions(false); + requestFocusInWindow(); + } + + private void cancel() + { + nameInput.setEditable(false); + nameInput.setText(marker.getMarker().getName()); + updateNameActions(false); + requestFocusInWindow(); + } + private void updateNameActions(boolean saveAndCancel) { save.setVisible(saveAndCancel); From 83d2a7e58b6db30879eafa9c2e3c57aca05abeaa Mon Sep 17 00:00:00 2001 From: William Collishaw Date: Sun, 30 Jun 2019 10:17:03 -0600 Subject: [PATCH 03/10] Clean up some instances of double white space --- .../java/net/runelite/cache/item/SpritePixels.java | 2 +- .../test/java/net/runelite/cache/AreaDumper.java | 2 +- .../net/runelite/client/game/AgilityShortcut.java | 4 ++-- .../plugins/cluescrolls/clues/CrypticClue.java | 10 +++++----- .../plugins/interfacestyles/WidgetOverride.java | 6 +++--- .../menuentryswapper/MenuEntrySwapperConfig.java | 2 +- .../menuentryswapper/MenuEntrySwapperPlugin.java | 2 +- .../plugins/nightmarezone/AbsorptionCounter.java | 2 +- .../net/runelite/client/plugins/poh/PohPlugin.java | 2 +- .../puzzlesolver/solver/pathfinding/IDAStarMM.java | 4 ++-- .../client/plugins/statusbars/Viewport.java | 4 ++-- .../plugins/worldhopper/WorldHopperPlugin.java | 2 +- .../plugins/worldmap/TeleportLocationData.java | 14 +++++++------- .../ui/overlay/components/PanelComponent.java | 2 +- .../net/runelite/mixins/WorldHoppingMixin.java | 2 +- 15 files changed, 30 insertions(+), 30 deletions(-) diff --git a/cache/src/main/java/net/runelite/cache/item/SpritePixels.java b/cache/src/main/java/net/runelite/cache/item/SpritePixels.java index 02079847f7..8bfada5bc2 100644 --- a/cache/src/main/java/net/runelite/cache/item/SpritePixels.java +++ b/cache/src/main/java/net/runelite/cache/item/SpritePixels.java @@ -108,7 +108,7 @@ class SpritePixels } - public void drawAtOn(Rasterizer2D graphics, int x, int y) + public void drawAtOn(Rasterizer2D graphics, int x, int y) { x += this.offsetX; y += this.offsetY; diff --git a/cache/src/test/java/net/runelite/cache/AreaDumper.java b/cache/src/test/java/net/runelite/cache/AreaDumper.java index 2aab1db48b..0b276fcce1 100644 --- a/cache/src/test/java/net/runelite/cache/AreaDumper.java +++ b/cache/src/test/java/net/runelite/cache/AreaDumper.java @@ -64,7 +64,7 @@ public class AreaDumper for (AreaDefinition area : areaManager.getAreas()) { - Files.asCharSink(new File(outDir, area.id + ".json"), Charset.defaultCharset()).write(gson.toJson(area)); + Files.asCharSink(new File(outDir, area.id + ".json"), Charset.defaultCharset()).write(gson.toJson(area)); ++count; } } 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 index dcee1e6acd..8e10ac081c 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java +++ b/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java @@ -84,7 +84,7 @@ public enum AgilityShortcut 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 + 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, CASTLE_WALL), YANILLE_WATCHTOWER_TRELLIS(18, "Trellis", null, TRELLIS_20056), COAL_TRUCKS_LOG_BALANCE(20, "Log Balance", new WorldPoint(2598, 3475, 0), LOG_BALANCE_23274), @@ -128,7 +128,7 @@ public enum AgilityShortcut 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), + 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), 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 ca75bf4ca8..403801b343 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 @@ -196,9 +196,9 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Search a bookcase in Lumbridge swamp.", BOOKCASE_9523, new WorldPoint(3146, 3177, 0), "Located in Father Urhney's house."), new CrypticClue("Surround my bones in fire, ontop the wooden pyre. Finally lay me to rest, before my one last test.", null, "Kill a confused/lost barbarian to receive mangled bones. Construct and burn a pyre ship. Kill the ferocious barbarian spirit that spawns to receive a clue casket."), new CrypticClue("Fiendish cooks probably won't dig the dirty dishes.", new WorldPoint(3043, 4974, 1), "Dig by the fire in the Rogues' Den."), - new CrypticClue("My life was spared but these voices remain, now guarding these iron gates is my bane.", "Key Master", new WorldPoint(1310, 1251, 0), "Speak to the Key Master in Cerberus' Lair."), + new CrypticClue("My life was spared but these voices remain, now guarding these iron gates is my bane.", "Key Master", new WorldPoint(1310, 1251, 0), "Speak to the Key Master in Cerberus' Lair."), new CrypticClue("Search the boxes in one of the tents in Al Kharid.", BOXES_361, new WorldPoint(3308, 3206, 0), "Search the boxes in the tent east of the Silk trader."), - new CrypticClue("One of several rhyming brothers, in business attire with an obsession for paper work.", "Piles", new WorldPoint(3186, 3936, 0), "Speak to Piles in the Wilderness Resource Area. An entry fee of 7,500 coins is required, or less if Wilderness Diaries have been completed."), + new CrypticClue("One of several rhyming brothers, in business attire with an obsession for paper work.", "Piles", new WorldPoint(3186, 3936, 0), "Speak to Piles in the Wilderness Resource Area. An entry fee of 7,500 coins is required, or less if Wilderness Diaries have been completed."), new CrypticClue("Search the drawers on the first floor of a building overlooking Ardougne's Market.", DRAWERS_352, new WorldPoint(2657, 3322, 1), "Climb the ladder in the house north of the market."), new CrypticClue("'A bag belt only?', he asked his balding brothers.", "Abbot Langley", new WorldPoint(3058, 3487, 0), "Talk-to Abbot Langley in Monastery west of Edgeville"), new CrypticClue("Search the drawers upstairs in Falador's shield shop.", DRAWERS, new WorldPoint(2971, 3386, 1), "Cassie's Shield Shop at the northern Falador entrance."), @@ -276,7 +276,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Ghommal wishes to be impressed by how strong your equipment is.", "Ghommal", new WorldPoint(2878, 3546, 0), "Speak to Ghommal at the Warriors' Guild with a total Melee Strength bonus of over 100."), new CrypticClue("Shhhh!", "Logosia", new WorldPoint(1633, 3808, 0), "Speak to Logosia in the Arceuus Library's ground floor."), new CrypticClue("Salty peter.", "Konoo", new WorldPoint(1703, 3524, 0), "Talk to Konoo who is digging saltpetre in Hosidius, south of the bank."), - new CrypticClue("Talk to Zeke in Al Kharid.", "Zeke", new WorldPoint(3287, 3190, 0), "Zeke is the owner of the scimitar shop in Al Kharid."), + new CrypticClue("Talk to Zeke in Al Kharid.", "Zeke", new WorldPoint(3287, 3190, 0), "Zeke is the owner of the scimitar shop in Al Kharid."), new CrypticClue("Guthix left his mark in a fiery lake, dig at the tip of it.", new WorldPoint(3069, 3935, 0), "Dig at the tip of the lava lake that is shaped like a Guthixian symbol, west of the Mage Arena."), new CrypticClue("Search the drawers in the upstairs of a house in Catherby.", DRAWERS_350, new WorldPoint(2809, 3451, 1), "Perdu's house in Catherby."), new CrypticClue("Search a crate in the Haymaker's arms.", CRATE_27532, new WorldPoint(1720, 3652, 1), "Search the crate in the north-east corner of The Haymaker's Arms tavern east of Kourend Castle."), @@ -294,9 +294,9 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Dig in the centre of a great kingdom of 5 cities.", new WorldPoint(1639, 3673, 0), "Dig in front of the large statue in the centre of Great Kourend."), new CrypticClue("Hopefully this set of armour will help you to keep surviving.", "Sir Vyvin", new WorldPoint(2982, 3336, 2), "Speak to Sir Vyvin while wearing a white platebody, and platelegs."), new CrypticClue("The beasts retreat, for their Queen is gone; the song of this town still plays on. Dig near the birthplace of a blade, be careful not to melt your spade.", new WorldPoint(2342, 3677, 0), "Dig in front of the small furnace in the Piscatoris Fishing Colony."), - new CrypticClue("Darkness wanders around me, but fills my mind with knowledge.", "Biblia", new WorldPoint(1633, 3825, 2), "Speak to Biblia on the Arceuus Library's top floor."), + new CrypticClue("Darkness wanders around me, but fills my mind with knowledge.", "Biblia", new WorldPoint(1633, 3825, 2), "Speak to Biblia on the Arceuus Library's top floor."), new CrypticClue("I would make a chemistry joke, but I'm afraid I wouldn't get a reaction.", "Chemist", new WorldPoint(2932, 3212, 0), "Talk to the Chemist in Rimmington"), - new CrypticClue("Show this to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Hazelmere is found upstairs on the island located just east of Yanille."), + new CrypticClue("Show this to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Hazelmere is found upstairs on the island located just east of Yanille."), 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 the Hosidius kitchens.", CRATE_27533, new WorldPoint(1683, 3616, 0), "The kitchens are north-west of the town in Hosidius."), new CrypticClue("Dig under Ithoi's cabin.", new WorldPoint(2529, 2838, 0), "Dig under Ithoi's cabin in the Corsair Cove."), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOverride.java b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOverride.java index 46997704a5..1998fb3808 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOverride.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOverride.java @@ -35,12 +35,12 @@ enum WidgetOverride FIXED_CORNER_TOP_LEFT_2005(Skin.AROUND_2005, "1026", WidgetInfo.FIXED_VIEWPORT_COMBAT_TAB), FIXED_CORNER_TOP_RIGHT_2005(Skin.AROUND_2005, "1027", WidgetInfo.FIXED_VIEWPORT_MAGIC_TAB), FIXED_CORNER_BOTTOM_LEFT_2005(Skin.AROUND_2005, "1028", WidgetInfo.FIXED_VIEWPORT_CLAN_CHAT_TAB), - FIXED_CORNER_BOTTOM_RIGHT_2005(Skin.AROUND_2005, "1029", WidgetInfo.FIXED_VIEWPORT_MUSIC_TAB), + FIXED_CORNER_BOTTOM_RIGHT_2005(Skin.AROUND_2005, "1029", WidgetInfo.FIXED_VIEWPORT_MUSIC_TAB), FIXED_TOP_LEFT_2005(Skin.AROUND_2005, "1030_top_left", WidgetInfo.FIXED_VIEWPORT_STATS_TAB, WidgetInfo.FIXED_VIEWPORT_QUESTS_TAB), - FIXED_TOP_RIGHT_2005(Skin.AROUND_2005, "1030_top_right", WidgetInfo.FIXED_VIEWPORT_EQUIPMENT_TAB, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB), + FIXED_TOP_RIGHT_2005(Skin.AROUND_2005, "1030_top_right", WidgetInfo.FIXED_VIEWPORT_EQUIPMENT_TAB, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB), FIXED_TOP_MIDDLE_2005(Skin.AROUND_2005, "1030_top_middle", WidgetInfo.FIXED_VIEWPORT_INVENTORY_TAB), FIXED_BOTTOM_LEFT_2005(Skin.AROUND_2005, "1030_bottom_left", WidgetInfo.FIXED_VIEWPORT_FRIENDS_TAB, WidgetInfo.FIXED_VIEWPORT_IGNORES_TAB), - FIXED_BOTTOM_RIGHT_2005(Skin.AROUND_2005, "1030_bottom_middle", WidgetInfo.FIXED_VIEWPORT_LOGOUT_TAB), + FIXED_BOTTOM_RIGHT_2005(Skin.AROUND_2005, "1030_bottom_middle", WidgetInfo.FIXED_VIEWPORT_LOGOUT_TAB), FIXED_BOTTOM_MIDDLE_2005(Skin.AROUND_2005, "1030_bottom_right", WidgetInfo.FIXED_VIEWPORT_OPTIONS_TAB, WidgetInfo.FIXED_VIEWPORT_EMOTES_TAB); private Skin skin; 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 58fc922c7b..8d9ee74b8a 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 @@ -165,7 +165,7 @@ public interface MenuEntrySwapperConfig extends Config @ConfigItem( keyName = "swapHardWoodGrove", name = "Hardwood Grove", - description = "Swap Quick-Pay(100) and Send-Parcel at Hardwood Grove" + description = "Swap Quick-Pay(100) and Send-Parcel at Hardwood Grove" ) default boolean swapHardWoodGrove() { 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 5ab6cb6aca..a443fe0800 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 @@ -362,7 +362,7 @@ public class MenuEntrySwapperPlugin extends Plugin final int eventId = event.getIdentifier(); final String option = Text.removeTags(event.getOption()).toLowerCase(); final String target = Text.removeTags(event.getTarget()).toLowerCase(); - final NPC hintArrowNpc = client.getHintArrowNpc(); + final NPC hintArrowNpc = client.getHintArrowNpc(); if (hintArrowNpc != null && hintArrowNpc.getIndex() == eventId 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 4671edde12..fffd16fe4a 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 @@ -39,7 +39,7 @@ public class AbsorptionCounter extends Counter AbsorptionCounter(BufferedImage image, Plugin plugin, int absorption, int threshold) { - super(image, plugin, absorption); + super(image, plugin, absorption); this.threshold = threshold; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohPlugin.java index 04df91d05c..be70c9689d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohPlugin.java @@ -80,7 +80,7 @@ public class PohPlugin extends Plugin private final Map pohObjects = new HashMap<>(); @Getter(AccessLevel.PACKAGE) - private final Map incenseBurners = new HashMap<>(); + private final Map incenseBurners = new HashMap<>(); @Inject private OverlayManager overlayManager; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStarMM.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStarMM.java index f96b6971bd..a869ee13c4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStarMM.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStarMM.java @@ -90,7 +90,7 @@ public class IDAStarMM extends IDAStar if (valCurrent != valTarget) { - moveTowardsVal(valTarget, i, row, true); + moveTowardsVal(valTarget, i, row, true); } } } @@ -107,7 +107,7 @@ public class IDAStarMM extends IDAStar if (valCurrent != valTarget) { - moveTowardsVal(valTarget, column, i, false); + moveTowardsVal(valTarget, column, i, false); } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/Viewport.java b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/Viewport.java index 737cda9df0..6161192c1d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/Viewport.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/Viewport.java @@ -34,9 +34,9 @@ import net.runelite.api.widgets.WidgetInfo; enum Viewport { RESIZED_BOX(WidgetInfo.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX, WidgetInfo.RESIZABLE_VIEWPORT_INTERFACE_CONTAINER, - new Point(20, -4), new Point( 0, -4)), + new Point(20, -4), new Point(0, -4)), RESIZED_BOTTOM(WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_INTERFACE_CONTAINER, - new Point(61, 8), new Point(35, -12)), + new Point(61, 8), new Point(35, -12)), FIXED(WidgetInfo.FIXED_VIEWPORT, WidgetInfo.FIXED_VIEWPORT_INTERFACE_CONTAINER, new Point(20, -4), new Point(0, -4)); 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 84abfcf9f5..0dce1c78b5 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 @@ -97,7 +97,7 @@ public class WorldHopperPlugin extends Plugin { private static final int WORLD_FETCH_TIMER = 10; private static final int WORLD_PING_TIMER = 10; - private static final int REFRESH_THROTTLE = 60_000; // ms + private static final int REFRESH_THROTTLE = 60_000; // ms private static final int TICK_THROTTLE = (int) Duration.ofMinutes(10).toMillis(); private static final int DISPLAY_SWITCHER_MAX_ATTEMPTS = 3; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java index ab2035ae74..520f48ec3d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java @@ -127,7 +127,7 @@ enum TeleportLocationData RELLEKKKA_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Rellekka", new WorldPoint(2664, 3643, 0), "enchanted_lyre_teleport_icon.png"), WATERBIRTH_ISLAND_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Waterbirth Island", new WorldPoint(2550, 3756, 0), "enchanted_lyre_teleport_icon.png"), NEITIZNOT_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Neitiznot", new WorldPoint(2336, 3801, 0), "enchanted_lyre_teleport_icon.png"), - JATIZSO_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Jatizso", new WorldPoint(2409, 3809, 0), "enchanted_lyre_teleport_icon.png"), + JATIZSO_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Jatizso", new WorldPoint(2409, 3809, 0), "enchanted_lyre_teleport_icon.png"), WEISS_ICY_BASALT(TeleportType.OTHER, "Icy Basalt", "Weiss", new WorldPoint(2846, 3940, 0), "icy_basalt_teleport_icon.png"), TROLL_STRONGHOLD_STONY_BASALT(TeleportType.OTHER, "Stony Basalt", "Troll Stronghold", new WorldPoint(2838, 3693, 0), "stony_basalt_teleport_icon.png"), KHAREDSTS_MEMOIRS_HOSIDIUS(TeleportType.OTHER, "Kharedst's Memoirs", "Lunch by the Lancalliums (Hosidius)", new WorldPoint(1713, 3612, 0), "kharedsts_memoirs_teleport_icon.png"), @@ -151,19 +151,19 @@ enum TeleportLocationData // Achievement Diary ARDOUGNE_CLOAK_MONASTERY(TeleportType.OTHER, "Ardougne Cloak", "Monastery", new WorldPoint(2606, 3222, 0), "ardougne_cloak_icon.png"), ARDOUGNE_CLOAK_FARM(TeleportType.OTHER, "Ardougne Cloak", "Farm", new WorldPoint(2673, 3375, 0), "ardougne_cloak_icon.png"), - EXPLORERS_RING(TeleportType.OTHER, "Explorer's Ring", new WorldPoint(3052, 3292, 0), "explorers_ring_icon.png"), + EXPLORERS_RING(TeleportType.OTHER, "Explorer's Ring", new WorldPoint(3052, 3292, 0), "explorers_ring_icon.png"), KARAMJA_GLOVES_GEM_MINE(TeleportType.OTHER, "Karamja Gloves", "Gem Mine (Underground)", new WorldPoint(2827, 2997, 0), "karamja_gloves_icon.png"), KARAMJA_GLOVES_DURADEL(TeleportType.OTHER, "Karamja Gloves", "Duradel", new WorldPoint(2870, 2981, 0), "karamja_gloves_icon.png"), DESERT_AMULET_NARDAH(TeleportType.OTHER, "Desert Amulet", "Nardah", new WorldPoint(3432, 2914, 0), "desert_amulet_icon.png"), DESERT_AMULKT_KALPHITE_CAVE(TeleportType.OTHER, "Desert Amulet", "Kalphite Cave", new WorldPoint(3322, 3122, 0), "desert_amulet_icon.png"), MORYTANIA_LEGS_SLIME_PIT(TeleportType.OTHER, "Morytania Legs", "Slime Pit (Underground)", new WorldPoint(3654, 3516, 0), "morytania_legs_icon.png"), MORYTANIA_LEGS_BURGH_DE_ROTT(TeleportType.OTHER, "Morytania Legs", "Burgh de Rott", new WorldPoint(3482, 3231, 0), "morytania_legs_icon.png"), - FREMENNIK_SEA_BOOTS(TeleportType.OTHER, "Fremennik Sea Boots", new WorldPoint(2640, 3675, 0), "fremennik_boots_icon.png"), - KANDARIN_HEADGEAR(TeleportType.OTHER, "Kandarin Headgear", new WorldPoint(2729, 3411, 0), "kandarin_headgear_icon.png"), + FREMENNIK_SEA_BOOTS(TeleportType.OTHER, "Fremennik Sea Boots", new WorldPoint(2640, 3675, 0), "fremennik_boots_icon.png"), + KANDARIN_HEADGEAR(TeleportType.OTHER, "Kandarin Headgear", new WorldPoint(2729, 3411, 0), "kandarin_headgear_icon.png"), WILDERNESS_SWORD(TeleportType.OTHER, "Wilderness Sword", new WorldPoint(3377, 3891, 0), "wilderness_sword_icon.png"), - WESTERN_BANNER(TeleportType.OTHER, "Western Banner", new WorldPoint(2329, 3685, 0), "western_banner_icon.png"), - RADAS_BLESSING_MOUNT_KARUULM(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1311, 3795, 0), "radas_blessing_icon.png"), - RADAS_BLESSING_WOODLANG(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1553, 3454, 0), "radas_blessing_icon.png"), + WESTERN_BANNER(TeleportType.OTHER, "Western Banner", new WorldPoint(2329, 3685, 0), "western_banner_icon.png"), + RADAS_BLESSING_MOUNT_KARUULM(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1311, 3795, 0), "radas_blessing_icon.png"), + RADAS_BLESSING_WOODLANG(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1553, 3454, 0), "radas_blessing_icon.png"), // Scrolls DIGSITE_SCROLL(TeleportType.SCROLL, "Digsite Teleport", new WorldPoint(3324, 3412, 0), "scroll_teleport_icon.png"), diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java index 6baf20985e..0d81a5bf18 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java @@ -136,7 +136,7 @@ public class PanelComponent implements LayoutableRenderableEntity totalWidth = Math.max(totalWidth, width); totalHeight = Math.max(totalHeight, height); - if (wrapping > 0 && i < children.size() - 1 && (i + 1) % wrapping == 0) + if (wrapping > 0 && i < children.size() - 1 && (i + 1) % wrapping == 0) { switch (orientation) { diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/WorldHoppingMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/WorldHoppingMixin.java index 2cbc773b23..78778e3993 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/WorldHoppingMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/WorldHoppingMixin.java @@ -47,6 +47,6 @@ public abstract class WorldHoppingMixin implements RSClient public void hopToWorld(World world) { final int worldId = world.getId(); - menuAction(worldId, WidgetInfo.WORLD_SWITCHER_LIST.getId(), MenuAction.WIDGET_DEFAULT.getId(), 1, "Switch", "" + (worldId - 300) + "", 683, 244); + menuAction(worldId, WidgetInfo.WORLD_SWITCHER_LIST.getId(), MenuAction.WIDGET_DEFAULT.getId(), 1, "Switch", "" + (worldId - 300) + "", 683, 244); } } From ba3edc1ecbf2a9dcbce5ea220a4f8d5211413518 Mon Sep 17 00:00:00 2001 From: psikoi Date: Sat, 29 Jun 2019 12:31:17 +0100 Subject: [PATCH 04/10] Add hover preview to screen markers --- .../screenmarkers/ui/ScreenMarkerPanel.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java index b0270ba49d..23b6cad174 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java @@ -261,6 +261,20 @@ class ScreenMarkerPanel extends JPanel } } }); + nameInput.getTextField().addMouseListener(new MouseAdapter() + { + @Override + public void mouseEntered(MouseEvent mouseEvent) + { + preview(true); + } + + @Override + public void mouseExited(MouseEvent mouseEvent) + { + preview(false); + } + }); nameWrapper.add(nameInput, BorderLayout.CENTER); nameWrapper.add(nameActions, BorderLayout.EAST); @@ -368,10 +382,7 @@ class ScreenMarkerPanel extends JPanel @Override public void mousePressed(MouseEvent mouseEvent) { - visible = !visible; - marker.getMarker().setVisible(visible); - plugin.updateConfig(); - updateVisibility(); + toggle(!visible); } @Override @@ -433,6 +444,24 @@ class ScreenMarkerPanel extends JPanel } + private void preview(boolean on) + { + if (visible) + { + return; + } + + marker.getMarker().setVisible(on); + } + + private void toggle(boolean on) + { + visible = on; + marker.getMarker().setVisible(visible); + plugin.updateConfig(); + updateVisibility(); + } + private void save() { marker.getMarker().setName(nameInput.getText()); From 5a6b39036d6163333fd142fd3640a9d54be68445 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Wed, 12 Jun 2019 22:41:13 -0700 Subject: [PATCH 05/10] HotColdClue: Refactor to use enums for temperatures --- .../cluescrolls/clues/HotColdClue.java | 127 +++++------------- .../clues/hotcold/HotColdTemperature.java | 84 ++++++++++++ .../hotcold/HotColdTemperatureChange.java | 55 ++++++++ .../hotcold/HotColdTemperatureChangeTest.java | 68 ++++++++++ .../clues/hotcold/HotColdTemperatureTest.java | 75 +++++++++++ 5 files changed, 319 insertions(+), 90 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChange.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChangeTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java index 826017744f..87f2b6c5e1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, Eadgars Ruse + * Copyright (c) 2019, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,8 +37,8 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import lombok.Getter; import net.runelite.api.NPC; import net.runelite.api.coords.LocalPoint; @@ -47,6 +48,8 @@ import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdArea; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation; +import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdTemperature; +import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdTemperatureChange; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; @@ -55,9 +58,6 @@ import net.runelite.client.ui.overlay.components.TitleComponent; @Getter public class HotColdClue extends ClueScroll implements LocationClueScroll, LocationsClueScroll, TextClueScroll, NpcClueScroll { - private static final Pattern INITIAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*)"); - private static final Pattern STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*), (.*) last time\\."); - private static final Pattern FINAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is visibly shaking.*"); private static final HotColdClue CLUE = new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Jorral may have a clue.", "Jorral", @@ -231,52 +231,31 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat public boolean update(final String message, final ClueScrollPlugin plugin) { - if (!message.startsWith("The device is")) + final HotColdTemperature temperature = HotColdTemperature.of(message); + + if (temperature == null) { return false; } - Matcher m1 = FINAL_STRANGE_DEVICE_MESSAGE.matcher(message); - Matcher m2 = STRANGE_DEVICE_MESSAGE.matcher(message); - Matcher m3 = INITIAL_STRANGE_DEVICE_MESSAGE.matcher(message); + final WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - // the order that these pattern matchers are checked is important - if (m1.find()) + if (localWorld == null) { - // final location for hot cold clue has been found - WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - - if (localWorld != null) - { - markFinalSpot(localWorld); - return true; - } - } - else if (m2.find()) - { - String temperature = m2.group(1); - String difference = m2.group(2); - WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - - if (localWorld != null) - { - updatePossibleArea(localWorld, temperature, difference); - return true; - } - } - else if (m3.find()) - { - String temperature = m3.group(1); - WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - - if (localWorld != null) - { - updatePossibleArea(localWorld, temperature, ""); - return true; - } + return false; } - return false; + if (temperature == HotColdTemperature.VISIBLY_SHAKING) + { + markFinalSpot(localWorld); + } + else + { + final HotColdTemperatureChange temperatureChange = HotColdTemperatureChange.of(message); + updatePossibleArea(localWorld, temperature, temperatureChange); + } + + return true; } @Override @@ -286,7 +265,7 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat digLocations.clear(); } - private void updatePossibleArea(WorldPoint currentWp, String temperature, String difference) + private void updatePossibleArea(@Nonnull final WorldPoint worldPoint, @Nonnull final HotColdTemperature temperature, @Nullable final HotColdTemperatureChange temperatureChange) { this.location = null; @@ -295,73 +274,41 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat digLocations.addAll(Arrays.asList(HotColdLocation.values())); } - int maxSquaresAway = 5000; - int minSquaresAway = 0; - - switch (temperature) - { - // when the strange device reads a temperature, that means that the center of the final dig location - // is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance) - case "ice cold": - maxSquaresAway = 5000; - minSquaresAway = 500; - break; - case "very cold": - maxSquaresAway = 499; - minSquaresAway = 200; - break; - case "cold": - maxSquaresAway = 199; - minSquaresAway = 150; - break; - case "warm": - maxSquaresAway = 149; - minSquaresAway = 100; - break; - case "hot": - maxSquaresAway = 99; - minSquaresAway = 70; - break; - case "very hot": - maxSquaresAway = 69; - minSquaresAway = 30; - break; - case "incredibly hot": - maxSquaresAway = 29; - minSquaresAway = 5; - break; - } + // when the strange device reads a temperature, that means that the center of the final dig location + // is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance) + int maxSquaresAway = temperature.getMaxDistance(); + int minSquaresAway = temperature.getMinDistance(); // rectangle r1 encompasses all of the points that are within the max possible distance from the player - Point p1 = new Point(currentWp.getX() - maxSquaresAway, currentWp.getY() - maxSquaresAway); + Point p1 = new Point(worldPoint.getX() - maxSquaresAway, worldPoint.getY() - maxSquaresAway); Rectangle r1 = new Rectangle((int) p1.getX(), (int) p1.getY(), 2 * maxSquaresAway + 1, 2 * maxSquaresAway + 1); // rectangle r2 encompasses all of the points that are within the min possible distance from the player - Point p2 = new Point(currentWp.getX() - minSquaresAway, currentWp.getY() - minSquaresAway); + Point p2 = new Point(worldPoint.getX() - minSquaresAway, worldPoint.getY() - minSquaresAway); Rectangle r2 = new Rectangle((int) p2.getX(), (int) p2.getY(), 2 * minSquaresAway + 1, 2 * minSquaresAway + 1); // eliminate from consideration dig spots that lie entirely within the min range or entirely outside of the max range digLocations.removeIf(entry -> r2.contains(entry.getRect()) || !r1.intersects(entry.getRect())); // if a previous world point has been recorded, we can consider the warmer/colder result from the strange device - if (lastWorldPoint != null) + if (lastWorldPoint != null && temperatureChange != null) { - switch (difference) + switch (temperatureChange) { - case "but colder than": + case COLDER: // eliminate spots that are absolutely warmer - digLocations.removeIf(entry -> isFirstPointCloserRect(currentWp, lastWorldPoint, entry.getRect())); + digLocations.removeIf(entry -> isFirstPointCloserRect(worldPoint, lastWorldPoint, entry.getRect())); break; - case "and warmer than": + case WARMER: // eliminate spots that are absolutely colder - digLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, currentWp, entry.getRect())); + digLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, worldPoint, entry.getRect())); break; - case "and the same temperature as": + case SAME: // I couldn't figure out a clean implementation for this case // not necessary for quickly determining final location } } - lastWorldPoint = currentWp; + lastWorldPoint = worldPoint; } private boolean isFirstPointCloserRect(WorldPoint firstWp, WorldPoint secondWp, Rectangle2D r) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java new file mode 100644 index 0000000000..850d33aec1 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java @@ -0,0 +1,84 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum HotColdTemperature +{ + ICE_COLD("ice cold", 500, 5000), + VERY_COLD("very cold", 200, 499), + COLD("cold", 150, 199), + WARM("warm", 100, 149), + HOT("hot", 70, 99), + VERY_HOT("very hot", 30, 69), + INCREDIBLY_HOT("incredibly hot", 5, 29), + VISIBLY_SHAKING("visibly shaking", 0, 4); + + private final String text; + private final int minDistance; + private final int maxDistance; + + private static final String DEVICE_USED_START_TEXT = "The device is "; + + /** + * Gets the temperature corresponding to the passed string. + * + * @param message A string containing a temperature value + * @return The corresponding enum for the passed string. + *

+ * Note that in cases where two temperature enums are equally likely to be the given temperature (say, two + * temperatures with identical text values), the behavior is undefined. + */ + public static HotColdTemperature of(final String message) + { + if (!message.startsWith(DEVICE_USED_START_TEXT)) + { + return null; + } + + final List possibleTemperatures = new ArrayList<>(); + + for (final HotColdTemperature temperature : values()) + { + if (message.contains(temperature.getText())) + { + possibleTemperatures.add(temperature); + } + } + + return possibleTemperatures.stream() + // For messages such as "The device is very cold", this will choose the Enum with text of greatest length so + // that VERY_COLD would be selected over COLD, though both Enums have matching text for this message. + .max(Comparator.comparingInt(x -> (x.getText()).length())) + .orElse(null); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChange.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChange.java new file mode 100644 index 0000000000..e9077bc9e1 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChange.java @@ -0,0 +1,55 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum HotColdTemperatureChange +{ + WARMER("and warmer than"), + SAME("and the same temperature as"), + COLDER("but colder than"); + + private final String text; + + public static HotColdTemperatureChange of(final String message) + { + if (!message.endsWith(" last time.")) + { + return null; + } + + for (final HotColdTemperatureChange change : values()) + { + if (message.contains(change.text)) + { + return change; + } + } + + return null; + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChangeTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChangeTest.java new file mode 100644 index 0000000000..9b7cdcaf3c --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChangeTest.java @@ -0,0 +1,68 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class HotColdTemperatureChangeTest +{ + private static final String[] VALID_MESSAGES = { + "The device is warm, and warmer than last time.", + "The device is cold, but colder than last time.", + "The device is very hot, and the same temperature as last time.", + }; + private static final String[] INVALID_MESSAGES = { + "The device is cold.", + "The device is ice cold.", + "The device is very cold.", + "The device is hot.", + "The device is incredibly hot.", + "The device is an octopus, and is wetter than last time", + "foobar", + "a q p w", + "My feet are cold, I should put them in some lukewarm water, or run hot water over them.", + "and warmer than and colder than and the same temperature", + }; + + @Test + public void testValidTemperatureChangeMessages() + { + for (final String message : VALID_MESSAGES) + { + assertNotNull(message, HotColdTemperatureChange.of(message)); + } + } + + @Test + public void testInvalidTemperatureChangeMessages() + { + for (final String message : INVALID_MESSAGES) + { + assertNull(message, HotColdTemperatureChange.of(message)); + } + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java new file mode 100644 index 0000000000..505df56346 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java @@ -0,0 +1,75 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class HotColdTemperatureTest +{ + private static final String[] VALID_MESSAGES = { + "The device is warm, and warmer than last time.", + "The device is visibly shaking and burns to the touch. This must be the spot.", + "The device is cold.", + "The device is ice cold.", + "The device is very cold.", + "The device is hot.", + "The device is incredibly hot.", + }; + private static final String[] INVALID_MESSAGES = { + "The device is an octopus, and is wetter than last time.", + "foobar", + "a q p w", + "My feet are cold, I should put them in some lukewarm water, or run hot water over them.", + }; + + @Test + public void testValidTemperatureMessages() + { + for (final String message : VALID_MESSAGES) + { + assertNotNull(message, HotColdTemperature.of(message)); + } + } + + @Test + public void testInvalidTemperatureMessages() + { + for (final String message : INVALID_MESSAGES) + { + assertNull(message, HotColdTemperature.of(message)); + } + } + + @Test + public void testAmbiguousTemperatureMessages() + { + assertEquals(HotColdTemperature.ICE_COLD, HotColdTemperature.of("The device is ice cold.")); + assertEquals(HotColdTemperature.VERY_COLD, HotColdTemperature.of("The device is very cold.")); + assertEquals(HotColdTemperature.VERY_HOT, HotColdTemperature.of("The device is very hot.")); + } +} From e5d4e7a8976505a9e2e0f23a1d66c76807bf33ca Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Wed, 12 Jun 2019 23:02:25 -0700 Subject: [PATCH 06/10] HotColdClue: Add hot-cold solver class This adds a general hot-cold puzzle solver class and implements it in HotColdClue. --- .../cluescrolls/clues/HotColdClue.java | 140 +++------- .../clues/hotcold/HotColdLocation.java | 3 +- .../clues/hotcold/HotColdSolver.java | 167 ++++++++++++ .../clues/hotcold/HotColdSolverTest.java | 258 ++++++++++++++++++ 4 files changed, 457 insertions(+), 111 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolver.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java index 87f2b6c5e1..1c970c33c8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java @@ -25,20 +25,15 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.Lists; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; -import java.util.List; +import java.util.Collection; +import java.util.EnumMap; import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import java.util.Set; +import java.util.stream.Collectors; import lombok.Getter; import net.runelite.api.NPC; import net.runelite.api.coords.LocalPoint; @@ -48,6 +43,7 @@ import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdArea; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation; +import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdSolver; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdTemperature; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdTemperatureChange; import net.runelite.client.ui.overlay.OverlayUtil; @@ -58,18 +54,17 @@ import net.runelite.client.ui.overlay.components.TitleComponent; @Getter public class HotColdClue extends ClueScroll implements LocationClueScroll, LocationsClueScroll, TextClueScroll, NpcClueScroll { + private static final int HOT_COLD_PANEL_WIDTH = 200; private static final HotColdClue CLUE = new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Jorral may have a clue.", "Jorral", "Speak to Jorral to receive a strange device."); - // list of potential places to dig - private List digLocations = new ArrayList<>(); private final String text; private final String npc; private final String solution; + private HotColdSolver hotColdSolver; private WorldPoint location; - private WorldPoint lastWorldPoint; public static HotColdClue forText(String text) { @@ -87,12 +82,13 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat this.npc = npc; this.solution = solution; setRequiresSpade(true); + initializeSolver(); } @Override public WorldPoint[] getLocations() { - return Lists.transform(digLocations, HotColdLocation::getWorldPoint).toArray(new WorldPoint[0]); + return hotColdSolver.getPossibleLocations().stream().map(HotColdLocation::getWorldPoint).toArray(WorldPoint[]::new); } @Override @@ -101,10 +97,10 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat panelComponent.getChildren().add(TitleComponent.builder() .text("Hot/Cold Clue") .build()); - panelComponent.setPreferredSize(new Dimension(200, 0)); + panelComponent.setPreferredSize(new Dimension(HOT_COLD_PANEL_WIDTH, 0)); // strange device has not been tested yet, show how to get it - if (lastWorldPoint == null && location == null) + if (hotColdSolver.getLastWorldPoint() == null && location == null) { if (getNpc() != null) { @@ -131,7 +127,9 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat panelComponent.getChildren().add(LineComponent.builder() .left("Possible areas:") .build()); - Map locationCounts = new HashMap<>(); + + final Map locationCounts = new EnumMap<>(HotColdArea.class); + final Collection digLocations = hotColdSolver.getPossibleLocations(); for (HotColdLocation hotColdLocation : digLocations) { @@ -159,17 +157,16 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat } else { - for (HotColdArea s : locationCounts.keySet()) + for (HotColdArea area : locationCounts.keySet()) { panelComponent.getChildren().add(LineComponent.builder() - .left(s.getName() + ":") + .left(area.getName() + ':') .build()); for (HotColdLocation hotColdLocation : digLocations) { - if (hotColdLocation.getHotColdArea() == s) + if (hotColdLocation.getHotColdArea() == area) { - Rectangle2D r = hotColdLocation.getRect(); panelComponent.getChildren().add(LineComponent.builder() .left("- " + hotColdLocation.getArea()) .leftColor(Color.LIGHT_GRAY) @@ -185,7 +182,7 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) { // when final location has been found - if (this.location != null) + if (location != null) { LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); @@ -198,19 +195,16 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat } // when strange device hasn't been activated yet, show Jorral - if (lastWorldPoint == null) + if (hotColdSolver.getLastWorldPoint() == null && plugin.getNpcsToMark() != null) { - // Mark NPC - if (plugin.getNpcsToMark() != null) + for (NPC npcToMark : plugin.getNpcsToMark()) { - for (NPC npc : plugin.getNpcsToMark()) - { - OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); - } + OverlayUtil.renderActorOverlayImage(graphics, npcToMark, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); } } // once the number of possible dig locations is below 10, show the dig spots + final Collection digLocations = hotColdSolver.getPossibleLocations(); if (digLocations.size() < 10) { // Mark potential dig locations @@ -251,8 +245,10 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat } else { + location = null; + final HotColdTemperatureChange temperatureChange = HotColdTemperatureChange.of(message); - updatePossibleArea(localWorld, temperature, temperatureChange); + hotColdSolver.signal(localWorld, temperature, temperatureChange); } return true; @@ -261,88 +257,14 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat @Override public void reset() { - this.lastWorldPoint = null; - digLocations.clear(); + initializeSolver(); } - private void updatePossibleArea(@Nonnull final WorldPoint worldPoint, @Nonnull final HotColdTemperature temperature, @Nullable final HotColdTemperatureChange temperatureChange) + private void initializeSolver() { - this.location = null; - - if (digLocations.isEmpty()) - { - digLocations.addAll(Arrays.asList(HotColdLocation.values())); - } - - // when the strange device reads a temperature, that means that the center of the final dig location - // is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance) - int maxSquaresAway = temperature.getMaxDistance(); - int minSquaresAway = temperature.getMinDistance(); - - // rectangle r1 encompasses all of the points that are within the max possible distance from the player - Point p1 = new Point(worldPoint.getX() - maxSquaresAway, worldPoint.getY() - maxSquaresAway); - Rectangle r1 = new Rectangle((int) p1.getX(), (int) p1.getY(), 2 * maxSquaresAway + 1, 2 * maxSquaresAway + 1); - // rectangle r2 encompasses all of the points that are within the min possible distance from the player - Point p2 = new Point(worldPoint.getX() - minSquaresAway, worldPoint.getY() - minSquaresAway); - Rectangle r2 = new Rectangle((int) p2.getX(), (int) p2.getY(), 2 * minSquaresAway + 1, 2 * minSquaresAway + 1); - - // eliminate from consideration dig spots that lie entirely within the min range or entirely outside of the max range - digLocations.removeIf(entry -> r2.contains(entry.getRect()) || !r1.intersects(entry.getRect())); - - // if a previous world point has been recorded, we can consider the warmer/colder result from the strange device - if (lastWorldPoint != null && temperatureChange != null) - { - switch (temperatureChange) - { - case COLDER: - // eliminate spots that are absolutely warmer - digLocations.removeIf(entry -> isFirstPointCloserRect(worldPoint, lastWorldPoint, entry.getRect())); - break; - case WARMER: - // eliminate spots that are absolutely colder - digLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, worldPoint, entry.getRect())); - break; - case SAME: - // I couldn't figure out a clean implementation for this case - // not necessary for quickly determining final location - } - } - - lastWorldPoint = worldPoint; - } - - private boolean isFirstPointCloserRect(WorldPoint firstWp, WorldPoint secondWp, Rectangle2D r) - { - WorldPoint p1 = new WorldPoint((int) r.getMaxX(), (int) r.getMaxY(), 0); - - if (!isFirstPointCloser(firstWp, secondWp, p1)) - { - return false; - } - - WorldPoint p2 = new WorldPoint((int) r.getMaxX(), (int) r.getMinY(), 0); - - if (!isFirstPointCloser(firstWp, secondWp, p2)) - { - return false; - } - - WorldPoint p3 = new WorldPoint((int) r.getMinX(), (int)r.getMaxY(), 0); - - if (!isFirstPointCloser(firstWp, secondWp, p3)) - { - return false; - } - - WorldPoint p4 = new WorldPoint((int) r.getMinX(), (int) r.getMinY(), 0); - return (isFirstPointCloser(firstWp, secondWp, p4)); - } - - private boolean isFirstPointCloser(WorldPoint firstWp, WorldPoint secondWp, WorldPoint wp) - { - int firstDistance = firstWp.distanceTo2D(wp); - int secondDistance = secondWp.distanceTo2D(wp); - return (firstDistance < secondDistance); + final Set locations = Arrays.stream(HotColdLocation.values()) + .collect(Collectors.toSet()); + hotColdSolver = new HotColdSolver(locations); } private void markFinalSpot(WorldPoint wp) @@ -355,4 +277,4 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat { return new String[] {npc}; } -} \ No newline at end of file +} 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 e41fd5357e..4259d3d29d 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 @@ -26,7 +26,6 @@ package net.runelite.client.plugins.cluescrolls.clues.hotcold; import java.awt.Rectangle; -import java.awt.geom.Rectangle2D; import lombok.AllArgsConstructor; import lombok.Getter; import net.runelite.api.coords.WorldPoint; @@ -180,7 +179,7 @@ public enum HotColdLocation private final HotColdArea hotColdArea; private final String area; - public Rectangle2D getRect() + public Rectangle getRect() { return new Rectangle(worldPoint.getX() - 4, worldPoint.getY() - 4, 9, 9); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolver.java new file mode 100644 index 0000000000..87414f0387 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolver.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2018, Eadgars Ruse + * 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.cluescrolls.clues.hotcold; + +import com.google.common.annotations.VisibleForTesting; +import java.awt.Rectangle; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import lombok.Getter; +import net.runelite.api.coords.WorldPoint; + +/** + * Solution finder for hot-cold style puzzles. + *

+ * These puzzles are established by having some way to test the distance from the solution via "warmth", where being + * colder means one is farther away from the target, and being warmer means one is closer to it, with the goal being to + * reach the most warm value to discover the solution point. Hot-cold puzzles in Old School Runescape are implemented + * with specific set of solution points, so this solver will filter from a provided set of possible solutions as new + * signals of temperatures and temperature changes are provided. + */ +@Getter +public class HotColdSolver +{ + private final Set possibleLocations; + @Nullable + private WorldPoint lastWorldPoint; + + public HotColdSolver(Set possibleLocations) + { + this.possibleLocations = possibleLocations; + } + + /** + * Process a hot-cold update given a {@link WorldPoint} where a check occurred and the resulting temperature and + * temperature change discovered at that point. This will filter the set of possible locations which can be the + * solution. + * + * @param worldPoint The point where a hot-cold check occurred + * @param temperature The temperature of the checked point + * @param temperatureChange The change of temperature of the checked point compared to the previously-checked point + * @return A set of {@link HotColdLocation}s which are still possible after the filtering occurs. This return value + * is the same as would be returned by {@code getPossibleLocations()}. + */ + public Set signal(@Nonnull final WorldPoint worldPoint, @Nonnull final HotColdTemperature temperature, @Nullable final HotColdTemperatureChange temperatureChange) + { + // when the strange device reads a temperature, that means that the center of the final dig location + // is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance) + int maxSquaresAway = temperature.getMaxDistance(); + int minSquaresAway = temperature.getMinDistance(); + + // maxDistanceArea encompasses all of the points that are within the max possible distance from the player + final Rectangle maxDistanceArea = new Rectangle( + worldPoint.getX() - maxSquaresAway, + worldPoint.getY() - maxSquaresAway, + 2 * maxSquaresAway + 1, + 2 * maxSquaresAway + 1); + // minDistanceArea encompasses all of the points that are within the min possible distance from the player + final Rectangle minDistanceArea = new Rectangle( + worldPoint.getX() - minSquaresAway, + worldPoint.getY() - minSquaresAway, + 2 * minSquaresAway + 1, + 2 * minSquaresAway + 1); + + // eliminate from consideration dig spots that lie entirely within the min range or entirely outside of the max range + possibleLocations.removeIf(entry -> minDistanceArea.contains(entry.getRect()) || !maxDistanceArea.intersects(entry.getRect())); + + // if a previous world point has been recorded, we can consider the warmer/colder result from the strange device + if (lastWorldPoint != null && temperatureChange != null) + { + switch (temperatureChange) + { + case COLDER: + // eliminate spots that are absolutely warmer + possibleLocations.removeIf(entry -> isFirstPointCloserRect(worldPoint, lastWorldPoint, entry.getRect())); + break; + case WARMER: + // eliminate spots that are absolutely colder + possibleLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, worldPoint, entry.getRect())); + break; + case SAME: + // I couldn't figure out a clean implementation for this case + // not necessary for quickly determining final location + } + } + + lastWorldPoint = worldPoint; + return getPossibleLocations(); + } + + /** + * Determines whether the first point passed is closer to each corner of the given rectangle than the second point. + * + * @param firstPoint First point to test. Return result will be relating to this point's location. + * @param secondPoint Second point to test + * @param rect Rectangle, whose corner points will be compared to the first and second points passed + * @return {@code true} if {@code firstPoint} is closer to each of {@code rect}'s four corner points than + * {@code secondPoint}, {@code false} otherwise. + * @see WorldPoint#distanceTo2D + */ + @VisibleForTesting + static boolean isFirstPointCloserRect(final WorldPoint firstPoint, final WorldPoint secondPoint, final Rectangle rect) + { + final WorldPoint nePoint = new WorldPoint((rect.x + rect.width), (rect.y + rect.height), 0); + + if (!isFirstPointCloser(firstPoint, secondPoint, nePoint)) + { + return false; + } + + final WorldPoint sePoint = new WorldPoint((rect.x + rect.width), rect.y, 0); + + if (!isFirstPointCloser(firstPoint, secondPoint, sePoint)) + { + return false; + } + + final WorldPoint nwPoint = new WorldPoint(rect.x, (rect.y + rect.height), 0); + + if (!isFirstPointCloser(firstPoint, secondPoint, nwPoint)) + { + return false; + } + + final WorldPoint swPoint = new WorldPoint(rect.x, rect.y, 0); + return (isFirstPointCloser(firstPoint, secondPoint, swPoint)); + } + + /** + * Determines whether the first point passed is closer to the given point of comparison than the second point. + * + * @param firstPoint First point to test. Return result will be relating to this point's location. + * @param secondPoint Second point to test + * @param worldPoint Point to compare to the first and second points passed + * @return {@code true} if {@code firstPoint} is closer to {@code worldPoint} than {@code secondPoint}, + * {@code false} otherwise. + * @see WorldPoint#distanceTo2D + */ + @VisibleForTesting + static boolean isFirstPointCloser(final WorldPoint firstPoint, final WorldPoint secondPoint, final WorldPoint worldPoint) + { + return firstPoint.distanceTo2D(worldPoint) < secondPoint.distanceTo2D(worldPoint); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java new file mode 100644 index 0000000000..413884d944 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java @@ -0,0 +1,258 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import com.google.common.collect.Sets; +import java.awt.Rectangle; +import java.util.Set; +import java.util.stream.Collectors; +import static junit.framework.TestCase.assertTrue; +import net.runelite.api.coords.WorldPoint; +import static net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdSolver.isFirstPointCloser; +import static net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdSolver.isFirstPointCloserRect; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import org.junit.Test; + +public class HotColdSolverTest +{ + private static final String RESPONSE_TEXT_ICE_COLD_COLDER = "The device is ice cold, but colder than last time."; + private static final String RESPONSE_TEXT_VERY_COLD_WARMER = "The device is very cold, and warmer than last time."; + private static final String RESPONSE_TEXT_COLD = "The device is cold."; + private static final String RESPONSE_TEXT_COLD_COLDER = "The device is cold, but colder than last time."; + private static final String RESPONSE_TEXT_COLD_WARMER = "The device is cold, and warmer than last time."; + private static final String RESPONSE_TEXT_COLD_SAME_TEMP = "The device is cold, and the same temperature as last time."; + private static final String RESPONSE_TEXT_VERY_HOT = "The device is very hot."; + private static final String RESPONSE_TEXT_VERY_HOT_COLDER = "The device is very hot, but colder than last time."; + private static final String RESPONSE_TEXT_VERY_HOT_WARMER = "The device is very hot, and warmer than last time."; + private static final String RESPONSE_TEXT_VERY_HOT_SAME_TEMP = "The device is very hot, and the same temperature as last time."; + + @Test + public void testOneStepSolution() + { + final Set foundLocation = Sets.immutableEnumSet(HotColdLocation.KARAMJA_KHARAZI_NE); + + testSolver(createHotColdSolver(), new WorldPoint(2852, 2992, 0), RESPONSE_TEXT_VERY_HOT, foundLocation); + } + + @Test + public void testIgnoreStartingTemperatureDifference() + { + final WorldPoint testedPoint = new WorldPoint(2852, 2992, 0); + final Set foundLocations = Sets.immutableEnumSet(HotColdLocation.KARAMJA_KHARAZI_NE); + + testSolver(createHotColdSolver(), testedPoint, RESPONSE_TEXT_VERY_HOT, foundLocations); + testSolver(createHotColdSolver(), testedPoint, RESPONSE_TEXT_VERY_HOT_COLDER, foundLocations); + testSolver(createHotColdSolver(), testedPoint, RESPONSE_TEXT_VERY_HOT_WARMER, foundLocations); + testSolver(createHotColdSolver(), testedPoint, RESPONSE_TEXT_VERY_HOT_SAME_TEMP, foundLocations); + } + + @Test + public void testSameTempNoChanges() + { + final HotColdSolver solver = createHotColdSolver(); + final WorldPoint testedPoint = new WorldPoint(2851, 2955, 0); + final Set foundLocations = Sets.immutableEnumSet( + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_KHARAZI_SW); + + testSolver(solver, testedPoint, RESPONSE_TEXT_VERY_HOT, foundLocations); + testSolver(solver, testedPoint, RESPONSE_TEXT_VERY_HOT_SAME_TEMP, foundLocations); + } + + @Test + public void testNoChangesAfterSolutionFound() + { + final HotColdSolver solver = createHotColdSolver(); + final Set intermediateFoundLocations = Sets.immutableEnumSet( + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_KHARAZI_SW); + final Set finalLocation = Sets.immutableEnumSet(HotColdLocation.KARAMJA_KHARAZI_NE); + + testSolver(solver, new WorldPoint(2851, 2955, 0), RESPONSE_TEXT_VERY_HOT, intermediateFoundLocations); + testSolver(solver, new WorldPoint(2852, 2955, 0), RESPONSE_TEXT_VERY_HOT_WARMER, finalLocation); + testSolver(solver, new WorldPoint(2851, 2955, 0), RESPONSE_TEXT_VERY_HOT_COLDER, finalLocation); + testSolver(solver, new WorldPoint(2465, 3495, 0), RESPONSE_TEXT_ICE_COLD_COLDER, finalLocation); + testSolver(solver, new WorldPoint(3056, 3291, 0), RESPONSE_TEXT_VERY_COLD_WARMER, finalLocation); + testSolver(solver, new WorldPoint(2571, 2956, 0), RESPONSE_TEXT_VERY_COLD_WARMER, finalLocation); + } + + @Test + public void testNarrowToFindSolutions() + { + final HotColdSolver solver = createHotColdSolver(); + final Set firstLocationsSet = Sets.immutableEnumSet( + HotColdLocation.FELDIP_HILLS_GNOME_GLITER, + HotColdLocation.FELDIP_HILLS_RED_CHIN, + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_CRASH_ISLAND); + final Set secondLocationsSet = firstLocationsSet.stream() + .filter(location -> location != HotColdLocation.FELDIP_HILLS_RED_CHIN) + .collect(Collectors.toSet()); + final Set thirdLocationSet = secondLocationsSet.stream() + .filter(location -> location != HotColdLocation.FELDIP_HILLS_GNOME_GLITER) + .collect(Collectors.toSet()); + final Set finalLocation = thirdLocationSet.stream() + .filter(location -> location != HotColdLocation.KARAMJA_CRASH_ISLAND) + .collect(Collectors.toSet()); + + testSolver(solver, new WorldPoint(2711, 2803, 0), RESPONSE_TEXT_COLD, firstLocationsSet); + testSolver(solver, new WorldPoint(2711, 2802, 0), RESPONSE_TEXT_COLD_SAME_TEMP, firstLocationsSet); + testSolver(solver, new WorldPoint(2716, 2802, 0), RESPONSE_TEXT_COLD_WARMER, secondLocationsSet); + testSolver(solver, new WorldPoint(2739, 2808, 0), RESPONSE_TEXT_COLD_WARMER, thirdLocationSet); + testSolver(solver, new WorldPoint(2810, 2757, 0), RESPONSE_TEXT_COLD_COLDER, finalLocation); + } + + @Test + public void testSomewhatDistantLocations() + { + // Activate device on Ape Atoll when solution point is HotColdLocation.KARAMJA_KHARAZI_NE + testSolver(createHotColdSolver(), new WorldPoint(2723, 2743, 0), RESPONSE_TEXT_COLD, + Sets.immutableEnumSet( + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_KHARAZI_SW, + HotColdLocation.KARAMJA_CRASH_ISLAND, + HotColdLocation.FELDIP_HILLS_SW, + HotColdLocation.FELDIP_HILLS_RANTZ, + HotColdLocation.FELDIP_HILLS_RED_CHIN, + HotColdLocation.FELDIP_HILLS_SE)); + + // Activate device near fairy ring DKP when solution point is HotColdLocation.KARAMJA_KHARAZI_NE + testSolver(createHotColdSolver(), new WorldPoint(2900, 3111, 0), RESPONSE_TEXT_COLD, + Sets.immutableEnumSet( + HotColdLocation.KARAMJA_WEST_BRIMHAVEN, + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.ASGARNIA_COW, + HotColdLocation.ASGARNIA_CRAFT_GUILD, + HotColdLocation.KANDARIN_WITCHHAVEN, + HotColdLocation.MISTHALIN_DRAYNOR_BANK)); + + // Activate device on Mudskipper Point when solution point is HotColdLocation.KARAMJA_KHARAZI_NE + testSolver(createHotColdSolver(), new WorldPoint(2985, 3106, 0), RESPONSE_TEXT_COLD, + Sets.immutableEnumSet( + HotColdLocation.KARAMJA_BRIMHAVEN_FRUIT_TREE, + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.ASGARNIA_COW, + HotColdLocation.ASGARNIA_CRAFT_GUILD, + HotColdLocation.MISTHALIN_LUMBRIDGE_2, + HotColdLocation.DESERT_BEDABIN_CAMP)); + } + + @Test + public void testIsFirstPointCloserRect() + { + assertFalse(isFirstPointCloserRect(new WorldPoint(0, 0, 0), new WorldPoint(0, 0, 0), new Rectangle(0, 0, 1, 1))); + assertFalse(isFirstPointCloserRect(new WorldPoint(1, 0, 0), new WorldPoint(5, 0, 0), new Rectangle(2, 1, 5, 5))); + assertFalse(isFirstPointCloserRect(new WorldPoint(1, 0, 0), new WorldPoint(0, 0, 0), new Rectangle(2, 0, 1, 2))); + assertFalse(isFirstPointCloserRect(new WorldPoint(0, 0, 0), new WorldPoint(1, 1, 1), new Rectangle(2, 2, 2, 2))); + assertFalse(isFirstPointCloserRect(new WorldPoint(0, 0, 0), new WorldPoint(4, 4, 4), new Rectangle(1, 1, 2, 2))); + assertFalse(isFirstPointCloserRect(new WorldPoint(3, 2, 0), new WorldPoint(1, 5, 0), new Rectangle(0, 0, 4, 4))); + + assertTrue(isFirstPointCloserRect(new WorldPoint(1, 1, 0), new WorldPoint(0, 1, 0), new Rectangle(2, 0, 3, 2))); + assertTrue(isFirstPointCloserRect(new WorldPoint(4, 4, 0), new WorldPoint(1, 1, 0), new Rectangle(3, 3, 2, 2))); + assertTrue(isFirstPointCloserRect(new WorldPoint(3, 2, 0), new WorldPoint(7, 0, 0), new Rectangle(1, 3, 4, 2))); + + } + + @Test + public void testIsFirstPointCloser() + { + assertFalse(isFirstPointCloser(new WorldPoint(0, 0, 0), new WorldPoint(0, 0, 0), new WorldPoint(0, 0, 0))); + assertFalse(isFirstPointCloser(new WorldPoint(0, 0, 0), new WorldPoint(0, 0, 1), new WorldPoint(0, 0, 0))); + assertFalse(isFirstPointCloser(new WorldPoint(1, 0, 0), new WorldPoint(0, 0, 0), new WorldPoint(1, 1, 0))); + assertFalse(isFirstPointCloser(new WorldPoint(2, 2, 0), new WorldPoint(0, 0, 0), new WorldPoint(1, 1, 0))); + + assertTrue(isFirstPointCloser(new WorldPoint(1, 0, 0), new WorldPoint(0, 0, 0), new WorldPoint(2, 0, 0))); + assertTrue(isFirstPointCloser(new WorldPoint(1, 1, 0), new WorldPoint(1, 0, 0), new WorldPoint(2, 2, 0))); + assertTrue(isFirstPointCloser(new WorldPoint(1, 1, 1), new WorldPoint(0, 1, 0), new WorldPoint(1, 1, 0))); + } + + /** + * Tests a hot-cold solver by signalling a test point, temperature, and temperature change to it and asserting the + * resulting possible location set is equal to that of a given set of expected locations. + * + * @param solver The hot-cold solver to signal to. + *
+ * Note: This will mutate the passed solver, which is helpful for testing + * multiple sequential steps. + * @param testPoint The {@link WorldPoint} where the signal occurs. + * @param deviceResponse The string containing the temperature and temperature change which is + * given when the hot-cold checking device is activated. + * @param expectedRemainingPossibleLocations A {@link Set} of {@link HotColdLocation}s which is expected to be + * given by {@link HotColdSolver#getPossibleLocations()} after it receives + * the signal formed by the other given arguments. + */ + private static void testSolver(final HotColdSolver solver, final WorldPoint testPoint, final String deviceResponse, final Set expectedRemainingPossibleLocations) + { + final HotColdTemperature temperature = HotColdTemperature.of(deviceResponse); + final HotColdTemperatureChange temperatureChange = HotColdTemperatureChange.of(deviceResponse); + + assertNotNull(temperature); + assertEquals(expectedRemainingPossibleLocations, solver.signal(testPoint, temperature, temperatureChange)); + } + + /** + * @return A hot-cold solver with a starting set of master hot-cold locations nearby the KARAMJA_KHARAZI_NE + * location. {@link HotColdLocation#values()} is not used as it may change with future game updates, and + * such changes would break this test suite. + */ + private static HotColdSolver createHotColdSolver() + { + final Set hotColdLocations = Sets.immutableEnumSet( + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_KHARAZI_SW, + HotColdLocation.KARAMJA_GLIDER, + HotColdLocation.KARAMJA_MUSA_POINT, + HotColdLocation.KARAMJA_BRIMHAVEN_FRUIT_TREE, + HotColdLocation.KARAMJA_WEST_BRIMHAVEN, + HotColdLocation.KARAMJA_CRASH_ISLAND, + HotColdLocation.DESERT_BEDABIN_CAMP, + HotColdLocation.DESERT_MENAPHOS_GATE, + HotColdLocation.DESERT_POLLNIVNEACH, + HotColdLocation.DESERT_SHANTY, + HotColdLocation.MISTHALIN_LUMBRIDGE, + HotColdLocation.MISTHALIN_LUMBRIDGE_2, + HotColdLocation.MISTHALIN_DRAYNOR_BANK, + HotColdLocation.ASGARNIA_COW, + HotColdLocation.ASGARNIA_PARTY_ROOM, + HotColdLocation.ASGARNIA_CRAFT_GUILD, + HotColdLocation.ASGARNIA_RIMMINGTON, + HotColdLocation.ASGARNIA_MUDSKIPPER, + HotColdLocation.KANDARIN_WITCHHAVEN, + HotColdLocation.KANDARIN_NECRO_TOWER, + HotColdLocation.KANDARIN_FIGHT_ARENA, + HotColdLocation.KANDARIN_TREE_GNOME_VILLAGE, + HotColdLocation.FELDIP_HILLS_GNOME_GLITER, + HotColdLocation.FELDIP_HILLS_JIGGIG, + HotColdLocation.FELDIP_HILLS_RANTZ, + HotColdLocation.FELDIP_HILLS_RED_CHIN, + HotColdLocation.FELDIP_HILLS_SE, + HotColdLocation.FELDIP_HILLS_SOUTH, + HotColdLocation.FELDIP_HILLS_SW + ); + return new HotColdSolver(hotColdLocations); + } +} From 76d4031445ae6cc8fa31b0face9bee66fd06c340 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Wed, 12 Jun 2019 23:28:52 -0700 Subject: [PATCH 07/10] cluescrolls: Add beginner hot-cold clues --- .../cluescrolls/clues/HotColdClue.java | 87 +++++++++++++++++-- .../clues/hotcold/HotColdLocation.java | 16 +++- .../clues/hotcold/HotColdTemperature.java | 48 +++++++--- .../hotcold/BeginnerHotColdLocationTest.java | 50 +++++++++++ .../clues/hotcold/HotColdSolverTest.java | 5 +- .../clues/hotcold/HotColdTemperatureTest.java | 12 +-- .../hotcold/MasterHotColdLocationTest.java | 49 +++++++++++ 7 files changed, 240 insertions(+), 27 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/BeginnerHotColdLocationTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/MasterHotColdLocationTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java index 1c970c33c8..5fad4e4207 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java @@ -34,7 +34,10 @@ import java.util.EnumMap; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import javax.annotation.Nullable; +import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.NPC; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; @@ -51,26 +54,37 @@ import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; +@EqualsAndHashCode(callSuper = false, exclude = { "hotColdSolver", "location" }) @Getter +@Slf4j public class HotColdClue extends ClueScroll implements LocationClueScroll, LocationsClueScroll, TextClueScroll, NpcClueScroll { private static final int HOT_COLD_PANEL_WIDTH = 200; - private static final HotColdClue CLUE = - new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Jorral may have a clue.", - "Jorral", - "Speak to Jorral to receive a strange device."); + private static final HotColdClue BEGINNER_CLUE = new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Reldo may have a clue.", + "Reldo", + "Speak to Reldo to receive a strange device."); + private static final HotColdClue MASTER_CLUE = new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Jorral may have a clue.", + "Jorral", + "Speak to Jorral to receive a strange device."); private final String text; private final String npc; private final String solution; + @Nullable private HotColdSolver hotColdSolver; private WorldPoint location; public static HotColdClue forText(String text) { - if (CLUE.text.equalsIgnoreCase(text)) + if (BEGINNER_CLUE.text.equalsIgnoreCase(text)) { - return CLUE; + BEGINNER_CLUE.reset(); + return BEGINNER_CLUE; + } + else if (MASTER_CLUE.text.equalsIgnoreCase(text)) + { + MASTER_CLUE.reset(); + return MASTER_CLUE; } return null; @@ -88,12 +102,22 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat @Override public WorldPoint[] getLocations() { + if (hotColdSolver == null) + { + return new WorldPoint[0]; + } + return hotColdSolver.getPossibleLocations().stream().map(HotColdLocation::getWorldPoint).toArray(WorldPoint[]::new); } @Override public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) { + if (hotColdSolver == null) + { + return; + } + panelComponent.getChildren().add(TitleComponent.builder() .text("Hot/Cold Clue") .build()); @@ -181,6 +205,11 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat @Override public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) { + if (hotColdSolver == null) + { + return; + } + // when final location has been found if (location != null) { @@ -194,7 +223,7 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat return; } - // when strange device hasn't been activated yet, show Jorral + // when strange device hasn't been activated yet, show npc who gives you the strange device if (hotColdSolver.getLastWorldPoint() == null && plugin.getNpcsToMark() != null) { for (NPC npcToMark : plugin.getNpcsToMark()) @@ -225,7 +254,27 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat public boolean update(final String message, final ClueScrollPlugin plugin) { - final HotColdTemperature temperature = HotColdTemperature.of(message); + if (hotColdSolver == null) + { + return false; + } + + final Set temperatureSet; + + if (this.equals(BEGINNER_CLUE)) + { + temperatureSet = HotColdTemperature.BEGINNER_HOT_COLD_TEMPERATURES; + } + else if (this.equals(MASTER_CLUE)) + { + temperatureSet = HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES; + } + else + { + temperatureSet = null; + } + + final HotColdTemperature temperature = HotColdTemperature.getFromTemperatureSet(temperatureSet, message); if (temperature == null) { @@ -239,7 +288,8 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat return false; } - if (temperature == HotColdTemperature.VISIBLY_SHAKING) + if ((this.equals(BEGINNER_CLUE) && temperature == HotColdTemperature.BEGINNER_VISIBLY_SHAKING) + || (this.equals(MASTER_CLUE) && temperature == HotColdTemperature.MASTER_VISIBLY_SHAKING)) { markFinalSpot(localWorld); } @@ -262,7 +312,26 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat private void initializeSolver() { + final boolean isBeginner; + + if (this.equals(BEGINNER_CLUE)) + { + isBeginner = true; + } + else if (this.equals(MASTER_CLUE)) + { + isBeginner = false; + } + else + { + log.warn("Hot cold solver could not be initialized, clue type is unknown; text: {}, npc: {}, solution: {}", + text, npc, solution); + hotColdSolver = null; + return; + } + final Set locations = Arrays.stream(HotColdLocation.values()) + .filter(l -> l.isBeginnerClue() == isBeginner) .collect(Collectors.toSet()); hotColdSolver = new HotColdSolver(locations); } 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 4259d3d29d..b3bd0c91db 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 @@ -1,6 +1,7 @@ /* * Copyright (c) 2018, Eadgars Ruse * Copyright (c) 2018, Adam + * Copyright (c) 2019, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +69,8 @@ public enum HotColdLocation DESERT_POLLNIVNEACH(new WorldPoint(3287, 2975, 0), DESERT, "West of Pollnivneach."), DESERT_MTA(new WorldPoint(3350, 3293, 0), DESERT, "Next to Mage Training Arena."), DESERT_SHANTY(new WorldPoint(3294, 3106, 0), DESERT, "South-west of Shantay Pass."), + DRAYNOR_MANOR_MUSHROOMS(true, new WorldPoint(3096, 3379, 0), MISTHALIN, "Patch of mushrooms just northwest of Draynor Manor"), + DRAYNOR_WHEAT_FIELD(true, new WorldPoint(3120, 3282, 0), MISTHALIN, "Inside the wheat field next to Draynor Village"), FELDIP_HILLS_JIGGIG(new WorldPoint(2413, 3055, 0), FELDIP_HILLS, "West of Jiggig, east of the fairy ring bkp."), FELDIP_HILLS_SW(new WorldPoint(2582, 2895, 0), FELDIP_HILLS, "West of the southeasternmost lake in Feldip Hills."), FELDIP_HILLS_GNOME_GLITER(new WorldPoint(2553, 2972, 0), FELDIP_HILLS, "East of the gnome glider (Lemantolly Undri)."), @@ -90,6 +93,7 @@ public enum HotColdLocation FREMENNIK_PROVINCE_ASTRAL_ALTER(new WorldPoint(2147, 3862, 0), FREMENNIK_PROVINCE, "Astral altar"), FREMENNIK_PROVINCE_LUNAR_VILLAGE(new WorldPoint(2087, 3915, 0), FREMENNIK_PROVINCE, "Lunar Isle, inside the village."), FREMENNIK_PROVINCE_LUNAR_NORTH(new WorldPoint(2106, 3949, 0), FREMENNIK_PROVINCE, "Lunar Isle, north of the village."), + ICE_MOUNTAIN(true, new WorldPoint(3007, 3475, 0), MISTHALIN, "Atop Ice Mountain"), KANDARIN_SINCLAR_MANSION(new WorldPoint(2726, 3588, 0), KANDARIN, "North-west of the Sinclair Mansion, near the log balance shortcut."), KANDARIN_CATHERBY(new WorldPoint(2774, 3433, 0), KANDARIN, "Catherby, between the bank and the beehives, near small rock formation."), KANDARIN_GRAND_TREE(new WorldPoint(2444, 3503, 0), KANDARIN, "Grand Tree, just east of the terrorchick gnome enclosure."), @@ -114,6 +118,7 @@ public enum HotColdLocation KARAMJA_KHARAZI_NE(new WorldPoint(2904, 2925, 0), KARAMJA, "North-eastern part of Kharazi Jungle."), KARAMJA_KHARAZI_SW(new WorldPoint(2783, 2898, 0), KARAMJA, "South-western part of Kharazi Jungle."), KARAMJA_CRASH_ISLAND(new WorldPoint(2910, 2737, 0), KARAMJA, "Northern part of Crash Island."), + LUMBRIDGE_COW_FIELD(true, new WorldPoint(3174, 3336, 0), MISTHALIN, "Cow field north of Lumbridge"), MISTHALIN_VARROCK_STONE_CIRCLE(new WorldPoint(3225, 3355, 0), MISTHALIN, "South of the stone circle near Varrock's entrance."), MISTHALIN_LUMBRIDGE(new WorldPoint(3238, 3169, 0), MISTHALIN, "Just north-west of the Lumbridge Fishing tutor."), MISTHALIN_LUMBRIDGE_2(new WorldPoint(3170, 3278, 0), MISTHALIN, "North of the pond between Lumbridge and Draynor Village."), @@ -130,6 +135,7 @@ public enum HotColdLocation MORYTANIA_MOS_LES_HARMLESS_BAR(new WorldPoint(3670, 2974, 0), MORYTANIA, "Near Mos Le'Harmless southern bar."), MORYTANIA_DRAGONTOOTH_NORTH(new WorldPoint(3813, 3567, 0), MORYTANIA, "Northern part of Dragontooth Island."), MORYTANIA_DRAGONTOOTH_SOUTH(new WorldPoint(3803, 3532, 0), MORYTANIA, "Southern part of Dragontooth Island."), + NORTHEAST_OF_AL_KHARID_MINE(true, new WorldPoint(3332, 3313, 0), MISTHALIN, "Northeast of Al Kharid Mine"), WESTERN_PROVINCE_EAGLES_PEAK(new WorldPoint(2297, 3530, 0), WESTERN_PROVINCE, "North-west of Eagles' Peak."), WESTERN_PROVINCE_PISCATORIS(new WorldPoint(2337, 3689, 0), WESTERN_PROVINCE, "Piscatoris Fishing Colony"), WESTERN_PROVINCE_PISCATORIS_HUNTER_AREA(new WorldPoint(2361, 3566, 0), WESTERN_PROVINCE, "Eastern part of Piscatoris Hunter area, south-west of the Falconry."), @@ -175,12 +181,20 @@ public enum HotColdLocation 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."); + private final boolean beginnerClue; private final WorldPoint worldPoint; private final HotColdArea hotColdArea; private final String area; + HotColdLocation(WorldPoint worldPoint, HotColdArea hotColdArea, String areaDescription) + { + this(false, worldPoint, hotColdArea, areaDescription); + } + public Rectangle getRect() { - return new Rectangle(worldPoint.getX() - 4, worldPoint.getY() - 4, 9, 9); + final int digRadius = beginnerClue ? HotColdTemperature.BEGINNER_VISIBLY_SHAKING.getMaxDistance() : + HotColdTemperature.MASTER_VISIBLY_SHAKING.getMaxDistance(); + return new Rectangle(worldPoint.getX() - digRadius, worldPoint.getY() - digRadius, digRadius * 2 + 1, digRadius * 2 + 1); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java index 850d33aec1..2dc5909000 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java @@ -24,9 +24,12 @@ */ package net.runelite.client.plugins.cluescrolls.clues.hotcold; +import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; import lombok.AllArgsConstructor; import lombok.Getter; @@ -40,8 +43,31 @@ public enum HotColdTemperature WARM("warm", 100, 149), HOT("hot", 70, 99), VERY_HOT("very hot", 30, 69), - INCREDIBLY_HOT("incredibly hot", 5, 29), - VISIBLY_SHAKING("visibly shaking", 0, 4); + BEGINNER_INCREDIBLY_HOT("incredibly hot", 4, 29), + BEGINNER_VISIBLY_SHAKING("visibly shaking", 0, 3), + MASTER_INCREDIBLY_HOT("incredibly hot", 5, 29), + MASTER_VISIBLY_SHAKING("visibly shaking", 0, 4); + + public static final Set BEGINNER_HOT_COLD_TEMPERATURES = Sets.immutableEnumSet( + ICE_COLD, + VERY_COLD, + COLD, + WARM, + HOT, + VERY_HOT, + BEGINNER_INCREDIBLY_HOT, + BEGINNER_VISIBLY_SHAKING + ); + public static final Set MASTER_HOT_COLD_TEMPERATURES = Sets.immutableEnumSet( + ICE_COLD, + VERY_COLD, + COLD, + WARM, + HOT, + VERY_HOT, + MASTER_INCREDIBLY_HOT, + MASTER_VISIBLY_SHAKING + ); private final String text; private final int minDistance; @@ -50,24 +76,26 @@ public enum HotColdTemperature private static final String DEVICE_USED_START_TEXT = "The device is "; /** - * Gets the temperature corresponding to the passed string. + * Gets the temperature from a set of temperatures corresponding to the passed string. * - * @param message A string containing a temperature value - * @return The corresponding enum for the passed string. + * @param temperatureSet A set of temperature values to select from + * @param message A string containing a temperature value + * @return The corresponding enum from the given temperature set. *

- * Note that in cases where two temperature enums are equally likely to be the given temperature (say, two - * temperatures with identical text values), the behavior is undefined. + * Note that in cases where two temperature values in the given set are equally likely to be the given + * temperature (say, two temperatures with identical text values), the behavior is undefined. */ - public static HotColdTemperature of(final String message) + @Nullable + public static HotColdTemperature getFromTemperatureSet(final Set temperatureSet, final String message) { - if (!message.startsWith(DEVICE_USED_START_TEXT)) + if (!message.startsWith(DEVICE_USED_START_TEXT) || temperatureSet == null) { return null; } final List possibleTemperatures = new ArrayList<>(); - for (final HotColdTemperature temperature : values()) + for (final HotColdTemperature temperature : temperatureSet) { if (message.contains(temperature.getText())) { diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/BeginnerHotColdLocationTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/BeginnerHotColdLocationTest.java new file mode 100644 index 0000000000..d67a00b989 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/BeginnerHotColdLocationTest.java @@ -0,0 +1,50 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class BeginnerHotColdLocationTest +{ + private static final Set BEGINNER_HOT_COLD_LOCATIONS = Arrays.stream(HotColdLocation.values()) + .filter(HotColdLocation::isBeginnerClue) + .collect(Collectors.toSet()); + private static final int EXPECTED_DIMENSION_SIZE = 7; + + @Test + public void beginnerHotColdLocationAreaTest() + { + + for (final HotColdLocation location : BEGINNER_HOT_COLD_LOCATIONS) + { + assertEquals(EXPECTED_DIMENSION_SIZE, location.getRect().height); + assertEquals(EXPECTED_DIMENSION_SIZE, location.getRect().width); + } + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java index 413884d944..a5c4cc4e31 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java @@ -26,6 +26,7 @@ package net.runelite.client.plugins.cluescrolls.clues.hotcold; import com.google.common.collect.Sets; import java.awt.Rectangle; +import java.util.EnumSet; import java.util.Set; import java.util.stream.Collectors; import static junit.framework.TestCase.assertTrue; @@ -207,7 +208,7 @@ public class HotColdSolverTest */ private static void testSolver(final HotColdSolver solver, final WorldPoint testPoint, final String deviceResponse, final Set expectedRemainingPossibleLocations) { - final HotColdTemperature temperature = HotColdTemperature.of(deviceResponse); + final HotColdTemperature temperature = HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, deviceResponse); final HotColdTemperatureChange temperatureChange = HotColdTemperatureChange.of(deviceResponse); assertNotNull(temperature); @@ -221,7 +222,7 @@ public class HotColdSolverTest */ private static HotColdSolver createHotColdSolver() { - final Set hotColdLocations = Sets.immutableEnumSet( + final Set hotColdLocations = EnumSet.of( HotColdLocation.KARAMJA_KHARAZI_NE, HotColdLocation.KARAMJA_KHARAZI_SW, HotColdLocation.KARAMJA_GLIDER, diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java index 505df56346..e9711dc433 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java @@ -52,7 +52,8 @@ public class HotColdTemperatureTest { for (final String message : VALID_MESSAGES) { - assertNotNull(message, HotColdTemperature.of(message)); + assertNotNull(message, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.BEGINNER_HOT_COLD_TEMPERATURES, message)); + assertNotNull(message, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, message)); } } @@ -61,15 +62,16 @@ public class HotColdTemperatureTest { for (final String message : INVALID_MESSAGES) { - assertNull(message, HotColdTemperature.of(message)); + assertNull(message, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.BEGINNER_HOT_COLD_TEMPERATURES, message)); + assertNull(message, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, message)); } } @Test public void testAmbiguousTemperatureMessages() { - assertEquals(HotColdTemperature.ICE_COLD, HotColdTemperature.of("The device is ice cold.")); - assertEquals(HotColdTemperature.VERY_COLD, HotColdTemperature.of("The device is very cold.")); - assertEquals(HotColdTemperature.VERY_HOT, HotColdTemperature.of("The device is very hot.")); + assertEquals(HotColdTemperature.ICE_COLD, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, "The device is ice cold.")); + assertEquals(HotColdTemperature.VERY_COLD, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, "The device is very cold.")); + assertEquals(HotColdTemperature.VERY_HOT, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, "The device is very hot.")); } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/MasterHotColdLocationTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/MasterHotColdLocationTest.java new file mode 100644 index 0000000000..abda26549d --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/MasterHotColdLocationTest.java @@ -0,0 +1,49 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class MasterHotColdLocationTest +{ + private static final Set MASTER_HOT_COLD_LOCATIONS = Arrays.stream(HotColdLocation.values()) + .filter(l -> !l.isBeginnerClue()) + .collect(Collectors.toSet()); + private static final int EXPECTED_DIMENSION_SIZE = 9; + + @Test + public void beginnerHotColdLocationAreaTest() + { + for (final HotColdLocation location : MASTER_HOT_COLD_LOCATIONS) + { + assertEquals(EXPECTED_DIMENSION_SIZE, location.getRect().height); + assertEquals(EXPECTED_DIMENSION_SIZE, location.getRect().width); + } + } +} From 60a23c901b8bc91b64bd12881648ae7bc6ecd982 Mon Sep 17 00:00:00 2001 From: tanlines Date: Tue, 2 Jul 2019 07:12:17 +1000 Subject: [PATCH 08/10] Add item charges for baskets and sacks (#9212) --- .../plugins/itemcharges/ItemChargeConfig.java | 48 +++++++++++----- .../itemcharges/ItemChargeOverlay.java | 7 ++- .../plugins/itemcharges/ItemChargeType.java | 4 +- .../plugins/itemcharges/ItemWithCharge.java | 57 +++++++++++++++++++ 4 files changed, 101 insertions(+), 15 deletions(-) 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 84667abcf3..df14d27f3d 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 @@ -173,10 +173,10 @@ public interface ItemChargeConfig extends Config } @ConfigItem( - keyName = "showBellowCharges", - name = "Show Bellow Charges", - description = "Configures if ogre bellow item charge is shown", - position = 12 + keyName = "showBellowCharges", + name = "Show Bellow Charges", + description = "Configures if ogre bellow item charge is shown", + position = 12 ) default boolean showBellowCharges() { @@ -184,10 +184,32 @@ public interface ItemChargeConfig extends Config } @ConfigItem( - keyName = "showAbyssalBraceletCharges", - name = "Show Abyssal Bracelet Charges", - description = "Configures if abyssal bracelet item charge is shown", - position = 13 + keyName = "showBasketCharges", + name = "Show Basket Charges", + description = "Configures if fruit basket item charge is shown", + position = 13 + ) + default boolean showBasketCharges() + { + return true; + } + + @ConfigItem( + keyName = "showSackCharges", + name = "Show Sack Charges", + description = "Configures if sack item charge is shown", + position = 14 + ) + default boolean showSackCharges() + { + return true; + } + + @ConfigItem( + keyName = "showAbyssalBraceletCharges", + name = "Show Abyssal Bracelet Charges", + description = "Configures if abyssal bracelet item charge is shown", + position = 15 ) default boolean showAbyssalBraceletCharges() { @@ -198,7 +220,7 @@ public interface ItemChargeConfig extends Config keyName = "recoilNotification", name = "Ring of Recoil Notification", description = "Configures if the ring of recoil breaking notification is shown", - position = 14 + position = 16 ) default boolean recoilNotification() { @@ -209,7 +231,7 @@ public interface ItemChargeConfig extends Config keyName = "showBindingNecklaceCharges", name = "Show Binding Necklace Charges", description = "Configures if binding necklace item charge is shown", - position = 15 + position = 17 ) default boolean showBindingNecklaceCharges() { @@ -238,7 +260,7 @@ public interface ItemChargeConfig extends Config keyName = "bindingNotification", name = "Binding Necklace Notification", description = "Configures if the binding necklace breaking notification is shown", - position = 16 + position = 18 ) default boolean bindingNotification() { @@ -249,7 +271,7 @@ public interface ItemChargeConfig extends Config keyName = "showExplorerRingCharges", name = "Show Explorer's Ring Alch Charges", description = "Configures if explorer's ring alchemy charges are shown", - position = 17 + position = 19 ) default boolean showExplorerRingCharges() { @@ -278,7 +300,7 @@ public interface ItemChargeConfig extends Config keyName = "showInfoboxes", name = "Show Infoboxes", description = "Configures whether to show an infobox equipped charge items", - position = 18 + position = 20 ) default boolean showInfoboxes() { 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 fba313e25d..10357f95f2 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 @@ -38,6 +38,8 @@ import static net.runelite.client.plugins.itemcharges.ItemChargeType.IMPBOX; import static net.runelite.client.plugins.itemcharges.ItemChargeType.TELEPORT; import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERCAN; import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERSKIN; +import static net.runelite.client.plugins.itemcharges.ItemChargeType.FRUIT_BASKET; +import static net.runelite.client.plugins.itemcharges.ItemChargeType.SACK; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.WidgetItemOverlay; import net.runelite.client.ui.overlay.components.TextComponent; @@ -109,6 +111,8 @@ class ItemChargeOverlay extends WidgetItemOverlay || (type == WATERCAN && !config.showWateringCanCharges()) || (type == WATERSKIN && !config.showWaterskinCharges()) || (type == BELLOWS && !config.showBellowCharges()) + || (type == FRUIT_BASKET && !config.showBasketCharges()) + || (type == SACK && !config.showSackCharges()) || (type == ABYSSAL_BRACELET && !config.showAbyssalBraceletCharges())) { return; @@ -129,6 +133,7 @@ class ItemChargeOverlay extends WidgetItemOverlay { return config.showTeleportCharges() || config.showDodgyCount() || config.showFungicideCharges() || config.showImpCharges() || config.showWateringCanCharges() || config.showWaterskinCharges() - || config.showBellowCharges() || config.showAbyssalBraceletCharges() || config.showExplorerRingCharges(); + || config.showBellowCharges() || config.showBasketCharges() || config.showSackCharges() + || config.showAbyssalBraceletCharges() || config.showExplorerRingCharges(); } } 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 827858d4d4..e88130725a 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 @@ -35,5 +35,7 @@ enum ItemChargeType WATERSKIN, DODGY_NECKLACE, BINDING_NECKLACE, - EXPLORER_RING + EXPLORER_RING, + FRUIT_BASKET, + SACK } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java index f696097817..986ed9d2ea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java @@ -37,6 +37,8 @@ import static net.runelite.client.plugins.itemcharges.ItemChargeType.IMPBOX; import static net.runelite.client.plugins.itemcharges.ItemChargeType.TELEPORT; import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERCAN; import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERSKIN; +import static net.runelite.client.plugins.itemcharges.ItemChargeType.FRUIT_BASKET; +import static net.runelite.client.plugins.itemcharges.ItemChargeType.SACK; @AllArgsConstructor @Getter @@ -47,6 +49,31 @@ enum ItemWithCharge ABRACE3(ABYSSAL_BRACELET, ABYSSAL_BRACELET3, 3), ABRACE4(ABYSSAL_BRACELET, ABYSSAL_BRACELET4, 4), ABRACE5(ABYSSAL_BRACELET, ABYSSAL_BRACELET5, 5), + BASKET_APPLES1(FRUIT_BASKET, APPLES1, 1), + BASKET_APPLES2(FRUIT_BASKET, APPLES2, 2), + BASKET_APPLES3(FRUIT_BASKET, APPLES3, 3), + BASKET_APPLES4(FRUIT_BASKET, APPLES4, 4), + BASKET_APPLES5(FRUIT_BASKET, APPLES5, 5), + BASKET_BANANAS1(FRUIT_BASKET, BANANAS1, 1), + BASKET_BANANAS2(FRUIT_BASKET, BANANAS2, 2), + BASKET_BANANAS3(FRUIT_BASKET, BANANAS3, 3), + BASKET_BANANAS4(FRUIT_BASKET, BANANAS4, 4), + BASKET_BANANAS5(FRUIT_BASKET, BANANAS5, 5), + BASKET_ORANGES1(FRUIT_BASKET, ORANGES1, 1), + BASKET_ORANGES2(FRUIT_BASKET, ORANGES2, 2), + BASKET_ORANGES3(FRUIT_BASKET, ORANGES3, 3), + BASKET_ORANGES4(FRUIT_BASKET, ORANGES4, 4), + BASKET_ORANGES5(FRUIT_BASKET, ORANGES5, 5), + BASKET_STRAWBERRIES1(FRUIT_BASKET, STRAWBERRIES1, 1), + BASKET_STRAWBERRIES2(FRUIT_BASKET, STRAWBERRIES2, 2), + BASKET_STRAWBERRIES3(FRUIT_BASKET, STRAWBERRIES3, 3), + BASKET_STRAWBERRIES4(FRUIT_BASKET, STRAWBERRIES4, 4), + BASKET_STRAWBERRIES5(FRUIT_BASKET, STRAWBERRIES5, 5), + BASKET_TOMATOES1(FRUIT_BASKET, TOMATOES1, 1), + BASKET_TOMATOES2(FRUIT_BASKET, TOMATOES2, 2), + BASKET_TOMATOES3(FRUIT_BASKET, TOMATOES3, 3), + BASKET_TOMATOES4(FRUIT_BASKET, TOMATOES4, 4), + BASKET_TOMATOES5(FRUIT_BASKET, TOMATOES5, 5), BELLOWS0(BELLOWS, OGRE_BELLOWS, 0), BELLOWS1(BELLOWS, OGRE_BELLOWS_1, 1), BELLOWS2(BELLOWS, OGRE_BELLOWS_2, 2), @@ -144,6 +171,36 @@ enum ItemWithCharge ROW3(TELEPORT, RING_OF_WEALTH_3, 3), ROW4(TELEPORT, RING_OF_WEALTH_4, 4), ROW5(TELEPORT, RING_OF_WEALTH_5, 5), + SACK_CABBAGES1(SACK, CABBAGES1, 1), + SACK_CABBAGES2(SACK, CABBAGES2, 2), + SACK_CABBAGES3(SACK, CABBAGES3, 3), + SACK_CABBAGES4(SACK, CABBAGES4, 4), + SACK_CABBAGES5(SACK, CABBAGES5, 5), + SACK_CABBAGES6(SACK, CABBAGES6, 6), + SACK_CABBAGES7(SACK, CABBAGES7, 7), + SACK_CABBAGES8(SACK, CABBAGES8, 8), + SACK_CABBAGES9(SACK, CABBAGES9, 9), + SACK_CABBAGES10(SACK, CABBAGES10, 10), + SACK_ONIONS1(SACK, ONIONS1, 1), + SACK_ONIONS2(SACK, ONIONS2, 2), + SACK_ONIONS3(SACK, ONIONS3, 3), + SACK_ONIONS4(SACK, ONIONS4, 4), + SACK_ONIONS5(SACK, ONIONS5, 5), + SACK_ONIONS6(SACK, ONIONS6, 6), + SACK_ONIONS7(SACK, ONIONS7, 7), + SACK_ONIONS8(SACK, ONIONS8, 8), + SACK_ONIONS9(SACK, ONIONS9, 9), + SACK_ONIONS10(SACK, ONIONS10, 10), + SACK_POTATOES1(SACK, POTATOES1, 1), + SACK_POTATOES2(SACK, POTATOES2, 2), + SACK_POTATOES3(SACK, POTATOES3, 3), + SACK_POTATOES4(SACK, POTATOES4, 4), + SACK_POTATOES5(SACK, POTATOES5, 5), + SACK_POTATOES6(SACK, POTATOES6, 6), + SACK_POTATOES7(SACK, POTATOES7, 7), + SACK_POTATOES8(SACK, POTATOES8, 8), + SACK_POTATOES9(SACK, POTATOES9, 9), + SACK_POTATOES10(SACK, POTATOES10, 10), SKILLS1(TELEPORT, SKILLS_NECKLACE1, 1), SKILLS2(TELEPORT, SKILLS_NECKLACE2, 2), SKILLS3(TELEPORT, SKILLS_NECKLACE3, 3), From 166e547f6706d6faa6393de5d859112b9db0b27c Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 1 Jul 2019 19:10:17 -0400 Subject: [PATCH 09/10] timers plugin: fix teleblock timers Co-authored-by: jordibenck --- .../client/plugins/timers/TimersPlugin.java | 43 +++--- .../plugins/timers/TimersPluginTest.java | 140 ++++++++++++++++++ 2 files changed, 163 insertions(+), 20 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java 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 f52a49c1ba..d8d4c07cee 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 @@ -27,6 +27,7 @@ package net.runelite.client.plugins.timers; import com.google.inject.Provides; import java.awt.image.BufferedImage; +import java.util.regex.Pattern; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; @@ -88,13 +89,10 @@ public class TimersPlugin extends Plugin private static final String CANNON_REPAIR_MESSAGE = "You repair your cannon, restoring it to working order."; private static final String CHARGE_EXPIRED_MESSAGE = "Your magical charge fades away."; private static final String CHARGE_MESSAGE = "You feel charged with magic power."; - private static final String DEADMAN_HALF_TELEBLOCK_MESSAGE = "A Tele Block spell has been cast on you. It will expire in 1 minute, 15 seconds."; private static final String EXTENDED_ANTIFIRE_DRINK_MESSAGE = "You drink some of your extended antifire potion."; private static final String EXTENDED_SUPER_ANTIFIRE_DRINK_MESSAGE = "You drink some of your extended super antifire potion."; private static final String FROZEN_MESSAGE = "You have been frozen!"; - private static final String FULL_TELEBLOCK_MESSAGE = "A Tele Block spell has been cast on you. It will expire in 5 minutes, 0 seconds."; private static final String GOD_WARS_ALTAR_MESSAGE = "you recharge your prayer."; - private static final String HALF_TELEBLOCK_MESSAGE = "A Tele Block spell has been cast on you. It will expire in 2 minutes, 30 seconds."; private static final String IMBUED_HEART_READY_MESSAGE = "Your imbued heart has regained its magical power."; private static final String MAGIC_IMBUE_EXPIRED_MESSAGE = "Your Magic Imbue charge has ended."; private static final String MAGIC_IMBUE_MESSAGE = "You are charged to combine runes!"; @@ -108,6 +106,10 @@ public class TimersPlugin extends Plugin private static final String SUPER_ANTIFIRE_EXPIRED_MESSAGE = "Your super antifire potion has expired."; private static final String SUPER_ANTIVENOM_DRINK_MESSAGE = "You drink some of your super antivenom potion"; + private static final Pattern DEADMAN_HALF_TELEBLOCK_PATTERN = Pattern.compile("A Tele Block spell has been cast on you by (.+). It will expire in 1 minute, 15 seconds."); + private static final Pattern FULL_TELEBLOCK_PATTERN = Pattern.compile("A Tele Block spell has been cast on you by (.+). It will expire in 5 minutes, 0 seconds."); + private static final Pattern HALF_TELEBLOCK_PATTERN = Pattern.compile("A Tele Block spell has been cast on you by (.+). It will expire in 2 minutes, 30 seconds."); + private TimerTimer freezeTimer; private int freezeTime = -1; // time frozen, in game ticks @@ -518,28 +520,29 @@ public class TimersPlugin extends Plugin removeGameTimer(MAGICIMBUE); } - if (config.showTeleblock() && event.getMessage().equals(FULL_TELEBLOCK_MESSAGE)) + if (config.showTeleblock()) { - createGameTimer(FULLTB); - } - - if (config.showTeleblock() && event.getMessage().equals(HALF_TELEBLOCK_MESSAGE)) - { - if (client.getWorldType().contains(WorldType.DEADMAN) - && !client.getWorldType().contains(WorldType.SEASONAL_DEADMAN) - && !client.getWorldType().contains(WorldType.DEADMAN_TOURNAMENT)) + if (FULL_TELEBLOCK_PATTERN.matcher(event.getMessage()).find()) { - createGameTimer(DMM_FULLTB); + createGameTimer(FULLTB); } - else + else if (HALF_TELEBLOCK_PATTERN.matcher(event.getMessage()).find()) { - createGameTimer(HALFTB); + if (client.getWorldType().contains(WorldType.DEADMAN) + && !client.getWorldType().contains(WorldType.SEASONAL_DEADMAN) + && !client.getWorldType().contains(WorldType.DEADMAN_TOURNAMENT)) + { + createGameTimer(DMM_FULLTB); + } + else + { + createGameTimer(HALFTB); + } + } + else if (DEADMAN_HALF_TELEBLOCK_PATTERN.matcher(event.getMessage()).find()) + { + createGameTimer(DMM_HALFTB); } - } - - if (config.showTeleblock() && event.getMessage().equals(DEADMAN_HALF_TELEBLOCK_MESSAGE)) - { - createGameTimer(DMM_HALFTB); } if (config.showAntiFire() && event.getMessage().contains(SUPER_ANTIFIRE_DRINK_MESSAGE)) diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java new file mode 100644 index 0000000000..f9ba35154d --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java @@ -0,0 +1,140 @@ +/* + * 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.timers; + +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.EnumSet; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.WorldType; +import net.runelite.api.events.ChatMessage; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.ui.overlay.infobox.InfoBox; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import static org.junit.Assert.assertEquals; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class TimersPluginTest +{ + private static final String DMM_HALF_TELEBLOCK_MESSAGE = "A Tele Block spell has been cast on you by Runelite. It will expire in 1 minute, 15 seconds."; + private static final String FULL_TELEBLOCK_MESSAGE = "A Tele Block spell has been cast on you by Runelite. It will expire in 5 minutes, 0 seconds."; + private static final String HALF_TELEBLOCK_MESSAGE = "A Tele Block spell has been cast on you by Runelite. It will expire in 2 minutes, 30 seconds."; + + @Inject + private TimersPlugin timersPlugin; + + @Mock + @Bind + private TimersConfig timersConfig; + + @Mock + @Bind + private Client client; + + @Mock + @Bind + private ItemManager itemManager; + + @Mock + @Bind + private SpriteManager spriteManager; + + @Mock + @Bind + private InfoBoxManager infoBoxManager; + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + } + + @Test + public void testHalfTeleblock() + { + when(timersConfig.showTeleblock()).thenReturn(true); + when(client.getWorldType()).thenReturn(EnumSet.of(WorldType.MEMBERS)); + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", HALF_TELEBLOCK_MESSAGE, "", 0); + timersPlugin.onChatMessage(chatMessage); + + ArgumentCaptor captor = ArgumentCaptor.forClass(InfoBox.class); + verify(infoBoxManager).addInfoBox(captor.capture()); + TimerTimer infoBox = (TimerTimer) captor.getValue(); + assertEquals(GameTimer.HALFTB, infoBox.getTimer()); + } + + @Test + public void testFullTeleblock() + { + when(timersConfig.showTeleblock()).thenReturn(true); + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", FULL_TELEBLOCK_MESSAGE, "", 0); + timersPlugin.onChatMessage(chatMessage); + + ArgumentCaptor captor = ArgumentCaptor.forClass(InfoBox.class); + verify(infoBoxManager).addInfoBox(captor.capture()); + TimerTimer infoBox = (TimerTimer) captor.getValue(); + assertEquals(GameTimer.FULLTB, infoBox.getTimer()); + } + + @Test + public void testDmmHalfTb() + { + when(timersConfig.showTeleblock()).thenReturn(true); + when(client.getWorldType()).thenReturn(EnumSet.of(WorldType.DEADMAN)); + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", DMM_HALF_TELEBLOCK_MESSAGE, "", 0); + timersPlugin.onChatMessage(chatMessage); + + ArgumentCaptor captor = ArgumentCaptor.forClass(InfoBox.class); + verify(infoBoxManager).addInfoBox(captor.capture()); + TimerTimer infoBox = (TimerTimer) captor.getValue(); + assertEquals(GameTimer.DMM_HALFTB, infoBox.getTimer()); + } + + @Test + public void testDmmFullTb() + { + when(timersConfig.showTeleblock()).thenReturn(true); + when(client.getWorldType()).thenReturn(EnumSet.of(WorldType.DEADMAN)); + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", HALF_TELEBLOCK_MESSAGE, "", 0); + timersPlugin.onChatMessage(chatMessage); + + ArgumentCaptor captor = ArgumentCaptor.forClass(InfoBox.class); + verify(infoBoxManager).addInfoBox(captor.capture()); + TimerTimer infoBox = (TimerTimer) captor.getValue(); + assertEquals(GameTimer.DMM_FULLTB, infoBox.getTimer()); + } +} \ No newline at end of file From 4fd1e47032279cad110d01b848d775d877bd43b8 Mon Sep 17 00:00:00 2001 From: Kyleeld <48519776+Kyleeld@users.noreply.github.com> Date: Tue, 2 Jul 2019 10:48:48 +0100 Subject: [PATCH 10/10] Update WorldHoppingMixin.java --- .../src/main/java/net/runelite/mixins/WorldHoppingMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/WorldHoppingMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/WorldHoppingMixin.java index 7780c090d4..f230fa8b45 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/WorldHoppingMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/WorldHoppingMixin.java @@ -15,7 +15,7 @@ public abstract class WorldHoppingMixin implements RSClient public void openWorldHopper() { // The clicked x & y coordinates (the last arguments) are not processed in the game or sent to Jagex, so they don't have to be real. - MenuAction(-1, WidgetInfo.WORLD_SWITCHER_BUTTON.getId(), MenuAction.WIDGET_DEFAULT.getId(), 1, "World Switcher", "", 658, 384); + invokeMenuAction(-1, WidgetInfo.WORLD_SWITCHER_BUTTON.getId(), MenuAction.WIDGET_DEFAULT.getId(), 1, "World Switcher", "", 658, 384); } @Inject @@ -23,6 +23,6 @@ public abstract class WorldHoppingMixin implements RSClient public void hopToWorld(World world) { final int worldId = world.getId(); - menuAction(worldId, WidgetInfo.WORLD_SWITCHER_LIST.getId(), MenuAction.WIDGET_DEFAULT.getId(), 1, "Switch", "" + (worldId - 300) + "", 683, 244); + invokeMenuAction(worldId, WidgetInfo.WORLD_SWITCHER_LIST.getId(), MenuAction.WIDGET_DEFAULT.getId(), 1, "Switch", "" + (worldId - 300) + "", 683, 244); } }