diff --git a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java index d99a7b2aaa..06cab49768 100644 --- a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java +++ b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java @@ -77,6 +77,7 @@ public class ProjectileID public static final int DEMONIC_GORILLA_BOULDER = 856; public static final int XARPUS_ACID = 1555; + public static final int CERB_FIRE = 1247; /** * missing: marble gargoyle, superior dark beast @@ -97,5 +98,5 @@ public class ProjectileID public static final int HYDRA_POISON = 1644; public static final int HYDRA_LIGHTNING = 1664; public static final int HYDRA_LIGHTNING_2 = 1665; - public static final int DRAKE_BREATH = 1637; + public static final int DRAKE_BREATH = 1637; } diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java index f88cba4e3f..609af8a704 100644 --- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java +++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java @@ -94,6 +94,15 @@ public final class ScriptID * Builds the chatbox input widget */ public static final int CHAT_PROMPT_INIT = 223; + + /** + * Joins a clan chat + * + * + */ + public static final int FORCE_JOIN_CC = 437; /** * Displays the game messages when clicking on an item inside the Items Kept on Death interface diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index ddd164c7f0..3af4961819 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -51,11 +51,6 @@ - - net.runelit - flexo - 1.0.2 - org.slf4j slf4j-api diff --git a/runelite-client/src/main/java/net/runelite/client/flexo/Flexo.java b/runelite-client/src/main/java/net/runelite/client/flexo/Flexo.java new file mode 100644 index 0000000000..3427279226 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/flexo/Flexo.java @@ -0,0 +1,282 @@ +/* + * + * Copyright (c) 2019, Zeruth + * 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. + * + */ + +/* +Modified java.awt.Robot for use with RuneLitePlus. Hopefully we can make it stand far apart. +Uses +https://github.com/JoonasVali/NaturalMouseMotion +for mouse motion. + */ + +package net.runelite.client.flexo; + +import com.github.joonasvali.naturalmouse.api.MouseMotionFactory; +import net.runelite.api.Client; +import net.runelite.client.ui.ClientUI; +import sun.awt.ComponentFactory; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.peer.RobotPeer; +import java.util.Random; +import java.util.logging.Logger; + +public class Flexo extends Robot { + public ThreadGroup flexoThreads = new ThreadGroup("flexo"); + public static boolean isActive; + public static double scale; + public static Client client; + public static ClientUI clientUI; + public static int fixedWidth = 765; + public static int fixedHeight = 503; + public static boolean isStretched; + public static int minDelay = 45; + public static MouseMotionFactory currentMouseMotionFactory; + public boolean pausedIndefinitely = false; + private Thread holdKeyThread; + private RobotPeer peer; + + public Flexo() throws AWTException { + if (GraphicsEnvironment.isHeadless()) { + throw new AWTException("headless environment"); + } + init(GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice()); + } + + private void init(GraphicsDevice screen) throws AWTException { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (toolkit instanceof ComponentFactory) { + peer = ((ComponentFactory)toolkit).createRobot(this, screen); + RobotDisposer disposer = new RobotDisposer(peer); + sun.java2d.Disposer.addRecord(anchor, disposer); + } + } + + private transient Object anchor = new Object(); + + static class RobotDisposer implements sun.java2d.DisposerRecord { + private final RobotPeer peer; + private RobotDisposer(RobotPeer peer) { + this.peer = peer; + } + public void dispose() { + if (peer != null) { + peer.dispose(); + } + } + } + + private void pauseMS(int delayMS) { + long initialMS = System.currentTimeMillis(); + while (System.currentTimeMillis()5) { + Logger.getAnonymousLogger().warning("Invalid mouse button ID. please use 1-5."); + return; + } + peer.mousePress(InputEvent.getMaskForButton(buttonID)); + this.delay(getMinDelay()); + } + + public synchronized void mousePressAndRelease(int buttonID) { + if (buttonID<1 || buttonID >5) { + Logger.getAnonymousLogger().warning("Invalid mouse button ID. please use 1-5."); + return; + } + peer.mousePress(InputEvent.getMaskForButton(buttonID)); + this.delay(getMinDelay()); + peer.mouseRelease(InputEvent.getMaskForButton(buttonID)); + this.delay(getMinDelay()); + } + + //TODO: Symbols are nut supported at this time + public synchronized void typeMessage(String message) { + + Random r = new Random(); + char[] charArray = message.toCharArray(); + for (char c : charArray) { + keyPress(KeyEvent.getExtendedKeyCodeForChar(c)); + this.delay(93+r.nextInt(getMinDelay())); + } + keyPress(KeyEvent.VK_ENTER); + this.delay(93+r.nextInt(getMinDelay())); + ClientUI.allowInput = true; + } + + + + @Override + public synchronized void mouseRelease(int buttonID) { + if (buttonID<1 || buttonID >5) { + Logger.getAnonymousLogger().warning("Invalid mouse button ID. please use 1-5."); + return; + } + peer.mouseRelease(InputEvent.getMaskForButton(buttonID)); + this.delay(getMinDelay()); + } + + private int getMinDelay() { + Random random = new Random(); + int random1 = random.nextInt(minDelay); + if (random1 < minDelay/2) + random1 = random.nextInt(minDelay/2) + minDelay/2+random.nextInt(minDelay/2); + return random1; + } + + private int getWheelDelay() { + Random random = new Random(); + int random1 = random.nextInt(minDelay); + if (random1 < minDelay/2) + random1 = random.nextInt(minDelay/2) + minDelay/2+random.nextInt(minDelay/2); + return random1; + } + + /** + * Rotates the scroll wheel on wheel-equipped mice. + * + * @param wheelAmt number of "notches" to move the mouse wheel + * Negative values indicate movement up/away from the user, + * positive values indicate movement down/towards the user. + * + * @since 1.4 + */ + @Override + public synchronized void mouseWheel(int wheelAmt) { + for (int i : new int[wheelAmt]) { + peer.mouseWheel(wheelAmt); + this.delay(getWheelDelay()); + } + } + + /** + * Presses a given key. The key should be released using the + * keyRelease method. + *

+ * Key codes that have more than one physical key associated with them + * (e.g. KeyEvent.VK_SHIFT could mean either the + * left or right shift key) will map to the left key. + * + * @param keycode Key to press (e.g. KeyEvent.VK_A) + * @throws IllegalArgumentException if keycode is not + * a valid key + * @see #keyRelease(int) + * @see java.awt.event.KeyEvent + */ + @Override + public synchronized void keyPress(int keycode) { + peer.keyPress(keycode); + this.delay(getMinDelay()); + } + + @Override + public synchronized void keyRelease(int keycode) { + peer.keyRelease(keycode); + this.delay(getMinDelay()); + } + + public synchronized void holdKey(int keycode, int timeMS) { + new Thread(() -> { + peer.keyPress(keycode); + long startTime = System.currentTimeMillis(); + while ((startTime + timeMS) > System.currentTimeMillis()) { } + peer.keyRelease(keycode); + this.delay(getMinDelay()); + }).start(); + } + + public synchronized void holdKeyIndefinitely(int keycode) { + holdKeyThread = new Thread(() -> { + pausedIndefinitely = true; + peer.keyPress(keycode); + while (pausedIndefinitely) { + try { + holdKeyThread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + peer.keyRelease(keycode); + this.delay(getMinDelay()); + }); + holdKeyThread.start(); + + } + + @Override + public Color getPixelColor(int x, int y) { + Color color = new Color(peer.getRGBPixel(x, y)); + return color; + } + + @Override + public void delay(int ms) { + pauseMS(ms); + } + + public int determineHorizontalOffset() { + return clientUI.getCanvasOffset().getX(); + } + + public int determineVerticalOffset() { + return clientUI.getCanvasOffset().getY(); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/flexo/FlexoMouse.java b/runelite-client/src/main/java/net/runelite/client/flexo/FlexoMouse.java new file mode 100644 index 0000000000..70bbf51ba6 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/flexo/FlexoMouse.java @@ -0,0 +1,190 @@ + +/* + * + * Copyright (c) 2019, Zeruth + * 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.flexo; + +import net.runelite.client.ui.ClientUI; + +import java.awt.*; +import java.util.Random; +import java.util.logging.Logger; + +public class FlexoMouse { + + /* + Should pass unstretched coords, handles all conversions here. + */ + public static Point getClickPoint(Rectangle rect) + { + if (rect!=null) { + Random r = new Random(); + int x = -1; + int y = -1; + x = rect.x+r.nextInt(rect.width); + y = rect.y+r.nextInt(rect.height); + + if (Flexo.isStretched) { + double wScale; + double hScale; + + if (Flexo.client.isResized()) { + wScale = (Flexo.client.getStretchedDimensions().width / Flexo.client.getRealDimensions().width); + hScale = (Flexo.client.getStretchedDimensions().height / Flexo.client.getRealDimensions().height); + int newX = (int)(x*wScale); + int newY = (int)(y*hScale); + if (newX>0 && newX< ClientUI.frame.getWidth()) { + if (newY>0 && newY< ClientUI.frame.getHeight()) { + return new Point(newX, newY); + } + } + Logger.getAnonymousLogger().warning("[RuneLit]Flexo - Off screen point attempted. Split the step, or rotate the screen."); + return null; + } else { + if (x>0 && x< ClientUI.frame.getWidth()) { + if (y>0 && y< ClientUI.frame.getHeight()) { + return new Point(x, y); + } + } + Logger.getAnonymousLogger().warning("[RuneLit]Flexo - Off screen point attempted. Split the step, or rotate the screen."); + return null; + } + + } else if (!Flexo.client.isResized()) { + int fixedWidth = 765; + int widthDif = ClientUI.frame.getWidth(); + + if (ClientUI.pluginToolbar.isVisible()) { + widthDif -= ClientUI.pluginToolbar.getWidth(); + } + if (ClientUI.pluginPanel!=null) + widthDif -= ClientUI.pluginPanel.getWidth(); + + widthDif -= fixedWidth; + if (x+(widthDif/2)>0 && x+(widthDif/2)< ClientUI.frame.getWidth()) { + if (y>0 && y< ClientUI.frame.getHeight()) { + return new Point(x, y); + } + } + Logger.getAnonymousLogger().warning("[RuneLit]Flexo - Off screen point attempted. Split the step, or rotate the screen."); + return null; + } + else { + if (x>0 && x< ClientUI.frame.getWidth()) { + if (y>0 && y< ClientUI.frame.getHeight()) { + return new Point(x, y); + } + } + Logger.getAnonymousLogger().warning("[RuneLit]Flexo - Off screen point attempted. Split the step, or rotate the screen."); + return null; + } + } + return null; + } + + public static Rectangle getClickArea(Rectangle rect) + { + if (Flexo.isStretched) + { + double wScale; + double hScale; + + if (Flexo.client.isResized()) { + wScale = (Flexo.client.getStretchedDimensions().width / Flexo.client.getRealDimensions().width); + hScale = (Flexo.client.getStretchedDimensions().height / Flexo.client.getRealDimensions().height); + } else { + wScale = ((double) Flexo.client.getStretchedDimensions().width) / Flexo.fixedWidth; + hScale = ((double) Flexo.client.getStretchedDimensions().height) / Flexo.fixedHeight; + } + + int xPadding = (int)rect.getWidth()/5; + int yPadding = (int)rect.getHeight()/5; + Random r = new Random(); + Rectangle clickRect = new Rectangle(); + clickRect.width = rect.width-xPadding*2; + clickRect.height = rect.height-yPadding*2; + clickRect.x = rect.x+xPadding; + clickRect.y = rect.y+yPadding; + if (clickRect.width>0&&clickRect.height>0) { + int x = clickRect.x+r.nextInt(clickRect.width); + int y = clickRect.y+r.nextInt(clickRect.height); + double tScale = 1 + (Flexo.scale / 100); + + if (Flexo.client.isResized()) { + return new Rectangle((int)(clickRect.x * wScale), (int)(clickRect.y * wScale), (int)(clickRect.width * wScale), (int)(clickRect.getHeight()*hScale)); + } else { + return new Rectangle((int)(clickRect.x), (int)(clickRect.y), (int)(clickRect.width), (int)(clickRect.getHeight())); + } + } + + } + //Fixed, not stretched + else if (!Flexo.client.isResized()) { + int fixedWidth = 765; + int widthDif = ClientUI.frame.getWidth(); + + if (ClientUI.pluginToolbar.isVisible()) { + widthDif -= ClientUI.pluginToolbar.getWidth(); + } + if (ClientUI.pluginPanel!=null) + widthDif -= ClientUI.pluginPanel.getWidth(); + + widthDif -= fixedWidth; + int xPadding = (int)rect.getWidth()/5; + int yPadding = (int)rect.getHeight()/5; + Random r = new Random(); + Rectangle clickRect = new Rectangle(); + clickRect.width = rect.width-xPadding; + clickRect.height = rect.height-yPadding; + clickRect.x = rect.x+xPadding; + clickRect.y = rect.y+yPadding; + if (clickRect.height>0&&clickRect.width>0) { + int x = clickRect.x + r.nextInt(clickRect.width); + int y = clickRect.y + r.nextInt(clickRect.height); + return new Rectangle((int) (clickRect.x), (int) (clickRect.y), (int) (clickRect.width), (int) (clickRect.getHeight())); + } + } + //Resizable, not stretched + else { + int xPadding = (int)rect.getWidth()/5; + int yPadding = (int)rect.getHeight()/5; + Random r = new Random(); + Rectangle clickRect = new Rectangle(); + clickRect.width = rect.width-xPadding*2; + clickRect.height = rect.height-yPadding*2; + clickRect.x = rect.x+xPadding; + clickRect.y = rect.y+yPadding; + if (clickRect.height>0&&clickRect.width>0) { + int x = clickRect.x+r.nextInt(clickRect.width); + int y = clickRect.y+r.nextInt(clickRect.height); + return new Rectangle((int)(clickRect.x), (int)(clickRect.y), (int)(clickRect.width), (int)(clickRect.getHeight())); + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java index b7111848a2..1fb9a72b29 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java @@ -107,11 +107,15 @@ public enum AoeProjectileInfo */ ADDY_DRAG_POISON(ProjectileID.ADDY_DRAG_POISON, 1), - /** - * the Breath of the Drake - */ - - DRAKE_BREATH(ProjectileID.DRAKE_BREATH, 1); + /** + * the Breath of the Drake + */ + DRAKE_BREATH(ProjectileID.DRAKE_BREATH, 1), + + /** + * Cerbs fire + */ + CERB_FIRE(ProjectileID.CERB_FIRE, 2); private static final Map map = new HashMap<>(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningConfig.java index 42e7b5efc8..3475d9f7b9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningConfig.java @@ -253,14 +253,25 @@ public interface AoeWarningConfig extends Config return true; } - @ConfigItem( - keyName = "drake", - name = "Drakes Breath", - description = "Configures if Drakes Breath tile markers are displayed" - ) - default boolean isDrakeEnabled() { - return true; - } + @ConfigItem( + keyName = "drake", + name = "Drakes Breath", + description = "Configures if Drakes Breath tile markers are displayed" + ) + default boolean isDrakeEnabled() + { + return true; + } + + @ConfigItem( + keyName = "cerbFire", + name = "Cerberus Fire", + description = "Configures if Cerberus fire tile markers are displayed" + ) + default boolean isCerbFireEnabled() + { + return true; + } @ConfigItem( keyName = "delay", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java index feaa5f27f6..9971635bb4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java @@ -300,8 +300,10 @@ public class AoeWarningPlugin extends Plugin return config.isXarpusEnabled(); case ADDY_DRAG_POISON: return config.addyDrags(); - case DRAKE_BREATH: - return config.isDrakeEnabled(); + case DRAKE_BREATH: + return config.isDrakeEnabled(); + case CERB_FIRE: + return config.isCerbFireEnabled(); } return false; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/blackjack/BlackjackPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/blackjack/BlackjackPlugin.java new file mode 100644 index 0000000000..dd71c6e89b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/blackjack/BlackjackPlugin.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.blackjack; + +import com.google.inject.Binder; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.*; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Authors gazivodag longstreet + */ +@PluginDescriptor( + name = "Blackjack", + description = "Uses chat messages and tick timers instead of animations to read", + tags = {"blackjack", "thieving"}, + type = PluginType.UTILITY +) +@Singleton +@Slf4j +public class BlackjackPlugin extends Plugin { + + @Inject + Client client; + + private static long timeSinceKnockout; + private static long timeSinceAggro; + + @Getter + private static long currentGameTick; + + @Override + public void configure(Binder binder) { + } + + @Override + protected void startUp() throws Exception { + currentGameTick = 0; + } + + @Override + protected void shutDown() throws Exception { + currentGameTick = 0; + } + + @Subscribe + public void onGameTick(GameTick gameTick) { + currentGameTick++; + } + + + @Subscribe + public void onChatMessage(ChatMessage chatMessage) { + if (chatMessage.getType() == ChatMessageType.SPAM) { + if (chatMessage.getMessage().equals("You smack the bandit over the head and render them unconscious.")) { + timeSinceKnockout = getCurrentGameTick(); + } + if (chatMessage.getMessage().equals("Your blow only glances off the bandit's head.")) { + timeSinceAggro = getCurrentGameTick(); + } + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded menuEntryAdded) { + String target = menuEntryAdded.getTarget().toLowerCase(); + if ((target.contains("bandit") | target.contains("menaphite thug"))) { + Quest quest = Quest.THE_FEUD; + if (quest.getState(client) == QuestState.FINISHED) { + if (currentGameTick < (timeSinceKnockout + 4)) { + stripSpecificEntries("pickpocket"); + } + if (currentGameTick < (timeSinceAggro + 4)) { + stripSpecificEntries("pickpocket"); + } + stripSpecificEntries("knock-out"); + } + } + } + + private void stripSpecificEntries(String exceptFor) { + MenuEntry[] currentEntires = client.getMenuEntries(); + MenuEntry[] newEntries = new MenuEntry[2]; + + for (MenuEntry currentEntry : currentEntires) { + if (currentEntry.getOption().toLowerCase().equals(exceptFor.toLowerCase())) { + newEntries[1] = currentEntry; + } + if (currentEntry.getOption().toLowerCase().equals("lure")) { + newEntries[0] = currentEntry; + } + } + + if (newEntries[0] != null && newEntries[1] != null) { + client.setMenuEntries(newEntries); + } + } + + +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java index 388ebb300a..44ff821be8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java @@ -70,6 +70,8 @@ import net.runelite.http.api.hiscore.HiscoreSkill; import net.runelite.http.api.hiscore.SingleHiscoreSkillResult; import net.runelite.http.api.hiscore.Skill; import net.runelite.http.api.item.ItemPrice; +import net.runelite.http.api.osbuddy.OSBGrandExchangeClient; +import net.runelite.http.api.osbuddy.OSBGrandExchangeResult; import org.apache.commons.text.WordUtils; @PluginDescriptor( @@ -98,6 +100,7 @@ public class ChatCommandsPlugin extends Plugin private final HiscoreClient hiscoreClient = new HiscoreClient(); private final ChatClient chatClient = new ChatClient(); + private final OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient(); private boolean logKills; private HiscoreEndpoint hiscoreEndpoint; // hiscore endpoint for current player @@ -597,19 +600,31 @@ public class ChatCommandsPlugin extends Plugin if (!results.isEmpty()) { ItemPrice item = retrieveFromList(results, search); + OSBGrandExchangeResult osbresult = new OSBGrandExchangeResult(); + try + { + osbresult = CLIENT.lookupItem(item.getId()); + } + catch (IOException e) + { + e.printStackTrace(); + } int itemId = item.getId(); int itemPrice = item.getPrice(); - final ChatMessageBuilder builder = new ChatMessageBuilder() - .append(ChatColorType.NORMAL) - .append("Price of ") - .append(ChatColorType.HIGHLIGHT) - .append(item.getName()) - .append(ChatColorType.NORMAL) - .append(": GE average ") - .append(ChatColorType.HIGHLIGHT) - .append(StackFormatter.formatNumber(itemPrice)); + final ChatMessageBuilder builder = new ChatMessageBuilder(); + builder.append(ChatColorType.NORMAL); + builder.append(ChatColorType.HIGHLIGHT); + builder.append(item.getName()); + builder.append(ChatColorType.NORMAL); + builder.append(": GE "); + builder.append(ChatColorType.HIGHLIGHT); + builder.append(StackFormatter.formatNumber(itemPrice)); + builder.append(ChatColorType.NORMAL); + builder.append(": OSB "); + builder.append(ChatColorType.HIGHLIGHT); + builder.append(StackFormatter.formatNumber(osbresult.getOverall_average())); ItemComposition itemComposition = itemManager.getItemComposition(itemId); if (itemComposition != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java index 1ec94fad94..8e2f32f2ba 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java @@ -1,420 +1,633 @@ +/* + * Copyright (c) 2017, Devin French + * Copyright (c) 2019, Adam + * Copyright (c) 2018, trimbe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package net.runelite.client.plugins.clanchat; -import net.runelite.client.plugins.*; -import net.runelite.client.game.*; -import net.runelite.client.callback.*; - +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.inject.Provides; +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; -import java.util.Objects; -import java.util.concurrent.*; -import net.runelite.client.config.*; -import com.google.inject.*; -import net.runelite.client.util.*; -import net.runelite.client.eventbus.*; -import com.google.common.base.*; -import net.runelite.api.widgets.*; -import net.runelite.client.ui.*; -import net.runelite.client.chat.*; -import java.awt.*; -import net.runelite.api.*; -import net.runelite.api.events.*; -import com.google.common.collect.*; -import java.util.*; -import java.util.function.*; -import net.runelite.client.ui.overlay.infobox.*; -import java.awt.image.*; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import javax.inject.Inject; +import net.runelite.api.ChatLineBuffer; +import net.runelite.api.ChatMessageType; +import net.runelite.api.ClanMember; +import net.runelite.api.ClanMemberRank; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.MessageNode; +import net.runelite.api.Opcodes; +import net.runelite.api.Player; +import net.runelite.api.Script; +import net.runelite.api.ScriptID; +import net.runelite.api.SpriteID; +import net.runelite.api.VarClientStr; +import net.runelite.api.Varbits; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.ClanChanged; +import net.runelite.api.events.ClanMemberJoined; +import net.runelite.api.events.ClanMemberLeft; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.PlayerDespawned; +import net.runelite.api.events.PlayerSpawned; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.events.VarClientStrChanged; +import net.runelite.api.events.WidgetMenuOptionClicked; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatMessageBuilder; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.ClanManager; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.menus.MenuManager; +import net.runelite.client.menus.WidgetMenuOption; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_OPAQUE_BACKGROUND; +import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_TRANSPARENT_BACKGROUND; +import static net.runelite.client.ui.JagexColors.CHAT_CLAN_TEXT_OPAQUE_BACKGROUND; +import static net.runelite.client.ui.JagexColors.CHAT_CLAN_TEXT_TRANSPARENT_BACKGROUND; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.util.Text; -@PluginDescriptor(name = "Clan Chat", description = "Add rank icons to users talking in clan chat", tags = { "icons", "rank", "recent" }) +@PluginDescriptor( + name = "Clan Chat", + description = "Add rank icons to users talking in clan chat", + tags = {"icons", "rank", "recent"} +) public class ClanChatPlugin extends Plugin { - private static final int MAX_CHATS = 10; + private static final int MAX_CHATS = 20; private static final String CLAN_CHAT_TITLE = "CC"; private static final String RECENT_TITLE = "Recent CCs"; private static final int JOIN_LEAVE_DURATION = 20; private static final int MESSAGE_DELAY = 10; + @Inject private Client client; + @Inject private ClanManager clanManager; + @Inject private ClanChatConfig config; + @Inject private InfoBoxManager infoBoxManager; + @Inject private SpriteManager spriteManager; + @Inject private ClientThread clientThread; - private List chats; - private static CopyOnWriteArrayList clanMembers; + + @Inject + private MenuManager menuManager; + + private List chats = new ArrayList<>(); + + public static CopyOnWriteArrayList getClanMembers() + { + return (CopyOnWriteArrayList) clanMembers.clone(); + } + + private static CopyOnWriteArrayList clanMembers = new CopyOnWriteArrayList<>(); private ClanChatIndicator clanMemberCounter; - private final Deque clanJoinMessages; - private Map activityBuffer; + /** + * queue of temporary messages added to the client + */ + private final Deque clanJoinMessages = new ArrayDeque<>(); + private Map activityBuffer = new HashMap<>(); private int clanJoinedTick; - public ClanChatPlugin() { - this.chats = new ArrayList(); - this.clanJoinMessages = new ArrayDeque(); - this.activityBuffer = new HashMap(); - } - - public static CopyOnWriteArrayList getClanMembers() { - return (CopyOnWriteArrayList)ClanChatPlugin.clanMembers.clone(); - } + private ConcurrentHashMap ccWidgetMap = new ConcurrentHashMap(); @Provides - ClanChatConfig getConfig(final ConfigManager configManager) { + ClanChatConfig getConfig(ConfigManager configManager) + { return configManager.getConfig(ClanChatConfig.class); } - public void startUp() { - this.chats = new ArrayList(Text.fromCSV(this.config.chatsData())); + @Override + public void startUp() + { + chats = new ArrayList<>(Text.fromCSV(config.chatsData())); } - public void shutDown() { - ClanChatPlugin.clanMembers.clear(); - this.removeClanCounter(); - this.resetClanChats(); + @Override + public void shutDown() + { + clanMembers.clear(); + removeClanCounter(); + resetClanChats(); } @Subscribe - public void onConfigChanged(final ConfigChanged configChanged) { - if (configChanged.getGroup().equals("clanchat")) { - if (!this.config.recentChats()) { - this.resetClanChats(); + public void onConfigChanged(ConfigChanged configChanged) + { + if (configChanged.getGroup().equals("clanchat")) + { + if (!config.recentChats()) + { + resetClanChats(); } - if (this.config.showClanCounter()) { - this.clientThread.invoke(this::addClanCounter); + + if (config.showClanCounter()) + { + clientThread.invoke(this::addClanCounter); } - else { - this.removeClanCounter(); + else + { + removeClanCounter(); } } } - @Subscribe - public void onClanMemberJoined(ClanMemberJoined event) - { - final ClanMember member = event.getMember(); - - if (member.getWorld() == client.getWorld()) - { - final Player local = client.getLocalPlayer(); - final String memberName = Text.toJagexName(member.getUsername()); - - for (final Player player : client.getPlayers()) - { - if (player != null && player != local && memberName.equals(Text.toJagexName(player.getName()))) - { - clanMembers.add(player); - addClanCounter(); - break; - } - } - } - - if (this.clanJoinedTick == this.client.getTickCount()) { - return; - } - if (!this.config.showJoinLeave() || member.getRank().getValue() < this.config.joinLeaveRank().getValue()) { - return; - } - if (!this.activityBuffer.containsKey(member.getUsername())) { - final ClanMemberActivity joinActivity = new ClanMemberActivity(ClanActivityType.JOINED, member, this.client.getTickCount()); - this.activityBuffer.put(member.getUsername(), joinActivity); - } - else { - this.activityBuffer.remove(member.getUsername()); - } - } - @Subscribe - public void onClanMemberLeft(final ClanMemberLeft event) { + public void onClanMemberJoined(ClanMemberJoined event) + { final ClanMember member = event.getMember(); - if (member.getWorld() == this.client.getWorld()) { + + if (member.getWorld() == client.getWorld()) + { + final Player local = client.getLocalPlayer(); final String memberName = Text.toJagexName(member.getUsername()); - final Iterator each = ClanChatPlugin.clanMembers.iterator(); - while (each.hasNext()) { - if (memberName.equals(Text.toJagexName(each.next().getName()))) { - each.remove(); - if (ClanChatPlugin.clanMembers.isEmpty()) { - this.removeClanCounter(); - break; - } + + for (final Player player : client.getPlayers()) + { + if (player != null && player != local && memberName.equals(Text.toJagexName(player.getName()))) + { + clanMembers.add(player); + addClanCounter(); break; } } } - if (!this.config.showJoinLeave() || member.getRank().getValue() < this.config.joinLeaveRank().getValue()) { + + // clan members getting initialized isn't relevant + if (clanJoinedTick == client.getTickCount()) + { return; } - if (!this.activityBuffer.containsKey(member.getUsername())) { - final ClanMemberActivity leaveActivity = new ClanMemberActivity(ClanActivityType.LEFT, member, this.client.getTickCount()); - this.activityBuffer.put(member.getUsername(), leaveActivity); + + if (!config.showJoinLeave() || + member.getRank().getValue() < config.joinLeaveRank().getValue()) + { + return; } - else { - this.activityBuffer.remove(member.getUsername()); + + // attempt to filter out world hopping joins + if (!activityBuffer.containsKey(member.getUsername())) + { + ClanMemberActivity joinActivity = new ClanMemberActivity(ClanActivityType.JOINED, + member, client.getTickCount()); + activityBuffer.put(member.getUsername(), joinActivity); + } + else + { + activityBuffer.remove(member.getUsername()); } } @Subscribe - public void onGameTick(final GameTick gameTick) { - if (this.client.getGameState() != GameState.LOGGED_IN) { - return; - } - final Widget clanChatTitleWidget = this.client.getWidget(WidgetInfo.CLAN_CHAT_TITLE); - if (clanChatTitleWidget != null) { - final Widget clanChatList = this.client.getWidget(WidgetInfo.CLAN_CHAT_LIST); - final Widget owner = this.client.getWidget(WidgetInfo.CLAN_CHAT_OWNER); - if (this.client.getClanChatCount() > 0) { - clanChatTitleWidget.setText("Clan Chat (" + this.client.getClanChatCount() + "/100)"); - } - else if (this.config.recentChats() && clanChatList.getChildren() == null && !Strings.isNullOrEmpty(owner.getText())) { - clanChatTitleWidget.setText("Recent Clan Chats"); - this.loadClanChats(); + public void onClanMemberLeft(ClanMemberLeft event) + { + final ClanMember member = event.getMember(); + + if (member.getWorld() == client.getWorld()) + { + final String memberName = Text.toJagexName(member.getUsername()); + final Iterator each = clanMembers.iterator(); + + while (each.hasNext()) + { + if (memberName.equals(Text.toJagexName(each.next().getName()))) + { + each.remove(); + + if (clanMembers.isEmpty()) + { + removeClanCounter(); + } + + break; + } } } - if (!this.config.showJoinLeave()) { + + if (!config.showJoinLeave() || + member.getRank().getValue() < config.joinLeaveRank().getValue()) + { return; } - this.timeoutClanMessages(); - this.addClanActivityMessages(); + + if (!activityBuffer.containsKey(member.getUsername())) + { + ClanMemberActivity leaveActivity = new ClanMemberActivity(ClanActivityType.LEFT, + member, client.getTickCount()); + activityBuffer.put(member.getUsername(), leaveActivity); + } + else + { + activityBuffer.remove(member.getUsername()); + } } - private void timeoutClanMessages() { - if (this.clanJoinMessages.isEmpty()) { + @Subscribe + public void onGameTick(GameTick gameTick) + { + if (client.getGameState() != GameState.LOGGED_IN) + { return; } + + Widget clanChatTitleWidget = client.getWidget(WidgetInfo.CLAN_CHAT_TITLE); + if (clanChatTitleWidget != null) + { + Widget clanChatList = client.getWidget(WidgetInfo.CLAN_CHAT_LIST); + Widget owner = client.getWidget(WidgetInfo.CLAN_CHAT_OWNER); + if (client.getClanChatCount() > 0) + { + clanChatTitleWidget.setText(CLAN_CHAT_TITLE + " (" + client.getClanChatCount() + "/100)"); + } + else if (config.recentChats() && clanChatList.getChildren() == null && !Strings.isNullOrEmpty(owner.getText())) + { + clanChatTitleWidget.setText(RECENT_TITLE); + + loadClanChats(); + } + } + + if (!config.showJoinLeave()) + { + return; + } + + timeoutClanMessages(); + + addClanActivityMessages(); + } + + private void timeoutClanMessages() + { + if (clanJoinMessages.isEmpty()) + { + return; + } + boolean removed = false; - final Iterator it = this.clanJoinMessages.iterator(); - while (it.hasNext()) { - final ClanJoinMessage clanJoinMessage = it.next(); - final MessageNode messageNode = clanJoinMessage.getMessageNode(); + + for (Iterator it = clanJoinMessages.iterator(); it.hasNext(); ) + { + ClanJoinMessage clanJoinMessage = it.next(); + MessageNode messageNode = clanJoinMessage.getMessageNode(); final int createdTick = clanJoinMessage.getTick(); - if (this.client.getTickCount() <= createdTick + 20) { + + if (client.getTickCount() > createdTick + JOIN_LEAVE_DURATION) + { + it.remove(); + + // If this message has been reused since, it will get a different id + if (clanJoinMessage.getGetMessageId() == messageNode.getId()) + { + ChatLineBuffer ccInfoBuffer = client.getChatLineMap().get(ChatMessageType.FRIENDSCHATNOTIFICATION.getType()); + if (ccInfoBuffer != null) + { + ccInfoBuffer.removeMessageNode(messageNode); + removed = true; + } + } + } + else + { + // Everything else in the deque is newer break; } - it.remove(); - if (clanJoinMessage.getGetMessageId() != messageNode.getId()) { - continue; - } - final ChatLineBuffer ccInfoBuffer = this.client.getChatLineMap().get(ChatMessageType.FRIENDSCHATNOTIFICATION.getType()); - if (ccInfoBuffer == null) { - continue; - } - ccInfoBuffer.removeMessageNode(messageNode); - removed = true; } - if (removed) { - this.clientThread.invoke(() -> this.client.runScript(216, new Object[0])); + + if (removed) + { + clientThread.invoke(() -> client.runScript(ScriptID.BUILD_CHATBOX)); } } - private void addClanActivityMessages() { - final Iterator activityIt = this.activityBuffer.values().iterator(); - while (activityIt.hasNext()) { - final ClanMemberActivity activity = activityIt.next(); - if (activity.getTick() < this.client.getTickCount() - 10) { + private void addClanActivityMessages() + { + Iterator activityIt = activityBuffer.values().iterator(); + + while (activityIt.hasNext()) + { + ClanMemberActivity activity = activityIt.next(); + + if (activity.getTick() < client.getTickCount() - MESSAGE_DELAY) + { activityIt.remove(); - this.addActivityMessage(activity.getMember(), activity.getActivityType()); + addActivityMessage(activity.getMember(), activity.getActivityType()); } } } - private void addActivityMessage(final ClanMember member, final ClanActivityType activityType) { - final String activityMessage = (activityType == ClanActivityType.JOINED) ? " has joined." : " has left."; + private void addActivityMessage(ClanMember member, ClanActivityType activityType) + { + final String activityMessage = activityType == ClanActivityType.JOINED ? " has joined." : " has left."; final ClanMemberRank rank = member.getRank(); - Color textColor = JagexColors.CHAT_CLAN_TEXT_OPAQUE_BACKGROUND; - Color channelColor = JagexColors.CHAT_CLAN_NAME_OPAQUE_BACKGROUND; + Color textColor = CHAT_CLAN_TEXT_OPAQUE_BACKGROUND; + Color channelColor = CHAT_CLAN_NAME_OPAQUE_BACKGROUND; int rankIcon = -1; - if (this.client.isResized() && this.client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1) { - textColor = JagexColors.CHAT_CLAN_TEXT_TRANSPARENT_BACKGROUND; - channelColor = JagexColors.CHAT_CLAN_NAME_TRANSPARENT_BACKGROUND; + + if (client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1) + { + textColor = CHAT_CLAN_TEXT_TRANSPARENT_BACKGROUND; + channelColor = CHAT_CLAN_NAME_TRANSPARENT_BACKGROUND; } - if (this.config.clanChatIcons() && rank != null && rank != ClanMemberRank.UNRANKED) { - rankIcon = this.clanManager.getIconNumber(rank); + + if (config.clanChatIcons() && rank != null && rank != ClanMemberRank.UNRANKED) + { + rankIcon = clanManager.getIconNumber(rank); } - final ChatMessageBuilder message = new ChatMessageBuilder().append("[").append(channelColor, this.client.getClanChatName()); - if (rankIcon > -1) { - message.append(" ").img(rankIcon); + + ChatMessageBuilder message = new ChatMessageBuilder() + .append("[") + .append(channelColor, client.getClanChatName()); + if (rankIcon > -1) + { + message + .append(" ") + .img(rankIcon); } - message.append("] ").append(textColor, member.getUsername() + activityMessage); + message + .append("] ") + .append(textColor, member.getUsername() + activityMessage); + final String messageString = message.build(); - this.client.addChatMessage(ChatMessageType.FRIENDSCHATNOTIFICATION, "", messageString, ""); - final ChatLineBuffer chatLineBuffer = this.client.getChatLineMap().get(ChatMessageType.FRIENDSCHATNOTIFICATION.getType()); + client.addChatMessage(ChatMessageType.FRIENDSCHATNOTIFICATION, "", messageString, ""); + + final ChatLineBuffer chatLineBuffer = client.getChatLineMap().get(ChatMessageType.FRIENDSCHATNOTIFICATION.getType()); final MessageNode[] lines = chatLineBuffer.getLines(); final MessageNode line = lines[0]; - final ClanJoinMessage clanJoinMessage = new ClanJoinMessage(line, line.getId(), this.client.getTickCount()); - this.clanJoinMessages.addLast(clanJoinMessage); + + ClanJoinMessage clanJoinMessage = new ClanJoinMessage(line, line.getId(), client.getTickCount()); + clanJoinMessages.addLast(clanJoinMessage); } @Subscribe - public void onVarClientStrChanged(final VarClientStrChanged strChanged) { - if (strChanged.getIndex() == VarClientStr.RECENT_CLAN_CHAT.getIndex() && this.config.recentChats()) { - this.updateRecentChat(this.client.getVar(VarClientStr.RECENT_CLAN_CHAT)); + public void onVarClientStrChanged(VarClientStrChanged strChanged) + { + if (strChanged.getIndex() == VarClientStr.RECENT_CLAN_CHAT.getIndex() && config.recentChats()) + { + updateRecentChat(client.getVar(VarClientStr.RECENT_CLAN_CHAT)); } } @Subscribe - public void onChatMessage(final ChatMessage chatMessage) { - if (this.client.getGameState() != GameState.LOADING && this.client.getGameState() != GameState.LOGGED_IN) { + public void onChatMessage(ChatMessage chatMessage) + { + if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN) + { return; } - if (this.client.getClanChatCount() <= 0) { + + if (client.getClanChatCount() <= 0) + { return; } - switch (chatMessage.getType()) { + + switch (chatMessage.getType()) + { case PRIVATECHAT: - case MODPRIVATECHAT: { - if (!this.config.privateMessageIcons()) { + case MODPRIVATECHAT: + if (!config.privateMessageIcons()) + { return; } break; - } case PUBLICCHAT: - case MODCHAT: { - if (!this.config.publicChatIcons()) { + case MODCHAT: + if (!config.publicChatIcons()) + { return; } break; - } - case FRIENDSCHAT: { - if (!this.config.clanChatIcons()) { + case FRIENDSCHAT: + if (!config.clanChatIcons()) + { return; } break; - } - default: { + default: return; - } } - this.insertClanRankIcon(chatMessage); + + insertClanRankIcon(chatMessage); } @Subscribe - public void onGameStateChanged(final GameStateChanged state) { - final GameState gameState = state.getGameState(); - if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.CONNECTION_LOST || gameState == GameState.HOPPING) { - ClanChatPlugin.clanMembers.clear(); - this.removeClanCounter(); - this.clanJoinMessages.clear(); - } - } + public void onGameStateChanged(GameStateChanged state) + { + GameState gameState = state.getGameState(); - @Subscribe - public void onPlayerSpawned(PlayerSpawned event) - { - final Player local = client.getLocalPlayer(); - final Player player = event.getPlayer(); + if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.CONNECTION_LOST || gameState == GameState.HOPPING) + { + clanMembers.clear(); + removeClanCounter(); - if (player != local && player.isClanMember()) - { - clanMembers.add(player); - addClanCounter(); - } - } - - @Subscribe - public void onPlayerDespawned(final PlayerDespawned event) { - if (ClanChatPlugin.clanMembers.remove(event.getPlayer()) && ClanChatPlugin.clanMembers.isEmpty()) { - this.removeClanCounter(); + clanJoinMessages.clear(); } } @Subscribe - public void onClanChanged(final ClanChanged event) { - if (event.isJoined()) { - this.clanJoinedTick = this.client.getTickCount(); + public void onPlayerSpawned(PlayerSpawned event) + { + final Player local = client.getLocalPlayer(); + final Player player = event.getPlayer(); + + if (player != local && player.isClanMember()) + { + clanMembers.add(player); + addClanCounter(); } - else { - ClanChatPlugin.clanMembers.clear(); - this.removeClanCounter(); - } - this.activityBuffer.clear(); } - int getClanAmount() { - return ClanChatPlugin.clanMembers.size(); + @Subscribe + public void onPlayerDespawned(PlayerDespawned event) + { + if (clanMembers.remove(event.getPlayer()) && clanMembers.isEmpty()) + { + removeClanCounter(); + } } - private void insertClanRankIcon(final ChatMessage message) { - final ClanMemberRank rank = this.clanManager.getRank(message.getName()); - if (rank != null && rank != ClanMemberRank.UNRANKED) { - final int iconNumber = this.clanManager.getIconNumber(rank); + @Subscribe + public void onClanChanged(ClanChanged event) + { + if (event.isJoined()) + { + clanJoinedTick = client.getTickCount(); + } + else + { + clanMembers.clear(); + removeClanCounter(); + } + + activityBuffer.clear(); + } + + int getClanAmount() + { + return clanMembers.size(); + } + + private void insertClanRankIcon(final ChatMessage message) + { + final ClanMemberRank rank = clanManager.getRank(message.getName()); + + if (rank != null && rank != ClanMemberRank.UNRANKED) + { + int iconNumber = clanManager.getIconNumber(rank); final String img = ""; - if (message.getType() == ChatMessageType.FRIENDSCHAT) { - message.getMessageNode().setSender(message.getMessageNode().getSender() + " " + img); + if (message.getType() == ChatMessageType.FRIENDSCHAT) + { + message.getMessageNode() + .setSender(message.getMessageNode().getSender() + " " + img); } - else { - message.getMessageNode().setName(img + message.getMessageNode().getName()); + else + { + message.getMessageNode() + .setName(img + message.getMessageNode().getName()); } - this.client.refreshChat(); + client.refreshChat(); } } - private void resetClanChats() { - final Widget clanChatList = this.client.getWidget(WidgetInfo.CLAN_CHAT_LIST); - final Widget clanChatTitleWidget = this.client.getWidget(WidgetInfo.CLAN_CHAT_TITLE); - if (clanChatList == null) { + + private void resetClanChats() + { + Widget clanChatList = client.getWidget(WidgetInfo.CLAN_CHAT_LIST); + Widget clanChatTitleWidget = client.getWidget(WidgetInfo.CLAN_CHAT_TITLE); + + if (clanChatList == null) + { return; } - if (this.client.getClanChatCount() == 0) { + + if (client.getClanChatCount() == 0) + { clanChatList.setChildren(null); } - clanChatTitleWidget.setText("Clan Chat"); + + clanChatTitleWidget.setText(CLAN_CHAT_TITLE); } - private void loadClanChats() { - final Widget clanChatList = this.client.getWidget(WidgetInfo.CLAN_CHAT_LIST); - if (clanChatList == null) { + private void loadClanChats() + { + Widget clanChatList = client.getWidget(WidgetInfo.CLAN_CHAT_LIST); + clanChatList.setScrollHeight( 14 * chats.size()); + clanChatList.revalidateScroll(); + if (clanChatList == null) + { return; } + int y = 2; clanChatList.setChildren(null); - for (final String chat : Lists.reverse(this.chats)) { - final Widget widget = clanChatList.createChild(-1, 4); + for (String chat : Lists.reverse(chats)) + { + Widget widget = clanChatList.createChild(-1, WidgetType.TEXT); widget.setFontId(494); - widget.setTextColor(16777215); + widget.setHasListener(true); + + widget.setTextColor(0xffffff); widget.setText(chat); + widget.setTextShadowed(true); + widget.setBorderType(1); + widget.setAction(0, "Join"); + widget.setOnOpListener(ScriptID.FORCE_JOIN_CC, widget.getText()); widget.setOriginalHeight(14); widget.setOriginalWidth(142); widget.setOriginalY(y); widget.setOriginalX(20); widget.revalidate(); + y += 14; } + clanChatList.revalidateScroll(); } - private void updateRecentChat(String s) { - if (Strings.isNullOrEmpty(s)) { + private void updateRecentChat(String s) + { + if (Strings.isNullOrEmpty(s)) + { return; } + s = Text.toJagexName(s); - final List chats = this.chats; - final String s2 = s; - Objects.requireNonNull(s2); - chats.removeIf(s2::equalsIgnoreCase); - this.chats.add(s); - while (this.chats.size() > 10) { - this.chats.remove(0); + + chats.removeIf(s::equalsIgnoreCase); + chats.add(s); + + while (chats.size() > MAX_CHATS) + { + chats.remove(0); } - this.config.chatsData(Text.toCSV(this.chats)); + + config.chatsData(Text.toCSV(chats)); } - private void removeClanCounter() { - this.infoBoxManager.removeInfoBox(this.clanMemberCounter); - this.clanMemberCounter = null; + private void removeClanCounter() + { + infoBoxManager.removeInfoBox(clanMemberCounter); + clanMemberCounter = null; } - private void addClanCounter() { - if (!this.config.showClanCounter() || this.clanMemberCounter != null || ClanChatPlugin.clanMembers.isEmpty()) { + private void addClanCounter() + { + if (!config.showClanCounter() || clanMemberCounter != null || clanMembers.isEmpty()) + { return; } - final BufferedImage image = this.spriteManager.getSprite(904, 0); - this.clanMemberCounter = new ClanChatIndicator(image, this); - this.infoBoxManager.addInfoBox(this.clanMemberCounter); - } - static { - ClanChatPlugin.clanMembers = new CopyOnWriteArrayList(); + final BufferedImage image = spriteManager.getSprite(SpriteID.TAB_CLAN_CHAT, 0); + clanMemberCounter = new ClanChatIndicator(image, this); + infoBoxManager.addInfoBox(clanMemberCounter); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetField.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetField.java index a4b21cb94d..ade94fa6f6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetField.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetField.java @@ -88,6 +88,7 @@ public class WidgetField } else { + setter.accept(widget, (T) value); log.warn("Type {} is not supported for editing", type); } setter.accept(widget, (T) value); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java index 1f78bddb9f..936d814725 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java @@ -26,6 +26,7 @@ package net.runelite.client.plugins.examine; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import java.io.IOException; import java.time.Instant; import java.util.ArrayDeque; import java.util.Deque; @@ -54,6 +55,8 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.util.StackFormatter; import net.runelite.http.api.examine.ExamineClient; +import net.runelite.http.api.osbuddy.OSBGrandExchangeClient; +import net.runelite.http.api.osbuddy.OSBGrandExchangeResult; /** * Submits examine info to the api @@ -72,6 +75,7 @@ public class ExaminePlugin extends Plugin private static final Pattern X_PATTERN = Pattern.compile("^\\d+ x "); private final Deque pending = new ArrayDeque<>(); + private final OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient(); private final Cache cache = CacheBuilder.newBuilder() .maximumSize(128L) .build(); @@ -342,11 +346,24 @@ public class ExaminePlugin extends Plugin if (gePrice > 0) { + OSBGrandExchangeResult osbresult = new OSBGrandExchangeResult(); + try + { + osbresult = CLIENT.lookupItem(itemComposition.getId()); + } + catch (IOException e) + { + e.printStackTrace(); + } message .append(ChatColorType.NORMAL) - .append(" GE average ") + .append(" GE ") .append(ChatColorType.HIGHLIGHT) - .append(StackFormatter.formatNumber(gePrice * quantity)); + .append(StackFormatter.formatNumber(gePrice * quantity)) + .append(ChatColorType.NORMAL) + .append(" OSB ") + .append(ChatColorType.HIGHLIGHT) + .append(StackFormatter.formatNumber(osbresult.getOverall_average() * quantity)); if (quantity > 1) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoPlugin.java index 441af6adab..66a9fb0477 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoPlugin.java @@ -53,6 +53,7 @@ import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.grounditems.GroundItem; import net.runelite.client.plugins.grounditems.GroundItemsPlugin; import net.runelite.client.plugins.stretchedmode.StretchedModeConfig; +import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.overlay.OverlayManager; import javax.inject.Inject; @@ -80,6 +81,9 @@ public class FlexoPlugin extends Plugin { @Inject private Client client; + + @Inject + private ClientUI clientUI; @Inject private ConfigManager configManager; @@ -112,6 +116,8 @@ public class FlexoPlugin extends Plugin { public void onBeforeRender(BeforeRender event) { if (Flexo.client==null) Flexo.client = client; + if (Flexo.clientUI==null) + Flexo.clientUI = clientUI; overlay.clickAreas = new ArrayList<>(); overlay.clickPoints = new ArrayList<>(); if (getConfig(configManager).getDebugNPCs()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingConfig.java new file mode 100644 index 0000000000..a178d3ad5b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingConfig.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018, Fluffeh + * 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.flinching; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("flinching") +public interface FlinchingConfig extends Config +{ + @ConfigItem( + + position = 0, + keyName = "hexColorFlinch", + name = "Overlay Color", + description = "Color of flinching timer overlay" + ) + default Color getFlinchOverlayColor() + { + return Color.CYAN; + } + + @ConfigItem( + + position = 1, + keyName = "flinchOverlaySize", + name = "Overlay Diameter", + description = "Flinch overlay timer diameter" + ) + default int getFlinchOverlaySize() + { + return 30; + } + + @ConfigItem( + + position = 2, + keyName = "flinchDelay", + name = "Flinch Timer Delay", + description = "Shows the appropriate time to attack while flinching milliseconds" + ) + default int getFlinchDelay() + { + return 5400; + } + + @ConfigItem( + + position = 3, + keyName = "flinchOnHitReceivedDelay", + name = "Flinch Hit Received Delay", + description = "Slightly longer delay after being attacked milliseconds" + ) + default int getFlinchAttackedDelay() + { + return 6600; + } + + @ConfigItem( + + position = 4, + keyName = "flinchResetOnHit", + name = "Reset on Hit", + description = "Timer resets after every attack from your character" + ) + default boolean getFlinchResetOnHit() + { + return true; + } + + @ConfigItem( + + position = 5, + keyName = "flinchResetOnHitReceived", + name = "Reset on Hit Received", + description = "Timer resets when your character gets attacked" + ) + default boolean getFlinchResetOnHitReceived() + { + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingOverlay.java new file mode 100644 index 0000000000..2c26db899f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingOverlay.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018, Fluffeh + * 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.flinching; + + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.Map; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +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; + + +public class FlinchingOverlay extends Overlay +{ + private final Client client; + private final FlinchingPlugin plugin; + private final FlinchingConfig config; + + private Color color; + private Color borderColor; + + private int overlaySize = 25; + + @Inject + FlinchingOverlay(Client client, FlinchingPlugin plugin, FlinchingConfig config) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.plugin = plugin; + this.config = config; + this.client = client; + + overlaySize = this.config.getFlinchOverlaySize(); + } + + @Override + public Dimension render(Graphics2D graphics) + { + drawOverlays(graphics); + return null; + } + + public void updateConfig() + { + borderColor = config.getFlinchOverlayColor(); + color = new Color(borderColor.getRed(), borderColor.getGreen(), borderColor.getBlue(), 100); + + overlaySize = config.getFlinchOverlaySize(); + } + + private void drawOverlays(Graphics2D graphics) + { + for (Map.Entry entry : plugin.GetTargets().entrySet()) + { + FlinchingTarget target = entry.getValue(); + + drawFlinchTimer(graphics, target.worldLocation, target.GetRemainingTimePercent()); + } + } + + + private void drawFlinchTimer(Graphics2D graphics, WorldPoint targetLocation, double fillAmount) + { + if (targetLocation.getPlane() != client.getPlane()) + { + return; + } + + LocalPoint localLoc = LocalPoint.fromWorld(client, targetLocation); + if (localLoc == null) + { + return; + } + + Point loc = Perspective.localToCanvas(client, localLoc, client.getPlane()); + + ProgressPieComponent pie = new ProgressPieComponent(); + pie.setDiameter(overlaySize); + pie.setFill(color); + pie.setBorderColor(borderColor); + pie.setPosition(loc); + pie.setProgress(fillAmount); + pie.render(graphics); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingPlugin.java new file mode 100644 index 0000000000..3780edce2e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingPlugin.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2018, Fluffeh + * 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.flinching; + +import net.runelite.client.eventbus.Subscribe; +import net.runelite.api.Client; +import net.runelite.api.Player; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.events.GameTick; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; +import javax.inject.Inject; +import net.runelite.api.Actor; +import net.runelite.api.NPC; +import net.runelite.api.GameState; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.NpcDespawned; +import net.runelite.client.config.ConfigManager; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.HitsplatApplied; +import com.google.inject.Provides; + + +@Slf4j +@PluginDescriptor( + name = "Flinching Timer", + description = "Time your attacks while flinching", + tags = {"overlay", "flinching", "timers", "combat"}, + enabledByDefault = false, + type = PluginType.PVM +) +public class FlinchingPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private OverlayManager overlayManager; + + @Inject + private FlinchingConfig config; + + @Inject + private FlinchingOverlay overlay; + + private int currentWorld = -1; + + private int currentInteractingId = -1; + private final Map flinchingTargets = new HashMap(); + + private boolean resetOnHit = true; + private boolean resetOnHitReceived = true; + + @Provides + FlinchingConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(FlinchingConfig.class); + } + + @Override + protected void startUp() + { + overlayManager.add(overlay); + + overlay.updateConfig(); + resetOnHit = config.getFlinchResetOnHit(); + resetOnHitReceived = config.getFlinchResetOnHitReceived(); + + ClearTargets(); + } + + @Override + protected void shutDown() + { + ClearTargets(); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("flinching")) + { + overlay.updateConfig(); + resetOnHit = config.getFlinchResetOnHit(); + resetOnHitReceived = config.getFlinchResetOnHitReceived(); + + Iterator> it = flinchingTargets.entrySet().iterator(); + while (it.hasNext()) + { + FlinchingTarget target = it.next().getValue(); + if(target != null) + { + target.SetDelayTime(config.getFlinchDelay(), config.getFlinchAttackedDelay()); + } + } + } + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGGED_IN) + { + if (currentWorld == -1) + { + currentWorld = client.getWorld(); + } + else if (currentWorld != client.getWorld()) + { + ClearTargets(); + } + } + } + + private void ClearTargets() + { + Iterator> it = flinchingTargets.entrySet().iterator(); + + while (it.hasNext()) + { + it.remove(); + } + } + + @Subscribe + private void onGameTick(GameTick tick) + { + if (client.getGameState() != GameState.LOGGED_IN) + { + + } + else + { + TickTargets(); + checkInteracting(); + } + } + + @Subscribe + public void onHitsplatApplied(HitsplatApplied hitsplatApplied) + { + Actor actor = hitsplatApplied.getActor(); + + if (actor instanceof NPC) + { + NPC hitTarget = (NPC) actor; + + int hitId = hitTarget.getId(); + if(hitId == currentInteractingId) + { + if (!flinchingTargets.containsKey(hitId)) + { + TargetGained(hitTarget); + } + else + { + FlinchingTarget currentTarget = flinchingTargets.get(hitId); + if(currentTarget != null) + { + if(resetOnHit) + { + currentTarget.TargetHit(); + } + } + } + } + } + else if(resetOnHitReceived && actor == client.getLocalPlayer()) + { + PlayerHit(); + } + } + + private void checkInteracting() + { + Player localPlayer = client.getLocalPlayer(); + Actor interacting = localPlayer.getInteracting(); + + if (interacting instanceof NPC) + { + NPC newTarget = (NPC) interacting; + currentInteractingId = newTarget.getId(); + + if(newTarget.getHealth() <= 0 || newTarget.isDead()) + { + if (flinchingTargets.containsKey(currentInteractingId)) + { + flinchingTargets.remove(currentInteractingId); + currentInteractingId = -1; + } + } + } + } + + private void TickTargets() + { + Iterator> it = flinchingTargets.entrySet().iterator(); + + while (it.hasNext()) + { + FlinchingTarget target = it.next().getValue(); + if(target != null) + { + target.Tick(); + if(target.isActive == false) + { + it.remove(); + } + } + else + { + it.remove(); + } + } + } + + @Subscribe + public void onNpcDespawned(NpcDespawned npcDespawned) + { + NPC actor = npcDespawned.getNpc(); + + int actorId = actor.getId(); + if (actor.isDead() && flinchingTargets.containsKey(actorId)) + { + TargetLost(actorId); + } + } + + private void TargetLost(int targetId) + { + flinchingTargets.remove(targetId); + } + + private void TargetGained(NPC _newTarget) + { + FlinchingTarget newTarget = new FlinchingTarget(_newTarget); + newTarget.SetDelayTime(config.getFlinchDelay(), config.getFlinchAttackedDelay()); + flinchingTargets.put(_newTarget.getId(), newTarget); + } + + public void PlayerHit() + { + Iterator> it = flinchingTargets.entrySet().iterator(); + while (it.hasNext()) + { + FlinchingTarget target = it.next().getValue(); + if(target != null) + { + target.PlayerHit(); + } + } + } + + public Map GetTargets() + { + return(flinchingTargets); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingTarget.java b/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingTarget.java new file mode 100644 index 0000000000..a654437e3f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/flinching/FlinchingTarget.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2018, Fluffeh + * 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.flinching; + +import java.time.Duration; +import java.time.Instant; +import lombok.Getter; +import net.runelite.api.NPC; +import net.runelite.api.coords.WorldPoint; + +public class FlinchingTarget +{ + private int currentDisplayLength = 5400; + + private boolean usingHitDelay = false; + + private int displayLength = 5400; + private int displayHitReceivedLength = 6600; + private Instant lastAttacked; + + public boolean isActive = false; + + @Getter + private int objectId; + private NPC targetObject; + + @Getter + public WorldPoint worldLocation; + + public FlinchingTarget(NPC target) + { + isActive = true; + + this.targetObject = target; + this.lastAttacked = Instant.now(); + this.objectId = target.getId(); + this.worldLocation = target.getWorldLocation(); + } + + public void TargetHit() + { + boolean shouldHit = true; + if(usingHitDelay) + { + if(GetRemainingTime() > displayLength) + { + shouldHit = false; + } + } + + if(shouldHit) + { + lastAttacked = Instant.now(); + + usingHitDelay = false; + currentDisplayLength = displayLength; + } + } + + public double GetRemainingTimePercent() + { + double remainingTime = GetRemainingTime(); + double timePercent = remainingTime / currentDisplayLength; + if(timePercent < 0) + { + timePercent = 0; + } + else if(timePercent > 1) + { + timePercent = 1; + } + + return(timePercent); + } + + private double GetRemainingTime() + { + Duration duration = Duration.between(lastAttacked, Instant.now()); + return( (currentDisplayLength - ((double)duration.toMillis()))); + } + + public void Tick() + { + if(targetObject == null) + { + isActive = false; + } + else + { + worldLocation = targetObject.getWorldLocation(); + + double remainingTime = GetRemainingTime(); + if(remainingTime <= 0) + { + isActive = false; + } + } + } + + public void SetDelayTime(int delayTime, int delayHitReceivedTime) + { + displayLength = delayTime; + displayHitReceivedLength = delayHitReceivedTime; + + if(usingHitDelay) + { + currentDisplayLength = displayHitReceivedLength; + } + else + { + currentDisplayLength = displayLength; + } + } + + public void PlayerHit() + { + usingHitDelay = true; + currentDisplayLength = displayHitReceivedLength; + + lastAttacked = Instant.now(); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersConfig.java index 7598d30597..2d5949a838 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersConfig.java @@ -7,26 +7,70 @@ import net.runelite.client.config.ConfigItem; @ConfigGroup("freezetimers") public interface FreezeTimersConfig extends Config { - + @ConfigItem( - keyName = "showOverlay", - name = "Show Players", - description = "Configure if the player overlay should be shown", - position = 1 + keyName = "showOverlay", + name = "Show Players", + description = "Configure if the player overlay should be shown", + position = 1 ) default boolean showPlayers() { return true; } - + @ConfigItem( - keyName = "showNpcs", - name = "Show NPCs", - description = "Configure if the npc overlay should be shown", - position = 2 + keyName = "showNpcs", + name = "Show NPCs", + description = "Configure if the npc overlay should be shown", + position = 2 ) default boolean showNpcs() { return false; } + + @ConfigItem( + keyName = "FreezeTimers", + name = "Show Freeze Timers", + description = "Toggle overlay for Freeze timers", + position = 3 + ) + default boolean FreezeTimers() + { + return true; + } + + @ConfigItem( + keyName = "TB", + name = "Show TB Timers", + description = "Toggle overlay for TB timers", + position = 4 + ) + default boolean TB() + { + return true; + } + + @ConfigItem( + keyName = "Veng", + name = "Show Veng Timers", + description = "Toggle overlay for Veng timers", + position = 5 + ) + default boolean Veng() + { + return true; + } + + @ConfigItem( + keyName = "noImage", + name = "Text Timers", + description = "Remove Images from Timers", + position = 6 + ) + default boolean noImage() + { + return false; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersOverlay.java index 04d9e5955a..c0252b19bf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersOverlay.java @@ -1,9 +1,18 @@ package net.runelite.client.plugins.freezetimers; +import java.awt.Color; +import static java.awt.Color.RED; +import static java.awt.Color.WHITE; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import javax.inject.Inject; import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.GraphicID; -import net.runelite.api.Player; import net.runelite.api.Point; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.Overlay; @@ -13,28 +22,21 @@ import net.runelite.client.ui.overlay.OverlayPriority; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.util.ImageUtil; -import javax.inject.Inject; -import java.awt.*; -import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; - -import static java.awt.Color.RED; -import static java.awt.Color.WHITE; -import static java.awt.Color.green; - public class FreezeTimersOverlay extends Overlay { - - @Inject - private Timers timers; - + private final FreezeTimersConfig config; private final Client client; private final Font timerFont = FontManager.getRunescapeBoldFont().deriveFont(14.0f); private final BufferedImage FREEZE_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "freeze.png"); private final BufferedImage TB_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "teleblock.png"); private final BufferedImage VENG_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "veng.png"); - + @Inject + private Timers timers; + private boolean lock; + private long finishedAtTest; + private Actor player; + @Inject public FreezeTimersOverlay(FreezeTimersConfig config, Client client) { @@ -44,7 +46,7 @@ public class FreezeTimersOverlay extends Overlay setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.UNDER_WIDGETS); } - + @Override public Dimension render(Graphics2D graphics) { @@ -58,30 +60,30 @@ public class FreezeTimersOverlay extends Overlay } return null; } - + private void renderOverlayFor(Graphics2D g, Actor actor) { if (timers.areAllTimersZero(actor)) { return; } - + int overlaysDrawn = 0; - - if (drawFreezeOverlay(g, actor, overlaysDrawn)) + + if (drawFreezeOverlay(g, actor, overlaysDrawn) && config.FreezeTimers()) { overlaysDrawn++; } - if (drawTBOverlay(g, actor, overlaysDrawn)) + if (drawTBOverlay(g, actor, overlaysDrawn) && config.TB()) { overlaysDrawn++; } - if (drawVengOverlay(g, actor, overlaysDrawn)) + if (drawVengOverlay(g, actor, overlaysDrawn) && config.Veng()) { overlaysDrawn++; } } - + private boolean drawFreezeOverlay(Graphics2D g, Actor actor, int overlaysDrawn) { long currentTick = System.currentTimeMillis(); @@ -90,13 +92,24 @@ public class FreezeTimersOverlay extends Overlay return false; } long finishedAt = timers.getTimerEnd(actor, TimerType.FREEZE); - + String text = processTickCounter(finishedAt); - - renderActorText(g, actor, text, overlaysDrawn, FREEZE_IMAGE); + Point poi = actor.getCanvasTextLocation(g, text, 0); + int xpoi = poi.getX(); + int ypoi = poi.getY(); + Point FixedPoint = new Point(xpoi, ypoi); + + if (config.noImage()) + { + renderTextLocation(g, text, 11, Font.BOLD, Color.WHITE, FixedPoint); + } + else + { + renderActorText(g, actor, text, overlaysDrawn, FREEZE_IMAGE); + } return true; } - + private boolean drawTBOverlay(Graphics2D g, Actor actor, int overlaysDrawn) { long currentTick = System.currentTimeMillis(); @@ -105,13 +118,31 @@ public class FreezeTimersOverlay extends Overlay return false; } long finishedAt = timers.getTimerEnd(actor, TimerType.TELEBLOCK); - + String text = processTickCounter(finishedAt); - - renderActorText(g, actor, text, overlaysDrawn, TB_IMAGE); + Point poi = actor.getCanvasTextLocation(g, text, 0); + int xpoi = poi.getX() + 20; + int ypoi = poi.getY(); + Point FixedPoint = new Point(xpoi, ypoi); + + if (config.noImage()) + { + if (timers.getTimerEnd(actor, TimerType.FREEZE) <= currentTick) + { + renderTextLocation(g, text, 11, Font.BOLD, Color.CYAN, poi); + } + if (timers.getTimerEnd(actor, TimerType.FREEZE) >= currentTick) + { + renderTextLocation(g, " | " + text, 11, Font.BOLD, Color.CYAN, FixedPoint); + } + } + else + { + renderActorText(g, actor, text, overlaysDrawn, TB_IMAGE); + } return true; } - + private boolean drawVengOverlay(Graphics2D g, Actor actor, int overlaysDrawn) { long currentTick = System.currentTimeMillis(); @@ -120,25 +151,42 @@ public class FreezeTimersOverlay extends Overlay return false; } long finishedAt = timers.getTimerEnd(actor, TimerType.VENG); - + String text = processTickCounter(finishedAt); - - renderActorText(g, actor, text, overlaysDrawn, VENG_IMAGE); + Point poi = actor.getCanvasTextLocation(g, text, 0); + int xpoi = poi.getX() - 20; + int ypoi = poi.getY(); + Point FixedPoint = new Point(xpoi, ypoi); + if (config.noImage()) + { + if (timers.getTimerEnd(actor, TimerType.FREEZE) <= currentTick) + { + renderTextLocation(g, text, 11, Font.BOLD, Color.RED, poi); + } + if (timers.getTimerEnd(actor, TimerType.FREEZE) >= currentTick) + { + renderTextLocation(g, text + " | ", 11, Font.BOLD, Color.RED, FixedPoint); + } + } + else + { + renderActorText(g, actor, text, overlaysDrawn, VENG_IMAGE); + } if (actor.getGraphic() == GraphicID.VENGEANCE || actor.getGraphic() == GraphicID.VENGEANCE_OTHER) { - + g.setColor(RED); Polygon poly = actor.getCanvasTilePoly(); if (poly != null) { OverlayUtil.renderPolygon(g, poly, RED); } - OverlayUtil.renderTextLocation(g, new Point((int)poly.getBounds2D().getCenterX(), - (int)poly.getBounds2D().getCenterY()), actor.getName(), RED); + OverlayUtil.renderTextLocation(g, new Point((int) poly.getBounds2D().getCenterX(), + (int) poly.getBounds2D().getCenterY()), actor.getName(), RED); } return true; } - + private void renderActorText(Graphics2D g, Actor actor, String text, int overlaysDrawn, BufferedImage image) { int yOffset = (overlaysDrawn * 18); @@ -147,9 +195,25 @@ public class FreezeTimersOverlay extends Overlay Rectangle rect = actor.getConvexHull().getBounds(); int xOffset = (int) rect.getWidth(); OverlayUtil.renderActorTextAndImage(g, actor, text, Color.WHITE, image, yOffset, - xOffset); + xOffset); } - + + private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint) + { + graphics.setFont(new Font("Arial", fontStyle, fontSize)); + if (canvasPoint != null) + { + final Point canvasCenterPoint = new Point( + canvasPoint.getX(), + canvasPoint.getY()); + final Point canvasCenterPoint_shadow = new Point( + canvasPoint.getX() + 1, + canvasPoint.getY() + 1); + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); + } + } + private String processTickCounter(long finishedAt) { long currentTick = System.currentTimeMillis(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersPlugin.java index ce582e790d..d3fd38f653 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersPlugin.java @@ -1,6 +1,7 @@ package net.runelite.client.plugins.freezetimers; import com.google.inject.Provides; +import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.events.GameTick; import net.runelite.api.events.GraphicChanged; @@ -8,52 +9,49 @@ 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.PluginManager; import net.runelite.client.plugins.PluginType; import net.runelite.client.ui.overlay.OverlayManager; -import javax.inject.Inject; - @PluginDescriptor( - name = "Freeze Timers", - description = "Shows a freeze timer overlay on players", - tags = {"freeze", "timers", "barrage", "teleblock", "pklite"}, - type = PluginType.PVP + name = "Freeze Timers", + description = "Shows a freeze timer overlay on players", + tags = {"freeze", "timers", "barrage", "teleblock", "pklite"}, + type = PluginType.PVP ) public class FreezeTimersPlugin extends Plugin { - + @Inject private Client client; - + @Inject private OverlayManager overlayManager; - + @Inject private Timers timers; - + @Inject private PrayerTracker prayerTracker; - + @Inject private FreezeTimersOverlay overlay; - + public void startUp() { overlayManager.add(overlay); } - + public void shutDown() { overlayManager.remove(overlay); } - + @Provides public FreezeTimersConfig getConfig(ConfigManager configManager) { return configManager.getConfig(FreezeTimersConfig.class); } - + @Subscribe public void onGraphicChanged(GraphicChanged graphicChanged) { @@ -73,15 +71,19 @@ public class FreezeTimersPlugin extends Plugin { length /= 2; } + if (timers.getTimerEnd(graphicChanged.getActor(), effect.getType()) > System.currentTimeMillis()) + { + return; + } timers.setTimerEnd(graphicChanged.getActor(), effect.getType(), - System.currentTimeMillis() + length); + System.currentTimeMillis() + length); } - + @Subscribe public void onGameTick(GameTick tickEvent) { timers.gameTick(); prayerTracker.gameTick(); } - + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PlayerSpellEffect.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PlayerSpellEffect.java index 6e524e9aa0..1d8f22a0e5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PlayerSpellEffect.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PlayerSpellEffect.java @@ -6,7 +6,7 @@ import lombok.Getter; @AllArgsConstructor public enum PlayerSpellEffect { - BIND("Bind", 181,5000, true, 0, TimerType.FREEZE), + BIND("Bind", 181, 5000, true, 0, TimerType.FREEZE), SNARE("Snare", 180, 10000, true, 1, TimerType.FREEZE), ENTANGLE("Entangle", 179, 15000, true, 2, TimerType.FREEZE), RUSH("Ice Rush", 361, 5000, false, 3, TimerType.FREEZE), @@ -17,7 +17,7 @@ public enum PlayerSpellEffect VENG("Vengeance", 726, 30000, false, 8, TimerType.VENG), VENG_OTHER("Vengeance Other", 725, 30000, false, 9, TimerType.VENG), NONE("Nothing", -69, 420, true, 9999, TimerType.THIS_SHIT_BROKE); - + @Getter private final String name; @Getter @@ -30,7 +30,7 @@ public enum PlayerSpellEffect private final int spriteIdx; @Getter private final TimerType type; - + public static PlayerSpellEffect getFromSpotAnim(int spotAnim) { for(PlayerSpellEffect effect : values()) @@ -40,5 +40,5 @@ public enum PlayerSpellEffect } return NONE; } - + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PrayerTracker.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PrayerTracker.java index a7aa54b710..3cecf8519a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PrayerTracker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PrayerTracker.java @@ -1,26 +1,25 @@ package net.runelite.client.plugins.freezetimers; +import java.util.HashMap; +import javax.inject.Inject; +import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.NPC; import net.runelite.api.Player; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.HashMap; - @Slf4j @Singleton public class PrayerTracker { - + @Inject private Client client; - + private HashMap> lastTick = new HashMap<>(); private HashMap> newTick = new HashMap<>(); - + public void gameTick() { lastTick.clear(); @@ -35,7 +34,7 @@ public class PrayerTracker processActor(npc); } } - + private void processActor(Actor actor) { if (!newTick.containsKey(actor)) @@ -43,20 +42,23 @@ public class PrayerTracker newTick.put(actor, new HashMap<>()); } if (actor instanceof Player) - if(actor instanceof Player) { + { + if (actor instanceof Player) + { newTick.get(actor).put("PrayerIcon", ((Player) actor).getOverheadIcon() == null ? -1 : ((Player) actor).getOverheadIcon().ordinal()); } + } newTick.get(actor).put("SpotAnim", actor.getGraphic()); } - + public int getPrayerIconLastTick(Actor p) { return lastTick.getOrDefault(p, new HashMap<>()).getOrDefault("PrayerIcon", -1337); } - + public int getSpotanimLastTick(Actor p) { return lastTick.getOrDefault(p, new HashMap<>()).getOrDefault("SpotAnim", -1337); } - + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/TimerType.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/TimerType.java index 699d9f6403..c9e30c4dc1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/TimerType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/TimerType.java @@ -5,5 +5,5 @@ public enum TimerType FREEZE, VENG, TELEBLOCK, - THIS_SHIT_BROKE; + THIS_SHIT_BROKE } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/Timers.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/Timers.java index 09f3694a2d..58345fcc06 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/Timers.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/Timers.java @@ -1,29 +1,27 @@ package net.runelite.client.plugins.freezetimers; +import java.util.HashMap; +import javax.inject.Inject; +import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; import net.runelite.api.Client; -import net.runelite.api.Player; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.HashMap; @Slf4j @Singleton public class Timers { - + @Inject private Client client; - + private HashMap> timerMap = new HashMap<>(); - + public void gameTick() { - + } - + public void setTimerEnd(Actor actor, TimerType type, long n) { if (!timerMap.containsKey(actor)) @@ -32,16 +30,16 @@ public class Timers } timerMap.get(actor).put(type, n); } - + public long getTimerEnd(Actor actor, TimerType type) { if (!timerMap.containsKey(actor)) { timerMap.put(actor, new HashMap<>()); } - return timerMap.get(actor).getOrDefault(type, (long)0); + return timerMap.get(actor).getOrDefault(type, (long) 0); } - + public boolean areAllTimersZero(Actor actor) { for (TimerType type : TimerType.values()) @@ -53,5 +51,5 @@ public class Timers } return true; } - + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/friendtagging/FriendTaggingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/friendtagging/FriendTaggingPlugin.java new file mode 100644 index 0000000000..1352b351bb --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/friendtagging/FriendTaggingPlugin.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2019. PKLite - All Rights Reserved + * Unauthorized modification, distribution, or possession of this source file, via any medium is strictly prohibited. + * Proprietary and confidential. Refer to PKLite License file for more information on + * full terms of this copyright and to determine what constitutes authorized use. + * Written by PKLite(ST0NEWALL, others) , 2019 + * + */ + +package net.runelite.client.plugins.friendtagging; + +import com.google.common.base.Strings; +import com.google.common.collect.ObjectArrays; + +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import javax.inject.Inject; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.*; +import net.runelite.api.events.*; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.chatbox.ChatboxPanelManager; +import net.runelite.client.game.chatbox.ChatboxTextInput; +import net.runelite.client.menus.MenuManager; +import net.runelite.client.menus.WidgetMenuOption; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.util.Text; +import org.apache.commons.lang3.ArrayUtils; + +@Slf4j +@PluginDescriptor( + name = "Friend Tagging", + description = "Tag people on your friends list.", + tags = {"PVP", "friend", "finder", "pk", "pklite"}, + type = PluginType.UTILITY +) +public class FriendTaggingPlugin extends Plugin +{ + public static ConcurrentHashMap taggedFriends = new ConcurrentHashMap<>(); + + private static final String CONFIG_GROUP = "friendtagging"; + private static final int CHARACTER_LIMIT = 30; + private static final String KEY_PREFIX = "tag_"; + private static final String ADD_TAG = "Add Tag"; + private static final String DELETE_TAG = "Delete Tag"; + private WidgetMenuOption friendsTabMenuOption = new WidgetMenuOption("Copy to", "clipboard", + WidgetInfo.FIXED_VIEWPORT_FRIENDS_TAB); + private WidgetMenuOption ignoreTabMenuOption = new WidgetMenuOption("Copy to", "clipboard", + WidgetInfo.FIXED_VIEWPORT_IGNORES_TAB); + private WidgetMenuOption friendTabResizableOption = new WidgetMenuOption("Copy to", "clipboard", + WidgetInfo.FIXED_VIEWPORT_FRIENDS_TAB); + private WidgetMenuOption ignoreTabResizableOption = new WidgetMenuOption("Copy to", "clipboard", + WidgetInfo.FIXED_VIEWPORT_IGNORES_TAB); + + @Inject + private Client client; + + @Inject + private ConfigManager configManager; + + @Inject + private MenuManager menuManager; + + @Inject + private ChatboxPanelManager chatboxPanelManager; + + @Override + protected void startUp() throws Exception + { + menuManager.addManagedCustomMenu(friendsTabMenuOption); + menuManager.addManagedCustomMenu(ignoreTabMenuOption); + menuManager.addManagedCustomMenu(friendTabResizableOption); + menuManager.addManagedCustomMenu(ignoreTabResizableOption); + loadFriendTags(); + } + + @Override + protected void shutDown() throws Exception + { + menuManager.removeManagedCustomMenu(friendsTabMenuOption); + menuManager.removeManagedCustomMenu(ignoreTabMenuOption); + menuManager.removeManagedCustomMenu(friendTabResizableOption); + menuManager.removeManagedCustomMenu(ignoreTabResizableOption); + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + final int groupId = WidgetInfo.TO_GROUP(event.getActionParam1()); + + if (groupId == WidgetInfo.FRIENDS_LIST.getGroupId() && event.getOption().equals("Message")) + { + // Friends have color tags + String friendName = Text.removeTags(event.getTarget()); + + // Build "Add Note" or "Edit Note" menu entry + final MenuEntry entry = new MenuEntry(); + entry.setOption(friendName == null || getTag(friendName) == null ? ADD_TAG : DELETE_TAG); + entry.setType(MenuAction.RUNELITE.getId()); + entry.setTarget(event.getTarget()); //Preserve color codes here + entry.setParam0(event.getActionParam0()); + entry.setParam1(event.getActionParam1()); + + // Add menu entry + final MenuEntry[] menuEntries = ObjectArrays.concat(client.getMenuEntries(), entry); + client.setMenuEntries(menuEntries); + } + } + + @Subscribe + public void onRemovedFriend(RemovedFriend event) + { + final String displayName = event.getName().trim().toLowerCase(); + deleteTag(displayName); + } + + @Subscribe + public void onNameableNameChanged(NameableNameChanged event) + { + final Nameable nameable = event.getNameable(); + + if (nameable instanceof Friend) + { + // Migrate a friend's note to their new display name + final Friend friend = (Friend) nameable; + if (friend.getName() != null && friend.getPrevName() != null) + { + migrateFriendTag(friend.getName(), friend.getPrevName()); + } + } + } + + @Subscribe + public void onWidgetMenuOptionClicked(WidgetMenuOptionClicked event) + { + if (event.getWidget().getId() == WidgetInfo.FIXED_VIEWPORT_FRIENDS_TAB.getId() && + Text.standardize(event.getMenuTarget()).equals(Text.standardize("clipboard"))) + { + friendIgnoreToClipboard(); + } + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked event) + { + if (WidgetInfo.TO_GROUP(event.getWidgetId()) == WidgetInfo.FRIENDS_LIST.getGroupId()) + { + if (Strings.isNullOrEmpty(event.getMenuTarget())) + { + return; + } + + final String sanitizedTarget = Text.removeTags(event.getMenuTarget()); + + if (event.getMenuOption().equals(ADD_TAG)) + { + event.consume(); + final ChatboxTextInput build = chatboxPanelManager.openTextInput("Enter the tag").value("") + .onDone((content) -> + { + if (content == null) + { + return; + } + content = Text.removeTags(content).trim(); + setTag(sanitizedTarget, content); + }).build(); + } + if (event.getMenuOption().equals(DELETE_TAG)) + { + event.consume(); + client.getLogger().info(sanitizedTarget); + taggedFriends.forEach((k, v) -> client.getLogger().info(k + ": ", v)); + deleteTag(sanitizedTarget); + } + } + + } + + /** + * Gets a tag from the currently loaded tags + * + * @param name the username of the player + * @return the text of the tag + */ + @NonNull + private String getTag(String name) + { + name = name.trim().toLowerCase(); + String keyName = KEY_PREFIX + name; + return taggedFriends.get(keyName); + } + + /** + * Sets a tag for a friend + * + * @param name the username of the player to tag + * @param tag the text of the tag + */ + private void setTag(String name, String tag) + { + client.getLogger().info("SETTING " + name + ": " + tag); + name = name.trim().toLowerCase(); + String keyName = KEY_PREFIX + name; + if (tag.length() <= CHARACTER_LIMIT) + { + taggedFriends.put(keyName, tag); + configManager.setConfiguration(CONFIG_GROUP, keyName, tag); + } + } + + /** + * Deletes a friends tag + * + * @param name the username of the friend to delete the tag for + */ + private void deleteTag(String name) + { + name = name.trim().toLowerCase(); + String keyName = KEY_PREFIX + name; + configManager.unsetConfiguration(CONFIG_GROUP, keyName); + taggedFriends.remove(keyName); + } + + /** + * Loads all of the friend tags for use with player indicators + */ + private void loadFriendTags() + { + String prefix = CONFIG_GROUP + "." + KEY_PREFIX; + for (String key : configManager.getConfigurationKeys(prefix)) + { + key = key.replace(CONFIG_GROUP + ".", ""); + String result = configManager.getConfiguration(CONFIG_GROUP, key); + if (Objects.nonNull(result) && !result.equals("")) + { + taggedFriends.put(key, configManager.getConfiguration(CONFIG_GROUP, key)); + } + } + } + + /** + * Migrate a friend note to a new display name, and remove the previous one. + * If current name already has a note, or previous name had none, do nothing. + */ + private void migrateFriendTag(String currentDisplayName, String prevDisplayName) + { + final String currentTag = getTag(currentDisplayName); + if (currentTag == null) + { + final String prevTag = getTag(prevDisplayName); + if (prevTag != null) + { + setTag(prevDisplayName, ""); + setTag(currentDisplayName, prevTag); + } + } + } + + /** + * This method combines the list of usernames on local players friend/ignore list into a comma delimited string + * and then copies it to the clipboard. + */ + private void friendIgnoreToClipboard() + { + StringBuilder friendsList = new StringBuilder(); + Friend[] friends = client.getFriends(); + Ignore[] ignores = client.getIgnores(); + String[] friendsIgnores = ArrayUtils.addAll(Arrays.stream(friends).map(Friend::getName).toArray(String[]::new), + Arrays.stream(ignores).map(Ignore::getName).toArray(String[]::new)); + HashSet names = new HashSet<>(Arrays.asList(friendsIgnores)); + names.forEach(n -> friendsList.append(n.toLowerCase()).append(",")); + StringSelection namesSelection = new StringSelection(friendsList.toString()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(namesSelection, namesSelection); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/HidePrayersConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/HidePrayersConfig.java index 8a92bed779..5ad0060269 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/HidePrayersConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/HidePrayersConfig.java @@ -1,35 +1,118 @@ -package net.runelite.client.plugins.hideprayers; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("hideprayers") -public interface HidePrayersConfig extends Config -{ - @ConfigItem( - position = 0, - keyName = "pk prayers", - name = "Hides none pk prayers", - description = "Hides widget icons." - ) - default boolean showPrayers() { return false; } - - @ConfigItem( - position = 1, - keyName = "eagle/mystic", - name = "Shows eagle and mystic prayers", - description = "Hides widget icons." - ) - default boolean showEagleMystic() { return false; } - - @ConfigItem( - position = 1, - keyName = "ultstr", - name = "Shows ultimate strength", - description = "Hides widget icons." - ) - default boolean showUltStrength() { return false; } - -} - +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.hideprayers; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("hideprayers") +public interface HidePrayersConfig extends Config +{ + @ConfigItem + ( + position = 0, + keyName = "pk prayers", + name = "Hides none pk prayers", + description = "Hides widget icons." + ) + default boolean showPrayers() + { + return false; + } + + @ConfigItem + ( + position = 1, + keyName = "eagle/mystic", + name = "Shows Eagle and Mystic Prayers", + description = "Hides widget icons." + ) + default boolean showEagleMystic() + { + return false; + } + + @ConfigItem + ( + position = 2, + keyName = "ultstr", + name = "Shows Ultimate Strength/Incredible Reflex/Steel Skin", + description = "Hides widget icons." + ) + default boolean showUltStrength() + { + return false; + } + + @ConfigItem + ( + position = 3, + keyName = "preserve", + name = "Shows Preserve", + description = "unides widget icons." + ) + default boolean showPreserve() + { + return false; + } + + @ConfigItem + ( + position = 4, + keyName = "redemption", + name = "Shows Redemption", + description = "unides widget icons." + ) + default boolean showRedemption() + { + return false; + } + + @ConfigItem + ( + position = 5, + keyName = "rapidheal", + name = "Shows Rapid Heal", + description = "unides widget icons." + ) + default boolean showRapidHeal() + { + return false; + } + + @ConfigItem + ( + position = 6, + keyName = "rapidRestore", + name = "Shows Rapid restore", + description = "unides widget icons." + ) + default boolean showRapidRestore() + { + return false; + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/HidePrayersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/HidePrayersPlugin.java index fa88699a97..546072b88c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/HidePrayersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/HidePrayersPlugin.java @@ -1,171 +1,297 @@ -package net.runelite.client.plugins.hideprayers; - -import com.google.common.collect.ImmutableList; -import net.runelite.client.eventbus.Subscribe; -import com.google.inject.Provides; -import net.runelite.api.*; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameStateChanged; -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.config.ConfigManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; - -import javax.inject.Inject; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -@PluginDescriptor( - name = "Hide Prayers", - description = "Hides specific Prayers in the Prayer tab.", - type = PluginType.UTILITY -) -public class HidePrayersPlugin extends Plugin { - private static final int PRAYER_COUNT = Prayer.values().length; - - private static final List PRAYER_WIDGET_INFO_LIST = ImmutableList.of(WidgetInfo.PRAYER_THICK_SKIN, - WidgetInfo.PRAYER_BURST_OF_STRENGTH, WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, WidgetInfo.PRAYER_SHARP_EYE, - WidgetInfo.PRAYER_MYSTIC_WILL, WidgetInfo.PRAYER_ROCK_SKIN, WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, - WidgetInfo.PRAYER_IMPROVED_REFLEXES, WidgetInfo.PRAYER_RAPID_RESTORE, WidgetInfo.PRAYER_RAPID_HEAL, - WidgetInfo.PRAYER_PROTECT_ITEM, WidgetInfo.PRAYER_HAWK_EYE, WidgetInfo.PRAYER_MYSTIC_LORE, - WidgetInfo.PRAYER_STEEL_SKIN, WidgetInfo.PRAYER_ULTIMATE_STRENGTH, WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, - WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, - WidgetInfo.PRAYER_PROTECT_FROM_MELEE, WidgetInfo.PRAYER_EAGLE_EYE, WidgetInfo.PRAYER_MYSTIC_MIGHT, - WidgetInfo.PRAYER_RETRIBUTION, WidgetInfo.PRAYER_REDEMPTION, WidgetInfo.PRAYER_SMITE, - WidgetInfo.PRAYER_PRESERVE, WidgetInfo.PRAYER_CHIVALRY, WidgetInfo.PRAYER_PIETY, WidgetInfo.PRAYER_RIGOUR, - WidgetInfo.PRAYER_AUGURY); - - @Inject - private Client client; - - @Inject - private HidePrayersConfig config; - - @Provides - HidePrayersConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(HidePrayersConfig.class); - } - - @Override - protected void startUp() throws Exception { - hidePrayers(); - } - - @Override - protected void shutDown() throws Exception { - restorePrayers(); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) { - if (event.getGameState() == GameState.LOGGED_IN) { - hidePrayers(); - } - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) { - if (event.getGroup().equals("hideprayers")) { - hidePrayers(); - } - } - - @Subscribe - public void onWidgetLoaded(WidgetLoaded event) { - if (event.getGroupId() == WidgetID.PRAYER_GROUP_ID || event.getGroupId() == WidgetID.QUICK_PRAYERS_GROUP_ID) { - hidePrayers(); - } - } - - private PrayerTabState getPrayerTabState() { - HashTable componentTable = client.getComponentTable(); - for (WidgetNode widgetNode : componentTable.getNodes()) { - if (widgetNode.getId() == WidgetID.PRAYER_GROUP_ID) { - return PrayerTabState.PRAYERS; - } else if (widgetNode.getId() == WidgetID.QUICK_PRAYERS_GROUP_ID) { - return PrayerTabState.QUICK_PRAYERS; - } - } - return PrayerTabState.NONE; - } - - private void restorePrayers() { - if (client.getGameState() != GameState.LOGGED_IN) - return; - - PrayerTabState prayerTabState = getPrayerTabState(); - - if (prayerTabState == PrayerTabState.PRAYERS) { - List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) - .filter(Objects::nonNull).collect(Collectors.toList()); - - if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) - return; - - for (int index = 0; index < PRAYER_COUNT; index++) - prayerWidgets.get(Prayer.values()[index].ordinal()).setHidden(false); - } - } - - private void hidePrayers() { - if (client.getGameState() != GameState.LOGGED_IN) - return; - - PrayerTabState prayerTabState = getPrayerTabState(); - - if (prayerTabState == PrayerTabState.PRAYERS) { - List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) - .filter(Objects::nonNull).collect(Collectors.toList()); - - if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) - return; - - for (int index = 0; index < PRAYER_COUNT; index++) { - Prayer prayer = Prayer.values()[index]; - Widget prayerWidget = prayerWidgets.get(prayer.ordinal()); - - if (!config.showPrayers() && !config.showEagleMystic()) - prayerWidget.setHidden(false); - - if (config.showPrayers()) { - prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false);// protect item - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false);// mage - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false);// range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false);// melee - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false);// smite - if (config.showEagleMystic()) { - prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(true);// rigour - prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(true);// augury - } else { - prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(false);// rigour - prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(false);// augury - } - if (config.showUltStrength()) { - prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(true);// piety - } else { - prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false);// piety - } - } - if (config.showEagleMystic()) { - prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false);// eagle - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false);// mystic - prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(true);// rigour - prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(true);// augury - } - if (config.showUltStrength()) { - prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false);// Ult Strength - prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(true);// piety - } - - } - } - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.hideprayers; + +import com.google.common.collect.ImmutableList; +import net.runelite.client.eventbus.Subscribe; +import com.google.inject.Provides; +import net.runelite.api.*; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameStateChanged; +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.config.ConfigManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import javax.inject.Inject; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@PluginDescriptor +( + name = "Hide Prayers", + description = "Hides specific Prayers in the Prayer tab.", + type = PluginType.UTILITY +) +public class HidePrayersPlugin extends Plugin +{ + private static final int PRAYER_COUNT = Prayer.values().length; + + private static final List PRAYER_WIDGET_INFO_LIST = ImmutableList.of( + WidgetInfo.PRAYER_THICK_SKIN, //0 + WidgetInfo.PRAYER_BURST_OF_STRENGTH, //1 + WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, //2 + WidgetInfo.PRAYER_SHARP_EYE, //3 + WidgetInfo.PRAYER_MYSTIC_WILL, //4 + WidgetInfo.PRAYER_ROCK_SKIN, //5 + WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, //6 + WidgetInfo.PRAYER_IMPROVED_REFLEXES, //7 + WidgetInfo.PRAYER_RAPID_RESTORE, //8 + WidgetInfo.PRAYER_RAPID_HEAL, //9 + WidgetInfo.PRAYER_PROTECT_ITEM, //10 + WidgetInfo.PRAYER_HAWK_EYE, //11 + WidgetInfo.PRAYER_MYSTIC_LORE, //12 + WidgetInfo.PRAYER_STEEL_SKIN, //13 + WidgetInfo.PRAYER_ULTIMATE_STRENGTH, //14 + WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, //15 + WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, //16 + WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, //17 + WidgetInfo.PRAYER_PROTECT_FROM_MELEE, //18 + WidgetInfo.PRAYER_EAGLE_EYE, //19 + WidgetInfo.PRAYER_MYSTIC_MIGHT, //20 + WidgetInfo.PRAYER_RETRIBUTION, //21 + WidgetInfo.PRAYER_REDEMPTION, //22 + WidgetInfo.PRAYER_SMITE, //23 + WidgetInfo.PRAYER_PRESERVE, //24 + WidgetInfo.PRAYER_CHIVALRY, //25 + WidgetInfo.PRAYER_PIETY, //26 + WidgetInfo.PRAYER_RIGOUR, //27 + WidgetInfo.PRAYER_AUGURY); //28 + + @Inject + private Client client; + + @Inject + private HidePrayersConfig config; + + @Provides + HidePrayersConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(HidePrayersConfig.class); + } + + @Override + protected void startUp() throws Exception + { + hidePrayers(); + } + + @Override + protected void shutDown() throws Exception + { + restorePrayers(); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGGED_IN) + { + hidePrayers(); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("hideprayers")) + { + hidePrayers(); + } + } + + @Subscribe + public void onWidgetLoaded(WidgetLoaded event) + { + if (event.getGroupId() == WidgetID.PRAYER_GROUP_ID || event.getGroupId() == WidgetID.QUICK_PRAYERS_GROUP_ID) + { + hidePrayers(); + } + } + + private PrayerTabState getPrayerTabState() + { + HashTable componentTable = client.getComponentTable(); + for (WidgetNode widgetNode : componentTable.getNodes()) + { + if (widgetNode.getId() == WidgetID.PRAYER_GROUP_ID) + { + return PrayerTabState.PRAYERS; + } + else if (widgetNode.getId() == WidgetID.QUICK_PRAYERS_GROUP_ID) + { + return PrayerTabState.QUICK_PRAYERS; + } + } + return PrayerTabState.NONE; + } + + private void restorePrayers() + { + if (client.getGameState() != GameState.LOGGED_IN) + return; + + PrayerTabState prayerTabState = getPrayerTabState(); + + if (prayerTabState == PrayerTabState.PRAYERS) + { + List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) + .filter(Objects::nonNull).collect(Collectors.toList()); + + if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + return; + + for (int index = 0; index < PRAYER_COUNT; index++) + prayerWidgets.get(Prayer.values()[index].ordinal()).setHidden(false); + } + } + + private void hidePrayers() + { + if (client.getGameState() != GameState.LOGGED_IN) + return; + + PrayerTabState prayerTabState = getPrayerTabState(); + + if (prayerTabState == PrayerTabState.PRAYERS) + { + List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) + .filter(Objects::nonNull).collect(Collectors.toList()); + + if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + return; + + for (int index = 0; index < PRAYER_COUNT; index++) + { + Prayer prayer = Prayer.values()[index]; + Widget prayerWidget = prayerWidgets.get(prayer.ordinal()); + + if (!config.showPrayers() && !config.showEagleMystic()) + prayerWidget.setHidden(false); + + if (config.showPrayers()) + { + prayerWidget.setHidden(true); + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false);// protect item + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false);// mage + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false);// range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false);// melee + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false);// smite + if (config.showEagleMystic()) + { + prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(true);// rigour + prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(true);// augury + } + else + { + prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(false);// rigour + prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(false);// augury + } + if (config.showUltStrength()) + { + prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(true);// piety + } + else + { + prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false);// piety + } + if (config.showPreserve()) + { + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(true);// Preserve + } + else + { + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false);// Preserve + } + if (config.showRedemption()) + { + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(true);// Redemption + } + else + { + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false);// Redemption + } + if (config.showRapidRestore()) + { + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(true);// Rapid Restore + } + else + { + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false);// Rapid Restore + } + if (config.showRapidHeal()) + { + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(true);// Rapid Heal + } + else + { + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false);// Rapid Heal + } + } + if (config.showEagleMystic()) + { + prayerWidget.setHidden(true); + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false);// eagle + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false);// mystic + prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(true);// rigour + prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(true);// augury + } + if (config.showUltStrength()) + { + prayerWidget.setHidden(true); + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false);// Steel Skin + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false);// Ult Strength + prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false);// Incredible Reflexes + prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(true);// piety + } + if (config.showPreserve()) + { + prayerWidget.setHidden(true); + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false);// Preserve + } + if (config.showRedemption()) + { + prayerWidget.setHidden(true); + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false);// Redemption + } + if (config.showRapidRestore()) + { + prayerWidget.setHidden(true); + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false);// Rapid Restore + } + if (config.showRapidHeal()) + { + prayerWidget.setHidden(true); + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false);// Rapid Heal + } + } + } + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PrayerTabState.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PrayerTabState.java index 699300f8a9..c0249c3f0e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PrayerTabState.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PrayerTabState.java @@ -1,8 +1,33 @@ -package net.runelite.client.plugins.hideprayers; - -public enum PrayerTabState -{ - NONE, - PRAYERS, - QUICK_PRAYERS -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.hideprayers; + +public enum PrayerTabState +{ + NONE, + PRAYERS, + QUICK_PRAYERS +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/locationchatter/LocationChatterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/locationchatter/LocationChatterPlugin.java deleted file mode 100644 index b15bc20df1..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/locationchatter/LocationChatterPlugin.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.locationchatter; - -import com.google.inject.Provides; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.ScriptID; -import net.runelite.api.VarClientStr; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.VarClientStrChanged; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.input.KeyManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginManager; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.plugins.wildernesslocations.WildernessLocationsPlugin; -import net.runelite.client.util.HotkeyListener; - -import javax.inject.Inject; - -@Slf4j -@PluginDescriptor( - name = "Location Chatter", - tags = {"location", "exilent", "pklite", "spammer"}, - type = PluginType.PVP - ) -public class LocationChatterPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private ClientThread clientThread; - - @Inject - LocationChatterConfig config; - - @Inject - private KeyManager keyManager; - - @Inject - private PluginManager pluginManager; - - private WildernessLocationsPlugin wildyLocsPlugin; - - private String oldChat = ""; - private int currentCooldown = 0; - private final int COOLDOWN_TICKS = 30; - - private final HotkeyListener hotkeyListener = new HotkeyListener(() -> config.keybind()) - { - @Override - public void hotkeyPressed() - { - sendLocToCC(); - } - }; - - @Override - public void startUp() - { - for (Plugin pl : pluginManager.getPlugins()) - { - if (pl instanceof WildernessLocationsPlugin) - { - wildyLocsPlugin = (WildernessLocationsPlugin) pl; - } - } - keyManager.registerKeyListener(hotkeyListener); - } - - @Override - public void shutDown() - { - keyManager.unregisterKeyListener(hotkeyListener); - } - - @Provides - LocationChatterConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(LocationChatterConfig.class); - } - - @Subscribe - public void onGameTick(GameTick tickEvent) - { - if (currentCooldown != 0) - { - currentCooldown--; - } - } - - @Subscribe - public void onVarClientStrChanged(VarClientStrChanged varClient) - { - String newChat = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT); - if (varClient.getIndex() == VarClientStr.CHATBOX_TYPED_TEXT.getIndex() && !newChat.equals(oldChat)) - { - oldChat = newChat; - } - } - - private boolean inClanChat() - { - return client.getWidget(WidgetInfo.CLAN_CHAT_TITLE) != null; - } - - private void sendMessage(String text) - { - int mode = 0; - if (inClanChat() && text.startsWith("/")) - { - mode = 2; - } - int finalMode = mode; - Runnable r = () -> - { - String cached = oldChat; - client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, text); - client.runScript(ScriptID.CHATBOX_INPUT, finalMode, text); - oldChat = cached; - client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, oldChat); - }; - clientThread.invoke(r); - } - - private void sendLocToCC() - { - if (currentCooldown != 0) - { - return; - } - - String location = wildyLocsPlugin.getLocationString(); - if (location.equals("")) - { - return; - } - sendMessage("/World: " + client.getWorld() + " Location: " + location); - currentCooldown = COOLDOWN_TICKS; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java index bba5994d89..c2f355d7f9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java @@ -59,6 +59,16 @@ public interface LootTrackerConfig extends Config return true; } + @ConfigItem( + keyName = "chestLootChat", + name = "Show chest loot value in chat", + description = "Show the value of items from CoX/ToB/Barrows chests in chat" + ) + default boolean chestLootChat() + { + return true; + } + @ConfigItem( keyName = "syncPanel", name = "Synchronize panel contents", @@ -70,4 +80,4 @@ public interface LootTrackerConfig extends Config { return true; } -} \ No newline at end of file +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index 5429ec5941..f561a87a25 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -51,6 +51,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; +import net.runelite.api.Item; import net.runelite.api.InventoryID; import net.runelite.api.ItemComposition; import net.runelite.api.ItemContainer; @@ -66,6 +67,10 @@ import net.runelite.api.widgets.WidgetID; import net.runelite.client.account.AccountSession; import net.runelite.client.account.SessionManager; import net.runelite.client.callback.ClientThread; +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.events.NpcLootReceived; @@ -80,6 +85,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; import net.runelite.client.util.ImageUtil; +import net.runelite.client.util.StackFormatter; import net.runelite.client.util.Text; import net.runelite.http.api.loottracker.GameItem; import net.runelite.http.api.loottracker.LootRecord; @@ -115,6 +121,9 @@ public class LootTrackerPlugin extends Plugin @Inject private ItemManager itemManager; + + @Inject + private ChatMessageManager chatMessageManager; @Inject private SpriteManager spriteManager; @@ -352,6 +361,29 @@ public class LootTrackerPlugin extends Plugin return; } + if (!(event.getGroupId() == WidgetID.CLUE_SCROLL_REWARD_GROUP_ID) && config.chestLootChat()) + { + Item[] items = container.getItems(); + long chestPrice = 0; + for (Item item : items) + { + long itemStack = (long) itemManager.getItemPrice(item.getId()) * (long) item.getQuantity(); + chestPrice += itemStack; + } + + final ChatMessageBuilder message = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append("Your loot is worth around ") + .append(StackFormatter.formatNumber(chestPrice)) + .append(" coins.") + .append(ChatColorType.NORMAL); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.ITEM_EXAMINE) + .runeLiteFormattedMessage(message.build()) + .build()); + } + // Convert container items to array of ItemStack final Collection items = Arrays.stream(container.getItems()) .filter(item -> item.getId() > 0) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningPlugin.java index 1a7fec63b7..e8f0691f8d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningPlugin.java @@ -37,10 +37,10 @@ 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.PluginType; import net.runelite.client.plugins.mining.MiningConfig; import net.runelite.client.task.Schedule; import net.runelite.client.ui.overlay.OverlayManager; - import javax.inject.Inject; import java.time.temporal.ChronoUnit; import java.util.HashSet; @@ -52,6 +52,7 @@ import static net.runelite.api.ObjectID.*; name = "Mining", description = "Show helpful information about Mining", tags = {"mining", "skilling", "overlay"}, + type = PluginType.UTILITY, enabledByDefault = false ) public class MiningPlugin extends Plugin diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/FriendMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/FriendMinimapOverlay.java deleted file mode 100644 index 6786d24ba6..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/FriendMinimapOverlay.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2018, Seth - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.playerindicators; - -import 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.OverlayUtil; - -import javax.inject.Inject; -import java.awt.*; - -public class FriendMinimapOverlay extends Overlay -{ - private final PlayerIndicatorsConfig config; - private final PlayerIndicatorsService playerIndicatorsService; - - @Inject - private FriendMinimapOverlay(PlayerIndicatorsConfig config, PlayerIndicatorsService playerIndicatorsService) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_WIDGETS); - this.config = config; - this.playerIndicatorsService = playerIndicatorsService; - } - - @Override - public Dimension render(Graphics2D graphics) - { - playerIndicatorsService.forEachPlayer((player, color) -> renderPlayerMinimapOverlay(graphics, player, color)); - return null; - } - - private void renderPlayerMinimapOverlay(Graphics2D graphics, Player actor, Color color) { - Point minimapLocation = actor.getMinimapLocation(); - if (!config.highlightFriends() || minimapLocation == null || color == null || actor.isClanMember()) - return; - OverlayUtil.renderMinimapLocation(graphics, minimapLocation, color); - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java index 7d7245222e..969103036b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java @@ -25,9 +25,12 @@ package net.runelite.client.plugins.playerindicators; import java.awt.Color; + +import net.runelite.api.ClanMemberRank; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Range; @ConfigGroup("playerindicators") public interface PlayerIndicatorsConfig extends Config @@ -137,48 +140,13 @@ public interface PlayerIndicatorsConfig extends Config name = "Non-clan member color", description = "Color of non-clan member names" ) - default Color getNonClanMemberColor() { return Color.RED; } - - @ConfigItem( - position = 10, - keyName = "drawAttackerNames", - name = "Highlight attacker players", - description = "Configures whether or not attacker players should be highlighted" - ) - default boolean highlightAttackerPlayers() + default Color getNonClanMemberColor() { - return false; + return Color.RED; } @ConfigItem( - position = 11, - keyName = "attackerColor", - name = "Attacker player color", - description = "Color of attacking player names" - ) - default Color getAttackerPlayerColor() { return new Color(241, 0, 108); } - - @ConfigItem( - position = 12, - keyName = "drawAttackableNames", - name = "Highlight attackable players", - description = "Configures whether or not attackable players should be highlighted" - ) - default boolean highlightAttackablePlayers() - { - return false; - } - - @ConfigItem( - position = 13, - keyName = "attackableColor", - name = "Attackable player color", - description = "Color of attackable player names" - ) - default Color getAttackablePlayerColor() { return new Color(231, 122,- 0); } - - @ConfigItem( - position = 14, + position = 10, keyName = "drawPlayerTiles", name = "Draw tiles under players", description = "Configures whether or not tiles under highlighted players should be drawn" @@ -189,29 +157,18 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 15, - keyName = "drawOverheadPlayerNames", - name = "Draw names above players", - description = "Configures whether or not player names should be drawn above players" + position = 11, + keyName = "playerNamePosition", + name = "Name position", + description = "Configures the position of drawn player names, or if they should be disabled" ) - default boolean drawOverheadPlayerNames() + default PlayerNameLocation playerNamePosition() { - return true; + return PlayerNameLocation.ABOVE_HEAD; } @ConfigItem( - position = 16, - keyName = "drawOverheadLevels", - name = "Draw combat levels above players", - description = "Configures whether or not combat levels should be drawn above players" - ) - default boolean drawOverheadLevels() - { - return false; - } - - @ConfigItem( - position = 17, + position = 12, keyName = "drawMinimapNames", name = "Draw names on minimap", description = "Configures whether or not minimap names for players with rendered names should be drawn" @@ -222,7 +179,7 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 18, + position = 13, keyName = "colorPlayerMenu", name = "Colorize player menu", description = "Color right click menu for players" @@ -233,7 +190,7 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 19, + position = 14, keyName = "clanMenuIcons", name = "Show clan ranks", description = "Add clan rank to right click menu and next to player names" @@ -243,108 +200,216 @@ public interface PlayerIndicatorsConfig extends Config return true; } - @ConfigItem( - position = 20, - keyName = "showOfflineFriends", - name = "Show offline friends", - description = "Draw friends names even if they're offline" - ) - default boolean showOfflineFriends() - { - return true; - } - @ConfigItem( - position = 21, - keyName = "drawHighlightedNames", - name = "Draw highlighted player names", - description = "Configures whether or not highlighted player names should be drawn" + position = 15, + keyName = "highlightTargets", + name = "Highlight attackable players in wilderness on the minimap", + description = "Highlights players on the minimap that the current player can attack based on combat/wilderness levels", + group = "Target Indicator" ) - default boolean drawHighlightedNames() + default boolean highlightTargets() { return false; } @ConfigItem( - keyName = "highlightedNames", - name = "Highlighted names", - description = "Clan caller names separated by a comma" + position = 16, + keyName = "highlightOverheadTargets", + name = "Highlights attackable players over their head", + description = "Highlights players over their head that the current player can attack based on combat/wilderness levels", + group = "Target Indicator" ) - default String getHighlightedNames() - { - return ""; - } - - @ConfigItem( - keyName = "highlightedNamesColor", - name = "Highlighted names color", - description = "Color of highlighted names" - ) - default Color getHighlightedNamesColor() - { - return Color.ORANGE; - } - - @ConfigItem( - position = 22, - keyName = "drawHighlightedTargetNames", - name = "Draw highlighted target names", - description = "Configures whether or not highlighted target names should be drawn" - ) - default boolean drawHighlightedTargetNames() + default boolean highlightOverheadTargets() { return false; } + @ConfigItem( + position = 17, + keyName = "targetColor", + name = "Target color", + description = "Color of attackable targets", + group = "Target Indicator" + ) + default Color getTargetColor() + { + return Color.RED; + } + + @ConfigItem( + position = 18, + keyName = "showCombat", + name = "Show Combat Levels", + description = "Show the combat level of attackable players next to their name.", + group = "Target Indicator" + ) + default boolean showCombatLevel() + { + return false; + } + + @ConfigItem( + position = 19, + keyName = "playerSkull", + name = "Show Skull Information", + description = "Indicate of the player is skulled.", + group = "Target Indicator" + ) + default boolean playerSkull() + { + return false; + } + + @ConfigItem( + position = 19, + keyName = "minimapSkullLocation", + name = "Skull Icon Location", + description = "The location of the skull icon for skulled players", + group = "Target Indicator" + ) + default PlayerIndicatorsPlugin.minimapSkullLocations skullLocation() + { + return PlayerIndicatorsPlugin.minimapSkullLocations.AFTER_NAME; + } + + @ConfigItem( + position = 19, + keyName = "skulledTargetsOnly", + name = "Tag Skulls Only", + description = "Only indicate skulled targets (which are also attackable)", + group = "Target Indicator" + ) + default boolean skulledTargetsOnly() + { + return false; + } + + @ConfigItem( + position = 19, + keyName = "targetRisk", + name = "Indicate Target Risk", + description = "Indicates the risk (in K GP) of the target", + group = "Target Indicator" + ) + default boolean targetRisk() + { + return false; + } + @ConfigItem( position = 23, - keyName = "highlightedTargetColor", - name = "Highlighted target color", - description = "Color of highlighted target names" + keyName = "rightClickOverhead", + name = "Add Overheads to Right Click Menu", + description = "Feature shows a player's overhead prayer in the right click menu. Useful for DDs, or extremely crowded areas." ) - default Color getHighlightedTargetColor() - { - return new Color(255, 100, 183); - } - - @ConfigItem( - position = 24, - keyName = "limitLevel", - name = "Limit Level", - description = "Limit the players to show +-x your level. Useful for BH" - ) - default boolean limitLevel() + default boolean rightClickOverhead() { return false; } @ConfigItem( - position = 25, - keyName = "level", - name = "Level", - description = "The level to limit players shown +-x" + keyName = "useClanchatRanks", + name = "Use Ranks as Callers", + description = "Uses clanchat ranks as the list of callers", + group = "Callers", + position = 24 ) - default int intLevel() + default boolean useClanchatRanks() { - return 5; + return false; } - @ConfigItem( - position = 26, - keyName = "wildernessOnly", - name = "Show only in wilderness", - description = "Toggle whether or not to only show player indicators in the wilderness" - ) - default boolean showInWildernessOnly() - { - return false; - } + @ConfigItem( + keyName = "callerRank", + name = "Minimum rank for Clan Caller", + description = "Chooses the minimum rank to use as clanchat callers.", + group = "Callers", + position = 25 + ) + default ClanMemberRank callerRank() + { + return ClanMemberRank.CAPTAIN; + } -/* @ConfigItem( + @ConfigItem( + keyName = "callers", + name = "List of callers to highlight", + description = "Highlights callers, only highlights one at a time. Separate each entry with a comma and enter" + + " in the order you want them highlighted.", + group = "Callers" + ) + default String callers() + { + return " "; + } + @ConfigItem( + keyName = "highlightCallers", + name = "Highlight Callers", + description = "Highlights Callers Onscreen", + group = "Callers" + ) + default boolean highlightCallers() + { + return true; + } + @ConfigItem( + position = 26, + keyName = "callerColor", + name = "Caller Color", + description = "Color of Indicated Callers", + group = "Callers" + ) + default Color callerColor() + { + return Color.WHITE; + } + @ConfigItem( position = 27, - keyName="rightClickOverhead", - name="Add Overheads to Right Click Menu", - description="Feature shows a player's overhead prayer in the right click menu. Useful for DDs, or extremely crowded areas.") + keyName = "highlightPile", + name = "Highlight Pile", + description = "Highlights Pile Onscreen", + group = "Callers" + ) + default boolean highlightPile() + { + return false; + } + @ConfigItem( + position = 29, + keyName = "drawPileHull", + name = "Draws the hull of the pile.", + description = "Draws the hull of the pile for best visibility.", + group = "Callers" + ) + default boolean drawPileHull() + { + return false; + } - default boolean rightClickOverhead() { return false; }*/ + @Range( + min = 1, + max = 10 + ) + @ConfigItem( + position = 30, + keyName = "pileColor", + name = "Pile Color", + description = "Color of Indicated Pile", + group = "Callers" + ) + default Color pileColor() + { + return Color.WHITE; + } + @ConfigItem( + position = 27, + keyName = "unchargedGlory", + name = "Uncharged Glory Indication", + description = "Indicates if players have an uncharged glory" + ) + default boolean unchargedGlory() + { + return false; + } + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsMinimapOverlay.java index 266def094c..10e722ea01 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsMinimapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsMinimapOverlay.java @@ -27,20 +27,32 @@ package net.runelite.client.plugins.playerindicators; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import javax.inject.Inject; import javax.inject.Singleton; +import net.runelite.api.Client; import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.friendtagging.FriendTaggingPlugin; 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 net.runelite.client.util.ImageUtil; @Singleton public class PlayerIndicatorsMinimapOverlay extends Overlay { private final PlayerIndicatorsService playerIndicatorsService; private final PlayerIndicatorsConfig config; + private final BufferedImage skullIcon = ImageUtil.getResourceStreamFromClass(PlayerIndicatorsPlugin.class, + "skull.png"); + @Inject + private ItemManager itemManager; + @Inject + private Client client; @Inject private PlayerIndicatorsMinimapOverlay(PlayerIndicatorsConfig config, PlayerIndicatorsService playerIndicatorsService) @@ -61,15 +73,60 @@ public class PlayerIndicatorsMinimapOverlay extends Overlay private void renderPlayerOverlay(Graphics2D graphics, Player actor, Color color) { - final String name = actor.getName().replace('\u00A0', ' '); - if (config.drawMinimapNames()) { - final net.runelite.api.Point minimapLocation = actor.getMinimapLocation(); + String name = actor.getName().replace('\u00A0', ' '); + String tag = ""; + String prefix = "tag_"; + if (FriendTaggingPlugin.taggedFriends.containsKey(prefix + name.trim().toLowerCase())) + { + tag = " [" + FriendTaggingPlugin.taggedFriends.get(prefix + name.trim().toLowerCase()) + "] "; + } + + name += tag; + + net.runelite.api.Point minimapLocation = actor.getMinimapLocation(); if (minimapLocation != null) { - OverlayUtil.renderTextLocation(graphics, minimapLocation, name, color); + if (config.showCombatLevel()) + { + if (config.showCombatLevel()) + { + name += "-(" + actor.getCombatLevel() + ")"; + } + } + if (config.drawMinimapNames()) + { + if (actor.getSkullIcon() != null && config.playerSkull()) + { + switch (actor.getSkullIcon()) + { + case SKULL: + + int width = graphics.getFontMetrics().stringWidth(name); + int height = graphics.getFontMetrics().getHeight(); + if (config.skullLocation().equals(PlayerIndicatorsPlugin.minimapSkullLocations.AFTER_NAME)) + { + OverlayUtil.renderImageLocation(graphics, new Point(minimapLocation.getX() + + width, minimapLocation.getY() - height), + ImageUtil.resizeImage(skullIcon, height, height)); + } + else + { + OverlayUtil.renderImageLocation(graphics, new Point(minimapLocation.getX(), + minimapLocation.getY() - height), + ImageUtil.resizeImage(skullIcon, height, height)); + minimapLocation = new Point(minimapLocation.getX() + skullIcon.getWidth(), + minimapLocation.getY()); + } + break; + default: + break; + } + } + OverlayUtil.renderTextLocation(graphics, minimapLocation, name, color); + } } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java index 2c1b3c4cbb..d475f0ea42 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, Tomas Slusny + * Copyright (c) 2019, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,23 +33,44 @@ import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.ClanMemberRank; import net.runelite.api.Client; +import net.runelite.api.ItemComposition; import net.runelite.api.Player; import net.runelite.api.Point; +import net.runelite.api.kit.KitType; import net.runelite.client.game.ClanManager; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.plugins.friendtagging.FriendTaggingPlugin; +import net.runelite.client.plugins.pvptools.PvpToolsPlugin; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.util.ImageUtil; +import net.runelite.client.util.PvPUtil; +import static net.runelite.client.util.StackFormatter.formatNumber; +import net.runelite.client.util.Text; @Singleton public class PlayerIndicatorsOverlay extends Overlay { + private static final int ACTOR_OVERHEAD_TEXT_MARGIN = 40; + private static final int ACTOR_HORIZONTAL_TEXT_MARGIN = 10; + private final PlayerIndicatorsService playerIndicatorsService; private final PlayerIndicatorsConfig config; private final ClanManager clanManager; - + private final BufferedImage skullIcon = ImageUtil.getResourceStreamFromClass(PlayerIndicatorsPlugin.class, + "skull.png"); + PvpToolsPlugin pvpToolsPlugin; @Inject private Client client; + @Inject + private SpriteManager spriteManager; + @Inject + private PlayerIndicatorsPlugin playerIndicatorsPlugin; + @Inject + private ItemManager itemManager; @Inject private PlayerIndicatorsOverlay(PlayerIndicatorsConfig config, PlayerIndicatorsService playerIndicatorsService, @@ -70,74 +92,156 @@ public class PlayerIndicatorsOverlay extends Overlay private void renderPlayerOverlay(Graphics2D graphics, Player actor, Color color) { - if (!config.drawOverheadPlayerNames() && !config.drawOverheadLevels()) + final PlayerNameLocation drawPlayerNamesConfig = config.playerNamePosition(); + if (drawPlayerNamesConfig == PlayerNameLocation.DISABLED) { return; } - String namee = actor.getName().replace('\u00A0', ' '); - String combatLevel = Integer.toString(actor.getCombatLevel()); - String playerInfo = ""; - Point minimapLocation = actor.getMinimapLocation(); - - if (minimapLocation != null) + final int zOffset; + switch (drawPlayerNamesConfig) { - graphics.fillOval(minimapLocation.getX() - 1, minimapLocation.getY() - 1, 2, 2); + case MODEL_CENTER: + case MODEL_RIGHT: + zOffset = actor.getLogicalHeight() / 2; + break; + default: + zOffset = actor.getLogicalHeight() + ACTOR_OVERHEAD_TEXT_MARGIN; } - if (config.drawOverheadPlayerNames()) - { - playerInfo = namee; - } + String name = Text.sanitize(actor.getName()); + Point textLocation = actor.getCanvasTextLocation(graphics, name, zOffset); - if (config.drawOverheadLevels()) + if (drawPlayerNamesConfig == PlayerNameLocation.MODEL_RIGHT) { - if (!playerInfo.isEmpty()) - { - playerInfo = playerInfo.concat("(" + combatLevel + ")"); - } - else - { - playerInfo = combatLevel; - } - } + textLocation = actor.getCanvasTextLocation(graphics, "", zOffset); - if (config.limitLevel()) - { - if (!(client.getLocalPlayer().getCombatLevel() >= actor.getCombatLevel() - config.intLevel() && client.getLocalPlayer().getCombatLevel() <= actor.getCombatLevel() + config.intLevel())) + if (textLocation == null) { return; } + + textLocation = new Point(textLocation.getX() + ACTOR_HORIZONTAL_TEXT_MARGIN, textLocation.getY()); } - String name = actor.getName().replace('\u00A0', ' ') + (config.limitLevel() ? " Lvl: " + actor.getCombatLevel() : ""); - int offset = actor.getLogicalHeight() + 40; - Point textLocation = actor.getCanvasTextLocation(graphics, playerInfo, offset); - - if (textLocation != null) + if (textLocation == null) { - if (config.showClanRanks() && actor.isClanMember()) + return; + } + + if (config.showClanRanks() && actor.isClanMember()) + { + final ClanMemberRank rank = clanManager.getRank(name); + + if (rank != ClanMemberRank.UNRANKED) { - ClanMemberRank rank = clanManager.getRank(name); + final BufferedImage clanchatImage = clanManager.getClanImage(rank); - if (rank != ClanMemberRank.UNRANKED) + if (clanchatImage != null) { - BufferedImage clanchatImage = clanManager.getClanImage(rank); + final int clanImageWidth = clanchatImage.getWidth(); + final int clanImageTextMargin; + final int clanImageNegativeMargin; - if (clanchatImage != null) + if (drawPlayerNamesConfig == PlayerNameLocation.MODEL_RIGHT) { - int width = clanchatImage.getWidth(); - int textHeight = graphics.getFontMetrics().getHeight() - graphics.getFontMetrics().getMaxDescent(); - Point imageLocation = new Point(textLocation.getX() - width / 2 - 1, textLocation.getY() - textHeight / 2 - clanchatImage.getHeight() / 2); - OverlayUtil.renderImageLocation(graphics, imageLocation, clanchatImage); - - // move text - textLocation = new Point(textLocation.getX() + width / 2, textLocation.getY()); + clanImageTextMargin = clanImageWidth; + clanImageNegativeMargin = 0; } + else + { + clanImageTextMargin = clanImageWidth / 2; + clanImageNegativeMargin = clanImageWidth / 2; + } + + final int textHeight = graphics.getFontMetrics().getHeight() - graphics.getFontMetrics().getMaxDescent(); + final Point imageLocation = new Point(textLocation.getX() - clanImageNegativeMargin - 1, textLocation.getY() - textHeight / 2 - clanchatImage.getHeight() / 2); + OverlayUtil.renderImageLocation(graphics, imageLocation, clanchatImage); + + // move text + textLocation = new Point(textLocation.getX() + clanImageTextMargin, textLocation.getY()); } } - - OverlayUtil.renderTextLocation(graphics, textLocation, playerInfo, color); } + + String tag = ""; + String prefix = "tag_"; + if (FriendTaggingPlugin.taggedFriends.containsKey(prefix + name.trim().toLowerCase())) + { + tag = " [" + FriendTaggingPlugin.taggedFriends.get(prefix + name.trim().toLowerCase()) + "] "; + name += tag; + } + + if (config.highlightCallers() && playerIndicatorsPlugin.isCaller(actor)) + { + name = "[C] " + name; + } + if (config.highlightPile() && playerIndicatorsPlugin.isPile(actor)) + { + name = "[P] " + name; + } + if (config.showCombatLevel()) + { + + OverlayUtil.renderTextLocation(graphics, textLocation, name + " (" + actor.getCombatLevel() + ")", + color); + + } + if (config.targetRisk() && PvPUtil.isAttackable(client, actor) && actor.getPlayerComposition() != null) + { + long totalValue = 0; + int newValue = 0; + StringBuilder stringBuilder = new StringBuilder(" "); + for (KitType kitType : KitType.values()) + { + ItemComposition itemComposition = + itemManager.getItemComposition(actor.getPlayerComposition().getEquipmentId(kitType)); + if (itemComposition != null || itemComposition.getName() != null) + { + totalValue = totalValue + itemComposition.getPrice(); + } + } + newValue = (int) (totalValue / 1000); + if (newValue != 0) + { + stringBuilder.append("(" + formatNumber(newValue) + "K)"); + name = name + stringBuilder; + } + } + if (config.unchargedGlory() && actor.getPlayerComposition() != null) + { + ItemComposition itemComposition = itemManager.getItemComposition(actor.getPlayerComposition().getEquipmentId(KitType.AMULET)); + if (itemComposition != null && itemComposition.getId() == 1704) //1704 is uncharged glory, to be certain + { + name = name + " cGLORY"; + } + } + if (actor.getSkullIcon() != null && config.playerSkull()) + { + switch (actor.getSkullIcon()) + { + case SKULL: + int width = graphics.getFontMetrics().stringWidth(name); + int height = graphics.getFontMetrics().getHeight(); + if (config.skullLocation().equals(PlayerIndicatorsPlugin.minimapSkullLocations.AFTER_NAME)) + { + OverlayUtil.renderImageLocation(graphics, new Point(textLocation.getX() + + width, textLocation.getY() - height), + ImageUtil.resizeImage(skullIcon, height, height)); + } + else + { + OverlayUtil.renderImageLocation(graphics, new Point(textLocation.getX(), + textLocation.getY() - height), + ImageUtil.resizeImage(skullIcon, height, height)); + textLocation = new Point(textLocation.getX() + skullIcon.getWidth(), + textLocation.getY()); + } + break; + default: + break; + } + } + OverlayUtil.renderTextLocation(graphics, textLocation, name, color); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsPlugin.java index 24e32c34e6..cbac52ca72 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsPlugin.java @@ -26,245 +26,313 @@ package net.runelite.client.plugins.playerindicators; import com.google.inject.Provides; import java.awt.Color; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; import javax.inject.Inject; -import net.runelite.api.*; - +import net.runelite.api.Actor; +import net.runelite.api.ClanMember; +import net.runelite.api.ClanMemberRank; import static net.runelite.api.ClanMemberRank.UNRANKED; +import net.runelite.api.Client; import static net.runelite.api.MenuAction.*; -import net.runelite.api.coords.WorldPoint; +import net.runelite.api.HeadIcon; +import net.runelite.api.MenuEntry; +import net.runelite.api.Player; +import net.runelite.api.events.ClanMemberJoined; +import net.runelite.api.events.ClanMemberLeft; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameTick; import net.runelite.api.events.MenuEntryAdded; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.game.ClanManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.util.ColorUtil; -import com.google.common.base.Splitter; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; - -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.InteractChanged; -import net.runelite.client.util.WildcardMatcher; - +import net.runelite.client.util.PvPUtil; @PluginDescriptor( - name = "Player Indicators", - description = "Highlight players on-screen and/or on the minimap", - tags = {"highlight", "minimap", "overlay", "players"}, - type = PluginType.PVP + name = "Player Indicators", + description = "Highlight players on-screen and/or on the minimap", + tags = {"highlight", "minimap", "overlay", "players", "pklite"} ) public class PlayerIndicatorsPlugin extends Plugin { - private static final Splitter COMMA_SPLITTER = Splitter.on(Pattern.compile("\\s*,\\s*")); @Inject private OverlayManager overlayManager; - + @Inject private PlayerIndicatorsConfig config; - + @Inject private PlayerIndicatorsOverlay playerIndicatorsOverlay; - + @Inject private PlayerIndicatorsTileOverlay playerIndicatorsTileOverlay; - - @Inject - private FriendMinimapOverlay friendMinimapOverlay; - + @Inject private PlayerIndicatorsMinimapOverlay playerIndicatorsMinimapOverlay; - + @Inject private Client client; - + @Inject private ClanManager clanManager; - - private Map highlightedPlayers = new HashMap<>(); - + @Provides PlayerIndicatorsConfig provideConfig(ConfigManager configManager) { return configManager.getConfig(PlayerIndicatorsConfig.class); } - + @Override protected void startUp() throws Exception { overlayManager.add(playerIndicatorsOverlay); overlayManager.add(playerIndicatorsTileOverlay); overlayManager.add(playerIndicatorsMinimapOverlay); - overlayManager.add(friendMinimapOverlay); - updateHighlightList(); + getCallerList(); } - + @Override protected void shutDown() throws Exception { overlayManager.remove(playerIndicatorsOverlay); overlayManager.remove(playerIndicatorsTileOverlay); overlayManager.remove(playerIndicatorsMinimapOverlay); - overlayManager.remove(friendMinimapOverlay); } - + + private ArrayList callers = new ArrayList<>(); + private List pileList; + @Subscribe - public void onInteractChanged(InteractChanged event) + public void onConfigChanged(ConfigChanged e) { - Actor actor = event.getActor(); - if (actor != null - && actor.getName() != null - && isHighlighted(actor)) + if (config.callers() != null && !config.callers().trim().equals("")) { - highlightedPlayers.put(actor.getName().toLowerCase(), actor.getInteracting()); + getCallerList(); } } - + @Subscribe - public void onConfigChanged(ConfigChanged event) + public void onGameTick(GameTick gameTick) { - if (event.getGroup().equals("playerindicators") && event.getKey().equals("highlightedNames")) + if (config.highlightPile() && callers != null) { - updateHighlightList(); + for (Player p : client.getPlayers()) + { + for (String name:callers) + { + Actor pile = null; + String finalName = name.toLowerCase().replace("_", " "); + if (p.getName().toLowerCase().replace("_", " ").equals(finalName)) + { + pile = p.getInteracting(); + if (pile != null) + { + pileList.set(callers.indexOf(name), pile.getName()); + //pileList.add(pile.getName()); + } + else + { + pileList.set(callers.indexOf(name), ""); + } + } + } + } } } - - private void updateHighlightList() + + @Subscribe + public void onClanMemberJoined(ClanMemberJoined event) { - highlightedPlayers.clear(); - for (String player : COMMA_SPLITTER.splitToList(config.getHighlightedNames().toLowerCase().trim())) - { - highlightedPlayers.put(player, null); - } + getCallerList(); } - - boolean isHighlighted(Actor player) + + @Subscribe + public void onClanMemberLeft(ClanMemberLeft event) { - for (Map.Entry map : highlightedPlayers.entrySet()) + getCallerList(); + } + + public void getCallerList() + { + callers.clear(); + if (config.useClanchatRanks() && client.getClanMembers() != null) { - if (WildcardMatcher.matches(map.getKey(), player.getName())) + for (ClanMember clanMember : client.getClanMembers()) + { + if (clanMember.getRank().getValue() > config.callerRank().getValue()) + { + callers.add(clanMember.getUsername()); + } + } + } + if (config.callers().contains(",")) + { + callers.addAll(Arrays.asList(config.callers().split(","))); + } + else + { + if (!config.callers().equals("") || config.callers().length() > 1) + { + callers.add(config.callers()); + } + } + pileList = Arrays.asList(new String[callers.size()]); + } + + public boolean isCaller(Player player) + { + if (callers != null) + { + for (String name:callers) + { + String finalName = name.toLowerCase().replace("_", " "); + if (player.getName().toLowerCase().replace("_", " ").equals(finalName)) + { + return true; + } + } + } + else {return false;} + return false; + } + + public boolean isPile(Player player) + { + if (Objects.nonNull(pileList) && pileList.size() > 0) + { + if (pileList.contains(player.getName())) { return true; } } return false; } - - boolean isHighlightedTarget(Player player) - { - return highlightedPlayers.containsValue(player); - } - + @Subscribe public void onMenuEntryAdded(MenuEntryAdded menuEntryAdded) { - if (config.showInWildernessOnly() && client.getVar(Varbits.IN_THE_WILDERNESS) != 1) - { - return; - } 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() - || type == RUNELITE.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() + || type == RUNELITE.getId()) { final Player localPlayer = client.getLocalPlayer(); Player[] players = client.getCachedPlayers(); Player player = null; - + if (identifier >= 0 && identifier < players.length) { player = players[identifier]; } - + if (player == null) { return; } - + int image = -1; + int image2 = -1; Color color = null; - - if (config.highlightFriends() && player.isFriend()) + + if (config.colorPlayerMenu() && client.isFriended(player.getName(), false)) { color = config.getFriendColor(); } - else if (config.drawClanMemberNames() && player.isClanMember()) + else if (config.colorPlayerMenu() && player.isClanMember()) { color = config.getClanMemberColor(); - + ClanMemberRank rank = clanManager.getRank(player.getName()); if (rank != UNRANKED) { image = clanManager.getIconNumber(rank); } } - else if (config.highlightTeamMembers() && player.getTeam() > 0 && localPlayer.getTeam() == player.getTeam()) + else if (config.colorPlayerMenu() && player.getTeam() > 0 && localPlayer.getTeam() == player.getTeam()) + { + color = config.getTeamMemberColor(); + } + else if (!player.isClanMember() && !player.isFriend() && !PvPUtil.isAttackable(client, player)) + { + color = config.getNonClanMemberColor(); + } + else if (config.colorPlayerMenu() && !player.isClanMember() && client.isFriended(player.getName(), false) && PvPUtil.isAttackable(client, player)) + { + color = config.getTargetColor(); + } + else if (config.colorPlayerMenu() && PvPUtil.isAttackable(client, player) && !player.isClanMember() && !player.isFriend()) + { + color = config.getTargetColor(); + } + if (config.rightClickOverhead() && !player.isClanMember() && player.getOverheadIcon() != null) { - color = config.getTeamMemberColor(); - } - else if (config.highlightNonClanMembers() && !player.isClanMember()) - { - color = config.getNonClanMemberColor(); - } - else if (config.drawHighlightedNames() && isHighlighted(player)) - { - color = config.getHighlightedNamesColor(); - } - else if (config.drawHighlightedTargetNames() && isHighlightedTarget(player)) - { - color = config.getHighlightedTargetColor(); - } - else if (config.highlightAttackerPlayers() && player.getInteracting() == localPlayer) - { - color = config.getAttackerPlayerColor(); - } - else if (config.highlightAttackablePlayers() && isWithinLevelRange(player.getCombatLevel())) - { - color = config.getAttackablePlayerColor(); - } -/* if (this.config.rightClickOverhead() && !player.isClanMember() && player.getOverheadIcon() != null) { // NEEDS TESTING - if (player.getOverheadIcon().equals((Object)HeadIcon.MAGIC)) { + if (player.getOverheadIcon().equals(HeadIcon.MAGIC)) + { image = 29; - } else if (player.getOverheadIcon().equals((Object)HeadIcon.RANGED)) { + } + else if (player.getOverheadIcon().equals(HeadIcon.RANGED)) + { image = 30; - } else if (player.getOverheadIcon().equals((Object)HeadIcon.MELEE)) { + } + else if (player.getOverheadIcon().equals(HeadIcon.MELEE)) + { image = 31; - } else if (player.getOverheadIcon().equals((Object)HeadIcon.REDEMPTION)) { + } + else if (player.getOverheadIcon().equals(HeadIcon.REDEMPTION)) + { image = 32; - } else if (player.getOverheadIcon().equals((Object)HeadIcon.RETRIBUTION)) { + } + else if (player.getOverheadIcon().equals(HeadIcon.RETRIBUTION)) + { image = 33; - } else if (player.getOverheadIcon().equals((Object)HeadIcon.SMITE)) { + } + else if (player.getOverheadIcon().equals(HeadIcon.SMITE)) + { image = 34; } - }*/ - + + } + if (config.playerSkull() && !player.isClanMember() && player.getSkullIcon() != null) + { + image2 = 35; + } + if (config.colorPlayerMenu() && config.highlightCallers() && this.isCaller(player)) + { + color = config.callerColor(); + } + if (config.colorPlayerMenu() && config.highlightPile() && this.isPile(player)) + { + color = config.pileColor(); + } if (image != -1 || color != null) { MenuEntry[] menuEntries = client.getMenuEntries(); MenuEntry lastEntry = menuEntries[menuEntries.length - 1]; - + + if (color != null && config.colorPlayerMenu()) { // strip out existing " + lastEntry.getTarget()); + lastEntry.setTarget(lastEntry.getTarget() + ""); } - + if (image2 != -1 && config.playerSkull()) + { + lastEntry.setTarget("" + lastEntry.getTarget()); + } + client.setMenuEntries(menuEntries); } } } - - public boolean isWithinLevelRange(int playerCombatLevel) - { - Widget levelRangeWidget = client.getWidget(WidgetInfo.PVP_ATTACK_RANGE); - Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL); - - int localPlayerLevel = client.getLocalPlayer().getCombatLevel(); - int lowerLevelBound = localPlayerLevel - 15; - int upperLevelBound = localPlayerLevel + 15; - - if (levelRangeWidget == null && wildernessLevelWidget == null) - { - return false; - } - - if (!levelRangeWidget.isHidden() && !wildernessLevelWidget.isHidden()) - { - int wildernessLevel = calculateWildernessLevel(client.getLocalPlayer().getWorldLocation()); - lowerLevelBound = localPlayerLevel - wildernessLevel - 15; - upperLevelBound = localPlayerLevel + wildernessLevel + 15; - return (playerCombatLevel >= lowerLevelBound && playerCombatLevel <= upperLevelBound); - } - else if (levelRangeWidget.isHidden() && !wildernessLevelWidget.isHidden()) - { - int wildernessLevel = calculateWildernessLevel(client.getLocalPlayer().getWorldLocation()); - lowerLevelBound = localPlayerLevel - wildernessLevel; - upperLevelBound = localPlayerLevel + wildernessLevel; - return (playerCombatLevel >= lowerLevelBound && playerCombatLevel <= upperLevelBound); - } - else - { - return (playerCombatLevel >= lowerLevelBound && playerCombatLevel <= upperLevelBound); - } - } - - public static int calculateWildernessLevel(WorldPoint userLocation) - { - int wildernessLevel = 0; - if (WorldPoint.isInZone(new WorldPoint(2944, 3520, 0), new WorldPoint(3391, 4351, 3), userLocation)) - { - wildernessLevel = ((userLocation.getY() - (55 * 64)) / 8) + 1; - } - else if (WorldPoint.isInZone(new WorldPoint(3008, 10112, 0), new WorldPoint(3071, 10175, 3), userLocation)) - { - wildernessLevel = ((userLocation.getY() - (155 * 64)) / 8) - 1; - } - else if (WorldPoint.isInZone(new WorldPoint(2944, 9920, 0), new WorldPoint(3391, 10879, 3), userLocation)) - { - wildernessLevel = ((userLocation.getY() - (155 * 64)) / 8) + 1; - } - return wildernessLevel; - } - + + public static enum minimapSkullLocations + { + BEFORE_NAME, + AFTER_NAME + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsService.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsService.java index e8aff835bd..5dda29c978 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsService.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsService.java @@ -30,96 +30,88 @@ import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.Client; import net.runelite.api.Player; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.api.Varbits; - - -import static net.runelite.client.plugins.playerindicators.PlayerIndicatorsPlugin.calculateWildernessLevel; +import net.runelite.client.util.PvPUtil; @Singleton -public class PlayerIndicatorsService { +public class PlayerIndicatorsService +{ private final Client client; private final PlayerIndicatorsConfig config; + private final PlayerIndicatorsPlugin playerIndicatorsPlugin; @Inject - private PlayerIndicatorsService(Client client, PlayerIndicatorsConfig config) { + private PlayerIndicatorsService(Client client, PlayerIndicatorsConfig config, PlayerIndicatorsPlugin plugin) + { this.config = config; this.client = client; + this.playerIndicatorsPlugin = plugin; } - public void forEachPlayer(final BiConsumer consumer) { - - if (config.showInWildernessOnly() && client.getVar(Varbits.IN_THE_WILDERNESS) != 1) - { - return; - } - + public void forEachPlayer(final BiConsumer consumer) + { if (!config.highlightOwnPlayer() && !config.drawClanMemberNames() - && !config.highlightFriends() && !config.highlightNonClanMembers() - && !config.highlightAttackablePlayers() && !config.highlightAttackerPlayers()) { + && !config.highlightFriends() && !config.highlightNonClanMembers() && !config.highlightTargets() + && !config.highlightPile() && !config.highlightCallers() && !config.highlightTeamMembers()) + { return; } final Player localPlayer = client.getLocalPlayer(); - for (Player player : client.getPlayers()) { - if (player == null || player.getName() == null) { + for (Player player : client.getPlayers()) + { + if (player == null || player.getName() == null) + { continue; } boolean isClanMember = player.isClanMember(); - if (player == localPlayer) { - if (config.highlightOwnPlayer()) { + if (player == localPlayer) + { + if (config.highlightOwnPlayer()) + { consumer.accept(player, config.getOwnPlayerColor()); } - } else if (config.highlightFriends() && (player.isFriend() || client.isFriended(player.getName(), false))) { + } + else if (config.highlightFriends() && client.isFriended(player.getName(), false)) + { consumer.accept(player, config.getFriendColor()); - } else if (config.drawClanMemberNames() && isClanMember) { + } + else if (config.drawClanMemberNames() && isClanMember) + { consumer.accept(player, config.getClanMemberColor()); - } else if (config.highlightTeamMembers() && localPlayer.getTeam() > 0 && localPlayer.getTeam() == player.getTeam()) { + } + else if (config.highlightTeamMembers() && localPlayer.getTeam() > 0 && + localPlayer.getTeam() == player.getTeam()) + { consumer.accept(player, config.getTeamMemberColor()); - } else if (config.highlightNonClanMembers() && !isClanMember) { + } + else if (config.highlightNonClanMembers() && !isClanMember) + { consumer.accept(player, config.getNonClanMemberColor()); - } else if (config.highlightAttackerPlayers() && player.getInteracting() == localPlayer) { - consumer.accept(player, config.getAttackerPlayerColor()); - } else if (config.highlightAttackablePlayers() && isWithinLevelRange(player.getCombatLevel())) { - consumer.accept(player, config.getAttackablePlayerColor()); - } - } - } - - public boolean isWithinLevelRange(int playerCombatLevel) - { - Widget levelRangeWidget = client.getWidget(WidgetInfo.PVP_ATTACK_RANGE); - Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL); - - int localPlayerLevel = client.getLocalPlayer().getCombatLevel(); - int lowerLevelBound = localPlayerLevel - 15; - int upperLevelBound = localPlayerLevel + 15; - - if (levelRangeWidget == null && wildernessLevelWidget == null) - { - return false; - } - - if (!levelRangeWidget.isHidden() && !wildernessLevelWidget.isHidden()) - { - lowerLevelBound = Integer.parseInt(levelRangeWidget.getText().split("-")[0]); - upperLevelBound = Integer.parseInt(levelRangeWidget.getText().split("-")[1]); - return (playerCombatLevel >= lowerLevelBound && playerCombatLevel <= upperLevelBound); - } - else if (levelRangeWidget.isHidden() && !wildernessLevelWidget.isHidden()) - { - int wildernessLevel = calculateWildernessLevel(client.getLocalPlayer().getWorldLocation()); - lowerLevelBound = localPlayerLevel - wildernessLevel; - upperLevelBound = localPlayerLevel + wildernessLevel; - return (playerCombatLevel >= lowerLevelBound && playerCombatLevel <= upperLevelBound); - } - else - { - return (playerCombatLevel >= lowerLevelBound && playerCombatLevel <= upperLevelBound); + } + else if (config.highlightTargets() && PvPUtil.isAttackable(client, player) && + !client.isFriended(player.getName(), false) && !player.isClanMember()) + { + if (config.skulledTargetsOnly() && player.getSkullIcon() != null) + { + consumer.accept(player, config.getTargetColor()); + } + else if (!config.skulledTargetsOnly()) + { + consumer.accept(player, config.getTargetColor()); + } + } + if (config.highlightCallers() && config.callers() != null && playerIndicatorsPlugin.isCaller(player)) + { + consumer.accept(player, config.callerColor()); + } + if (config.highlightPile() && playerIndicatorsPlugin.isPile(player) + && !player.isClanMember()) + { + consumer.accept(player, config.pileColor()); + } } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsTileOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsTileOverlay.java index 0e7c2e31fc..bc5a49fbc1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsTileOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsTileOverlay.java @@ -25,9 +25,7 @@ package net.runelite.client.plugins.playerindicators; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Polygon; +import java.awt.*; import javax.inject.Inject; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -39,12 +37,15 @@ public class PlayerIndicatorsTileOverlay extends Overlay { private final PlayerIndicatorsService playerIndicatorsService; private final PlayerIndicatorsConfig config; + private final PlayerIndicatorsPlugin playerIndicatorsPlugin; @Inject - private PlayerIndicatorsTileOverlay(PlayerIndicatorsConfig config, PlayerIndicatorsService playerIndicatorsService) + private PlayerIndicatorsTileOverlay(PlayerIndicatorsConfig config, + PlayerIndicatorsService playerIndicatorsService, PlayerIndicatorsPlugin plugin) { this.config = config; this.playerIndicatorsService = playerIndicatorsService; + this.playerIndicatorsPlugin = plugin; setLayer(OverlayLayer.ABOVE_SCENE); setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.MED); @@ -53,21 +54,51 @@ public class PlayerIndicatorsTileOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - if (!config.drawTiles()) + if (config.drawPileHull()) + { + playerIndicatorsService.forEachPlayer((player, color) -> + { + if (playerIndicatorsPlugin.isPile(player)) + { + Polygon objectClickbox = player.getConvexHull(); + + renderPoly(graphics, config.pileColor(), objectClickbox); + + if (objectClickbox != null) + { + + } + } + }); + } + if (!config.drawTiles() /*&& !config.drawPlayerHull()*/) { return null; } - - playerIndicatorsService.forEachPlayer((player, color) -> + else if (config.drawTiles()) { - final Polygon poly = player.getCanvasTilePoly(); - - if (poly != null) + playerIndicatorsService.forEachPlayer((player, color) -> { - OverlayUtil.renderPolygon(graphics, poly, color); - } - }); + final Polygon poly = player.getCanvasTilePoly(); + if (poly != null) + { + OverlayUtil.renderPolygon(graphics, poly, color); + } + }); + } return null; } + + private void renderPoly(Graphics2D graphics, Color color, Polygon polygon) + { + if (polygon != null) + { + graphics.setColor(color); + graphics.setStroke(new BasicStroke(2)); + graphics.draw(polygon); + graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20)); + graphics.fill(polygon); + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/locationchatter/LocationChatterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PlayerContainer.java similarity index 61% rename from runelite-client/src/main/java/net/runelite/client/plugins/locationchatter/LocationChatterConfig.java rename to runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PlayerContainer.java index 33bbf214ff..6c1370ef76 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/locationchatter/LocationChatterConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PlayerContainer.java @@ -1,40 +1,56 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.locationchatter; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.Keybind; - -@ConfigGroup("locationchatter") -public interface LocationChatterConfig extends Config -{ - @ConfigItem(keyName = "keybind", name = "Send to CC", description = "Configure button to send current location to CC") - default Keybind keybind() - { - return Keybind.NOT_SET; - } -} +/* + * Copyright (c) 2019, gazivodag + * 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.prayagainstplayer; + +import net.runelite.api.Player; + +/** + * Contains a player object + * When they attacked me + * And (in milliseconds) when to expire the overlay around them + */ +public class PlayerContainer { + + private Player player; + private long whenTheyAttackedMe; + private int millisToExpireHighlight; + + public PlayerContainer(Player player, long whenTheyAttackedMe, int millisToExpireHighlight) { + this.player = player; + this.whenTheyAttackedMe = whenTheyAttackedMe; + this.millisToExpireHighlight = millisToExpireHighlight; + } + + + //getters + public Player getPlayer() { + return player; + } + public long getWhenTheyAttackedMe() { + return whenTheyAttackedMe; + } + public int getMillisToExpireHighlight() { return millisToExpireHighlight; }; + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerConfig.java new file mode 100644 index 0000000000..ce453fd3d9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerConfig.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2019, gazivodag + * 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.prayagainstplayer; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +import java.awt.*; + +@ConfigGroup("prayagainstplayer") +public interface PrayAgainstPlayerConfig extends Config { + @ConfigItem( + position = 0, + keyName = "attackerPlayerColor", + name = "Attacker color", + description = "This is the color that will be used to highlight attackers." + ) + default Color attackerPlayerColor() { return new Color(0xFF0006); } + + @ConfigItem( + position = 1, + keyName = "potentialPlayerColor", + name = "Potential Attacker color", + description = "This is the color that will be used to highlight potential attackers." + ) + default Color potentialPlayerColor() { return new Color(0xFFFF00); } + + //// + @ConfigItem( + position = 2, + keyName = "attackerTargetTimeout", + name = "Attacker Timeout", + description = "Seconds until attacker is no longer highlighted." + ) + default int attackerTargetTimeout() { return 10; } + + @ConfigItem( + position = 3, + keyName = "potentialTargetTimeout", + name = "Potential Attacker Timeout", + description = "Seconds until potential attacker is no longer highlighted." + ) + default int potentialTargetTimeout() { return 10; } + + @ConfigItem( + position = 4, + keyName = "newSpawnTimeout", + name = "New Player Timeout", + description = "Seconds until logged in/spawned player is no longer highlighted." + ) + default int newSpawnTimeout() { return 5; } + //// + + //// + @ConfigItem( + position = 5, + keyName = "ignoreFriends", + name = "Ignore Friends", + description = "This lets you decide whether you want friends to be highlighted by this plugin." + ) + default boolean ignoreFriends() { return true; } + + @ConfigItem( + position = 6, + keyName = "ignoreClanMates", + name = "Ignore Clan Mates", + description = "This lets you decide whether you want clan mates to be highlighted by this plugin." + ) + default boolean ignoreClanMates() { return true; } + //// + + @ConfigItem( + position = 7, + keyName = "markNewPlayer", + name = "Mark new player as potential attacker", + description = "Marks someone that logged in or teleported as a potential attacker for your safety\nDO NOT RUN THIS IN WORLD 1-2 GRAND EXCHANGE!" + ) + default boolean markNewPlayer() { return false; } + + @ConfigItem( + position = 8, + keyName = "drawTargetPrayAgainst", + name = "Draw what to pray on attacker", + description = "Tells you what to pray from what weapon the attacker is holding" + ) + default boolean drawTargetPrayAgainst() { return true; } + + @ConfigItem( + position = 9, + keyName = "drawPotentialTargetPrayAgainst", + name = "Draw what to pray on potential attacker", + description = "Tells you what to pray from what weapon the potential attacker is holding" + ) + default boolean drawPotentialTargetPrayAgainst() { return true; } + + @ConfigItem( + position = 10, + keyName = "drawTargetPrayAgainstPrayerTab", + name = "Draw what to pray from prayer tab", + description = "Tells you what to pray from what weapon the attacker is holding from the prayer tab" + ) + default boolean drawTargetPrayAgainstPrayerTab() { return false; } + + @ConfigItem( + position = 11, + keyName = "drawTargetsName", + name = "Draw name on attacker", + description = "Configures whether or not the attacker\'s name should be shown" + ) + default boolean drawTargetsName() { return true; } + + @ConfigItem( + position = 12, + keyName = "drawPotentialTargetsName", + name = "Draw name on potential attacker", + description = "Configures whether or not the potential attacker\'s name should be shown" + ) + default boolean drawPotentialTargetsName() { return true; } + + @ConfigItem( + position = 13, + keyName = "drawTargetHighlight", + name = "Draw highlight around attacker", + description = "Configures whether or not the attacker should be highlighted" + ) + default boolean drawTargetHighlight() { return true; } + + @ConfigItem( + position = 14, + keyName = "drawPotentialTargetHighlight", + name = "Draw highlight around potential attacker", + description = "Configures whether or not the potential attacker should be highlighted" + ) + default boolean drawPotentialTargetHighlight() { return true; } + + @ConfigItem( + position = 15, + keyName = "drawTargetTile", + name = "Draw tile under attacker", + description = "Configures whether or not the attacker\'s tile be highlighted" + ) + default boolean drawTargetTile() { return false; } + + @ConfigItem( + position = 16, + keyName = "drawPotentialTargetTile", + name = "Draw tile under potential attacker", + description = "Configures whether or not the potential attacker\'s tile be highlighted" + ) + default boolean drawPotentialTargetTile() { return false; } + + @ConfigItem( + position = 17, + keyName = "drawUnknownWeapons", + name = "Draw unknown weapons", + description = "Configures whether or not the unknown weapons should be shown when a player equips one" + ) + default boolean drawUnknownWeapons() { return false; } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerOverlay.java new file mode 100644 index 0000000000..e54efd8127 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerOverlay.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2019, gazivodag + * 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.prayagainstplayer; + +import net.runelite.api.Client; +import net.runelite.api.ItemComposition; +import net.runelite.api.Player; +import net.runelite.api.kit.KitType; +import net.runelite.client.ui.overlay.*; +import net.runelite.client.util.Text; +import net.runelite.api.Point; + +import javax.inject.Inject; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.ConcurrentModificationException; + +class PrayAgainstPlayerOverlay extends Overlay { + + private final PrayAgainstPlayerPlugin plugin; + private final PrayAgainstPlayerConfig config; + private final Client client; + + @Inject + private PrayAgainstPlayerOverlay(PrayAgainstPlayerPlugin plugin, PrayAgainstPlayerConfig config, Client client) { + super(plugin); + this.plugin = plugin; + this.config = config; + this.client = client; + + setLayer(OverlayLayer.ABOVE_SCENE); + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + } + + + @Override + public Dimension render(Graphics2D graphics) { + renderPotentialPlayers(graphics); + renderAttackingPlayers(graphics); + return null; + } + + private void renderPotentialPlayers(Graphics2D graphics) { + if (plugin.getPotentialPlayersAttackingMe() == null || !plugin.getPotentialPlayersAttackingMe().isEmpty()) { + try { + for (PlayerContainer container : plugin.getPotentialPlayersAttackingMe()) { + if ((System.currentTimeMillis() > (container.getWhenTheyAttackedMe() + container.getMillisToExpireHighlight())) && (container.getPlayer().getInteracting() != client.getLocalPlayer())) { + plugin.removePlayerFromPotentialContainer(container); + } + if (config.drawPotentialTargetsName()) renderNameAboveHead(graphics, container.getPlayer(), config.potentialPlayerColor()); + if (config.drawPotentialTargetHighlight()) renderHighlightedPlayer(graphics, container.getPlayer(), config.potentialPlayerColor()); + if (config.drawPotentialTargetTile()) renderTileUnderPlayer(graphics, container.getPlayer(), config.potentialPlayerColor()); + if (config.drawPotentialTargetPrayAgainst()) renderPrayAgainstOnPlayer(graphics, container.getPlayer(), config.potentialPlayerColor()); + } + } catch (ConcurrentModificationException e) { + } + } + } + + private void renderAttackingPlayers(Graphics2D graphics) { + if (plugin.getPlayersAttackingMe() == null || !plugin.getPlayersAttackingMe().isEmpty()) { + try { + for (PlayerContainer container : plugin.getPlayersAttackingMe()) { + if ((System.currentTimeMillis() > (container.getWhenTheyAttackedMe() + container.getMillisToExpireHighlight())) && (container.getPlayer().getInteracting() != client.getLocalPlayer())) { + plugin.removePlayerFromAttackerContainer(container); + } + + if (config.drawTargetsName()) renderNameAboveHead(graphics, container.getPlayer(), config.attackerPlayerColor()); + if (config.drawTargetHighlight()) renderHighlightedPlayer(graphics, container.getPlayer(), config.attackerPlayerColor()); + if (config.drawTargetTile()) renderTileUnderPlayer(graphics, container.getPlayer(), config.attackerPlayerColor()); + if (config.drawTargetPrayAgainst()) renderPrayAgainstOnPlayer(graphics, container.getPlayer(), config.attackerPlayerColor()); + } + } catch (ConcurrentModificationException e) { + } + } + } + + private void renderNameAboveHead(Graphics2D graphics, Player player, Color color) { + final String name = Text.sanitize(player.getName()); + final int offset = player.getLogicalHeight() + 40; + Point textLocation = player.getCanvasTextLocation(graphics, name, offset); + if (textLocation != null) { + OverlayUtil.renderTextLocation(graphics, textLocation, name, color); + } + } + + private void renderHighlightedPlayer(Graphics2D graphics, Player player, Color color) { + try { + OverlayUtil.renderPolygon(graphics, player.getConvexHull(), color); + } catch (NullPointerException e) { + } + } + + private void renderTileUnderPlayer(Graphics2D graphics, Player player, Color color) { + Polygon poly = player.getCanvasTilePoly(); + OverlayUtil.renderPolygon(graphics, poly, color); + } + + private void renderPrayAgainstOnPlayer(Graphics2D graphics, Player player, Color color) { + final int offset = (player.getLogicalHeight() / 2) + 75; + BufferedImage icon; + + switch (WeaponType.checkWeaponOnPlayer(client, player)) { + case WEAPON_MELEE: + icon = plugin.getProtectionIcon(WeaponType.WEAPON_MELEE); + break; + case WEAPON_MAGIC: + icon = plugin.getProtectionIcon(WeaponType.WEAPON_MAGIC); + break; + case WEAPON_RANGED: + icon = plugin.getProtectionIcon(WeaponType.WEAPON_RANGED); + break; + default: + icon = null; + break; + } + try { + if (icon != null) { + Point point = player.getCanvasImageLocation(icon, offset); + OverlayUtil.renderImageLocation(graphics, point, icon); + } else { + if (config.drawUnknownWeapons()) { + int itemId = player.getPlayerComposition().getEquipmentId(KitType.WEAPON); + ItemComposition itemComposition = client.getItemDefinition(itemId); + + final String str = itemComposition.getName().toUpperCase(); + Point point = player.getCanvasTextLocation(graphics, str, offset); + OverlayUtil.renderTextLocation(graphics, point, str, color); + } + } + } catch (Exception e) { + } + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerOverlayPrayerTab.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerOverlayPrayerTab.java new file mode 100644 index 0000000000..4e505675f6 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerOverlayPrayerTab.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019, gazivodag + * 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.prayagainstplayer; + +import net.runelite.api.Client; +import net.runelite.api.Player; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.ui.overlay.*; + +import javax.inject.Inject; +import java.awt.*; +import java.util.ConcurrentModificationException; + +class PrayAgainstPlayerOverlayPrayerTab extends Overlay { + + private final PrayAgainstPlayerPlugin plugin; + private final PrayAgainstPlayerConfig config; + private final Client client; + + @Inject + private PrayAgainstPlayerOverlayPrayerTab (PrayAgainstPlayerPlugin plugin, PrayAgainstPlayerConfig config, Client client) { + super(plugin); + this.plugin = plugin; + this.config = config; + this.client = client; + + setPosition(OverlayPosition.DETACHED); + setLayer(OverlayLayer.ALWAYS_ON_TOP); + setPriority(OverlayPriority.MED); + } + + + @Override + public Dimension render(Graphics2D graphics) { + if (plugin.getPlayersAttackingMe() == null || !plugin.getPlayersAttackingMe().isEmpty()) { + try { + for (PlayerContainer container : plugin.getPlayersAttackingMe()) { + if (plugin.getPlayersAttackingMe() != null && plugin.getPlayersAttackingMe().size() > 0) { + //no reason to show you what prayers to pray in your prayer tab if multiple people are attacking you + if ((plugin.getPlayersAttackingMe().size() == 1) && (config.drawTargetPrayAgainstPrayerTab())) { + renderPrayerToClick(graphics, container.getPlayer()); + } + } + } + } catch (ConcurrentModificationException e) { + } + } + return null; + } + + private void renderPrayerToClick(Graphics2D graphics, Player player) { + Widget PROTECT_FROM_MAGIC = client.getWidget(WidgetInfo.PRAYER_PROTECT_FROM_MAGIC); + Widget PROTECT_FROM_RANGED = client.getWidget(WidgetInfo.PRAYER_PROTECT_FROM_MISSILES); + Widget PROTECT_FROM_MELEE = client.getWidget(WidgetInfo.PRAYER_PROTECT_FROM_MELEE); + Color color = Color.RED; + if (PROTECT_FROM_MELEE.isHidden()) return; + switch (WeaponType.checkWeaponOnPlayer(client, player)) { + case WEAPON_MAGIC: + OverlayUtil.renderPolygon(graphics, rectangleToPolygon(PROTECT_FROM_MAGIC.getBounds()), color); + break; + case WEAPON_MELEE: + OverlayUtil.renderPolygon(graphics, rectangleToPolygon(PROTECT_FROM_MELEE.getBounds()), color); + break; + case WEAPON_RANGED: + OverlayUtil.renderPolygon(graphics, rectangleToPolygon(PROTECT_FROM_RANGED.getBounds()), color); + break; + default: + break; + } + } + + private static Polygon rectangleToPolygon(Rectangle rect) { + int[] xpoints = {rect.x, rect.x + rect.width, rect.x + rect.width, rect.x}; + int[] ypoints = {rect.y, rect.y, rect.y + rect.height, rect.y + rect.height}; + return new Polygon(xpoints, ypoints, 4); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerPlugin.java new file mode 100644 index 0000000000..0f9d144bcb --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerPlugin.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2019, gazivodag + * 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.prayagainstplayer; + +import com.google.inject.Provides; +import net.runelite.api.*; +import net.runelite.api.events.*; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.ImageUtil; + +import javax.inject.Inject; +import java.awt.*; +import java.awt.image.*; +import java.util.ArrayList; +import java.util.Arrays; + +@PluginDescriptor( + name = "Pray Against Player", + description = "Use plugin in PvP situations for best results!!", + tags = {"highlight", "pvp", "overlay", "players"}, + type = PluginType.PVP +) + +/** + * I am fully aware that there is plenty of overhead and is a MESS! + * If you'd like to contribute please do! + */ +public class PrayAgainstPlayerPlugin extends Plugin { + + private static final int[] PROTECTION_ICONS = { + SpriteID.PRAYER_PROTECT_FROM_MISSILES, + SpriteID.PRAYER_PROTECT_FROM_MELEE, + SpriteID.PRAYER_PROTECT_FROM_MAGIC + }; + private static final Dimension PROTECTION_ICON_DIMENSION = new Dimension(33, 33); + private static final Color PROTECTION_ICON_OUTLINE_COLOR = new Color(33, 33, 33); + public final BufferedImage[] ProtectionIcons = new BufferedImage[PROTECTION_ICONS.length]; + + private ArrayList potentialPlayersAttackingMe; + private ArrayList playersAttackingMe; + + @Inject + private Client client; + + @Inject + private SpriteManager spriteManager; + + @Inject + private OverlayManager overlayManager; + + @Inject + private PrayAgainstPlayerOverlay overlay; + + @Inject + private PrayAgainstPlayerOverlayPrayerTab overlayPrayerTab; + + @Inject + private PrayAgainstPlayerConfig config; + + @Provides + PrayAgainstPlayerConfig provideConfig(ConfigManager configManager) { + return configManager.getConfig(PrayAgainstPlayerConfig.class); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) { + if (gameStateChanged.getGameState() == GameState.LOGGED_IN) { + loadProtectionIcons(); + } + } + + @Override + protected void startUp() { + potentialPlayersAttackingMe = new ArrayList<>(); + playersAttackingMe = new ArrayList<>(); + overlayManager.add(overlay); + overlayManager.add(overlayPrayerTab); + } + + @Override + protected void shutDown() throws Exception { + overlayManager.remove(overlay); + overlayManager.remove(overlayPrayerTab); + } + + @Subscribe + protected void onAnimationChanged(AnimationChanged animationChanged) { + if ((animationChanged.getActor() instanceof Player) && (animationChanged.getActor().getInteracting() instanceof Player) && (animationChanged.getActor().getInteracting() == client.getLocalPlayer())) { + Player sourcePlayer = (Player) animationChanged.getActor(); + + //is the client is a friend/clan and the config is set to ignore friends/clan dont add them to list + if (client.isFriended(sourcePlayer.getName(), true) && config.ignoreFriends()) return; + if (client.isClanMember(sourcePlayer.getName()) && config.ignoreClanMates()) return; + + if ((sourcePlayer.getAnimation() != -1) && (!isBlockAnimation(sourcePlayer.getAnimation()))) { + //if attacker attacks again, reset his timer so overlay doesn't go away + if (findPlayerInAttackerList(sourcePlayer) != null) { + resetPlayerFromAttackerContainerTimer(findPlayerInAttackerList(sourcePlayer)); + } + //if he attacks and he was in the potential attackers list, remove him + if (!potentialPlayersAttackingMe.isEmpty() && potentialPlayersAttackingMe.contains(findPlayerInPotentialList(sourcePlayer))) { + removePlayerFromPotentialContainer(findPlayerInPotentialList(sourcePlayer)); + } + //if he's not in the attackers list, add him + if (findPlayerInAttackerList(sourcePlayer) == null) { + PlayerContainer container = new PlayerContainer(sourcePlayer, System.currentTimeMillis(), (config.attackerTargetTimeout() * 1000)); + playersAttackingMe.add(container); + } + } + } + } + + @Subscribe + protected void onInteractingChanged(InteractingChanged interactingChanged) { + //if someone interacts with you, add them to the potential attackers list + if ((interactingChanged.getSource() instanceof Player) && (interactingChanged.getTarget() instanceof Player)) { + Player sourcePlayer = (Player) interactingChanged.getSource(); + Player targetPlayer = (Player) interactingChanged.getTarget(); + if ((targetPlayer == client.getLocalPlayer()) && (findPlayerInPotentialList(sourcePlayer) == null)) { //we're being interacted with + + //is the client is a friend/clan and the config is set to ignore friends/clan dont add them to list + if (client.isFriended(sourcePlayer.getName(), true) && config.ignoreFriends()) return; + if (client.isClanMember(sourcePlayer.getName()) && config.ignoreClanMates()) return; + + PlayerContainer container = new PlayerContainer(sourcePlayer, System.currentTimeMillis(), (config.potentialTargetTimeout() * 1000)); + potentialPlayersAttackingMe.add(container); + } + } + } + + @Subscribe + protected void onPlayerDespawned(PlayerDespawned playerDespawned) { + PlayerContainer container = findPlayerInAttackerList(playerDespawned.getPlayer()); + PlayerContainer container2 = findPlayerInPotentialList(playerDespawned.getPlayer()); + if (container != null) { + playersAttackingMe.remove(container); + } + if (container2 != null) { + potentialPlayersAttackingMe.remove(container2); + } + } + + @Subscribe + protected void onPlayerSpawned(PlayerSpawned playerSpawned) { + if (config.markNewPlayer()) { + Player p = playerSpawned.getPlayer(); + + if (client.isFriended(p.getName(), true) && config.ignoreFriends()) return; + if (client.isClanMember(p.getName()) && config.ignoreClanMates()) return; + + PlayerContainer container = findPlayerInPotentialList(p); + if (container == null) { + container = new PlayerContainer(p, System.currentTimeMillis(), (config.newSpawnTimeout() * 1000)); + potentialPlayersAttackingMe.add(container); + } + } + } + + PlayerContainer findPlayerInAttackerList(Player player) { + if (playersAttackingMe.isEmpty()) { + return null; + } + for (int i = 0 ; i < playersAttackingMe.size() ; i++) { + PlayerContainer container = playersAttackingMe.get(i); + if (container.getPlayer() == player) { + return container; + } + } + return null; + } + + PlayerContainer findPlayerInPotentialList(Player player) { + if (potentialPlayersAttackingMe.isEmpty()) { + return null; + } + for (int i = 0 ; i < potentialPlayersAttackingMe.size() ; i++) { + PlayerContainer container = potentialPlayersAttackingMe.get(i); + if (container.getPlayer() == player) { + return container; + } + } + return null; + } + + /** + * Resets player timer in case he attacks again, so his highlight doesn't go away so easily + * @param container + */ + public void resetPlayerFromAttackerContainerTimer(PlayerContainer container) { + removePlayerFromAttackerContainer(container); + PlayerContainer newContainer = new PlayerContainer(container.getPlayer(), System.currentTimeMillis(), (config.attackerTargetTimeout() * 1000)); + playersAttackingMe.add(newContainer); + } + + + public void removePlayerFromPotentialContainer(PlayerContainer container) { + if ((potentialPlayersAttackingMe != null) && (!potentialPlayersAttackingMe.isEmpty()) && (potentialPlayersAttackingMe.contains(container))) { + potentialPlayersAttackingMe.remove(container); + } + } + + public void removePlayerFromAttackerContainer(PlayerContainer container) { + if ((playersAttackingMe != null) && (!playersAttackingMe.isEmpty()) && (playersAttackingMe.contains(container))) { + playersAttackingMe.remove(container); + } + } + + private boolean isBlockAnimation(int anim) { + switch (anim) { + case AnimationID.BLOCK_DEFENDER: + case AnimationID.BLOCK_NO_SHIELD: + case AnimationID.BLOCK_SHIELD: + case AnimationID.BLOCK_SWORD: + case AnimationID.BLOCK_UNARMED: + return true; + default: + return false; + } + } + + public ArrayList getPotentialPlayersAttackingMe() { return potentialPlayersAttackingMe; } + public ArrayList getPlayersAttackingMe() { return playersAttackingMe; } + + //All of the methods below are from the Zulrah plugin!!! Credits to it's respective owner + private void loadProtectionIcons() { + final IndexedSprite[] protectionIcons = {}; + final IndexedSprite[] newProtectionIcons = Arrays.copyOf(protectionIcons, PROTECTION_ICONS.length); + int curPosition = 0; + + for (int i = 0; i < PROTECTION_ICONS.length; i++, curPosition++) + { + final int resource = PROTECTION_ICONS[i]; + ProtectionIcons[i] = rgbaToIndexedBufferedImage(ProtectionIconFromSprite(spriteManager.getSprite(resource, 0))); + newProtectionIcons[curPosition] = createIndexedSprite(client, ProtectionIcons[i]); + } + } + + private static IndexedSprite createIndexedSprite(final Client client, final BufferedImage bufferedImage) { + final IndexColorModel indexedCM = (IndexColorModel) bufferedImage.getColorModel(); + + final int width = bufferedImage.getWidth(); + final int height = bufferedImage.getHeight(); + final byte[] pixels = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData(); + final int[] palette = new int[indexedCM.getMapSize()]; + indexedCM.getRGBs(palette); + + final IndexedSprite newIndexedSprite = client.createIndexedSprite(); + newIndexedSprite.setPixels(pixels); + newIndexedSprite.setPalette(palette); + newIndexedSprite.setWidth(width); + newIndexedSprite.setHeight(height); + newIndexedSprite.setOriginalWidth(width); + newIndexedSprite.setOriginalHeight(height); + newIndexedSprite.setOffsetX(0); + newIndexedSprite.setOffsetY(0); + return newIndexedSprite; + } + + private static BufferedImage rgbaToIndexedBufferedImage(final BufferedImage sourceBufferedImage) { + final BufferedImage indexedImage = new BufferedImage( + sourceBufferedImage.getWidth(), + sourceBufferedImage.getHeight(), + BufferedImage.TYPE_BYTE_INDEXED); + + final ColorModel cm = indexedImage.getColorModel(); + final IndexColorModel icm = (IndexColorModel) cm; + + final int size = icm.getMapSize(); + final byte[] reds = new byte[size]; + final byte[] greens = new byte[size]; + final byte[] blues = new byte[size]; + icm.getReds(reds); + icm.getGreens(greens); + icm.getBlues(blues); + + final WritableRaster raster = indexedImage.getRaster(); + final int pixel = raster.getSample(0, 0, 0); + final IndexColorModel resultIcm = new IndexColorModel(8, size, reds, greens, blues, pixel); + final BufferedImage resultIndexedImage = new BufferedImage(resultIcm, raster, sourceBufferedImage.isAlphaPremultiplied(), null); + resultIndexedImage.getGraphics().drawImage(sourceBufferedImage, 0, 0, null); + return resultIndexedImage; + } + + private static BufferedImage ProtectionIconFromSprite(final BufferedImage freezeSprite) { + final BufferedImage freezeCanvas = ImageUtil.resizeCanvas(freezeSprite, PROTECTION_ICON_DIMENSION.width, PROTECTION_ICON_DIMENSION.height); + return ImageUtil.outlineImage(freezeCanvas, PROTECTION_ICON_OUTLINE_COLOR); + } + + BufferedImage getProtectionIcon(WeaponType weaponType) { + switch (weaponType) { + case WEAPON_RANGED: + return ProtectionIcons[0]; + case WEAPON_MELEE: + return ProtectionIcons[1]; + case WEAPON_MAGIC: + return ProtectionIcons[2]; + } + return null; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/WeaponType.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/WeaponType.java new file mode 100644 index 0000000000..1dc00c8311 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/WeaponType.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2019, gazivodag + * 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.prayagainstplayer; + +import net.runelite.api.Client; +import net.runelite.api.ItemComposition; +import net.runelite.api.Player; +import net.runelite.api.kit.KitType; + +enum WeaponType { + + WEAPON_MELEE, + WEAPON_RANGED, + WEAPON_MAGIC, + WEAPON_UNKNOWN; + + /** + * im fully aware this could of been done better!!! + * @param client + * @param attacker + * @return + */ + public static WeaponType checkWeaponOnPlayer (Client client, Player attacker) { + int itemId = attacker.getPlayerComposition().getEquipmentId(KitType.WEAPON); + ItemComposition itemComposition = client.getItemDefinition(itemId); + String weaponNameGivenLowerCase = itemComposition.getName().toLowerCase(); + + if (itemId == -1) return WEAPON_MELEE; + if (weaponNameGivenLowerCase == null || weaponNameGivenLowerCase.toLowerCase().contains("null")) return WEAPON_MELEE; + + for (String meleeWeaponName : meleeWeaponNames) { + if (weaponNameGivenLowerCase.contains(meleeWeaponName) && !weaponNameGivenLowerCase.contains("thrownaxe")) { + return WEAPON_MELEE; + } + } + + for (String rangedWeaponName : rangedWeaponNames) { + if (weaponNameGivenLowerCase.contains(rangedWeaponName)) { + return WEAPON_RANGED; + } + } + + for (String magicWeaponName : magicWeaponNames) { + if (weaponNameGivenLowerCase.contains(magicWeaponName)) { + return WEAPON_MAGIC; + } + } + + return WEAPON_UNKNOWN; + + } + + private static String[] meleeWeaponNames = { + "sword", + "scimitar", + "dagger", + "spear", + "mace", + "axe", + "whip", + "tentacle", + "-ket-", + "-xil-", + "warhammer", + "halberd", + "claws", + "hasta", + "scythe", + "maul", + "anchor", + "sabre", + "excalibur", + "machete", + "dragon hunter lance", + "event rpg", + "silverlight", + "darklight", + "arclight", + "flail", + "granite hammer", + "rapier", + "bulwark" + }; + + private static String[] rangedWeaponNames = { + "bow", + "blowpipe", + "xil-ul", + "knife", + "dart", + "thrownaxe", + "chinchompa", + "ballista" + }; + + private static String[] magicWeaponNames = { + "staff", + "trident", + "wand", + "dawnbringer" + }; + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/QuestGuideLinks.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/QuestGuideLinks.java new file mode 100644 index 0000000000..c61fa5e81c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/QuestGuideLinks.java @@ -0,0 +1,207 @@ +package net.runelite.client.plugins.slayermusiq; + +import net.runelite.client.util.LinkBrowser; +import net.runelite.api.ChatMessageType; +import net.runelite.api.events.ChatMessage; +import net.runelite.client.chat.ChatColorType; +import net.runelite.client.chat.ChatMessageBuilder; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.chat.QueuedMessage; + +public class QuestGuideLinks { + private static final Link[] QUEST_GUIDE_LINKS = { + // Free Quests + new Link("Cook's Assistant", "https://www.youtube.com/watch?v=ehmtDRelj3c"), + new Link("Romeo & Juliet", "https://www.youtube.com/watch?v=rH_biWSNWVY"), + new Link("Demon Slayer", "https://www.youtube.com/watch?v=hgACrzJSiQk"), + new Link("Shield of Arrav", "https://www.youtube.com/watch?v=a_imLDKUdzg"), + new Link("Sheep Shearer", "https://www.youtube.com/watch?v=XFG3aNwK68s"), + new Link("The Restless Ghost", "https://www.youtube.com/watch?v=UkWNcsG_pXM"), + new Link("Ernest the Chicken", "https://www.youtube.com/watch?v=cq8NIVhSqh4"), + new Link("Vampire Slayer", "https://www.youtube.com/watch?v=FcEuxsDJWCU"), + new Link("Imp Catcher", "https://www.youtube.com/watch?v=LHgnl0FbOzk"), + new Link("Prince Ali Rescue", "https://www.youtube.com/watch?v=hrSPl1GfFaw"), + new Link("Doric's Quest", "https://www.youtube.com/watch?v=5TYyxHU27a4"), + new Link("Black Knights' Fortress", "https://www.youtube.com/watch?v=aekoZi3f9cU"), + new Link("Witch's Potion", "https://www.youtube.com/watch?v=XV4i5sPUvXo"), + new Link("The Knight's Sword", "https://www.youtube.com/watch?v=UkBWaI0rOqE"), + new Link("Goblin Diplomacy", "https://www.youtube.com/watch?v=P9BKOb_dLoY"), + new Link("Pirate's Treasure", "https://www.youtube.com/watch?v=zcD87PQW8Qk"), + new Link("Dragon Slayer", "https://www.youtube.com/watch?v=bMtCjlFOaBI"), + new Link("Rune Mysteries", "https://www.youtube.com/watch?v=l8ZhaN8uoS0"), + new Link("Misthalin Mystery", "https://www.youtube.com/watch?v=QlFqVAobAlQ"), + new Link("The Corsair Curse", "https://www.youtube.com/watch?v=wi7mUAHExz4"), + new Link("X Marks the Spot", "https://www.youtube.com/watch?v=GhRgvEG5jxQ"), + // Members Quests + new Link("Druidic Ritual", "https://www.youtube.com/watch?v=QIfU6HSmH4w"), + new Link("Lost City", "https://www.youtube.com/watch?v=T-kQNUSjFZI"), + new Link("Witch's House", "https://www.youtube.com/watch?v=TLsg7Wa-LUA"), + new Link("Merlin's Crystal", "https://www.youtube.com/watch?v=ESX-qriNtCE"), + new Link("Heroes' Quest", "https://www.youtube.com/watch?v=hK2N0WLKviE"), + new Link("Scorpion Catcher", "https://www.youtube.com/watch?v=xpqdec7_ZWg"), + new Link("Family Crest", "https://www.youtube.com/watch?v=0mk_Cgjr738"), + new Link("Monk's Friend", "https://www.youtube.com/watch?v=avi4y4G3Hcw"), + new Link("Temple of Ikov", "https://www.youtube.com/watch?v=5K7jDgr_4Z4"), + new Link("Clock Tower", "https://www.youtube.com/watch?v=GUCkkQFzyDw"), + new Link("Holy Grail", "https://www.youtube.com/watch?v=cgXoV1QlYco"), + new Link("Tree Gnome Village", "https://www.youtube.com/watch?v=T6Su__yuyRI"), + new Link("Fight Arena", "https://www.youtube.com/watch?v=4Nqjep2E5pw"), + new Link("Hazeel Cult", "https://www.youtube.com/watch?v=2_fhFJW6cNY"), + new Link("Sheep Herder", "https://www.youtube.com/watch?v=akC9FeYCG1Q"), + new Link("Plague City", "https://www.youtube.com/watch?v=Hf2wQQZL5CU"), + new Link("Waterfall Quest", "https://www.youtube.com/watch?v=xWBSnGkQTi4"), + new Link("Jungle Potion", "https://www.youtube.com/watch?v=xqLKsFz08As"), + new Link("The Grand Tree", "https://www.youtube.com/watch?v=N5e_Jus_E-Y"), + new Link("Underground Pass", "https://www.youtube.com/watch?v=5klGJg1wY8k"), + new Link("Observatory Quest", "https://www.youtube.com/watch?v=yxa9B6svv44"), + new Link("Watchtower", "https://www.youtube.com/watch?v=Vb10GoYP7FE"), + new Link("Dwarf Cannon", "https://www.youtube.com/watch?v=pROFg5jcCR0"), + new Link("Murder Mystery", "https://www.youtube.com/watch?v=P1IDGCA2f9o"), + new Link("The Dig Site", "https://www.youtube.com/watch?v=TOdcWV4MzuU"), + new Link("Gertrude's Cat", "https://www.youtube.com/watch?v=g7S09wA8EAY"), + new Link("Legends' Quest", "https://www.youtube.com/watch?v=Lid8enDEF_U"), + new Link("Death Plateau", "https://www.youtube.com/watch?v=SIQFmTvnb6w"), + new Link("Big Chompy Bird Hunting", "https://www.youtube.com/watch?v=s2fytMOHJXI"), + new Link("Elemental Workshop I", "https://www.youtube.com/watch?v=tbZD2RDqvfQ"), + new Link("Nature Spirit", "https://www.youtube.com/watch?v=Enf8vUWb5o0"), + new Link("Priest in Peril", "https://www.youtube.com/watch?v=fyYri6wUQIU"), + new Link("Regicide", "https://www.youtube.com/watch?v=KkWM-ok3C4Y"), + new Link("Tai Bwo Wannai Trio", "https://www.youtube.com/watch?v=Mdair5mvZL0"), + new Link("Troll Stronghold", "https://www.youtube.com/watch?v=zqmUs-f3AKA"), + new Link("Horror from the Deep", "https://www.youtube.com/watch?v=9htK8kb6DR8"), + new Link("Throne of Miscellania", "https://www.youtube.com/watch?v=fzGMnv2skBE"), + new Link("Monkey Madness I", "https://www.youtube.com/watch?v=VnoRfeBnPFA"), + new Link("Haunted Mine", "https://www.youtube.com/watch?v=cIc6loJHm9Q"), + new Link("Troll Romance", "https://www.youtube.com/watch?v=j2zifZVu7Gc"), + new Link("In Search of the Myreque", "https://www.youtube.com/watch?v=5nmYFHdAXAQ"), + new Link("Creature of Fenkenstrain", "https://www.youtube.com/watch?v=swqUVIs7B7M"), + new Link("Roving Elves", "https://www.youtube.com/watch?v=J3qf9DnT9cA"), + new Link("One Small Favour", "https://www.youtube.com/watch?v=ix_0-W3e9ps"), + new Link("Mountain Daughter", "https://www.youtube.com/watch?v=HETx_LX7aiY"), + new Link("Between a Rock...", "https://www.youtube.com/watch?v=cB11I45EGgA"), + new Link("The Golem", "https://www.youtube.com/watch?v=qpEHpiO6lLw"), + new Link("Desert Treasure", "https://www.youtube.com/watch?v=BuIqulIsICo"), + new Link("Icthlarin's Little Helper", "https://www.youtube.com/watch?v=wpNKm8_vUOM"), + new Link("Tears of Guthix", "https://www.youtube.com/watch?v=EMonDNI0uPk"), + new Link("The Lost Tribe", "https://www.youtube.com/watch?v=spZErjRnCdc"), + new Link("The Giant Dwarf", "https://www.youtube.com/watch?v=Z7PsGpOYgxY"), + new Link("Recruitment Drive", "https://www.youtube.com/watch?v=sOuzMpA_xtw"), + new Link("Mourning's Ends Part I", "https://www.youtube.com/watch?v=vuzAdk-h3c0"), + new Link("Garden of Tranquillity", "https://www.youtube.com/watch?v=7hbCzYnLCsQ"), + new Link("A Tail of Two Cats", "https://www.youtube.com/watch?v=SgN9Yw_YqHk"), + new Link("Wanted!", "https://www.youtube.com/watch?v=ZHZAKDCfXGs"), + new Link("Mourning's Ends Part II", "https://www.youtube.com/watch?v=FK5sLogGbU8"), + new Link("Rum Deal", "https://www.youtube.com/watch?v=I14CIu5x2S8"), + new Link("Shadow of the Storm", "https://www.youtube.com/watch?v=5ZvWd3XCQjI"), + new Link("Ratcatchers", "https://www.youtube.com/watch?v=s7G22fEuhTc"), + new Link("Spirits of the Elid", "https://www.youtube.com/watch?v=A1zAX55hZC0"), + new Link("Devious Minds", "https://www.youtube.com/watch?v=_UtlFmrWt1w"), + new Link("Enakhra's Lament", "https://www.youtube.com/watch?v=Y3kEIPYVaVE"), + new Link("Cabin Fever", "https://www.youtube.com/watch?v=k5DtxNXhOaw"), + new Link("Fairytale I - Growing Pains", "https://www.youtube.com/watch?v=cfGI9qFOmsg"), + new Link("Recipe for Disaster", "https://www.youtube.com/watch?v=hrAyyInJaTA"), + new Link("In Aid of the Myreque", "https://www.youtube.com/watch?v=O2Ru2NmuTaA"), + new Link("A Soul's Bane", "https://www.youtube.com/watch?v=dp8dp79qp6I"), + new Link("Rag and Bone Man", "https://www.youtube.com/watch?v=3owXSeN56W8"), + new Link("Swan Song", "https://www.youtube.com/watch?v=IpmERThXv2g"), + new Link("Royal Trouble", "https://www.youtube.com/watch?v=bVWUlKzNXEg"), + new Link("Death to the Dorgeshuun", "https://www.youtube.com/watch?v=2XJHuLhig98"), + new Link("Fairytale II - Cure a Queen", "https://www.youtube.com/watch?v=P6KkRk4_e3U"), + new Link("Lunar Diplomacy", "https://www.youtube.com/watch?v=vmeSKb7IBgQ"), + new Link("The Eyes of Glouphrie", "https://www.youtube.com/watch?v=0YCPwmZcxKA"), + new Link("Darkness of Hallowvale", "https://www.youtube.com/watch?v=QziKl99qdtU"), + new Link("Elemental Workshop II", "https://www.youtube.com/watch?v=Bb4E7ecIgv0"), + new Link("My Arm's Big Adventure", "https://www.youtube.com/watch?v=xa1KWOewgYA"), + new Link("Enlightened Journey", "https://www.youtube.com/watch?v=XAPthC8d7k0"), + new Link("Eagles' Peak", "https://www.youtube.com/watch?v=KDxIrrwXp7U"), + new Link("Animal Magnetism", "https://www.youtube.com/watch?v=kUyjXA7TaFU"), + new Link("Contact!", "https://www.youtube.com/watch?v=czn-yWABBWs"), + new Link("Cold War", "https://www.youtube.com/watch?v=0m1KpP-qKWI"), + new Link("The Fremennik Isles", "https://www.youtube.com/watch?v=EvxhiOWmraY"), + new Link("The Great Brain Robbery", "https://www.youtube.com/watch?v=ImHFASuNUN8"), + new Link("What Lies Below", "https://www.youtube.com/watch?v=f_9nVMGTtuo"), + new Link("Olaf's Quest", "https://www.youtube.com/watch?v=mXV5bM1NFMM"), + new Link("Dream Mentor", "https://www.youtube.com/watch?v=XDLUu0Kf0sE"), + new Link("Grim Tales", "https://www.youtube.com/watch?v=dFB0Q6v8Apw"), + new Link("King's Ransom", "https://www.youtube.com/watch?v=UJz9ZfF3uCY"), + new Link("Shilo Village", "https://www.youtube.com/watch?v=bDvBi8FT-QI"), + new Link("Biohazard", "https://www.youtube.com/watch?v=n9k87LwOGMk"), + new Link("Tower of Life", "https://www.youtube.com/watch?v=KReMcWpeY3k"), + new Link("Rag and Bone Man II", "https://www.youtube.com/watch?v=KGdHiDDUX_U"), + new Link("Zogre Flesh Eaters", "https://www.youtube.com/watch?v=vzm4949kXP4"), + new Link("Monkey Madness II", "https://www.youtube.com/watch?v=ykE5LbjABaI"), + new Link("Client of Kourend", "https://www.youtube.com/watch?v=Y-KIHF-cL9w"), + new Link("The Queen of Thieves", "https://www.youtube.com/watch?v=W94zFZVrHkQ"), + new Link("Bone Voyage", "https://www.youtube.com/watch?v=-VTR4p8kPmI"), + new Link("Dragon Slayer II", "https://www.youtube.com/watch?v=4BMb3Zwzk_U"), + new Link("The Depths of Despair", "https://www.youtube.com/watch?v=CaVUk2eAsKs"), + new Link("A Taste of Hope", "https://www.youtube.com/watch?v=VjdgEIizdSc"), + new Link("Tale of the Righteous", "https://www.youtube.com/watch?v=99yiv0tPl58"), + new Link("Making Friends with My Arm", "https://www.youtube.com/watch?v=DltzzhIsM_Q"), + new Link("The Ascent of Arceuus", "https://www.youtube.com/watch?v=4VQnfrv6S18"), + new Link("The Forsaken Tower", "https://www.youtube.com/watch?v=con0sXl5NBY"), + new Link("Fishing Contest", "https://www.youtube.com/watch?v=XYSv37A_l5w"), + new Link("Tribal Totem", "https://www.youtube.com/watch?v=XkUEIjr886M"), + new Link("Sea Slug", "https://www.youtube.com/watch?v=oOZVfa5SkVQ"), + new Link("The Tourist Trap", "https://www.youtube.com/watch?v=0bmSCCepMvo"), + new Link("Eadgar's Ruse", "https://www.youtube.com/watch?v=aVQ3DjTElXg"), + new Link("Shades of Mort'ton", "https://www.youtube.com/watch?v=eF05R8OMxgg"), + new Link("The Fremennik Trials", "https://www.youtube.com/watch?v=YUIvEgcvl5c"), + new Link("Ghosts Ahoy", "https://www.youtube.com/watch?v=aNBkLOywDfM"), + new Link("The Feud", "https://www.youtube.com/watch?v=nlBSc9IUklA"), + new Link("Forgettable Tale...", "https://www.youtube.com/watch?v=3HvFd6AxNU0"), + new Link("Making History", "https://www.youtube.com/watch?v=bOTGi2zAuhs"), + new Link("The Hand in the Sand", "https://www.youtube.com/watch?v=gdNLcZ-l1Lw"), + new Link("The Slug Menace", "https://www.youtube.com/watch?v=BRQbdr3JEZ8"), + new Link("Another Slice of H.A.M.", "https://www.youtube.com/watch?v=Yq3db7827Lk") + }; + + private static class Link { + + private String questName; + private String url; + + public Link(String questName, String url) { + this.questName = questName; + this.url = url; + } + + public String getQuestName() { + return questName; + } + + public void openURL() { + LinkBrowser.browse(this.url); + } + + } + + private static boolean openGuide(String questName) { + for (Link link : QUEST_GUIDE_LINKS) { + if (link.getQuestName().equals(questName)) { + link.openURL(); + return true; + } + } + return false; + } + + private static void logQuestNotFoundError(String questName, ChatMessageManager chatMessageManager) { + String chatMessage = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append("Could not find Slayermusiq1 guide for " + questName) + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.GAMEMESSAGE) + .runeLiteFormattedMessage(chatMessage) + .build()); + } + + public static void tryOpenGuide(String questName, ChatMessageManager chatMessageManager) { + boolean success = openGuide(questName); + if (!success) { + logQuestNotFoundError(questName, chatMessageManager); + } + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/SlayermusiqPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/SlayermusiqPlugin.java new file mode 100644 index 0000000000..0689ba8289 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/SlayermusiqPlugin.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2018, Jeremy Berchtold + * 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. + */ + + +// Based off RuneLite's Wiki Plugin +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.slayermusiq; + +import com.google.inject.Provides; +import com.google.common.primitives.Ints; +import java.awt.Dimension; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.inject.Inject; +import javax.swing.SwingUtilities; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.util.Text; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; + +@PluginDescriptor( + name = "Slayermusiq1 Guides", + description = "Adds a right-click option to go to Slayermusiq1's guides from the quest tab", + tags = {"quest", "guide", "slayermusiq"}, + type = PluginType.UTILITY +) +@Slf4j +public class SlayermusiqPlugin extends Plugin +{ + + private static final int[] QUESTLIST_WIDGET_IDS = new int[] + { + WidgetInfo.QUESTLIST_FREE_CONTAINER.getId(), + WidgetInfo.QUESTLIST_MEMBERS_CONTAINER.getId(), + WidgetInfo.QUESTLIST_MINIQUEST_CONTAINER.getId(), + }; + + private static final String MENUOP_SLAYERMUSIQ = "Slayermusiq"; + + @Inject + private Client client; + + @Inject + private ChatMessageManager chatMessageManager; + + @Override + protected void startUp() throws Exception + { + // + } + + @Override + protected void shutDown() throws Exception + { + // + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + int widgetID = event.getActionParam1(); + if (Ints.contains(QUESTLIST_WIDGET_IDS, widgetID) && "Read Journal:".equals(event.getOption())) { + MenuEntry[] menuEntries = client.getMenuEntries(); + + MenuEntry newMenuEntry = createSlayermusiqOptionMenuEntry(event); + menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1); + menuEntries[menuEntries.length - 1] = newMenuEntry; + + client.setMenuEntries(menuEntries); + } + } + + @Subscribe + private void onMenuOptionClicked(MenuOptionClicked ev) { + if (ev.getMenuAction() == MenuAction.RUNELITE && ev.getMenuOption().equals(MENUOP_SLAYERMUSIQ)) { + ev.consume(); + String quest = Text.removeTags(ev.getMenuTarget()); + QuestGuideLinks.tryOpenGuide(quest, chatMessageManager); + } + } + + private MenuEntry createSlayermusiqOptionMenuEntry(MenuEntryAdded event) { + int widgetIndex = event.getActionParam0(); + int widgetID = event.getActionParam1(); + + MenuEntry menuEntry = new MenuEntry(); + menuEntry.setTarget(event.getTarget()); + menuEntry.setOption(MENUOP_SLAYERMUSIQ); + menuEntry.setParam0(widgetIndex); + menuEntry.setParam1(widgetID); + menuEntry.setType(MenuAction.RUNELITE.getId()); + + return menuEntry; + } + +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookConfig.java index 1a47110f61..9bc8e243f9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookConfig.java @@ -78,8 +78,8 @@ public interface SpellbookConfig extends Config @ConfigItem( keyName = "filter", name = "Unfiltered spells", - description = "Spells you don't want to filter, seperated with a comma" - ) + description = "Spells you don't want to filter, seperated with a comma.
\"'s can be used in front and behind spells (eg: '\"c' matches all spells starting with a c" + ) // ^ JAJAJJAJAJAJAJA BRAZIL default String filter() { return ""; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java index 82181d6911..8175c05f3f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java @@ -81,6 +81,13 @@ public class SpellbookPlugin extends Plugin private static final WidgetMenuOption RESIZABLE_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_MAGIC_TAB); private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_MAGIC_TAB); private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_MAGIC_TAB); + private enum WordFilterMode + { + CONTAINS, + EQUALS, + STARTSWITH, + ENDSWITH + } @Inject private Client client; @@ -143,9 +150,7 @@ public class SpellbookPlugin extends Plugin saveSpells(); config.canDrag(false); mouseManager.unregisterMouseListener(mouseListener); - mouseManager.unregisterMouseWheelListener(mouseListener); - mouseListener = null; } @@ -168,16 +173,13 @@ public class SpellbookPlugin extends Plugin String key = event.getKey(); - if ("canDrag".equals(key)) - { - refreshMagicTabOption(); - } - else if ("filter".equals(key)) + if ("filter".equals(key)) { loadFilter(); } clientThread.invokeLater(this::runRebuild); + refreshMagicTabOption(); } @Subscribe @@ -241,7 +243,46 @@ public class SpellbookPlugin extends Plugin return; } - iStack[iStackSize - 2] = notFilteredSpells.stream().anyMatch(spell::contains) ? 1 : 0; + for (String str : notFilteredSpells) + { + WordFilterMode mode = getFilterMode(str); + str = str.replaceAll("\"", ""); + + if (mode == WordFilterMode.CONTAINS) + { + if (spell.contains(str)) + { + iStack[iStackSize - 2] = 1; + break; + } + } + else if (mode == WordFilterMode.STARTSWITH) + { + if (spell.startsWith(str)) + { + iStack[iStackSize - 2] = 1; + break; + } + } + else if (mode == WordFilterMode.ENDSWITH) + { + if (spell.endsWith(str)) + { + iStack[iStackSize - 2] = 1; + break; + } + } + else if (mode == WordFilterMode.EQUALS) + { + if (spell.equals(str)) + { + iStack[iStackSize - 2] = 1; + break; + } + } + + iStack[iStackSize - 2] = 0; + } } else if ("isMobileSpellbookEnabled".equals(event.getEventName())) { @@ -273,7 +314,7 @@ public class SpellbookPlugin extends Plugin .map(Spell::getName) .filter(s -> notFilteredSpells .stream() - .anyMatch(s::contains)) + .anyMatch(s.replaceAll("\"", "" )::contains)) .count(); @@ -436,6 +477,24 @@ public class SpellbookPlugin extends Plugin ); } + private static WordFilterMode getFilterMode(String s) + { + if (!s.contains("\"")) + { + return WordFilterMode.CONTAINS; + } + if (s.startsWith("\"")) + { + return s.endsWith("\"") ? WordFilterMode.EQUALS : WordFilterMode.STARTSWITH; + } + else if (s.endsWith("\"")) + { + return WordFilterMode.ENDSWITH; + } + + return WordFilterMode.CONTAINS; // but probably null soz + } + boolean isOnSpellWidget(java.awt.Point point) { Widget boundsWidget = client.getWidget(WidgetInfo.SPELLBOOK_FILTERED_BOUNDS); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tickcounter/TickCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/tickcounter/TickCounterPlugin.java index cc17572eba..f049b722c7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tickcounter/TickCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tickcounter/TickCounterPlugin.java @@ -25,7 +25,7 @@ import net.runelite.client.ui.overlay.OverlayManager; @PluginDescriptor(name = "Tick Counter", description = "Counts combat activity for nearby players", enabledByDefault = false, - type = PluginType.UTILITY + type = PluginType.PVP ) public class TickCounterPlugin extends Plugin { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsConfig.java new file mode 100644 index 0000000000..91545b3074 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019. PKLite - All Rights Reserved + * Unauthorized modification, distribution, or possession of this source file, via any medium is strictly prohibited. + * Proprietary and confidential. Refer to PKLite License file for more information on + * full terms of this copyright and to determine what constitutes authorized use. + * Written by PKLite(ST0NEWALL, others) , 2019 + * + */ + +package net.runelite.client.plugins.wildernesslocations; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Keybind; + +@ConfigGroup("wildernesslocations") +public interface WildernessLocationsConfig extends Config +{ + + @ConfigItem( + keyName = "drawOverlay", + name = "Draw Overlay", + description = "Configure drawing wilderness locations overlay", + position = 1 + ) + default boolean drawOverlay() + { + return true; + } + + @ConfigItem( + keyName = "keybind", + name = "Send to CC", + description = "Configure button to send current location to CC", + position = 2 + ) + default Keybind keybind() + { + return Keybind.NOT_SET; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsOverlay.java index 8ab198dc28..d8148ab8bf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsOverlay.java @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2019. PKLite - All Rights Reserved + * Unauthorized modification, distribution, or possession of this source file, via any medium is strictly prohibited. + * Proprietary and confidential. Refer to PKLite License file for more information on + * full terms of this copyright and to determine what constitutes authorized use. + * Written by PKLite(ST0NEWALL, others) , 2019 + * + */ + package net.runelite.client.plugins.wildernesslocations; import java.awt.Dimension; @@ -14,6 +23,9 @@ public class WildernessLocationsOverlay extends Overlay { private final WildernessLocationsPlugin plugin; private TextComponent textComponent; + + @Inject + private WildernessLocationsConfig wildyConfig; @Inject public WildernessLocationsOverlay(Client client, WildernessLocationsPlugin plugin) @@ -29,7 +41,7 @@ public class WildernessLocationsOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - if (plugin.isRenderLocation()) + if (plugin.isRenderLocation() && wildyConfig.drawOverlay()) { textComponent.setText(plugin.getLocationString()); return textComponent.render(graphics); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsPlugin.java index b1036cde55..31f8ef045b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsPlugin.java @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2019. PKLite - All Rights Reserved + * Unauthorized modification, distribution, or possession of this source file, via any medium is strictly prohibited. + * Proprietary and confidential. Refer to PKLite License file for more information on + * full terms of this copyright and to determine what constitutes authorized use. + * Written by PKLite(ST0NEWALL, others) , 2019 + * + */ + package net.runelite.client.plugins.wildernesslocations; @@ -7,25 +16,36 @@ import java.util.Map; import java.util.Objects; import javax.inject.Inject; +import com.google.inject.Provides; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; +import net.runelite.api.ScriptID; +import net.runelite.api.VarClientStr; import net.runelite.api.Varbits; import net.runelite.api.coords.WorldArea; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.GameTick; +import net.runelite.api.events.VarClientStrChanged; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.PluginManager; +import net.runelite.client.plugins.PluginType; import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.HotkeyListener; import net.runelite.client.util.WildernessLocation; +@Slf4j @PluginDescriptor( - name = "Wild Locations", - description = "Indicates the players current location in the wild", - tags = {"Wildy", "Wilderness Location", "location", "loc", "pvp", "pklite"}, - type = PluginType.PVP + name = "Wild Locations", + description = "Indicates the players current location in the wild", + tags = {"Wildy", "Wilderness Location", "location", "loc", "pvp", "pklite"}, + type = PluginType.PVP ) public class WildernessLocationsPlugin extends Plugin { @@ -39,29 +59,63 @@ public class WildernessLocationsPlugin extends Plugin @Inject private WildernessLocationsOverlay overlay = new WildernessLocationsOverlay(this.client, this); - private final HashMap wildLocs = getLocationMap(); @Getter private boolean renderLocation; + @Getter private String locationString = ""; - private WorldPoint worldPoint = null; + @Inject + private ClientThread clientThread; + + @Inject + private WildernessLocationsConfig wildyConfig; + + @Inject + private KeyManager keyManager; + + private String oldChat = ""; + private int currentCooldown = 0; + private final int COOLDOWN_TICKS = 30; + private WorldPoint worldPoint = null; + private final HashMap wildLocs = getLocationMap(); + + private final HotkeyListener hotkeyListener = new HotkeyListener(() -> wildyConfig.keybind()) + { + @Override + public void hotkeyPressed() + { + sendLocToCC(); + } + }; + + @Provides + WildernessLocationsConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(WildernessLocationsConfig.class); + } @Override protected void startUp() throws Exception { overlayManager.add(overlay); + keyManager.registerKeyListener(hotkeyListener); } @Override protected void shutDown() throws Exception { overlayManager.remove(overlay); + keyManager.unregisterKeyListener(hotkeyListener); } @Subscribe public void onGameTick(GameTick event) { + if (currentCooldown != 0) + { + currentCooldown--; + } renderLocation = client.getVar(Varbits.IN_WILDERNESS) == 1; if (renderLocation) { @@ -78,7 +132,6 @@ public class WildernessLocationsPlugin extends Plugin } } - private String location() { int dist = 10000; @@ -134,4 +187,53 @@ public class WildernessLocationsPlugin extends Plugin hashMap.put(wildernessLocation.getWorldArea(), wildernessLocation.getName())); return hashMap; } + + @Subscribe + public void onVarClientStrChanged(VarClientStrChanged varClient) + { + String newChat = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT); + if (varClient.getIndex() == VarClientStr.CHATBOX_TYPED_TEXT.getIndex() && !newChat.equals(oldChat)) + { + oldChat = newChat; + } + } + + private boolean inClanChat() + { + return client.getWidget(WidgetInfo.CLAN_CHAT_TITLE) != null; + } + + private void sendMessage(String text) + { + int mode = 0; + if (inClanChat() && text.startsWith("/")) + { + mode = 2; + } + int finalMode = mode; + Runnable r = () -> + { + String cached = oldChat; + client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, text); + client.runScript(ScriptID.CHATBOX_INPUT, finalMode, text); + oldChat = cached; + client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, oldChat); + }; + clientThread.invoke(r); + } + + private void sendLocToCC() + { + if (currentCooldown != 0) + { + return; + } + String location = getLocationString(); + if (location.equals("")) + { + return; + } + sendMessage("/World: " + client.getWorld() + " Location: " + location); + currentCooldown = COOLDOWN_TICKS; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesConfig.java index eab7c91c30..cc88234686 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesConfig.java @@ -55,11 +55,22 @@ public interface XpGlobesConfig extends Config return false; } + @ConfigItem( + keyName = "Time to level", + name = "Display TTL", + description = "Displays time left to level", + position = 2 + ) + default boolean enableTimeToLevel() + { + return true; + } + @ConfigItem( keyName = "enableCustomArcColor", name = "Enable custom arc color", description = "Enables the custom coloring of the globe's arc instead of using the skill's default color.", - position = 2 + position = 3 ) default boolean enableCustomArcColor() { @@ -71,7 +82,7 @@ public interface XpGlobesConfig extends Config keyName = "Progress arc color", name = "Progress arc color", description = "Change the color of the progress arc in the xp orb", - position = 3 + position = 4 ) default Color progressArcColor() { @@ -83,7 +94,7 @@ public interface XpGlobesConfig extends Config keyName = "Progress orb outline color", name = "Progress orb outline color", description = "Change the color of the progress orb outline", - position = 4 + position = 5 ) default Color progressOrbOutLineColor() { @@ -95,7 +106,7 @@ public interface XpGlobesConfig extends Config keyName = "Progress orb background color", name = "Progress orb background color", description = "Change the color of the progress orb background", - position = 5 + position = 6 ) default Color progressOrbBackgroundColor() { @@ -106,7 +117,7 @@ public interface XpGlobesConfig extends Config keyName = "Progress arc width", name = "Progress arc width", description = "Change the stroke width of the progress arc", - position = 6 + position = 7 ) default int progressArcStrokeWidth() { @@ -117,7 +128,7 @@ public interface XpGlobesConfig extends Config keyName = "Orb size", name = "Size of orbs", description = "Change the size of the xp orbs", - position = 7 + position = 8 ) default int xpOrbSize() { @@ -128,7 +139,7 @@ public interface XpGlobesConfig extends Config keyName = "Orb duration", name = "Duration of orbs", description = "Change the duration the xp orbs are visible", - position = 8 + position = 9 ) default int xpOrbDuration() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java index 81171840e1..168476b376 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java @@ -293,12 +293,15 @@ public class XpGlobesOverlay extends Overlay .build()); } - String timeLeft = xpTrackerService.getTimeTillGoal(mouseOverSkill.getSkill()); - xpTooltip.getChildren().add(LineComponent.builder() - .left("Time left:") - .leftColor(Color.ORANGE) - .right(timeLeft) - .build()); + if (config.enableTimeToLevel()) + { + String timeLeft = xpTrackerService.getTimeTillGoal(mouseOverSkill.getSkill()); + xpTooltip.getChildren().add(LineComponent.builder() + .left("Time left:") + .leftColor(Color.ORANGE) + .right(timeLeft) + .build()); + } } xpTooltip.render(graphics); diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/playerindicators/skull.png b/runelite-client/src/main/resources/net/runelite/client/plugins/playerindicators/skull.png new file mode 100644 index 0000000000..09869ea0e1 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/playerindicators/skull.png differ diff --git a/runelite-client/src/main/scripts/437.hash b/runelite-client/src/main/scripts/437.hash new file mode 100644 index 0000000000..22831dda47 --- /dev/null +++ b/runelite-client/src/main/scripts/437.hash @@ -0,0 +1 @@ +3A111DACE3611F4C4FB53F60FC180F863D5FC222D24EE301B08D49496658F802 \ No newline at end of file diff --git a/runelite-client/src/main/scripts/437.rs2asm b/runelite-client/src/main/scripts/437.rs2asm new file mode 100644 index 0000000000..d5cf4b8ae3 --- /dev/null +++ b/runelite-client/src/main/scripts/437.rs2asm @@ -0,0 +1,11 @@ +.id 437 +.int_stack_count 1 +.string_stack_count 0 +.int_var_count 1 +.string_var_count 1 + sload 0 + clan_joinchat + sconst "joinCC" + runelite_callback + return + diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClanMemberManagerMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClanMemberManagerMixin.java index 25e01ce1ca..aca7addbb5 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClanMemberManagerMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClanMemberManagerMixin.java @@ -40,11 +40,16 @@ public abstract class RSClanMemberManagerMixin implements RSClanMemberManager { @Shadow("clientInstance") private static RSClient client; + private RSNameable nameable; + private RSName name; + private RSName prevName; @Inject @Override public void rl$add(RSName name, RSName prevName) { + this.name = name; + this.prevName = prevName; ClanMember member = findByName(name); if (member == null) { @@ -59,6 +64,7 @@ public abstract class RSClanMemberManagerMixin implements RSClanMemberManager @Override public void rl$remove(RSNameable nameable) { + this.nameable = nameable; ClanMember member = findByName(nameable.getRsName()); if (member == null) {