diff --git a/runelite-api/src/main/java/net/runelite/api/InventoryID.java b/runelite-api/src/main/java/net/runelite/api/InventoryID.java index 000bb8aa52..ff099afd70 100644 --- a/runelite-api/src/main/java/net/runelite/api/InventoryID.java +++ b/runelite-api/src/main/java/net/runelite/api/InventoryID.java @@ -57,6 +57,10 @@ public enum InventoryID * Chambers of Xeric chest inventory. */ CHAMBERS_OF_XERIC_CHEST(581), + /** + * Looting Bag inventory + */ + LOOTING_BAG(516), /** * Theater of Blood reward chest inventory (Raids 2) */ @@ -78,4 +82,4 @@ public enum InventoryID { return id; } -} +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fkeyremapping/fKeyRemappingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/fkeyremapping/fKeyRemappingPlugin.java index 78199bfcc5..4bee22c082 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fkeyremapping/fKeyRemappingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fkeyremapping/fKeyRemappingPlugin.java @@ -16,6 +16,7 @@ import net.runelite.client.plugins.PluginDescriptor; name = "fKeyRemapping", description = "Used for interface hotkeys", tags = {"hotkey", "remapping"}, + type = "utility", enabledByDefault = true ) public class fKeyRemappingPlugin extends Plugin diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerOverlay.java new file mode 100644 index 0000000000..85a07780de --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerOverlay.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2018 AWPH-I + * 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.lootingbagviewer; + +import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemContainer; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.ImageComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; + +import javax.inject.Inject; +import java.awt.*; +import java.awt.image.BufferedImage; + +class LootingBagViewerOverlay extends Overlay +{ + private static final int INVENTORY_SIZE = 28; + private static final int PLACEHOLDER_WIDTH = 36; + private static final int PLACEHOLDER_HEIGHT = 32; + private static final ImageComponent PLACEHOLDER_IMAGE = new ImageComponent(new BufferedImage(PLACEHOLDER_WIDTH, PLACEHOLDER_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR)); + + private final Client client; + private final ItemManager itemManager; + + private final PanelComponent panelComponent = new PanelComponent(); + + private ItemContainer itemContainer; + private Item[] items; + + @Inject + private LootingBagViewerOverlay(Client client, ItemManager itemManager) + { + setPosition(OverlayPosition.BOTTOM_RIGHT); + panelComponent.setWrapping(4); + panelComponent.setGap(new Point(6, 4)); + panelComponent.setOrientation(PanelComponent.Orientation.HORIZONTAL); + this.itemManager = itemManager; + this.client = client; + + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (itemContainer == null) + { + if(client.getItemContainer(InventoryID.LOOTING_BAG) != null) { + itemContainer = client.getItemContainer(InventoryID.LOOTING_BAG); + items = itemContainer.getItems(); + } + return null; + } + else if(itemContainer != null && client.getItemContainer(InventoryID.LOOTING_BAG) != null) + { + itemContainer = client.getItemContainer(InventoryID.LOOTING_BAG); + Item[] tempItems = itemContainer.getItems(); + + for(int i = 0; i < items.length; i++) + { + if(!items[i].equals(tempItems[i])) + { + items = tempItems; + } + } + } + + panelComponent.getChildren().clear(); + + for (int i = 0; i < INVENTORY_SIZE; i++) + { + if (i < items.length) + { + final Item item = items[i]; + if (item.getQuantity() > 0) + { + final BufferedImage image = getImage(item); + if (image != null) + { + panelComponent.getChildren().add(new ImageComponent(image)); + continue; + } + } + } + + // put a placeholder image so each item is aligned properly and the panel is not resized + panelComponent.getChildren().add(PLACEHOLDER_IMAGE); + } + + return panelComponent.render(graphics); + } + + private BufferedImage getImage(Item item) + { + return itemManager.getImage(item.getId(), item.getQuantity(), item.getQuantity() > 1); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerPlugin.java new file mode 100644 index 0000000000..5d28a4bbea --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerPlugin.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 AWPH-I + * 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.lootingbagviewer; + +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; + +import javax.inject.Inject; + +@PluginDescriptor( + name = "PvP Looting Bag Viewer", + description = "Add an overlay showing the contents of your looting bag", + tags = {"alternate", "items", "overlay", "second"}, + type = "utility", + enabledByDefault = false +) +public class LootingBagViewerPlugin extends Plugin +{ + @Inject + private net.runelite.client.plugins.lootingbagviewer.LootingBagViewerOverlay overlay; + + @Inject + private OverlayManager overlayManager; + + @Override + public void startUp() + { + overlayManager.add(overlay); + } + + @Override + public void shutDown() + { + overlayManager.remove(overlay); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/BatSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/BatSolver.java new file mode 100644 index 0000000000..ebbad81a54 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/BatSolver.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving.BatSolver; + +import java.util.Map; +import java.util.HashSet; +import java.util.HashMap; +import java.util.TreeSet; +import java.util.List; +import java.util.ArrayList; +import static net.runelite.client.plugins.raidsthieving.BatSolver.SolutionSet.SOLUTION_SETS; + +public class BatSolver +{ + private Map numberOfSolutionsWithPoison; + private final SolutionSet solution; + + private final HashSet grubsChests; + + public BatSolver(ThievingRoomType roomType) + { + solution = new SolutionSet(roomType); + grubsChests = new HashSet<>(); + } + + public void addEmptyChest(int chestId) + { + // When a new empty chest is found, add it to the current solution set + solution.addEmptyChest(chestId); + calculateChanceOfPoison(); + } + + public void addGrubsChest(int chestId) + { + // When a chest with grubs is found, keep track of it to invalidate solutions + grubsChests.add(chestId); + calculateChanceOfPoison(); + } + + public TreeSet matchSolutions() + { + TreeSet possibleEmptyChests = new TreeSet<>(); + for (SolutionSet knownSolution : SolutionSet.SOLUTION_SETS) + { + if (knownSolution.getType() == solution.getType() && matchSolution(knownSolution)) + { + possibleEmptyChests.addAll(knownSolution.getEmptyChests()); + } + } + + return possibleEmptyChests; + } + + private boolean matchSolution(SolutionSet testSolution) + { + for (Integer grubsChest : grubsChests) + { + if (testSolution.containsChest(grubsChest)) + { + // If one of the chests is known to have grubs, it cannot be a solution + return false; + } + } + + boolean matchesAll = true; + boolean everMatched = false; + for (int i : solution.getEmptyChests()) + { + if (!testSolution.containsChest(i)) + { + matchesAll = false; + } + else + { + everMatched = true; + } + } + return matchesAll && everMatched; + } + + public ThievingRoomType getType() + { + return solution.getType(); + } + + + public void calculateChanceOfPoison() + { + if (getType() == null) + { + numberOfSolutionsWithPoison = null; + return; + } + + numberOfSolutionsWithPoison = new HashMap<>(); + for (SolutionSet sol : getPosssibleSolutions()) + { + if (getType() == sol.getType() && (solution.getEmptyChests().size() == 0 || matchSolution(sol))) + { + for (Integer i : sol.getEmptyChests()) + { + if (numberOfSolutionsWithPoison.containsKey(i)) + { + numberOfSolutionsWithPoison.put(i, numberOfSolutionsWithPoison.get(i) + 1); + } + else + { + numberOfSolutionsWithPoison.put(i, 1); + } + } + } + } + } + + private List getPosssibleSolutions() + { + List possibleSolutions = new ArrayList<>(); + for (SolutionSet soln : SOLUTION_SETS) + { + // Check if we've found grubs in one of the chests, invalidating it as an solution + boolean foundMatch = false; + for (int i : grubsChests) + { + if (soln.containsChest(i)) + { + foundMatch = true; + } + } + if (!foundMatch) + { + possibleSolutions.add(soln); + } + } + return possibleSolutions; + } + + public double relativeLikelihoodPoison(int chestId) + { + // Returns a double between 0 and 1 of how likely the chest has poison based on the number of possible solutions + // Uses a Sigmoid like function to give good contrast in drawn opacity, + // perhaps could be changed to something more accurate quantitavely. + if (numberOfSolutionsWithPoison == null) + { + calculateChanceOfPoison(); + } + if (numberOfSolutionsWithPoison == null) + { + return 1.0; + } + int mostFrequentPoison = 0; + for (Map.Entry entry : numberOfSolutionsWithPoison.entrySet()) + { + if (entry.getValue() > mostFrequentPoison) + { + mostFrequentPoison = entry.getValue(); + } + } + int timesFound = 0; + if (numberOfSolutionsWithPoison.containsKey(chestId)) + { + timesFound = numberOfSolutionsWithPoison.get(chestId); + } + double chestChance = (double) (timesFound) / (double) (mostFrequentPoison); + return 1. / (1 + Math.exp(5 - 10 * chestChance)); + } + + public int getNumberOfEmptyChests() + { + return solution.getEmptyChests().size(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ChestIdentifier.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ChestIdentifier.java new file mode 100644 index 0000000000..7346e4ecf6 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ChestIdentifier.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving.BatSolver; + +import net.runelite.client.plugins.raidsthieving.InstancePoint; +import net.runelite.client.plugins.raidsthieving.ThievingChest; +import java.util.HashMap; +import java.util.Map; + +public class ChestIdentifier +{ + public ChestIdentifier(ThievingRoomType roomType) + { + chestIds = new HashMap<>(); + switch (roomType) + { + case LEFT_TURN: + chestIds.put(new InstancePoint(3283, 5379), 1); + chestIds.put(new InstancePoint(3285, 5380), 2); + chestIds.put(new InstancePoint(3279, 5381), 3); + chestIds.put(new InstancePoint(3287, 5382), 4); + chestIds.put(new InstancePoint(3281, 5382), 5); + chestIds.put(new InstancePoint(3284, 5383), 6); + chestIds.put(new InstancePoint(3283, 5384), 7); + chestIds.put(new InstancePoint(3286, 5384), 8); + chestIds.put(new InstancePoint(3288, 5384), 9); + chestIds.put(new InstancePoint(3277, 5385), 10); + chestIds.put(new InstancePoint(3280, 5385), 11); + chestIds.put(new InstancePoint(3285, 5386), 12); + chestIds.put(new InstancePoint(3290, 5386), 13); + chestIds.put(new InstancePoint(3275, 5387), 14); + chestIds.put(new InstancePoint(3287, 5387), 15); + chestIds.put(new InstancePoint(3288, 5387), 16); + chestIds.put(new InstancePoint(3281, 5388), 17); + chestIds.put(new InstancePoint(3291, 5388), 18); + chestIds.put(new InstancePoint(3280, 5389), 19); + chestIds.put(new InstancePoint(3285, 5389), 20); + chestIds.put(new InstancePoint(3289, 5389), 21); + chestIds.put(new InstancePoint(3283, 5390), 22); + chestIds.put(new InstancePoint(3285, 5390), 23); + chestIds.put(new InstancePoint(3288, 5390), 24); + chestIds.put(new InstancePoint(3290, 5390), 25); + chestIds.put(new InstancePoint(3282, 5391), 26); + chestIds.put(new InstancePoint(3289, 5391), 27); + chestIds.put(new InstancePoint(3292, 5391), 28); + chestIds.put(new InstancePoint(3279, 5392), 29); + chestIds.put(new InstancePoint(3276, 5393), 30); + chestIds.put(new InstancePoint(3279, 5393), 31); + chestIds.put(new InstancePoint(3284, 5393), 32); + chestIds.put(new InstancePoint(3285, 5393), 33); + chestIds.put(new InstancePoint(3291, 5393), 34); + chestIds.put(new InstancePoint(3275, 5394), 35); + chestIds.put(new InstancePoint(3277, 5394), 36); + chestIds.put(new InstancePoint(3288, 5394), 37); + chestIds.put(new InstancePoint(3276, 5395), 38); + chestIds.put(new InstancePoint(3281, 5395), 39); + chestIds.put(new InstancePoint(3285, 5395), 40); + chestIds.put(new InstancePoint(3287, 5395), 41); + chestIds.put(new InstancePoint(3289, 5395), 42); + chestIds.put(new InstancePoint(3274, 5396), 43); + chestIds.put(new InstancePoint(3283, 5396), 44); + chestIds.put(new InstancePoint(3285, 5396), 45); + chestIds.put(new InstancePoint(3288, 5396), 46); + chestIds.put(new InstancePoint(3272, 5397), 47); + chestIds.put(new InstancePoint(3280, 5397), 48); + chestIds.put(new InstancePoint(3277, 5398), 49); + chestIds.put(new InstancePoint(3281, 5398), 50); + chestIds.put(new InstancePoint(3284, 5398), 51); + chestIds.put(new InstancePoint(3276, 5399), 52); + chestIds.put(new InstancePoint(3278, 5399), 53); + chestIds.put(new InstancePoint(3283, 5399), 54); + chestIds.put(new InstancePoint(3285, 5399), 55); + chestIds.put(new InstancePoint(3277, 5400), 56); + chestIds.put(new InstancePoint(3284, 5400), 57); + chestIds.put(new InstancePoint(3288, 5400), 58); + chestIds.put(new InstancePoint(3281, 5401), 59); + chestIds.put(new InstancePoint(3286, 5401), 60); + chestIds.put(new InstancePoint(3279, 5402), 61); + chestIds.put(new InstancePoint(3285, 5402), 62); + chestIds.put(new InstancePoint(3280, 5403), 63); + chestIds.put(new InstancePoint(3283, 5403), 64); + break; + case RIGHT_TURN: + chestIds.put(new InstancePoint(3338, 5405), 1); + chestIds.put(new InstancePoint(3334, 5405), 2); + chestIds.put(new InstancePoint(3342, 5404), 3); + chestIds.put(new InstancePoint(3340, 5404), 4); + chestIds.put(new InstancePoint(3345, 5403), 5); + chestIds.put(new InstancePoint(3334, 5403), 6); + chestIds.put(new InstancePoint(3330, 5403), 7); + chestIds.put(new InstancePoint(3343, 5402), 8); + chestIds.put(new InstancePoint(3342, 5402), 9); + chestIds.put(new InstancePoint(3339, 5402), 10); + chestIds.put(new InstancePoint(3338, 5402), 11); + chestIds.put(new InstancePoint(3336, 5402), 12); + chestIds.put(new InstancePoint(3347, 5401), 13); + chestIds.put(new InstancePoint(3330, 5401), 14); + chestIds.put(new InstancePoint(3345, 5400), 15); + chestIds.put(new InstancePoint(3341, 5400), 16); + chestIds.put(new InstancePoint(3337, 5400), 17); + chestIds.put(new InstancePoint(3334, 5400), 18); + chestIds.put(new InstancePoint(3345, 5399), 19); + chestIds.put(new InstancePoint(3343, 5399), 20); + chestIds.put(new InstancePoint(3340, 5399), 21); + chestIds.put(new InstancePoint(3335, 5399), 22); + chestIds.put(new InstancePoint(3331, 5399), 23); + chestIds.put(new InstancePoint(3338, 5398), 24); + chestIds.put(new InstancePoint(3337, 5398), 25); + chestIds.put(new InstancePoint(3345, 5397), 26); + chestIds.put(new InstancePoint(3341, 5397), 27); + chestIds.put(new InstancePoint(3334, 5397), 28); + chestIds.put(new InstancePoint(3331, 5397), 29); + chestIds.put(new InstancePoint(3346, 5396), 30); + chestIds.put(new InstancePoint(3343, 5396), 31); + chestIds.put(new InstancePoint(3339, 5396), 32); + chestIds.put(new InstancePoint(3335, 5396), 33); + chestIds.put(new InstancePoint(3333, 5396), 34); + chestIds.put(new InstancePoint(3340, 5395), 35); + chestIds.put(new InstancePoint(3337, 5395), 36); + chestIds.put(new InstancePoint(3334, 5395), 37); + chestIds.put(new InstancePoint(3345, 5394), 38); + chestIds.put(new InstancePoint(3342, 5394), 39); + chestIds.put(new InstancePoint(3332, 5394), 40); + chestIds.put(new InstancePoint(3343, 5393), 41); + chestIds.put(new InstancePoint(3341, 5393), 42); + chestIds.put(new InstancePoint(3338, 5393), 43); + chestIds.put(new InstancePoint(3335, 5393), 44); + chestIds.put(new InstancePoint(3334, 5393), 45); + chestIds.put(new InstancePoint(3346, 5392), 46); + chestIds.put(new InstancePoint(3342, 5392), 47); + chestIds.put(new InstancePoint(3332, 5392), 48); + chestIds.put(new InstancePoint(3350, 5391), 49); + chestIds.put(new InstancePoint(3346, 5391), 50); + chestIds.put(new InstancePoint(3340, 5391), 51); + chestIds.put(new InstancePoint(3339, 5391), 52); + chestIds.put(new InstancePoint(3336, 5391), 53); + chestIds.put(new InstancePoint(3333, 5391), 54); + chestIds.put(new InstancePoint(3349, 5390), 55); + chestIds.put(new InstancePoint(3343, 5390), 56); + chestIds.put(new InstancePoint(3337, 5390), 57); + chestIds.put(new InstancePoint(3335, 5390), 58); + chestIds.put(new InstancePoint(3344, 5389), 59); + chestIds.put(new InstancePoint(3340, 5389), 60); + chestIds.put(new InstancePoint(3336, 5389), 61); + chestIds.put(new InstancePoint(3333, 5389), 62); + chestIds.put(new InstancePoint(3346, 5388), 63); + chestIds.put(new InstancePoint(3340, 5387), 64); + chestIds.put(new InstancePoint(3337, 5386), 65); + chestIds.put(new InstancePoint(3333, 5386), 66); + chestIds.put(new InstancePoint(3338, 5385), 67); + chestIds.put(new InstancePoint(3336, 5385), 68); + chestIds.put(new InstancePoint(3337, 5384), 69); + chestIds.put(new InstancePoint(3340, 5382), 70); + chestIds.put(new InstancePoint(3334, 5383), 71); + chestIds.put(new InstancePoint(3340, 5379), 72); + chestIds.put(new InstancePoint(3338, 5380), 73); + chestIds.put(new InstancePoint(3336, 5381), 74); + break; + case STRAIGHT: + chestIds.put(new InstancePoint(3308, 5378), 1); + chestIds.put(new InstancePoint(3305, 5379), 2); + chestIds.put(new InstancePoint(3307, 5379), 3); + chestIds.put(new InstancePoint(3304, 5381), 4); + chestIds.put(new InstancePoint(3310, 5381), 5); + chestIds.put(new InstancePoint(3302, 5382), 6); + chestIds.put(new InstancePoint(3307, 5382), 7); + chestIds.put(new InstancePoint(3312, 5382), 8); + chestIds.put(new InstancePoint(3317, 5382), 9); + chestIds.put(new InstancePoint(3319, 5382), 10); + chestIds.put(new InstancePoint(3304, 5383), 11); + chestIds.put(new InstancePoint(3305, 5383), 12); + chestIds.put(new InstancePoint(3307, 5383), 13); + chestIds.put(new InstancePoint(3310, 5383), 14); + chestIds.put(new InstancePoint(3315, 5383), 15); + chestIds.put(new InstancePoint(3320, 5383), 16); + chestIds.put(new InstancePoint(3300, 5384), 17); + chestIds.put(new InstancePoint(3309, 5384), 18); + chestIds.put(new InstancePoint(3311, 5384), 19); + chestIds.put(new InstancePoint(3313, 5384), 20); + chestIds.put(new InstancePoint(3317, 5384), 21); + chestIds.put(new InstancePoint(3318, 5384), 22); + chestIds.put(new InstancePoint(3302, 5385), 23); + chestIds.put(new InstancePoint(3306, 5385), 24); + chestIds.put(new InstancePoint(3310, 5385), 25); + chestIds.put(new InstancePoint(3313, 5385), 26); + chestIds.put(new InstancePoint(3320, 5385), 27); + chestIds.put(new InstancePoint(3302, 5386), 28); + chestIds.put(new InstancePoint(3305, 5386), 29); + chestIds.put(new InstancePoint(3316, 5386), 30); + chestIds.put(new InstancePoint(3321, 5386), 31); + chestIds.put(new InstancePoint(3300, 5387), 32); + chestIds.put(new InstancePoint(3308, 5387), 33); + chestIds.put(new InstancePoint(3314, 5387), 34); + chestIds.put(new InstancePoint(3317, 5387), 35); + chestIds.put(new InstancePoint(3301, 5388), 36); + chestIds.put(new InstancePoint(3306, 5388), 37); + chestIds.put(new InstancePoint(3312, 5388), 38); + chestIds.put(new InstancePoint(3322, 5388), 39); + chestIds.put(new InstancePoint(3309, 5389), 40); + chestIds.put(new InstancePoint(3311, 5389), 41); + chestIds.put(new InstancePoint(3313, 5389), 42); + chestIds.put(new InstancePoint(3316, 5389), 43); + chestIds.put(new InstancePoint(3320, 5389), 44); + chestIds.put(new InstancePoint(3300, 5390), 45); + chestIds.put(new InstancePoint(3303, 5390), 46); + chestIds.put(new InstancePoint(3304, 5390), 47); + chestIds.put(new InstancePoint(3312, 5390), 48); + chestIds.put(new InstancePoint(3320, 5390), 49); + chestIds.put(new InstancePoint(3307, 5391), 50); + chestIds.put(new InstancePoint(3310, 5391), 51); + chestIds.put(new InstancePoint(3317, 5391), 52); + chestIds.put(new InstancePoint(3318, 5391), 53); + chestIds.put(new InstancePoint(3323, 5391), 54); + chestIds.put(new InstancePoint(3301, 5392), 55); + chestIds.put(new InstancePoint(3303, 5392), 56); + chestIds.put(new InstancePoint(3309, 5392), 57); + chestIds.put(new InstancePoint(3314, 5392), 58); + chestIds.put(new InstancePoint(3322, 5392), 59); + chestIds.put(new InstancePoint(3305, 5393), 60); + chestIds.put(new InstancePoint(3307, 5393), 61); + chestIds.put(new InstancePoint(3316, 5393), 62); + chestIds.put(new InstancePoint(3309, 5394), 63); + chestIds.put(new InstancePoint(3312, 5394), 64); + chestIds.put(new InstancePoint(3322, 5394), 65); + chestIds.put(new InstancePoint(3310, 5379), 66); + break; + } + + } + + public int indentifyChest(ThievingChest chest) + { + int id = chestIds.get(chest.getInstancePoint()); + chest.setChestId(id); + return id; + } + + private Map chestIds; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/SolutionSet.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/SolutionSet.java new file mode 100644 index 0000000000..dc1c3c3dc2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/SolutionSet.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving.BatSolver; + +import lombok.Getter; +import java.util.HashSet; +import java.util.Arrays; +import java.util.Set; + +// Each Thieving room has 4 empty chests +// User-reported data shows these 4 come in groups, +// +// e.g. if there is an empty chest in L room chest 1, the other empty chests could be 16, 17, 38, 54, 55 +// See https://dikkenoob.github.io/ for more information + +public class SolutionSet +{ + public static final SolutionSet[] SOLUTION_SETS = + { + new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 16, 17, 55), + new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 17, 38, 54), + new SolutionSet(ThievingRoomType.LEFT_TURN, 2, 7, 21, 37), + new SolutionSet(ThievingRoomType.LEFT_TURN, 3, 5, 19, 30), + new SolutionSet(ThievingRoomType.LEFT_TURN, 3, 11, 15, 40), + new SolutionSet(ThievingRoomType.LEFT_TURN, 4, 22, 27, 46), + new SolutionSet(ThievingRoomType.LEFT_TURN, 5, 9, 19, 45), + new SolutionSet(ThievingRoomType.LEFT_TURN, 6, 24, 26, 41), + new SolutionSet(ThievingRoomType.LEFT_TURN, 6, 26, 32, 52), + new SolutionSet(ThievingRoomType.LEFT_TURN, 7, 13, 44, 59), + new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 14, 41, 43), + new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 10, 28, 33), + new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 31, 47, 50), + new SolutionSet(ThievingRoomType.LEFT_TURN, 10, 35, 54, 63), + new SolutionSet(ThievingRoomType.LEFT_TURN, 10, 30, 32, 59), + new SolutionSet(ThievingRoomType.LEFT_TURN, 12, 40, 53, 56), + new SolutionSet(ThievingRoomType.LEFT_TURN, 12, 13, 42, 54), + new SolutionSet(ThievingRoomType.LEFT_TURN, 13, 22, 27, 46), + new SolutionSet(ThievingRoomType.LEFT_TURN, 14, 18, 23, 51), + new SolutionSet(ThievingRoomType.LEFT_TURN, 15, 43, 44, 58), + new SolutionSet(ThievingRoomType.LEFT_TURN, 15, 16, 42, 45), + new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 29, 45, 51), + new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 25, 32, 34), + new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 28, 51, 62), + new SolutionSet(ThievingRoomType.LEFT_TURN, 21, 39, 41, 58), + new SolutionSet(ThievingRoomType.LEFT_TURN, 22, 25, 54, 64), + new SolutionSet(ThievingRoomType.LEFT_TURN, 23, 31, 47, 55), + new SolutionSet(ThievingRoomType.LEFT_TURN, 23, 33, 37, 60), + new SolutionSet(ThievingRoomType.LEFT_TURN, 24, 34, 55), + new SolutionSet(ThievingRoomType.LEFT_TURN, 26, 50, 63, 27), + new SolutionSet(ThievingRoomType.LEFT_TURN, 29, 39, 41, 61), + new SolutionSet(ThievingRoomType.LEFT_TURN, 33, 46, 52, 57), + new SolutionSet(ThievingRoomType.LEFT_TURN, 34, 45, 49, 60), + new SolutionSet(ThievingRoomType.LEFT_TURN, 36, 40, 42, 62), + new SolutionSet(ThievingRoomType.LEFT_TURN, 37, 38, 51, 64), + new SolutionSet(ThievingRoomType.LEFT_TURN, 48, 53, 55, 56), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 1, 6, 28, 41), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 1, 42, 55, 60), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 2, 10, 31, 44), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 2, 33, 51, 68), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 3, 31, 43, 46), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 3, 5, 21, 48), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 4, 20, 24, 33), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 4, 38, 47), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 5, 21, 48), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 5, 17, 35, 63), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 7, 17, 45, 47), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 7, 37, 41, 52), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 8, 13, 40, 42), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 8, 20, 24, 30), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 9, 15, 23, 35), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 11, 13, 21, 50), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 11, 18, 37, 39), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 12, 14, 27, 34), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 14, 45, 67, 71), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 16, 22, 29, 32), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 18, 28, 31, 64), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 19, 21, 63, 69), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 20, 51, 68, 72), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 22, 29, 56, 61), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 23, 53, 66, 74), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 26, 35, 53, 59), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 27, 30, 55, 57), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 31, 58, 60, 73), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 34, 57, 58, 70), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 38, 56, 61, 70), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 40, 54, 65, 72), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 42, 46, 65), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 47, 49, 66, 67), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 48, 62, 69), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 9, 19, 32, 41), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 16, 26, 36, 39), + new SolutionSet(ThievingRoomType.STRAIGHT, 1, 39, 43, 51), + new SolutionSet(ThievingRoomType.STRAIGHT, 2, 15, 20, 53), + new SolutionSet(ThievingRoomType.STRAIGHT, 3, 10, 42, 44), + new SolutionSet(ThievingRoomType.STRAIGHT, 4, 14, 38, 52), + new SolutionSet(ThievingRoomType.STRAIGHT, 5, 6, 35, 41), + new SolutionSet(ThievingRoomType.STRAIGHT, 7, 16, 34, 49), + new SolutionSet(ThievingRoomType.STRAIGHT, 9, 12, 26, 27), + new SolutionSet(ThievingRoomType.STRAIGHT, 13, 25, 30, 31), + new SolutionSet(ThievingRoomType.STRAIGHT, 15, 20, 53), + new SolutionSet(ThievingRoomType.STRAIGHT, 17, 24, 34, 58), + new SolutionSet(ThievingRoomType.STRAIGHT, 18, 23, 35, 57), + new SolutionSet(ThievingRoomType.STRAIGHT, 19, 26, 47, 65), + new SolutionSet(ThievingRoomType.STRAIGHT, 21, 33, 36, 61), + new SolutionSet(ThievingRoomType.STRAIGHT, 21, 54, 66), + new SolutionSet(ThievingRoomType.STRAIGHT, 22, 25, 46, 55), + new SolutionSet(ThievingRoomType.STRAIGHT, 24, 34, 58), + new SolutionSet(ThievingRoomType.STRAIGHT, 28, 40, 52, 62), + new SolutionSet(ThievingRoomType.STRAIGHT, 29, 41, 42, 63), + new SolutionSet(ThievingRoomType.STRAIGHT, 30, 32, 37, 64), + new SolutionSet(ThievingRoomType.STRAIGHT, 39, 43, 51), + new SolutionSet(ThievingRoomType.STRAIGHT, 43, 45, 50, 60), + new SolutionSet(ThievingRoomType.STRAIGHT, 51, 53, 56, 59) + }; + + SolutionSet(ThievingRoomType type) + { + this.type = type; + emptyChests = new HashSet<>(); + } + + private SolutionSet(ThievingRoomType type, Integer... emptyChests) + { + this.type = type; + this.emptyChests = new HashSet<>(Arrays.asList(emptyChests)); + } + + public void addEmptyChest(int chestId) + { + emptyChests.add(chestId); + } + + public boolean containsChest(int chestId) + { + return emptyChests.contains(chestId); + } + + @Getter + private ThievingRoomType type; + + @Getter + private Set emptyChests; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ThievingRoomType.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ThievingRoomType.java new file mode 100644 index 0000000000..f709b2d435 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ThievingRoomType.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving.BatSolver; + +// There are three distinct Thieving rooms, distinguished by the position of the entrance relative to the exit +// e.g. If you enter the room and must turn left to get to the exit and trough, this is a LEFT_TURN + +import net.runelite.client.plugins.raidsthieving.InstancePoint; + +public enum ThievingRoomType +{ + LEFT_TURN(3271, 5389), + RIGHT_TURN(3350, 5399), + STRAIGHT(3317, 5397); + + private final int x; + private final int y; + + ThievingRoomType(int x, int y) + { + this.x = x; + this.y = y; + } + + public static ThievingRoomType IdentifyByInstancePoint(InstancePoint point) + { + for (ThievingRoomType type : ThievingRoomType.values()) + { + if (Math.abs(type.x - point.getX()) <= 1 && + Math.abs(type.y - point.getY()) <= 1) + { + return type; + } + } + + return null; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ChestOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ChestOverlay.java new file mode 100644 index 0000000000..5e09486f89 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ChestOverlay.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving; + +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.plugins.raidsthieving.BatSolver.BatSolver; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; +import javax.inject.Inject; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.Map; +import java.util.TreeSet; + +/** + * Represents the overlay that shows timers on traps that are placed by the + * player. + */ +public class ChestOverlay extends Overlay +{ + + private final Client client; + private final RaidsThievingPlugin plugin; + private final RaidsThievingConfig config; + + @Inject + ChestOverlay(Client client, RaidsThievingPlugin plugin, RaidsThievingConfig config) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.plugin = plugin; + this.config = config; + this.client = client; + } + + @Override + public Dimension render(Graphics2D graphics) + { + drawChests(graphics); + return null; + } + + /** + * Updates the timer colors. + */ + public void updateConfig() + { + } + + /** + * Iterates over all the traps that were placed by the local player, and + * draws a circle or a timer on the trap, depending on the trap state. + * + * @param graphics + */ + private void drawChests(Graphics2D graphics) + { + + for (Map.Entry entry : plugin.getChests().entrySet()) + { + ThievingChest chest = entry.getValue(); + WorldPoint pos = entry.getKey(); + + + if (chest != null) + { + if (!plugin.isBatsFound() && !chest.isEverOpened()) + { + if (shouldDrawChest(pos)) + { + Color drawColor = new Color(config.getPotentialBatColor().getRed(), + config.getPotentialBatColor().getGreen(), + config.getPotentialBatColor().getBlue(), + getChestOpacity(pos)); + drawCircleOnTrap(graphics, chest, drawColor); + } + } + if (chest.isPoison()) + { + drawCircleOnTrap(graphics, chest, config.getPoisonTrapColor()); + } + } + } + } + + private boolean shouldDrawChest(WorldPoint chestPos) + { + if (plugin.numberOfEmptyChestsFound() == 0) + { + return true; + } + int chestId = plugin.getChestId(chestPos); + BatSolver solver = plugin.getSolver(); + if (solver != null && chestId != -1) + { + TreeSet matches = solver.matchSolutions(); + return matches.contains(chestId) || matches.size() == 0; + } + return true; + } + + /** + * Draws a timer on a given trap. + * + * @param graphics + * @param chest The chest on which the circle needs to be drawn + * @param fill The fill color of the timer + */ + private void drawCircleOnTrap(Graphics2D graphics, ThievingChest chest, Color fill) + { + if (chest.getLocalPoint().getPlane() != client.getPlane()) + { + return; + } + LocalPoint localLoc = LocalPoint.fromWorld(client, chest.getLocalPoint()); + if (localLoc == null) + { + return; + } + Point loc = Perspective.localToCanvas(client, localLoc, chest.getLocalPoint().getPlane()); + + ProgressPieComponent pie = new ProgressPieComponent(); + pie.setFill(fill); + pie.setBorderColor(Color.BLACK); + pie.setPosition(loc); + pie.setProgress(1); + if (graphics != null && loc != null) + { + pie.render(graphics); + } + } + + private int getChestOpacity(WorldPoint chestPos) + { + int chestId = plugin.getChestId(chestPos); + BatSolver solver = plugin.getSolver(); + if (solver != null && chestId != -1) + { + return (int) (255 * solver.relativeLikelihoodPoison(chestId)); + } + return 255; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/InstancePoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/InstancePoint.java new file mode 100644 index 0000000000..0df80aeb65 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/InstancePoint.java @@ -0,0 +1,98 @@ +package net.runelite.client.plugins.raidsthieving; + +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.Point; +import net.runelite.api.coords.WorldPoint; + +import java.util.Objects; + +/** + * Represents a point in the instance chunk, invariant of rotation. + */ +@Getter +public class InstancePoint +{ + private static final int CHUNK_SIZE = 8; + private static final double CHUNK_OFFSET = 3.5; + + public InstancePoint(int x, int y, int rot) + { + this.x = x; + this.y = y; + this.rot = rot; + } + + public InstancePoint(int x, int y) + { + this.x = x; + this.y = y; + this.rot = 0; + } + + public static InstancePoint buildFromPoint(WorldPoint worldPoint, Client client) + { + Point point = new Point(worldPoint.getX(), worldPoint.getY()); + Point base = new Point(client.getBaseX(), client.getBaseY()); + int plane = worldPoint.getPlane(); + + int deltaX = point.getX() - base.getX(); + int deltaY = point.getY() - base.getY(); + int chunkIndexX = deltaX / CHUNK_SIZE; + int chunkIndexY = deltaY / CHUNK_SIZE; + + int chunkData = client.getInstanceTemplateChunks()[plane][chunkIndexX][chunkIndexY]; + int rotation = chunkData >> 1 & 0x3; + int y = (chunkData >> 3 & 0x7FF) * 8; + int x = (chunkData >> 14 & 0x3FF) * 8; + + return buildFromTile(base, point, rotation, new Point(x, y)); + } + + public static InstancePoint buildFromTile(Point base, Point tile, int rot, Point chunkOrigin) + { + int deltaX = tile.getX() - base.getX(); + int deltaY = tile.getY() - base.getY(); + + double chunkOffsetX = (deltaX % CHUNK_SIZE) - CHUNK_OFFSET; + double chunkOffsetY = (deltaY % CHUNK_SIZE) - CHUNK_OFFSET; + + for (int i = 0; i < rot; i++) + { + double temp = chunkOffsetX; + chunkOffsetX = -chunkOffsetY; + chunkOffsetY = temp; + } + + chunkOffsetX += CHUNK_OFFSET; + chunkOffsetY += CHUNK_OFFSET; + + int invariantChunkOffsetX = (int) chunkOffsetX; + int invariantChunkOffsetY = (int) chunkOffsetY; + + return new InstancePoint( + chunkOrigin.getX() + invariantChunkOffsetX, + chunkOrigin.getY() + invariantChunkOffsetY, + rot); + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InstancePoint that = (InstancePoint) o; + return x == that.x && + y == that.y; + } + + @Override + public int hashCode() + { + return Objects.hash(x, y); + } + + private int x; + private int y; + private int rot; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConfig.java new file mode 100644 index 0000000000..bb055edf4e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConfig.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017, Tim Lehner + * 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.raidsthieving; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import java.awt.Color; + +@ConfigGroup("raidsthievingplugin") +public interface RaidsThievingConfig extends Config +{ + @ConfigItem( + position = 1, + keyName = "hexColorPotentialBat", + name = "Potential Bat", + description = "Color of marker for chests which could have bat" + ) + default Color getPotentialBatColor() + { + return Color.YELLOW; + } + + @ConfigItem( + position = 2, + keyName = "hexColorPoison", + name = "Poison trap", + description = "Color of chest with poison" + ) + default Color getPoisonTrapColor() + { + return Color.GREEN; + } + + @ConfigItem( + position = 5, + keyName = "batNotify", + name = "Notify when found", + description = "Send notification if you see bats being found." + ) + default boolean batFoundNotify() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConstants.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConstants.java new file mode 100644 index 0000000000..965934a01b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConstants.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Tim Lehner + * 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.raidsthieving; + +public class RaidsThievingConstants +{ + public static final int CLOSED_CHEST_ID = 29742; + public static final int OPEN_EMPTY_CHEST = 29743; + public static final int OPEN_FULL_CHEST_1 = 29744; + public static final int OPEN_FULL_CHEST_2 = 29745; + public static final int EMPTY_TROUGH = 29746; + public static final int[] STORAGE = {29769, 29770, 29771, 29772}; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingPlugin.java new file mode 100644 index 0000000000..10873e02d8 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingPlugin.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2017, Tim Lehner + * 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.raidsthieving; + +import com.google.inject.Provides; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import net.runelite.api.GraphicsObject; +import net.runelite.api.Varbits; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GraphicsObjectCreated; +import net.runelite.api.events.VarbitChanged; +import net.runelite.client.Notifier; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.raidsthieving.BatSolver.BatSolver; +import net.runelite.client.plugins.raidsthieving.BatSolver.ChestIdentifier; +import net.runelite.client.plugins.raidsthieving.BatSolver.ThievingRoomType; +import net.runelite.client.ui.overlay.OverlayManager; +import javax.inject.Inject; +import java.text.MessageFormat; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@PluginDescriptor( + name = "Raids Bat Finder", + description = "Tracks which chests need to be searched for bats and which poison", + tags = {"overlay", "skilling", "raid"}, + type = "PVM" +) +public class RaidsThievingPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private OverlayManager overlayManager; + + @Inject + private ChestOverlay overlay; + + @Inject + private Notifier notifier; + + @Inject + private RaidsThievingConfig config; + + @Getter + private final Map chests = new HashMap<>(); + + @Getter + private Instant lastActionTime = Instant.ofEpochMilli(0); + + private boolean inRaidChambers; + + @Getter + private boolean batsFound; + + @Getter + private BatSolver solver; + + @Getter + private ChestIdentifier mapper; + + + @Provides + RaidsThievingConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(RaidsThievingConfig.class); + } + + @Override + protected void startUp() + { + overlayManager.add(overlay); + overlay.updateConfig(); + reset(); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + lastActionTime = Instant.ofEpochMilli(0); + chests.clear(); + } + + + @Subscribe + public void onGameObjectSpawned(GameObjectSpawned event) + { + GameObject obj = event.getGameObject(); + WorldPoint loc = obj.getWorldLocation(); + InstancePoint absLoc = InstancePoint.buildFromPoint(loc, client); + + if (obj.getId() == RaidsThievingConstants.EMPTY_TROUGH) + { + ThievingRoomType type = ThievingRoomType.IdentifyByInstancePoint(absLoc); + + if (type != null) + { + solver = new BatSolver(type); + mapper = new ChestIdentifier(type); + for (ThievingChest chest : chests.values()) + { + mapper.indentifyChest(chest); + } + } + else + { + log.error(MessageFormat.format("Unable to identify room type with: {0} {1} {2} {3} {4}.", + loc.getX(), loc.getY(), absLoc.getX(), absLoc.getY(), absLoc.getRot())); + log.error("Please report this @https://github.com/runelite/runelite/pull/4914!"); + } + } + if (obj.getId() == RaidsThievingConstants.CLOSED_CHEST_ID) + { + if (!chests.containsKey(loc)) + { + ThievingChest chest = new ThievingChest(obj, absLoc); + + if (mapper != null) + { + mapper.indentifyChest(chest); + } + + chests.put(loc, chest); + } + else + { + checkForBats(); + } + } + + if (obj.getId() == RaidsThievingConstants.OPEN_FULL_CHEST_1 || + obj.getId() == RaidsThievingConstants.OPEN_FULL_CHEST_2) + { + ThievingChest chest = chests.get(obj.getWorldLocation()); + // We found a chest that has grubs + log.info(MessageFormat.format("Found grubs at {0}, {1} chestId: {2}", loc.getX(), loc.getY(), chest.getChestId())); + if (solver != null && chest.getChestId() != -1) + { + chest.setEverOpened(true); + solver.addGrubsChest(chest.getChestId()); + } + checkForBats(); + } + + if (obj.getId() == RaidsThievingConstants.OPEN_EMPTY_CHEST) + { + ThievingChest chest = chests.get(obj.getWorldLocation()); + // We found a chest that could have poison + if (solver != null && chest.getChestId() != -1) + { + chest.setEmpty(true); + chest.setEverOpened(true); + solver.addEmptyChest(chest.getChestId()); + } + } + } + + + @Subscribe + public void onGraphicsObjectCreated(GraphicsObjectCreated event) + { + GraphicsObject obj = event.getGraphicsObject(); + if (obj.getId() == 184) + { + log.debug("Found poison splat"); + WorldPoint loc = WorldPoint.fromLocal(client, obj.getLocation()); + chests.get(loc).setPoison(true); + } + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + boolean setting = client.getVar(Varbits.IN_RAID) == 1; + + if (inRaidChambers != setting) + { + inRaidChambers = setting; + reset(); + } + + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("raidsthievingplugin")) + { + overlay.updateConfig(); + } + } + + private void reset() + { + chests.clear(); + batsFound = false; + solver = null; + mapper = null; + } + + public int numberOfEmptyChestsFound() + { + int total = 0; + for (ThievingChest chest : chests.values()) + { + if (chest.isEmpty()) + { + total++; + } + } + return total; + } + + + private boolean checkForBats() + { + for (ThievingChest chest : chests.values()) + { + if (chest.isEmpty() && !chest.isPoison()) + { + batsFound = true; + if (config.batFoundNotify()) + { + notifier.notify("Bats have been found!"); + } + return true; + } + } + return false; + } + + public int getChestId(WorldPoint worldPoint) + { + return chests.get(worldPoint).getChestId(); + } +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ThievingChest.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ThievingChest.java new file mode 100644 index 0000000000..05a58d554e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ThievingChest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019, Tim Lehner + * 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.raidsthieving; + +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.GameObject; +import net.runelite.api.coords.WorldPoint; + +/** + * Wrapper class for a GameObject that represents a chest in the thieving room of Chambers of Xeric. + */ +@Getter +public class ThievingChest +{ + /** + * If the chest has never been opened, it could have bats. + */ + @Setter + private boolean everOpened; + + /** + * If the chest is empty, it could have bats. + */ + @Setter + private boolean empty; + + /** + * If the chest contains a poison trap instead. + */ + @Setter + private boolean poison; + + + @Setter + private int chestId; + + private final WorldPoint localPoint; + private final InstancePoint instancePoint; + + /** + * Constructor for a ThievingChest object + * + * @param gameObject The gameobject thats corresponds with this trap. + */ + ThievingChest(GameObject gameObject, InstancePoint instancePoint) + { + this.everOpened = false; + this.poison = false; + this.empty = false; + localPoint = gameObject.getWorldLocation(); + this.instancePoint = instancePoint; + this.chestId = -1; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanConfig.java new file mode 100644 index 0000000000..20775b1d35 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanConfig.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018, Infinitay + * Copyright (c) 2018, Shaun Dreclin + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.rememberclan; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("rememberclan") +public interface RememberClanConfig extends Config +{ + @ConfigItem( + position = 1, + keyName = "clanname", + name = "Clan Name", + description = "Clanname to always remember" + ) + default String clanname() + { + return ""; + } + + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanPlugin.java new file mode 100644 index 0000000000..2b5dd54b35 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanPlugin.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018, Infinitay + * Copyright (c) 2018, Shaun Dreclin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.runelite.client.plugins.rememberclan; + +import com.google.inject.Provides; +import javax.inject.Inject; + +import net.runelite.api.*; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.vars.AccountType; +import net.runelite.client.chat.ChatColorType; +import net.runelite.client.chat.ChatMessageBuilder; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.chat.QueuedMessage; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; + +@PluginDescriptor( + name = "Remember Clan", + description = "Remember a specific clan!", + type = "utility", + enabledByDefault = false +) +public class RememberClanPlugin extends Plugin +{ + + @Inject + private Client client; + + @Inject + private RememberClanConfig config; + + @Inject + private ChatMessageManager chatMessageManager; + + private boolean loggingIn; + + @Provides + RememberClanConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(RememberClanConfig.class); + } + + @Subscribe + public void onGameTick(GameTick event) + { + client.setVar(VarClientStr.RECENT_CLAN_CHAT,config.clanname()); + + } + + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/stronghold/StrongholdAnswer.java b/runelite-client/src/main/java/net/runelite/client/plugins/stronghold/StrongholdAnswer.java new file mode 100644 index 0000000000..2146cd8708 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/stronghold/StrongholdAnswer.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019, FlaxOnEm + * 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.stronghold; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.runelite.api.widgets.Widget; + +import java.util.HashMap; +import java.util.Map; + +@Getter +@RequiredArgsConstructor +enum StrongholdAnswer { + PAIR_0("To pass you must answer me this: Hey adventurer!
You've been randomly selected for a prize of 1 year of
free membership! I'm just going to need some of your
account details so I can put it on your account!", "No way! I'm reporting you to Jagex!"), + PAIR_1("To pass you must answer me this: Can I leave my
account logged in while I'm out of the room?", "No."), + PAIR_2("To pass you must answer me this: How do I remove a
hijacker from my account?", "Use the Account Recovery System."), + PAIR_3("To pass you must answer me this: What do you do if
someone asks you for your password or bank PIN to
make you a player moderator?", "Don't give them the information and send an 'Abuse report'."), + PAIR_4("To pass you must answer me this: You're watching a
stream by someone claiming to be Jagex offering double
xp. What do you do?", "Report the stream as a scam. Real Jagex streams have a 'verified' mark."), + PAIR_5("To pass you must answer me this: My friend asks me
for my password so that he can do a difficult quest for
me. Do I give it to them?", "Don't give them my password."), + PAIR_6("To pass you must answer me this: Who can I give my
password to?", "Nobody."), + PAIR_7("To pass you must answer me this: How do I set up
two-factor authentication for my Old School RuneScape
account?", "Through account settings on oldschool.runescape.com."), + PAIR_8("To pass you must answer me this: What is an example
of a good bank PIN?", "The birthday of a famous person or event."), + PAIR_9("To pass you must answer me this: What should you do
if your real-life friend asks for your password so he
can check your stats?", "Don't give out your password to anyone. Not even close friends."), + PAIR_A("To pass you must answer me this: A player tells you to
search for a video online, click the link in the description
and comment on the forum post to win a cash prize.
What do you do?", "Report the player for phishing."), + PAIR_B("To pass you must answer me this: You have been
offered an opportunity to check out a free giveaway or
double XP signup via email or in game chat. What
should I do?", "Report the incident and do not click any links."), + PAIR_C("To pass you must answer me this: How do I set a
bank PIN?", "Talk to any banker."), + PAIR_D("To pass you must answer me this: What do I do if a
moderator asks me for my account details?", "Politely tell them no and then use the 'Report Abuse' button."), + PAIR_E("To pass you must answer me this: You are part way
through the Stronghold of Security when you have to
answer another question. After you answer the question,
you should...", "Read the text and follow the advice given."), + PAIR_F("To pass you must answer me this: Will Jagex prevent
me from saying my PIN in game?", "No."), + PAIR_G("that sound?", "No way! You'll just take my gold for your own! Reported!"), + PAIR_H("To pass you must answer me this: What should I do if
I receive an email asking me to verify my identity or
Account details due to suspicious activity?", "Don't click any links, forward the email to reportphishing@jagex.com."), + PAIR_I("To pass you must answer me this: A website claims that
they can make me a player moderator. What should I
do?", "Inform Jagex by emailing reportphishing@jagex.com."), + PAIR_J("react?", "Don't share your information and report the player."), + PAIR_K("To pass you must answer me this: What do you do if
someone asks you for your password or bank PIN to
make you a member for free?", "Don't tell them anything and click the 'Report Abuse' button."), + PAIR_L("To pass you must answer me this: Is it OK to buy an
Old School RuneScape account?", "No, you should never buy an account."), + PAIR_M("To pass you must answer me this: You have been
offered an opportunity to check out a free giveaway or
double XP signup via social media or stream. What
should I do?", "Report the incident and do not click any links."), + PAIR_N("To pass you must answer me this: Where is it safe to
use my Old School RuneScape password?", "Only on the Old School RuneScape website."), + PAIR_O("To pass you must answer me this: What is the best
way to secure your account?", "Authenticator and two-step login on my registered email."), + PAIR_P("To pass you must answer me this: Who is it ok to
share my account with?", "Nobody."), + PAIR_Q("To pass you must answer me this: What should you do
if another player messages you recommending a website
to purchase items and/or gold?", "Do not visit the website and report the player who messaged you."), + PAIR_R("To pass you must answer me this: Whose responsibility
is it to keep your account secure?", "Me."), + PAIR_S("To pass you must answer me this: Is it safe to pay
someone to level your account?", "No, you should never allow anyone to level your account."), + PAIR_T("To pass you must answer me this: What do I do if my
account is compromised?", "Secure my device and reset my password."), + PAIR_U("respond?", "Decline the offer and report that player."), + PAIR_V("To pass you must answer me this: A player says that
Jagex prevents you from saying your password
backwards in game. What do you do?", "Don't type in my password backwards and report the player."), + PAIR_W("To pass you must answer me this: What do I do if I
think I have a keylogger or virus?", "Virus scan my device then change my password."), + PAIR_X("To pass you must answer me this: What is the best
security step you can take to keep your registered
email secure?", "Set up 2 step authentication with my email provider."); + + static final Map MATCHES = new HashMap<>(); + + static { + for (StrongholdAnswer strongholdAnswer : StrongholdAnswer.values()) { + MATCHES.put(strongholdAnswer.question, strongholdAnswer.answer); + } + } + + private final String question; + private final String answer; + + static Widget findCorrect(final String question, final Widget[] widgets) { + final String s = MATCHES.get(question); + + for (Widget widget: widgets) { + if (widget != null && widget.getText().equals(s)) + return widget; + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/stronghold/StrongholdPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/stronghold/StrongholdPlugin.java new file mode 100644 index 0000000000..cae099dc1e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/stronghold/StrongholdPlugin.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2019, FlaxOnEm + * 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.stronghold; + +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.events.ClientTick; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.ColorUtil; + +import javax.inject.Inject; +import java.awt.Color; + +@PluginDescriptor( + name = "Stronghold", + description = "Highlights the correct answer to Stronghold of Security questions", + tags = {"stronghold", "security", "overlay", "answer", "highlight"}, + type = "utility" +) +@Slf4j +public class StrongholdPlugin extends Plugin { + private static final Color ANSWER_COLOR = new Color(230, 0, 230); + + @Inject + private Client client; + + private boolean queueNPCDialogue; + private boolean queueNPCOption; + private String questionCache; + + @Subscribe + public void onWidgetLoaded(WidgetLoaded widgetLoaded) { + switch (widgetLoaded.getGroupId()) { + case WidgetID.DIALOG_NPC_GROUP_ID: + queueNPCDialogue = true; + break; + case WidgetID.DIALOG_OPTION_GROUP_ID: + queueNPCOption = true; + break; + } + } + + @Subscribe + public void onClientTick(ClientTick t) { + if (queueNPCDialogue) { + queueNPCDialogue = false; + onNPCDialogue(); + } + if (queueNPCOption) { + queueNPCOption = false; + onNPCOption(); + } + } + + private void onNPCDialogue() { + final Widget debugWidget = client.getWidget(WidgetInfo.DIALOG_NPC_TEXT); + final String npcText = debugWidget.getText(); + if (StrongholdAnswer.MATCHES.containsKey(npcText)) + questionCache = npcText; + } + + private void onNPCOption() { + if (questionCache == null) + return; + + final Widget optionsWidget = client.getWidget(WidgetInfo.DIALOG_OPTION); + if (optionsWidget == null) + return; + + final Widget[] widgets = optionsWidget.getParent().getChildren(); + + final Widget answerWidget = StrongholdAnswer.findCorrect(questionCache, widgets); + questionCache = null; + if (answerWidget == null) + return; + + final String answerText = answerWidget.getText(); + answerWidget.setText(ColorUtil.wrapWithColorTag(answerText, ANSWER_COLOR)); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorConfig.java new file mode 100644 index 0000000000..c665baaa70 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorConfig.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2018, Andrew EP | ElPinche256 + * 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.warindicators; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("warIndicators") + +public interface WarIndicatorConfig extends Config +{ + @ConfigItem( + position = 0, + keyName = "highLightCallers", + name = "Highlight Callers", + description = "Highlight listed caller(s)" + ) + default boolean highLightCallers() + { + return true; + } + + @ConfigItem( + position = 1, + keyName = "callerColor", + name = "Caller(s) Color", + description = "Color to highlight caller's name" + ) + default Color getCallerColor() + { + return new Color(36, 255, 237); + } + + @ConfigItem( + position = 2, + keyName = "callerMinimap", + name = "Callers on Minimap", + description = "Show your caller(s) on the minimap" + ) + default boolean callerMinimap() + { + return false; + } + + + @ConfigItem( + position = 3, + keyName = "callerTile", + name = "Show Caller's Tile", + description = "Show the tile your target is standing on" + ) + default boolean callerTile() + { + return false; + } + + @ConfigItem( + position = 4, + keyName = "activeCallers", + name = "Callers", + description = "Adds a user to your caller list. Format: (caller), (caller)" + ) + default String getActiveCallers() + { + return ""; + } + + @ConfigItem( + position = 5, + keyName = "activeCallers", + name = "", + description = "" + ) + void setActiveCallers(String key); + + + @ConfigItem( + position = 6, + keyName = "highlightSnipes", + name = "Highlight Targets", + description = "Highlight listed target(s)" + ) + default boolean highlightSnipes() + { + return true; + } + + @ConfigItem( + position = 7, + keyName = "snipeColor", + name = "Target(s) Color", + description = "Color to highlight target name" + ) + default Color getSnipeColor() + { + return new Color(255, 0, 0); + } + + @ConfigItem( + position = 8, + keyName = "snipeMinimap", + name = "Targets on Minimap", + description = "Show your target on the minimap" + ) + default boolean snipeMinimap() + { + return false; + } + + @ConfigItem( + position = 9, + keyName = "snipeTile", + name = "Show Target's Tile", + description = "Show the tile your target is standing on" + ) + default boolean snipeTile() + { + return false; + } + + @ConfigItem( + position = 10, + keyName = "targetedSnipes", + name = "Targets", + description = "Adds a user to your snipe list. Format: (target), (target)" + ) + default String getTargetedSnipes() + { + return ""; + } + + @ConfigItem( + position = 11, + keyName = "targetedSnipes", + name = "", + description = "" + ) + + void setTargetedSnipe(String key); +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorMiniMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorMiniMapOverlay.java new file mode 100644 index 0000000000..d7fa0cc92a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorMiniMapOverlay.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018, Andrew EP | ElPinche256 + * 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.warindicators; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import javax.inject.Singleton; +import net.runelite.api.Player; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; +import org.apache.commons.lang3.ArrayUtils; + +@Singleton +public class WarIndicatorMiniMapOverlay extends Overlay +{ + private final WarIndicatorService warIndicatorService; + private final WarIndicatorConfig config; + + @Inject + private WarIndicatorMiniMapOverlay(WarIndicatorConfig config, WarIndicatorService warIndicatorService) + { + this.config = config; + this.warIndicatorService = warIndicatorService; + setLayer(OverlayLayer.ABOVE_WIDGETS); + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + } + + @Override + public Dimension render(Graphics2D graphics) + { + warIndicatorService.forEachPlayer((player, color) -> renderPlayerOverlay(graphics, player, color)); + return null; + } + + private void renderPlayerOverlay(Graphics2D graphics, Player actor, Color color) + { + final String name = actor.getName().replace('\u00A0', ' '); + final net.runelite.api.Point minimapLocation = actor.getMinimapLocation(); + + String[] callers = config.getActiveCallers().split(", "); + String[] targets = config.getTargetedSnipes().split(", "); + + if (config.callerMinimap() && ArrayUtils.contains(callers, actor.getName())) + { + if (minimapLocation != null) + { + OverlayUtil.renderTextLocation(graphics, minimapLocation, name, color); + } + } + + if (config.snipeMinimap() && ArrayUtils.contains(targets, actor.getName())) + { + if (minimapLocation != null) + { + OverlayUtil.renderTextLocation(graphics, minimapLocation, name, color); + } + } + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorOverlay.java new file mode 100644 index 0000000000..7ca7cc20c0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorOverlay.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018, Andrew EP | ElPinche256 + * 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.warindicators; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.apache.commons.lang3.ArrayUtils; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; + +@Singleton +public class WarIndicatorOverlay extends Overlay +{ + private final WarIndicatorService warIndicatorService; + private final WarIndicatorConfig config; + + @Inject + private WarIndicatorOverlay(WarIndicatorConfig config, WarIndicatorService warIndicatorService) + { + this.config = config; + this.warIndicatorService = warIndicatorService; + setLayer(OverlayLayer.ABOVE_SCENE); + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + } + + @Override + public Dimension render(Graphics2D graphics) + { + warIndicatorService.forEachPlayer((player, color) -> renderPlayerOverlay(graphics, player, color)); + return null; + } + + private void renderPlayerOverlay(Graphics2D graphics, Player actor, Color color) + { + if (!config.highlightSnipes() && !config.highLightCallers()) + { + return; + } + + Polygon poly = actor.getCanvasTilePoly(); + String[] callers = config.getActiveCallers().split(", "); + String[] targets = config.getTargetedSnipes().split(", "); + + if (config.callerTile() && ArrayUtils.contains(callers, actor.getName())) + { + if (poly != null) + { + OverlayUtil.renderPolygon(graphics, poly, color); + } + } + + if (config.snipeTile() && ArrayUtils.contains(targets, actor.getName())) + { + if (poly != null) + { + OverlayUtil.renderPolygon(graphics, poly, color); + } + } + + String name = actor.getName().replace('\u00A0', ' '); + int offset = actor.getLogicalHeight() + 40; + Point textLocation = actor.getCanvasTextLocation(graphics, name, offset); + + if (textLocation != null) + { + OverlayUtil.renderTextLocation(graphics, textLocation, name, color); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorPlugin.java new file mode 100644 index 0000000000..9dc378547c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorPlugin.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2018, Andrew EP | ElPinche256 + * 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.warindicators; + +import com.google.common.collect.Sets; +import com.google.common.eventbus.Subscribe; +import com.google.inject.Provides; +import java.awt.Color; +import java.util.Collection; +import javax.inject.Inject; +import org.apache.commons.lang3.ArrayUtils; +import net.runelite.api.Client; +import static net.runelite.api.MenuAction.FOLLOW; +import static net.runelite.api.MenuAction.ITEM_USE_ON_PLAYER; +import static net.runelite.api.MenuAction.PLAYER_EIGTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FIFTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FIRST_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FOURTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SECOND_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SEVENTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SIXTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_THIRD_OPTION; +import static net.runelite.api.MenuAction.SPELL_CAST_ON_PLAYER; +import static net.runelite.api.MenuAction.TRADE; +import net.runelite.api.MenuEntry; +import net.runelite.api.Player; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "War calling indicators", + description = "War War War.", + tags = {"skill", "total", "max", "PVP"}, + type = "PVP", + enabledByDefault = false +) +public class WarIndicatorPlugin extends Plugin +{ + @Inject + private OverlayManager overlayManager; + + @Inject + private WarIndicatorConfig config; + + @Inject + private WarIndicatorOverlay warIndicatorOverlay; + + @Inject + private WarIndicatorMiniMapOverlay warIndicatorMiniMapOverlay; + + @Inject + private Client client; + + @Provides + WarIndicatorConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(WarIndicatorConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(warIndicatorOverlay); + overlayManager.add(warIndicatorMiniMapOverlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(warIndicatorOverlay); + overlayManager.remove(warIndicatorMiniMapOverlay); + } + + @Subscribe + public void onMenuEntryAdd(MenuEntryAdded menuEntryAdded) + { + int type = menuEntryAdded.getType(); + + if (type >= 2000) + { + type -= 2000; + } + + int identifier = menuEntryAdded.getIdentifier(); + if (type == FOLLOW.getId() || type == TRADE.getId() + || type == SPELL_CAST_ON_PLAYER.getId() + || type == ITEM_USE_ON_PLAYER.getId() + || type == PLAYER_FIRST_OPTION.getId() + || type == PLAYER_SECOND_OPTION.getId() + || type == PLAYER_THIRD_OPTION.getId() + || type == PLAYER_FOURTH_OPTION.getId() + || type == PLAYER_FIFTH_OPTION.getId() + || type == PLAYER_SIXTH_OPTION.getId() + || type == PLAYER_SEVENTH_OPTION.getId() + || type == PLAYER_EIGTH_OPTION.getId()) + { + Player[] players = client.getCachedPlayers(); + Player player = null; + String player2 = null; + + String[] callers = config.getActiveCallers().split(", "); + String[] targets = config.getTargetedSnipes().split(", "); + + if (identifier >= 0 && identifier < players.length) + { + player = players[identifier]; + player2 = players[identifier].getName(); + } + + if (player == null) + { + return; + } + + Color color = null; + + if (config.highLightCallers() && ArrayUtils.contains(callers, player2)) + { + color = config.getCallerColor(); + } + + if (config.highlightSnipes() && ArrayUtils.contains(targets, player2)) + { + color = config.getSnipeColor(); + } + + if (color != null) + { + MenuEntry[] menuEntries = client.getMenuEntries(); + MenuEntry lastEntry = menuEntries[menuEntries.length - 1]; + String target = lastEntry.getTarget(); + + int idx = target.indexOf('>'); + if (idx != -1) + { + target = target.substring(idx + 1); + } + + lastEntry.setTarget("" + target); + client.setMenuEntries(menuEntries); + } + + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorService.java b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorService.java new file mode 100644 index 0000000000..cb6c8127b5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorService.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018, Andrew EP | ElPinche256 + * 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.warindicators; + +import net.runelite.api.Client; +import net.runelite.api.Player; +import javax.inject.Inject; +import javax.inject.Singleton; +import java.awt.*; +import java.util.function.BiConsumer; + +@Singleton +public class WarIndicatorService +{ + private final Client client; + private final WarIndicatorConfig config; + + @Inject + private WarIndicatorService(Client client, WarIndicatorConfig config) + { + this.config = config; + this.client = client; + } + + public void forEachPlayer(final BiConsumer consumer) + { + if (!config.highlightSnipes() && !config.highLightCallers()) + { + return; + } + + if (config.highlightSnipes()) + { + for (Player player : client.getPlayers()) + { + if (player == null || player.getName() == null) + { + continue; + } + + String[] targets = config.getTargetedSnipes().split(", "); + + if (targets == null) + { + return; + } + + for (int i = 0; i < targets.length; i++) + { + if (player.getName().equalsIgnoreCase(targets[i])) + { + consumer.accept(player, config.getSnipeColor()); + } + } + } + } + + if (config.highLightCallers()) + { + for (Player player : client.getPlayers()) + { + if (player == null || player.getName() == null) + { + continue; + } + + String[] callers = config.getActiveCallers().split(", "); + + if (callers == null) + { + return; + } + + for (int i = 0; i < callers.length; i++) + { + if (player.getName().equalsIgnoreCase(callers[i])) + { + consumer.accept(player, config.getCallerColor()); + } + } + } + } + } +}