From d6af3d5b463390b30e9c8e8cd2439275592aa963 Mon Sep 17 00:00:00 2001 From: Yuri Moens Date: Sun, 23 Jan 2022 03:06:18 +0100 Subject: [PATCH] Add quickprayer support for buff prayers --- .../reisub/openosrs/prayerflick/Config.java | 38 ++++- .../openosrs/prayerflick/Prayerflick.java | 60 +++++--- .../openosrs/prayerflick/ProtectFrom.java | 15 -- .../openosrs/prayerflick/QuickPrayer.java | 132 ++++++++++++++++++ release/prayerflick-1.1.0.jar | Bin 7406 -> 9533 bytes 5 files changed, 203 insertions(+), 42 deletions(-) delete mode 100644 prayerflick/src/main/java/io/reisub/openosrs/prayerflick/ProtectFrom.java create mode 100644 prayerflick/src/main/java/io/reisub/openosrs/prayerflick/QuickPrayer.java diff --git a/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/Config.java b/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/Config.java index 9b700d5..1ce1e1d 100644 --- a/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/Config.java +++ b/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/Config.java @@ -84,11 +84,41 @@ public interface Config extends net.runelite.client.config.Config { return new Keybind(KeyEvent.VK_3, InputEvent.CTRL_DOWN_MASK); } + @ConfigItem( + keyName = "hotkeyMeleeBuff", + name = "Melee buff hotkey", + description = "When you press this key melee buff(s) will be set as quickprayer", + position = 23 + ) + default Keybind hotkeyMeleeBuff() { + return new Keybind(KeyEvent.VK_Q, InputEvent.CTRL_DOWN_MASK); + } + + @ConfigItem( + keyName = "hotkeyRangedBuff", + name = "Ranged buff hotkey", + description = "When you press this key ranged buff will be set as quickprayer", + position = 24 + ) + default Keybind hotkeyRangedBuff() { + return new Keybind(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK); + } + + @ConfigItem( + keyName = "hotkeyMagicBuff", + name = "Magic buff hotkey", + description = "When you press this key magic buff will be set as quickprayer", + position = 25 + ) + default Keybind hotkeyMagicBuff() { + return new Keybind(KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK); + } + @ConfigItem( keyName = "openInventory", name = "Open inventory", description = "Open inventory after swapping quickprayers", - position = 23 + position = 26 ) default boolean openInventory() { return true; } @@ -96,7 +126,7 @@ public interface Config extends net.runelite.client.config.Config { keyName = "allowToggleOff", name = "Allow toggling off", description = "Will allow turning the protect prayer off when pressing the hotkey for the current one.", - position = 24 + position = 27 ) default boolean allowToggleOff() { return true; } @@ -104,7 +134,7 @@ public interface Config extends net.runelite.client.config.Config { keyName = "jadPrayerFlick", name = "Jad Auto Prayer Flick", description = "Automatically swap prayers against Jad.", - position = 30 + position = 40 ) default boolean jadPrayerFlick() { return true; } @@ -112,7 +142,7 @@ public interface Config extends net.runelite.client.config.Config { keyName = "hesporiPrayerFlick", name = "Hespori Auto Prayer Flick", description = "Automatically swap prayers against Hespori.", - position = 31 + position = 41 ) default boolean hesporiPrayerFlick() { return true; } diff --git a/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/Prayerflick.java b/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/Prayerflick.java index c8dc0a4..02c368b 100644 --- a/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/Prayerflick.java +++ b/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/Prayerflick.java @@ -7,7 +7,7 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.api.*; import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.GameTick; -import net.runelite.api.events.VarbitChanged; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; @@ -17,6 +17,7 @@ import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDependency; import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.iutils.api.Prayers; import net.runelite.client.plugins.iutils.game.Game; import net.runelite.client.plugins.iutils.game.iWidget; import net.runelite.client.plugins.iutils.iUtils; @@ -70,7 +71,8 @@ public class Prayerflick extends Plugin implements KeyListener { private boolean toggleFlicking; private boolean firstFlick; private boolean toggledOff; - private volatile ProtectFrom currently; + private volatile QuickPrayer currentOverhead; + private int level; @Override protected void startUp() { @@ -124,12 +126,12 @@ public class Prayerflick extends Plugin implements KeyListener { switch (actor.getAnimation()) { case AnimationID.TZTOK_JAD_MAGIC_ATTACK: case JALTOK_JAD_MAGE_ATTACK: - setPrayer(ProtectFrom.MAGIC, false); + setPrayer(false, QuickPrayer.PROTECT_FROM_MAGIC); game.utils.sendGameMessage("Pray against magic!"); break; case AnimationID.TZTOK_JAD_RANGE_ATTACK: case JALTOK_JAD_RANGE_ATTACK: - setPrayer(ProtectFrom.MISSILES, false); + setPrayer(false, QuickPrayer.PROTECT_FROM_MISSILES); game.utils.sendGameMessage("Pray against missiles!"); break; } @@ -138,10 +140,10 @@ public class Prayerflick extends Plugin implements KeyListener { if (config.hesporiPrayerFlick()) { switch (actor.getAnimation()) { case HESPORI_MAGE_ATTACK: - setPrayer(ProtectFrom.MAGIC, false); + setPrayer(false, QuickPrayer.PROTECT_FROM_MAGIC); break; case HESPORI_RANGE_ATTACK: - setPrayer(ProtectFrom.MISSILES, false); + setPrayer(false, QuickPrayer.PROTECT_FROM_MISSILES); break; } } @@ -158,6 +160,8 @@ public class Prayerflick extends Plugin implements KeyListener { @Override public void keyPressed(KeyEvent e) { + level = game.baseLevel(Skill.PRAYER); + if (config.prayerFlickHotkey().matches(e)) { if (toggleFlicking) { toggledOff = true; @@ -167,42 +171,52 @@ public class Prayerflick extends Plugin implements KeyListener { toggleFlicking = !toggleFlicking; } else if (config.hotkeyMelee().matches(e)) { - setPrayer(ProtectFrom.MELEE, config.allowToggleOff()); + setPrayer(config.allowToggleOff(), QuickPrayer.PROTECT_FROM_MELEE); } else if (config.hotkeyMissiles().matches(e)) { - setPrayer(ProtectFrom.MISSILES, config.allowToggleOff()); + setPrayer(config.allowToggleOff(), QuickPrayer.PROTECT_FROM_MISSILES); } else if (config.hotkeyMagic().matches(e)) { - setPrayer(ProtectFrom.MAGIC, config.allowToggleOff()); + setPrayer(config.allowToggleOff(), QuickPrayer.PROTECT_FROM_MAGIC); + } else if (config.hotkeyMeleeBuff().matches(e)) { + setPrayer(config.allowToggleOff(), QuickPrayer.getBestMeleeBuff(level)); + } else if (config.hotkeyRangedBuff().matches(e)) { + setPrayer(config.allowToggleOff(), QuickPrayer.getBestRangedBuff(level)); + } else if (config.hotkeyMagicBuff().matches(e)) { + setPrayer(config.allowToggleOff(), QuickPrayer.getBestMagicBuff(level)); } } @Override public void keyReleased(KeyEvent e) {} - private void setPrayer(ProtectFrom protectFrom, boolean allowToggleOff) { - if (!allowToggleOff && protectFrom == currently) return; + private void setPrayer(boolean allowToggleOff, QuickPrayer... quickPrayers) { + if (!allowToggleOff && quickPrayers[0] == currentOverhead) return; - if (currently == protectFrom) { - currently = ProtectFrom.NONE; - } else { - currently = protectFrom; + if (currentOverhead == quickPrayers[0]) { + currentOverhead = QuickPrayer.NONE; + } else if (quickPrayers[0] == QuickPrayer.PROTECT_FROM_MAGIC + || quickPrayers[0] == QuickPrayer.PROTECT_FROM_MISSILES + || quickPrayers[0] == QuickPrayer.PROTECT_FROM_MELEE) { + currentOverhead = quickPrayers[0]; } executor.schedule(() -> { - iWidget quickPrayers = game.widget(WidgetInfo.MINIMAP_QUICK_PRAYER_ORB); - if (quickPrayers == null) return; + iWidget quickPrayersWidget = game.widget(WidgetInfo.MINIMAP_QUICK_PRAYER_ORB); + if (quickPrayersWidget == null) return; - quickPrayers.interact(1); + quickPrayersWidget.interact(1); game.waitUntil(() -> { - iWidget w = game.widget(77, 4); + iWidget w = game.widget(WidgetID.QUICK_PRAYERS_GROUP_ID, 4); return w != null && !w.hidden(); }); - iWidget protection = game.widget(77, 4, protectFrom.getChildId()); - if (protection == null) return; + for (QuickPrayer quickPrayer : quickPrayers) { + iWidget protection = game.widget(WidgetID.QUICK_PRAYERS_GROUP_ID, 4, quickPrayer.getChildId()); + if (protection == null) return; - protection.interact(0); + protection.interact(0); + } - iWidget update = game.widget(77, 5); + iWidget update = game.widget(WidgetID.QUICK_PRAYERS_GROUP_ID, 5); if (update == null) return; update.interact(0); diff --git a/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/ProtectFrom.java b/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/ProtectFrom.java deleted file mode 100644 index ef58ecc..0000000 --- a/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/ProtectFrom.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.reisub.openosrs.prayerflick; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@AllArgsConstructor -@Getter -public enum ProtectFrom { - NONE(0), - MAGIC(12), - MISSILES(13), - MELEE(14); - - private final int childId; -} diff --git a/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/QuickPrayer.java b/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/QuickPrayer.java new file mode 100644 index 0000000..2cfc031 --- /dev/null +++ b/prayerflick/src/main/java/io/reisub/openosrs/prayerflick/QuickPrayer.java @@ -0,0 +1,132 @@ +package io.reisub.openosrs.prayerflick; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.widgets.WidgetID; + +@AllArgsConstructor +@Getter +public enum QuickPrayer { + NONE(0, 0), + THICK_SKIN(WidgetID.QuickPrayer.THICK_SKIN_CHILD_ID, 1), + BURST_OF_STRENGTH(WidgetID.QuickPrayer.BURST_OF_STRENGTH_CHILD_ID, 4), + CLARITY_OF_THOUGHT(WidgetID.QuickPrayer.CLARITY_OF_THOUGHT_CHILD_ID, 7), + SHARP_EYE(WidgetID.QuickPrayer.SHARP_EYE_CHILD_ID, 8), + MYSTIC_WILL(WidgetID.QuickPrayer.MYSTIC_WILL_CHILD_ID, 9), + ROCK_SKIN(WidgetID.QuickPrayer.ROCK_SKIN_CHILD_ID, 10), + SUPERHUMAN_STRENGTH(WidgetID.QuickPrayer.SUPERHUMAN_STRENGTH_CHILD_ID, 13), + IMPROVED_REFLEXES(WidgetID.QuickPrayer.IMPROVED_REFLEXES_CHILD_ID, 16), + RAPID_RESTORE(WidgetID.QuickPrayer.RAPID_RESTORE_CHILD_ID, 19), + RAPID_HEAL(WidgetID.QuickPrayer.RAPID_HEAL_CHILD_ID, 22), + PROTECT_ITEM(WidgetID.QuickPrayer.PROTECT_ITEM_CHILD_ID, 25), + HAWK_EYE(WidgetID.QuickPrayer.HAWK_EYE_CHILD_ID, 26), + MYSTIC_LORE(WidgetID.QuickPrayer.MYSTIC_LORE_CHILD_ID, 27), + STEEL_SKIN(WidgetID.QuickPrayer.STEEL_SKIN_CHILD_ID, 28), + ULTIMATE_STRENGTH(WidgetID.QuickPrayer.ULTIMATE_STRENGTH_CHILD_ID, 31), + INCREDIBLE_REFLEXES(WidgetID.QuickPrayer.INCREDIBLE_REFLEXES_CHILD_ID, 34), + PROTECT_FROM_MAGIC(WidgetID.QuickPrayer.PROTECT_FROM_MAGIC_CHILD_ID, 37), + PROTECT_FROM_MISSILES(WidgetID.QuickPrayer.PROTECT_FROM_MISSILES_CHILD_ID, 40), + PROTECT_FROM_MELEE(WidgetID.QuickPrayer.PROTECT_FROM_MELEE_CHILD_ID, 43), + EAGLE_EYE(WidgetID.QuickPrayer.EAGLE_EYE_CHILD_ID, 44), + MYSTIC_MIGHT(WidgetID.QuickPrayer.MYSTIC_MIGHT_CHILD_ID, 45), + RETRIBUTION(WidgetID.QuickPrayer.RETRIBUTION_CHILD_ID, 46), + REDEMPTION(WidgetID.QuickPrayer.REDEMPTION_CHILD_ID, 49), + SMITE(WidgetID.QuickPrayer.SMITE_CHILD_ID, 52), + PRESERVE(WidgetID.QuickPrayer.PRESERVE_CHILD_ID, 55), + CHIVALRY(WidgetID.QuickPrayer.CHIVALRY_CHILD_ID, 60), + PIETY(WidgetID.QuickPrayer.PIETY_CHILD_ID, 70), + RIGOUR(WidgetID.QuickPrayer.RIGOUR_CHILD_ID, 74), + AUGURY(WidgetID.QuickPrayer.AUGURY_CHILD_ID, 77); + + private final int childId; + private final int level; + + public static QuickPrayer[] getBestMeleeBuff(int level) { + if (level >= PIETY.level) { + return new QuickPrayer[] { PIETY }; + } else if (level >= CHIVALRY.level) { + return new QuickPrayer[] { CHIVALRY }; + } else { + QuickPrayer[] quickPrayers; + if (level >= 7) { + quickPrayers = new QuickPrayer[3]; + quickPrayers[0] = getBestDefence(level); + quickPrayers[1] = getBestStrength(level); + quickPrayers[2] = getBestAttack(level); + } else if (level >= 4) { + quickPrayers = new QuickPrayer[2]; + quickPrayers[0] = getBestDefence(level); + quickPrayers[1] = getBestStrength(level); + } else { + quickPrayers = new QuickPrayer[1]; + quickPrayers[0] = getBestDefence(level); + } + + return quickPrayers; + } + } + + private static QuickPrayer getBestAttack(int level) { + if (level >= INCREDIBLE_REFLEXES.level) { + return INCREDIBLE_REFLEXES; + } else if (level >= IMPROVED_REFLEXES.level) { + return IMPROVED_REFLEXES; + } else if (level >= CLARITY_OF_THOUGHT.level) { + return CLARITY_OF_THOUGHT; + } + + return null; + } + + private static QuickPrayer getBestStrength(int level) { + if (level >= ULTIMATE_STRENGTH.level) { + return ULTIMATE_STRENGTH; + } else if (level >= SUPERHUMAN_STRENGTH.level) { + return SUPERHUMAN_STRENGTH; + } else if (level >= BURST_OF_STRENGTH.level) { + return BURST_OF_STRENGTH; + } + + return null; + } + + private static QuickPrayer getBestDefence(int level) { + if (level >= STEEL_SKIN.level) { + return STEEL_SKIN; + } else if (level >= ROCK_SKIN.level) { + return ROCK_SKIN; + } else if (level >= THICK_SKIN.level) { + return THICK_SKIN; + } + + return null; + } + + public static QuickPrayer[] getBestRangedBuff(int level) { + if (level >= RIGOUR.level) { + return new QuickPrayer[] { RIGOUR }; + } else if (level >= EAGLE_EYE.level) { + return new QuickPrayer[] { EAGLE_EYE }; + } else if (level >= HAWK_EYE.level) { + return new QuickPrayer[] { HAWK_EYE }; + } else if (level >= SHARP_EYE.level) { + return new QuickPrayer[] { SHARP_EYE }; + } + + return new QuickPrayer[]{}; + } + + public static QuickPrayer[] getBestMagicBuff(int level) { + if (level >= AUGURY.level) { + return new QuickPrayer[] { AUGURY }; + } else if (level >= MYSTIC_MIGHT.level) { + return new QuickPrayer[] { MYSTIC_MIGHT }; + } else if (level >= MYSTIC_LORE.level) { + return new QuickPrayer[] { MYSTIC_LORE }; + } else if (level >= MYSTIC_WILL.level) { + return new QuickPrayer[] { MYSTIC_WILL }; + } + + return new QuickPrayer[]{}; + } +} diff --git a/release/prayerflick-1.1.0.jar b/release/prayerflick-1.1.0.jar index fb0fd9fad941da00e5234f157f9330e9995d46f0..d2d2ec04f55aec0daad1242024b7382a40468989 100644 GIT binary patch delta 8354 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 CdIa16 delta 6166 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 d@ZT={e-qWy|Ck8>TaHwg7f=2nrT~sJC