diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/Prayer.java b/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/Prayer.java
new file mode 100644
index 0000000000..3446d9f233
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/Prayer.java
@@ -0,0 +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.autoprayerswitch;
+
+import net.runelite.api.widgets.WidgetInfo;
+
+public enum Prayer
+{
+ PROTECT_FROM_MELEE(net.runelite.api.Prayer.PROTECT_FROM_MELEE, "Protect from Melee", WidgetInfo.PRAYER_PROTECT_FROM_MELEE.getId()), PROTECT_FROM_MAGIC(net.runelite.api.Prayer.PROTECT_FROM_MAGIC, "Protect from Magic", WidgetInfo.PRAYER_PROTECT_FROM_MAGIC.getId()), PROTECT_FROM_MISSILES(net.runelite.api.Prayer.PROTECT_FROM_MISSILES, "Protect from Missiles", WidgetInfo.PRAYER_PROTECT_FROM_MISSILES.getId());
+
+ private final net.runelite.api.Prayer prayer;
+ private final String name;
+ private final int widgetId;
+
+ private Prayer(net.runelite.api.Prayer prayer, String name, int widgetId)
+ {
+ this.prayer = prayer;this.name = name;this.widgetId = widgetId;
+ }
+
+ public net.runelite.api.Prayer getPrayer()
+ {
+ return this.prayer;
+ }
+
+ public String getName()
+ {
+ return this.name;
+ }
+
+ public int getWidgetId()
+ {
+ return this.widgetId;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/SwitchConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/SwitchConfig.java
new file mode 100644
index 0000000000..b687658319
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/SwitchConfig.java
@@ -0,0 +1,33 @@
+/*
+ * 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.autoprayerswitch;
+
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+
+@ConfigGroup("switch")
+public abstract interface SwitchConfig
+ extends Config
+{}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/SwitchPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/SwitchPlugin.java
new file mode 100644
index 0000000000..0f7b87731e
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/SwitchPlugin.java
@@ -0,0 +1,151 @@
+/*
+ * 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.autoprayerswitch;
+
+import net.runelite.client.plugins.PluginType;
+import org.slf4j.LoggerFactory;
+import net.runelite.api.MenuAction;
+import net.runelite.api.Actor;
+import net.runelite.api.events.InteractingChanged;
+import net.runelite.api.kit.KitType;
+import net.runelite.api.events.GameTick;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.api.events.PlayerDespawned;
+import com.google.inject.Provides;
+import net.runelite.client.config.ConfigManager;
+import net.runelite.api.Player;
+import javax.inject.Inject;
+import net.runelite.api.Client;
+import org.slf4j.Logger;
+import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.plugins.Plugin;
+
+@PluginDescriptor(
+ name="Switch Plugin",
+ description="Automatically switches prayers based on opponents equipment",
+ tags={"loudpacks", "prayer", "switches", "auto"},
+ type = PluginType.PVP
+)
+public class SwitchPlugin
+ extends Plugin
+{
+ private static final Logger log = LoggerFactory.getLogger(SwitchPlugin.class);
+ @Inject
+ private Client client;
+ @Inject
+ private SwitchConfig config;
+ private Player opponent;
+ private Prayer prayer;
+
+ @Provides
+ SwitchConfig provideConfig(ConfigManager configManager)
+ {
+ return (SwitchConfig)configManager.getConfig(SwitchConfig.class);
+ }
+
+ protected void startUp() {}
+
+ protected void shutDown()
+ {
+ if (this.prayer != null) {
+ deactivatePrayer(this.prayer);
+ }
+ this.opponent = null;
+ this.prayer = null;
+ }
+
+ @Subscribe
+ public void onPlayerDespawned(PlayerDespawned event)
+ {
+ if (this.opponent == null) {
+ return;
+ }
+ Player player = event.getPlayer();
+ if (player.equals(this.opponent))
+ {
+ this.opponent = null;
+ if (this.prayer != null) {
+ deactivatePrayer(this.prayer);
+ }
+ }
+ }
+
+ @Subscribe
+ public void onGameTick(GameTick event)
+ {
+ if (this.opponent == null) {
+ return;
+ }
+ int weapon = this.opponent.getPlayerComposition().getEquipmentId(KitType.WEAPON);
+ Prayer counterPrayer = WeaponMap.getMappingForID(weapon);
+ if (counterPrayer != null) {
+ activatePrayer(counterPrayer);
+ }
+ }
+
+ @Subscribe
+ public void onInteractingChanged(InteractingChanged event)
+ {
+ boolean inPvp = false;
+ for (String option : this.client.getPlayerOptions()) {
+ if ((option != null) && ((option.equals("Attack")) || (option.equals("Fight")))) {
+ inPvp = true;
+ }
+ }
+ if (!inPvp) {
+ return;
+ }
+ Actor source = event.getSource();
+ if (!(source instanceof Player)) {
+ return;
+ }
+ Actor target = event.getTarget();
+ if (!(target instanceof Player)) {
+ return;
+ }
+ if (target != this.client.getLocalPlayer()) {
+ return;
+ }
+ this.opponent = ((Player)source);
+ }
+
+ private void activatePrayer(Prayer prayer)
+ {
+ if (!this.client.isPrayerActive(prayer.getPrayer()))
+ {
+ // client.invokeMenuAction(-1, prayer.getWidgetId(), MenuAction.WIDGET_DEFAULT.getId(), 1, "Activate", "
" + prayer.getName() + "", 50, 50);
+ this.prayer = prayer;
+ }
+ }
+
+ private void deactivatePrayer(Prayer prayer)
+ {
+ if (this.client.isPrayerActive(prayer.getPrayer()))
+ {
+ //client.invokeMenuAction(-1, prayer.getWidgetId(), MenuAction.WIDGET_DEFAULT.getId(), 1, "Deactivate", "" + prayer.getName() + "", 50, 50);
+ this.prayer = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/WeaponMap.java b/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/WeaponMap.java
new file mode 100644
index 0000000000..46e7277b99
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/autoprayerswitch/WeaponMap.java
@@ -0,0 +1,135 @@
+/*
+ * 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.autoprayerswitch;
+
+public enum WeaponMap
+{
+ NONE(-1, Prayer.PROTECT_FROM_MELEE),
+ DDS(5698, Prayer.PROTECT_FROM_MELEE),
+ DDP(5680, Prayer.PROTECT_FROM_MELEE),
+ DD(1215, Prayer.PROTECT_FROM_MELEE),
+ DDPP(1231, Prayer.PROTECT_FROM_MELEE),
+ WHIP(4151, Prayer.PROTECT_FROM_MELEE),
+ D_SCIM(4587, Prayer.PROTECT_FROM_MELEE),
+ TENTACLE(12006, Prayer.PROTECT_FROM_MELEE),
+ AGS(11802, Prayer.PROTECT_FROM_MELEE),
+ G_MAUL(4153, Prayer.PROTECT_FROM_MELEE),
+ DWH(13576, Prayer.PROTECT_FROM_MELEE),
+ D_CLAWS(13652, Prayer.PROTECT_FROM_MELEE),
+ STAT_WH(22622, Prayer.PROTECT_FROM_MELEE),
+ VEST_LS(22613, Prayer.PROTECT_FROM_MELEE),
+ VEST_SPEAR(22610, Prayer.PROTECT_FROM_MELEE),
+ BGS(11804, Prayer.PROTECT_FROM_MELEE),
+ ZGS(11808, Prayer.PROTECT_FROM_MELEE),
+ SGS(11806, Prayer.PROTECT_FROM_MELEE),
+ RAPIER(22324, Prayer.PROTECT_FROM_MELEE),
+ DMACE(1434, Prayer.PROTECT_FROM_MELEE),
+ D2H(7158, Prayer.PROTECT_FROM_MELEE),
+ DHAL(3204, Prayer.PROTECT_FROM_MELEE),
+ DSPEAR(1249, Prayer.PROTECT_FROM_MELEE),
+ DSPEARPP(5716, Prayer.PROTECT_FROM_MELEE),
+ DSPEARP(1263, Prayer.PROTECT_FROM_MELEE),
+ DSPEARPPP(5730, Prayer.PROTECT_FROM_MELEE),
+ ELDER(21003, Prayer.PROTECT_FROM_MELEE),
+ ELDER_2(21205, Prayer.PROTECT_FROM_MELEE),
+ LEAF(20727, Prayer.PROTECT_FROM_MELEE),
+ RUNE_CBOW(9185, Prayer.PROTECT_FROM_MISSILES),
+ HEAVY_BAL(19481, Prayer.PROTECT_FROM_MISSILES),
+ LIGHT_BAL(19478, Prayer.PROTECT_FROM_MISSILES),
+ DRAG_CBOW(21902, Prayer.PROTECT_FROM_MISSILES),
+ ACB(11785, Prayer.PROTECT_FROM_MISSILES),
+ MOR_JAV(22636, Prayer.PROTECT_FROM_MISSILES),
+ MOR_TA(22634, Prayer.PROTECT_FROM_MISSILES),
+ DARK_BOW(11235, Prayer.PROTECT_FROM_MISSILES),
+ DARK_BOW2(12765, Prayer.PROTECT_FROM_MISSILES),
+ DARK_BOW3(12766, Prayer.PROTECT_FROM_MISSILES),
+ DARK_BOW4(12767, Prayer.PROTECT_FROM_MISSILES),
+ DARK_BOW5(12768, Prayer.PROTECT_FROM_MISSILES),
+ BLOW_PIPE(12926, Prayer.PROTECT_FROM_MISSILES),
+ MSB(861, Prayer.PROTECT_FROM_MISSILES),
+ MSB2(20558, Prayer.PROTECT_FROM_MISSILES),
+ MSB3(12788, Prayer.PROTECT_FROM_MISSILES),
+ DK(22804, Prayer.PROTECT_FROM_MISSILES),
+ DK2(22812, Prayer.PROTECT_FROM_MISSILES),
+ DK3(22814, Prayer.PROTECT_FROM_MISSILES),
+ DKP(22806, Prayer.PROTECT_FROM_MISSILES),
+ DKP2(22808, Prayer.PROTECT_FROM_MISSILES),
+ DKP3(22810, Prayer.PROTECT_FROM_MISSILES),
+ RK(868, Prayer.PROTECT_FROM_MISSILES),
+ RKP(876, Prayer.PROTECT_FROM_MISSILES),
+ RKP2(5660, Prayer.PROTECT_FROM_MISSILES),
+ RKP3(5667, Prayer.PROTECT_FROM_MISSILES),
+ ANCIENT_STAFF(4675, Prayer.PROTECT_FROM_MAGIC),
+ ZURIEL(22647, Prayer.PROTECT_FROM_MAGIC),
+ MASTER_WAND(6914, Prayer.PROTECT_FROM_MAGIC),
+ AHRIM(4710, Prayer.PROTECT_FROM_MAGIC),
+ AHRIM_25(4865, Prayer.PROTECT_FROM_MAGIC),
+ AHRIM_50(4864, Prayer.PROTECT_FROM_MAGIC),
+ AHRIM_75(4863, Prayer.PROTECT_FROM_MAGIC),
+ AHRIM_100(4862, Prayer.PROTECT_FROM_MAGIC),
+ KODAI(21006, Prayer.PROTECT_FROM_MAGIC),
+ TOXIC(12904, Prayer.PROTECT_FROM_MAGIC),
+ STAFF_OF_DEAD(11791, Prayer.PROTECT_FROM_MAGIC),
+ TOXIC_TRIDENT_U(12900, Prayer.PROTECT_FROM_MAGIC),
+ TRIDENT_U(11908, Prayer.PROTECT_FROM_MAGIC),
+ STAFF_LIGHT(22296, Prayer.PROTECT_FROM_MAGIC),
+ WATER_BSTAFF(1395, Prayer.PROTECT_FROM_MAGIC),
+ WATER_STAFF(1383, Prayer.PROTECT_FROM_MAGIC),
+ WATER_MSTAFF(1403, Prayer.PROTECT_FROM_MAGIC),
+ MUD(6562, Prayer.PROTECT_FROM_MAGIC),
+ MUD2(6563, Prayer.PROTECT_FROM_MAGIC),
+ MUD3(11998, Prayer.PROTECT_FROM_MAGIC),
+ MUD4(12000, Prayer.PROTECT_FROM_MAGIC),
+ MUD5(772, Prayer.PROTECT_FROM_MAGIC),
+ MUD6(20736, Prayer.PROTECT_FROM_MAGIC),
+ MUD7(20739, Prayer.PROTECT_FROM_MAGIC),
+ MUD8(20736, Prayer.PROTECT_FROM_MAGIC),
+ MUD9(20736, Prayer.PROTECT_FROM_MAGIC),
+ MUD10(20736, Prayer.PROTECT_FROM_MAGIC),
+ ZAM(2417, Prayer.PROTECT_FROM_MAGIC),
+ GUTH(2416, Prayer.PROTECT_FROM_MAGIC),
+ SARA(2415, Prayer.PROTECT_FROM_MAGIC),
+ TOX(22292, Prayer.PROTECT_FROM_MAGIC),
+ TOX2(12899, Prayer.PROTECT_FROM_MAGIC),
+ TOX3(11907, Prayer.PROTECT_FROM_MAGIC),
+ TOX4(22288, Prayer.PROTECT_FROM_MAGIC);
+
+ private final int id;
+ private final Prayer prayer;
+
+ public static Prayer getMappingForID(final int id) {
+ for (final WeaponMap map : values()) {
+ if (map.id == id) {
+ return map.prayer;
+ }
+ }
+ return null;
+ }
+
+ private WeaponMap(final int id, final Prayer prayer) {
+ this.id = id;
+ this.prayer = prayer;
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/autospec/SpecConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/autospec/SpecConfig.java
new file mode 100644
index 0000000000..e547796c80
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/autospec/SpecConfig.java
@@ -0,0 +1,40 @@
+/*
+ * 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.autospec;
+
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+import net.runelite.client.config.ConfigItem;
+
+@ConfigGroup("autospecs")
+public abstract interface SpecConfig
+ extends Config
+{
+ @ConfigItem(keyName="toggle", name="Continuous Toggle", description="Continuously enabled special attack when supported weapons are equipped.")
+ default boolean continuousToggle()
+ {
+ return false;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/autospec/SpecPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/autospec/SpecPlugin.java
new file mode 100644
index 0000000000..751b53d1b3
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/autospec/SpecPlugin.java
@@ -0,0 +1,115 @@
+/*
+ * 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.autospec;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.inject.Provides;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.api.Client;
+import net.runelite.api.GameState;
+import net.runelite.api.MenuAction;
+import net.runelite.api.Player;
+import net.runelite.api.PlayerComposition;
+import net.runelite.api.VarPlayer;
+import net.runelite.api.events.GameTick;
+import net.runelite.api.events.MenuOptionClicked;
+import net.runelite.api.kit.KitType;
+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;
+
+
+@PluginDescriptor(
+ name="Auto Spec",
+ description="Automatically enables special attack when supported weapons are equipped",
+ tags={"special", "pvp", "attack"},
+ type = PluginType.PVP,
+ enabledByDefault=false
+)
+@Slf4j
+@Singleton
+public class SpecPlugin
+ extends Plugin
+{
+ private static final ImmutableMap WEAPONS = ImmutableMap.builder().put(4153, 50).put(5698, 25).put(13652, 50).put(11802, 50).put(11806, 50).put(11804, 50).put(10887, 50).put(11235, 55).build();
+ @Inject
+ private Client client;
+ @Inject
+ private SpecConfig config;
+
+ @Provides
+ SpecConfig getConfig(ConfigManager configManager)
+ {
+ return (SpecConfig)configManager.getConfig(SpecConfig.class);
+ }
+
+ @Subscribe
+ public void onGameTick(GameTick event)
+ {
+ if (this.client.getGameState() != GameState.LOGGED_IN) {
+ return;
+ }
+ if (!this.config.continuousToggle()) {
+ return;
+ }
+ PlayerComposition composition = this.client.getLocalPlayer().getPlayerComposition();
+ Integer cost = (Integer)WEAPONS.get(Integer.valueOf(composition.getEquipmentId(KitType.WEAPON)));
+ if ((cost != null) && (!specialEnabled()) && (this.client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) >= cost.intValue() * 10)) {
+ enableSpecial();
+ }
+ }
+
+ @Subscribe
+ public void onMenuOptionClicked(MenuOptionClicked event)
+ {
+ if (this.client.getGameState() != GameState.LOGGED_IN) {
+ return;
+ }
+ boolean equipped = event.getMenuOption().equals("Wield");
+ if (!equipped) {
+ return;
+ }
+ Integer cost = (Integer)WEAPONS.get(Integer.valueOf(event.getId()));
+ if ((cost != null) && (!specialEnabled()) && (this.client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) >= cost.intValue() * 10)) {
+ enableSpecial();
+ }
+ }
+
+ private void enableSpecial()
+ {
+ //this.client.invokeMenuAction(-1, 38862883, MenuAction.WIDGET_DEFAULT.getId(), 1, "Use Special Attack", "", 50, 50);
+ }
+
+ private boolean specialEnabled()
+ {
+ return this.client.getVar(VarPlayer.SPECIAL_ATTACK_ENABLED) == 1;
+ }
+}
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/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..714767554e
--- /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.UTILITY
+)
+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);
+ }
+}
\ No newline at end of file
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/prayagainstplayer/PlayerContainer.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PlayerContainer.java
new file mode 100644
index 0000000000..6c1370ef76
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PlayerContainer.java
@@ -0,0 +1,56 @@
+/*
+ * 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"
+ };
+
+}