From bd1cdc90ac82126aeb8b8c934c69e6f0ab7c99c7 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Thu, 26 May 2022 09:35:56 -0700 Subject: [PATCH 01/17] item stats: Clean up saradomin brew code --- .../plugins/itemstats/potions/SaradominBrew.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SaradominBrew.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SaradominBrew.java index 2eaea550f4..5baa696909 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SaradominBrew.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SaradominBrew.java @@ -57,9 +57,8 @@ public class SaradominBrew implements Effect SimpleStatBoost hitpoints = new SimpleStatBoost(HITPOINTS, true, perc(percH, deltaB)); SimpleStatBoost defence = new SimpleStatBoost(DEFENCE, true, perc(percD, deltaB)); BoostedStatBoost calc = new BoostedStatBoost(null, false, perc(percSD, -deltaR)); - changes.setStatChanges(Stream.concat( + changes.setStatChanges(Stream.of( Stream.of(hitpoints.effect(client)), - Stream.concat( Stream.of(defence.effect(client)), Stream.of(saradominBrewStats) .filter(stat -> 1 < stat.getValue(client)) @@ -67,12 +66,13 @@ public class SaradominBrew implements Effect { calc.setStat(stat); return calc.effect(client); - }) - ) - ).toArray(StatChange[]::new)); + })) + .reduce(Stream::concat) + .orElseGet(Stream::empty) + .toArray(StatChange[]::new)); changes.setPositivity(Stream.of(changes.getStatChanges()) - .map(sc -> sc.getPositivity()) + .map(StatChange::getPositivity) .max(Comparator.naturalOrder()).get()); return changes; } -} \ No newline at end of file +} From f6f454665a870f7fe962b380e363e4a229592845 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Sat, 8 Jan 2022 04:06:40 +0000 Subject: [PATCH 02/17] item stats: add support for stat boosts with a cap --- .../plugins/itemstats/CappedStatBoost.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/itemstats/CappedStatBoost.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/CappedStatBoost.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/CappedStatBoost.java new file mode 100644 index 0000000000..99aa241a44 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/CappedStatBoost.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022 Hydrox6 + * 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.itemstats; + +import net.runelite.api.Client; +import net.runelite.client.plugins.itemstats.delta.DeltaCalculator; +import net.runelite.client.plugins.itemstats.stats.Stat; + +/** + * A stat boost using the real stat level, that can only boost a certain amount above the stat level. + */ +public class CappedStatBoost extends StatBoost +{ + private final DeltaCalculator deltaCalculator; + private final DeltaCalculator capCalculator; + + public CappedStatBoost(Stat stat, DeltaCalculator deltaCalculator, DeltaCalculator capCalculator) + { + super(stat, true); + this.deltaCalculator = deltaCalculator; + this.capCalculator = capCalculator; + } + + @Override + public int heals(Client client) + { + final int current = getStat().getValue(client); + final int max = getStat().getMaximum(client); + final int delta = deltaCalculator.calculateDelta(max); + final int cap = capCalculator.calculateDelta(max); + + if (delta + current <= max + cap) + { + return delta; + } + + return max + cap - current; + } + +} From f678dd21885fe27264729f29d56d1dae584a61c2 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Fri, 13 May 2022 23:14:38 +0100 Subject: [PATCH 03/17] item stats: add ancient brew --- .../plugins/itemstats/ItemStatChanges.java | 2 + .../itemstats/potions/AncientBrew.java | 77 +++++++++++++++++++ .../plugins/itemstats/ItemStatEffectTest.java | 38 +++++++++ 3 files changed, 117 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/AncientBrew.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java index bd97701644..b54b3c6ee6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java @@ -33,6 +33,7 @@ import lombok.extern.slf4j.Slf4j; import static net.runelite.api.ItemID.*; import static net.runelite.client.plugins.itemstats.Builders.*; import net.runelite.client.plugins.itemstats.food.Anglerfish; +import net.runelite.client.plugins.itemstats.potions.AncientBrew; import net.runelite.client.plugins.itemstats.potions.GauntletPotion; import net.runelite.client.plugins.itemstats.potions.PrayerPotion; import net.runelite.client.plugins.itemstats.potions.SaradominBrew; @@ -196,6 +197,7 @@ public class ItemStatChanges CASTLEWARS_BREW4, CASTLEWARS_BREW3, CASTLEWARS_BREW2, CASTLEWARS_BREW1); add(combo(2, boost(ATTACK, perc(0.15, 5)), boost(STRENGTH, perc(0.15, 5))), SUPER_COMBAT_POTION4_23543, SUPER_COMBAT_POTION3_23545, SUPER_COMBAT_POTION2_23547, SUPER_COMBAT_POTION1_23549 /* LMS */); + add(new AncientBrew(), ANCIENT_BREW1, ANCIENT_BREW2, ANCIENT_BREW3, ANCIENT_BREW4); // Regular overload (NMZ) add(combo(5, boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5)), boost(RANGED, perc(.15, 5)), boost(MAGIC, perc(.15, 5)), heal(HITPOINTS, -50)), OVERLOAD_1, OVERLOAD_2, OVERLOAD_3, OVERLOAD_4); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/AncientBrew.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/AncientBrew.java new file mode 100644 index 0000000000..08e705dcb0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/AncientBrew.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022 Hydrox6 + * 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.itemstats.potions; + +import lombok.NoArgsConstructor; +import net.runelite.api.Client; +import net.runelite.client.plugins.itemstats.BoostedStatBoost; +import static net.runelite.client.plugins.itemstats.Builders.perc; +import net.runelite.client.plugins.itemstats.CappedStatBoost; +import net.runelite.client.plugins.itemstats.Effect; +import net.runelite.client.plugins.itemstats.SimpleStatBoost; +import net.runelite.client.plugins.itemstats.StatChange; +import net.runelite.client.plugins.itemstats.StatsChanges; +import net.runelite.client.plugins.itemstats.stats.Stat; +import static net.runelite.client.plugins.itemstats.stats.Stats.ATTACK; +import static net.runelite.client.plugins.itemstats.stats.Stats.DEFENCE; +import static net.runelite.client.plugins.itemstats.stats.Stats.MAGIC; +import static net.runelite.client.plugins.itemstats.stats.Stats.PRAYER; +import static net.runelite.client.plugins.itemstats.stats.Stats.STRENGTH; +import java.util.Comparator; +import java.util.stream.Stream; + +@NoArgsConstructor +public class AncientBrew implements Effect +{ + private static final Stat[] LOWERED_STATS = { + ATTACK, STRENGTH, DEFENCE + }; + private static final CappedStatBoost PRAYER_BOOST = new CappedStatBoost(PRAYER, perc(.1, 2), perc(.05, 0)); + private static final SimpleStatBoost MAGIC_BOOST = new SimpleStatBoost(MAGIC, true, perc(.05, 2)); + private static final BoostedStatBoost MELEE_DRAIN = new BoostedStatBoost(null, false, perc(.1, -2)); + + @Override + public StatsChanges calculate(Client client) + { + StatsChanges changes = new StatsChanges(0); + changes.setStatChanges(Stream.of( + Stream.of(PRAYER_BOOST.effect(client)), + Stream.of(MAGIC_BOOST.effect(client)), + Stream.of(LOWERED_STATS) + .filter(stat -> 1 < stat.getValue(client)) + .map(stat -> + { + MELEE_DRAIN.setStat(stat); + return MELEE_DRAIN.effect(client); + })) + .reduce(Stream::concat) + .orElseGet(Stream::empty) + .toArray(StatChange[]::new)); + changes.setPositivity(Stream.of(changes.getStatChanges()) + .map(StatChange::getPositivity) + .max(Comparator.naturalOrder()).get()); + return changes; + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatEffectTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatEffectTest.java index 8f498a6f46..b75313dd3e 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatEffectTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatEffectTest.java @@ -178,4 +178,42 @@ public class ItemStatEffectTest } } } + + @Test + public void testAncientBrew() + { + final Effect ancientBrew = new ItemStatChanges().get(ItemID.ANCIENT_BREW4); + + assertEquals(4, skillChange(Skill.PRAYER, 99, 99, ancientBrew)); + assertEquals(11, skillChange(Skill.PRAYER, 99, 90, ancientBrew)); + assertEquals(11, skillChange(Skill.PRAYER, 99, 0, ancientBrew)); + assertEquals(2, skillChange(Skill.PRAYER, 50, 50, ancientBrew)); + assertEquals(7, skillChange(Skill.PRAYER, 50, 40, ancientBrew)); + assertEquals(0, skillChange(Skill.PRAYER, 1, 1, ancientBrew)); + assertEquals(1, skillChange(Skill.PRAYER, 1, 0, ancientBrew)); + } + + private int skillChange(Skill skill, int maxValue, int currentValue, Effect effect) + { + if (effect == null) + { + throw new IllegalArgumentException("Applied effect is null"); + } + + when(client.getRealSkillLevel(skill)).thenReturn(maxValue); + when(client.getBoostedSkillLevel(skill)).thenReturn(currentValue); + final StatsChanges statsChanges = effect.calculate(client); + + for (final StatChange statChange : statsChanges.getStatChanges()) + { + if (!statChange.getStat().getName().equals(skill.getName())) + { + continue; + } + + return statChange.getRelative(); + } + + return 0; + } } From 3f7b182aefea8988e2173c7aae3ea792635756a5 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Thu, 26 May 2022 10:52:12 -0700 Subject: [PATCH 04/17] item stats: Use variables for reused potion effects --- .../plugins/itemstats/ItemStatChanges.java | 92 +++++++++++-------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java index b54b3c6ee6..19bd488b39 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java @@ -32,6 +32,7 @@ import java.util.Map; import lombok.extern.slf4j.Slf4j; import static net.runelite.api.ItemID.*; import static net.runelite.client.plugins.itemstats.Builders.*; +import net.runelite.client.plugins.itemstats.delta.DeltaPercentage; import net.runelite.client.plugins.itemstats.food.Anglerfish; import net.runelite.client.plugins.itemstats.potions.AncientBrew; import net.runelite.client.plugins.itemstats.potions.GauntletPotion; @@ -164,49 +165,59 @@ public class ItemStatChanges add(combo(heal(RUN_ENERGY, 20), boost(THIEVING, 3)), SUMMER_SQIRKJUICE); // Combat potions - add(boost(ATTACK, perc(.10, 3)), ATTACK_POTION1, ATTACK_POTION2, ATTACK_POTION3, ATTACK_POTION4); - add(boost(STRENGTH, perc(.10, 3)), STRENGTH_POTION1, STRENGTH_POTION2, STRENGTH_POTION3, STRENGTH_POTION4); + final SingleEffect attackPot = boost(ATTACK, perc(.10, 3)); + final SingleEffect strengthPot = boost(STRENGTH, perc(.10, 3)); + final SingleEffect magicPot = boost(MAGIC, 4); + final SingleEffect imbuedHeart = boost(MAGIC, perc(.10, 1)); + final SingleEffect rangingPot = boost(RANGED, perc(.10, 4)); + final SingleEffect superAttackPot = boost(ATTACK, perc(.15, 5)); + final SingleEffect superStrengthPot = boost(STRENGTH, perc(.15, 5)); + final SingleEffect superDefencePot = boost(DEFENCE, perc(.15, 5)); + final SingleEffect superMagicPot = boost(MAGIC, perc(.15, 5)); + final SingleEffect superRangingPot = boost(RANGED, perc(.15, 5)); + final SingleEffect divinePot = heal(HITPOINTS, -10); + add(attackPot, ATTACK_POTION1, ATTACK_POTION2, ATTACK_POTION3, ATTACK_POTION4); + add(strengthPot, STRENGTH_POTION1, STRENGTH_POTION2, STRENGTH_POTION3, STRENGTH_POTION4); add(boost(DEFENCE, perc(.10, 3)), DEFENCE_POTION1, DEFENCE_POTION2, DEFENCE_POTION3, DEFENCE_POTION4); - add(boost(MAGIC, 4), MAGIC_POTION1, MAGIC_POTION2, MAGIC_POTION3, MAGIC_POTION4); - add(boost(RANGED, perc(.10, 4)), RANGING_POTION1, RANGING_POTION2, RANGING_POTION3, RANGING_POTION4, + add(magicPot, MAGIC_POTION1, MAGIC_POTION2, MAGIC_POTION3, MAGIC_POTION4); + add(rangingPot, RANGING_POTION1, RANGING_POTION2, RANGING_POTION3, RANGING_POTION4, RANGING_POTION4_23551, RANGING_POTION3_23553, RANGING_POTION2_23555, RANGING_POTION1_23557 /* LMS */); - add(combo(2, boost(ATTACK, perc(.10, 3)), boost(STRENGTH, perc(.10, 3))), - COMBAT_POTION1, COMBAT_POTION2, COMBAT_POTION3, COMBAT_POTION4, + add(combo(2, attackPot, strengthPot), COMBAT_POTION1, COMBAT_POTION2, COMBAT_POTION3, COMBAT_POTION4, COMBAT_POTION4_26150, COMBAT_POTION3_26151, COMBAT_POTION2_26152, COMBAT_POTION1_26153 /* Deadman starter pack */); - add(boost(ATTACK, perc(.15, 5)), SUPER_ATTACK1, SUPER_ATTACK2, SUPER_ATTACK3, SUPER_ATTACK4); - add(boost(STRENGTH, perc(.15, 5)), SUPER_STRENGTH1, SUPER_STRENGTH2, SUPER_STRENGTH3, SUPER_STRENGTH4); - add(boost(DEFENCE, perc(.15, 5)), SUPER_DEFENCE1, SUPER_DEFENCE2, SUPER_DEFENCE3, SUPER_DEFENCE4); + add(superAttackPot, SUPER_ATTACK1, SUPER_ATTACK2, SUPER_ATTACK3, SUPER_ATTACK4); + add(superStrengthPot, SUPER_STRENGTH1, SUPER_STRENGTH2, SUPER_STRENGTH3, SUPER_STRENGTH4); + add(superDefencePot, SUPER_DEFENCE1, SUPER_DEFENCE2, SUPER_DEFENCE3, SUPER_DEFENCE4); add(boost(MAGIC, 3), MAGIC_ESSENCE1, MAGIC_ESSENCE2, MAGIC_ESSENCE3, MAGIC_ESSENCE4); - add(combo(3, boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5))), SUPER_COMBAT_POTION1, SUPER_COMBAT_POTION2, SUPER_COMBAT_POTION3, SUPER_COMBAT_POTION4); + add(combo(3, superAttackPot, superStrengthPot, superDefencePot), SUPER_COMBAT_POTION1, SUPER_COMBAT_POTION2, SUPER_COMBAT_POTION3, SUPER_COMBAT_POTION4); add(combo(3, boost(ATTACK, perc(.20, 2)), boost(STRENGTH, perc(.12, 2)), heal(PRAYER, perc(.10, 0)), new BoostedStatBoost(DEFENCE, false, perc(.10, -2)), new BoostedStatBoost(HITPOINTS, false, perc(-.12, 0))), ZAMORAK_BREW1, ZAMORAK_BREW2, ZAMORAK_BREW3, ZAMORAK_BREW4); add(new SaradominBrew(0.15, 0.2, 0.1, 2, 2), SARADOMIN_BREW1, SARADOMIN_BREW2, SARADOMIN_BREW3, SARADOMIN_BREW4, SARADOMIN_BREW4_23575, SARADOMIN_BREW3_23577, SARADOMIN_BREW2_23579, SARADOMIN_BREW1_23581 /* LMS */); - add(boost(RANGED, perc(.15, 5)), SUPER_RANGING_1, SUPER_RANGING_2, SUPER_RANGING_3, SUPER_RANGING_4); - add(boost(MAGIC, perc(.15, 5)), SUPER_MAGIC_POTION_1, SUPER_MAGIC_POTION_2, SUPER_MAGIC_POTION_3, SUPER_MAGIC_POTION_4); - add(combo(2, boost(RANGED, perc(0.1, 4)), boost(DEFENCE, perc(0.15, 5))), BASTION_POTION1, BASTION_POTION2, BASTION_POTION3, BASTION_POTION4); - add(combo(2, boost(MAGIC, 4), boost(DEFENCE, perc(0.15, 5))), BATTLEMAGE_POTION1, BATTLEMAGE_POTION2, BATTLEMAGE_POTION3, BATTLEMAGE_POTION4); - add(combo(boost(MAGIC, 4), heal(HITPOINTS, -10)), DIVINE_MAGIC_POTION1, DIVINE_MAGIC_POTION2, DIVINE_MAGIC_POTION3, DIVINE_MAGIC_POTION4); - add(combo(boost(RANGED, perc(.10, 4)), heal(HITPOINTS, -10)), DIVINE_RANGING_POTION1, DIVINE_RANGING_POTION2, DIVINE_RANGING_POTION3, DIVINE_RANGING_POTION4); - add(combo(boost(ATTACK, perc(.15, 5)), heal(HITPOINTS, -10)), DIVINE_SUPER_ATTACK_POTION1, DIVINE_SUPER_ATTACK_POTION2, DIVINE_SUPER_ATTACK_POTION3, DIVINE_SUPER_ATTACK_POTION4); - add(combo(boost(STRENGTH, perc(.15, 5)), heal(HITPOINTS, -10)), DIVINE_SUPER_STRENGTH_POTION1, DIVINE_SUPER_STRENGTH_POTION2, DIVINE_SUPER_STRENGTH_POTION3, DIVINE_SUPER_STRENGTH_POTION4); - add(combo(boost(DEFENCE, perc(.15, 5)), heal(HITPOINTS, -10)), DIVINE_SUPER_DEFENCE_POTION1, DIVINE_SUPER_DEFENCE_POTION2, DIVINE_SUPER_DEFENCE_POTION3, DIVINE_SUPER_DEFENCE_POTION4); - add(combo(3, boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5)), heal(HITPOINTS, -10)), DIVINE_SUPER_COMBAT_POTION1, DIVINE_SUPER_COMBAT_POTION2, DIVINE_SUPER_COMBAT_POTION3, DIVINE_SUPER_COMBAT_POTION4); - add(combo(2, boost(RANGED, perc(0.1, 4)), boost(DEFENCE, perc(0.15, 5)), heal(HITPOINTS, -10)), DIVINE_BASTION_POTION1, DIVINE_BASTION_POTION2, DIVINE_BASTION_POTION3, DIVINE_BASTION_POTION4); - add(combo(2, boost(MAGIC, 4), boost(DEFENCE, perc(0.15, 5)), heal(HITPOINTS, -10)), DIVINE_BATTLEMAGE_POTION1, DIVINE_BATTLEMAGE_POTION2, DIVINE_BATTLEMAGE_POTION3, DIVINE_BATTLEMAGE_POTION4); - add(combo(5, boost(ATTACK, perc(0.15, 5)), boost(STRENGTH, perc(0.15, 5)), boost(DEFENCE, perc(0.15, 5)), boost(RANGED, perc(0.1, 4)), boost(MAGIC, perc(0.1, 1))), + add(superRangingPot, SUPER_RANGING_1, SUPER_RANGING_2, SUPER_RANGING_3, SUPER_RANGING_4); + add(superMagicPot, SUPER_MAGIC_POTION_1, SUPER_MAGIC_POTION_2, SUPER_MAGIC_POTION_3, SUPER_MAGIC_POTION_4); + add(combo(2, rangingPot, superDefencePot), BASTION_POTION1, BASTION_POTION2, BASTION_POTION3, BASTION_POTION4); + add(combo(2, magicPot, superDefencePot), BATTLEMAGE_POTION1, BATTLEMAGE_POTION2, BATTLEMAGE_POTION3, BATTLEMAGE_POTION4); + add(combo(magicPot, divinePot), DIVINE_MAGIC_POTION1, DIVINE_MAGIC_POTION2, DIVINE_MAGIC_POTION3, DIVINE_MAGIC_POTION4); + add(combo(rangingPot, divinePot), DIVINE_RANGING_POTION1, DIVINE_RANGING_POTION2, DIVINE_RANGING_POTION3, DIVINE_RANGING_POTION4); + add(combo(superAttackPot, divinePot), DIVINE_SUPER_ATTACK_POTION1, DIVINE_SUPER_ATTACK_POTION2, DIVINE_SUPER_ATTACK_POTION3, DIVINE_SUPER_ATTACK_POTION4); + add(combo(superStrengthPot, divinePot), DIVINE_SUPER_STRENGTH_POTION1, DIVINE_SUPER_STRENGTH_POTION2, DIVINE_SUPER_STRENGTH_POTION3, DIVINE_SUPER_STRENGTH_POTION4); + add(combo(superDefencePot, divinePot), DIVINE_SUPER_DEFENCE_POTION1, DIVINE_SUPER_DEFENCE_POTION2, DIVINE_SUPER_DEFENCE_POTION3, DIVINE_SUPER_DEFENCE_POTION4); + add(combo(3, superAttackPot, superStrengthPot, superDefencePot, divinePot), DIVINE_SUPER_COMBAT_POTION1, DIVINE_SUPER_COMBAT_POTION2, DIVINE_SUPER_COMBAT_POTION3, DIVINE_SUPER_COMBAT_POTION4); + add(combo(2, rangingPot, superDefencePot, divinePot), DIVINE_BASTION_POTION1, DIVINE_BASTION_POTION2, DIVINE_BASTION_POTION3, DIVINE_BASTION_POTION4); + add(combo(2, magicPot, superDefencePot, divinePot), DIVINE_BATTLEMAGE_POTION1, DIVINE_BATTLEMAGE_POTION2, DIVINE_BATTLEMAGE_POTION3, DIVINE_BATTLEMAGE_POTION4); + add(combo(5, superAttackPot, superStrengthPot, superDefencePot, rangingPot, imbuedHeart), CASTLEWARS_BREW4, CASTLEWARS_BREW3, CASTLEWARS_BREW2, CASTLEWARS_BREW1); - add(combo(2, boost(ATTACK, perc(0.15, 5)), boost(STRENGTH, perc(0.15, 5))), + add(combo(2, superAttackPot, superStrengthPot), SUPER_COMBAT_POTION4_23543, SUPER_COMBAT_POTION3_23545, SUPER_COMBAT_POTION2_23547, SUPER_COMBAT_POTION1_23549 /* LMS */); add(new AncientBrew(), ANCIENT_BREW1, ANCIENT_BREW2, ANCIENT_BREW3, ANCIENT_BREW4); // Regular overload (NMZ) - add(combo(5, boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5)), boost(RANGED, perc(.15, 5)), boost(MAGIC, perc(.15, 5)), heal(HITPOINTS, -50)), OVERLOAD_1, OVERLOAD_2, OVERLOAD_3, OVERLOAD_4); + add(combo(5, superAttackPot, superStrengthPot, superDefencePot, superRangingPot, superMagicPot, heal(HITPOINTS, -50)), OVERLOAD_1, OVERLOAD_2, OVERLOAD_3, OVERLOAD_4); // Bandages (Castle Wars) add(new CastleWarsBandage(), BANDAGES); // Bandages (Theatre of Blood entry mode) - add(combo(8, food(20), heal(PRAYER, perc(0.25, 5)), heal(RUN_ENERGY, 20), boost(ATTACK, perc(0.15, 4)), boost(STRENGTH, perc(0.15, 4)), boost(DEFENCE, perc(0.15, 4)), boost(RANGED, perc(0.1, 4)), boost(MAGIC, 4)), BANDAGES_25730); + add(combo(8, food(20), heal(PRAYER, perc(0.25, 5)), heal(RUN_ENERGY, 20), boost(ATTACK, perc(0.15, 4)), boost(STRENGTH, perc(0.15, 4)), boost(DEFENCE, perc(0.15, 4)), rangingPot, magicPot), BANDAGES_25730); // Recovery potions add(combo(5, heal(ATTACK, perc(.30, 10)), heal(STRENGTH, perc(.30, 10)), heal(DEFENCE, perc(.30, 10)), heal(RANGED, perc(.30, 10)), heal(MAGIC, perc(.30, 10))), RESTORE_POTION1, RESTORE_POTION2, RESTORE_POTION3, RESTORE_POTION4); @@ -221,24 +232,27 @@ public class ItemStatChanges add(new StaminaPotion(), STAMINA_POTION1, STAMINA_POTION2, STAMINA_POTION3, STAMINA_POTION4); // Raids potions (+) - add(combo(5, boost(ATTACK, perc(.16, 6)), boost(STRENGTH, perc(.16, 6)), boost(DEFENCE, perc(.16, 6)), boost(RANGED, perc(.16, 6)), boost(MAGIC, perc(.16, 6)), heal(HITPOINTS, -50)), OVERLOAD_1_20993, OVERLOAD_2_20994, OVERLOAD_3_20995, OVERLOAD_4_20996); - add(combo(3, boost(ATTACK, perc(.16, 6)), boost(STRENGTH, perc(.16, 6)), boost(DEFENCE, perc(.16, 6))), ELDER_1_20921, ELDER_2_20922, ELDER_3_20923, ELDER_4_20924); - add(combo(2, boost(RANGED, perc(.16, 6)), boost(DEFENCE, perc(.16, 6))), TWISTED_1_20933, TWISTED_2_20934, TWISTED_3_20935, TWISTED_4_20936); - add(combo(2, boost(MAGIC, perc(.16, 6)), boost(DEFENCE, perc(.16, 6))), KODAI_1_20945, KODAI_2_20946, KODAI_3_20947, KODAI_4_20948); + final DeltaPercentage coxPlusPotionBoost = perc(.16, 6); + add(combo(5, boost(ATTACK, coxPlusPotionBoost), boost(STRENGTH, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost), boost(RANGED, coxPlusPotionBoost), boost(MAGIC, coxPlusPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20993, OVERLOAD_2_20994, OVERLOAD_3_20995, OVERLOAD_4_20996); + add(combo(3, boost(ATTACK, coxPlusPotionBoost), boost(STRENGTH, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), ELDER_1_20921, ELDER_2_20922, ELDER_3_20923, ELDER_4_20924); + add(combo(2, boost(RANGED, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), TWISTED_1_20933, TWISTED_2_20934, TWISTED_3_20935, TWISTED_4_20936); + add(combo(2, boost(MAGIC, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), KODAI_1_20945, KODAI_2_20946, KODAI_3_20947, KODAI_4_20948); add(new SuperRestore(.30, 11), REVITALISATION_1_20957, REVITALISATION_2_20958, REVITALISATION_3_20959, REVITALISATION_4_20960); add(new SaradominBrew(0.15, 0.2, 0.1, 5, 4), XERICS_AID_1_20981, XERICS_AID_2_20982, XERICS_AID_3_20983, XERICS_AID_4_20984); // Raids potions - add(combo(5, boost(ATTACK, perc(.13, 5)), boost(STRENGTH, perc(.13, 5)), boost(DEFENCE, perc(.13, 5)), boost(RANGED, perc(.13, 5)), boost(MAGIC, perc(.13, 5)), heal(HITPOINTS, -50)), OVERLOAD_1_20989, OVERLOAD_2_20990, OVERLOAD_3_20991, OVERLOAD_4_20992); - add(combo(3, boost(ATTACK, perc(.13, 5)), boost(STRENGTH, perc(.13, 5)), boost(DEFENCE, perc(.13, 5))), ELDER_POTION_1, ELDER_POTION_2, ELDER_POTION_3, ELDER_POTION_4); - add(combo(2, boost(RANGED, perc(.13, 5)), boost(DEFENCE, perc(.13, 5))), TWISTED_POTION_1, TWISTED_POTION_2, TWISTED_POTION_3, TWISTED_POTION_4); - add(combo(2, boost(MAGIC, perc(.13, 5)), boost(DEFENCE, perc(.13, 5))), KODAI_POTION_1, KODAI_POTION_2, KODAI_POTION_3, KODAI_POTION_4); + final DeltaPercentage coxPotionBoost = perc(.13, 5); + add(combo(5, boost(ATTACK, coxPotionBoost), boost(STRENGTH, coxPotionBoost), boost(DEFENCE, coxPotionBoost), boost(RANGED, coxPotionBoost), boost(MAGIC, coxPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20989, OVERLOAD_2_20990, OVERLOAD_3_20991, OVERLOAD_4_20992); + add(combo(3, boost(ATTACK, coxPotionBoost), boost(STRENGTH, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), ELDER_POTION_1, ELDER_POTION_2, ELDER_POTION_3, ELDER_POTION_4); + add(combo(2, boost(RANGED, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), TWISTED_POTION_1, TWISTED_POTION_2, TWISTED_POTION_3, TWISTED_POTION_4); + add(combo(2, boost(MAGIC, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), KODAI_POTION_1, KODAI_POTION_2, KODAI_POTION_3, KODAI_POTION_4); // Raids potions (-) - add(combo(5, boost(ATTACK, perc(.10, 4)), boost(STRENGTH, perc(.10, 4)), boost(DEFENCE, perc(.10, 4)), boost(RANGED, perc(.10, 4)), boost(MAGIC, perc(.10, 4)), heal(HITPOINTS, -50)), OVERLOAD_1_20985, OVERLOAD_2_20986, OVERLOAD_3_20987, OVERLOAD_4_20988); - add(combo(3, boost(ATTACK, perc(.10, 4)), boost(STRENGTH, perc(.10, 4)), boost(DEFENCE, perc(.10, 4))), ELDER_1, ELDER_2, ELDER_3, ELDER_4); - add(combo(3, boost(RANGED, perc(.10, 4)), boost(DEFENCE, perc(.10, 4))), TWISTED_1, TWISTED_2, TWISTED_3, TWISTED_4); - add(combo(3, boost(MAGIC, perc(.10, 4)), boost(DEFENCE, perc(.10, 4))), KODAI_1, KODAI_2, KODAI_3, KODAI_4); + final DeltaPercentage coxMinusPotionBoost = perc(.10, 4); + add(combo(5, boost(ATTACK, coxMinusPotionBoost), boost(STRENGTH, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost), boost(RANGED, coxMinusPotionBoost), boost(MAGIC, coxMinusPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20985, OVERLOAD_2_20986, OVERLOAD_3_20987, OVERLOAD_4_20988); + add(combo(3, boost(ATTACK, coxMinusPotionBoost), boost(STRENGTH, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), ELDER_1, ELDER_2, ELDER_3, ELDER_4); + add(combo(3, boost(RANGED, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), TWISTED_1, TWISTED_2, TWISTED_3, TWISTED_4); + add(combo(3, boost(MAGIC, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), KODAI_1, KODAI_2, KODAI_3, KODAI_4); // Skill potions add(boost(AGILITY, 3), AGILITY_POTION1, AGILITY_POTION2, AGILITY_POTION3, AGILITY_POTION4); @@ -265,7 +279,7 @@ public class ItemStatChanges // Other add(combo(range(food(1), food(3)), heal(RUN_ENERGY, 10)), PURPLE_SWEETS_10476); add(new SpicyStew(), SPICY_STEW); - add(boost(MAGIC, perc(.10, 1)), IMBUED_HEART); + add(imbuedHeart, IMBUED_HEART); add(combo(boost(ATTACK, 2), boost(STRENGTH, 1), heal(PRAYER, 1), heal(DEFENCE, -1)), JANGERBERRIES); add(new CaveNightshade(), CAVE_NIGHTSHADE); From b76e6fc56d423e28f618484f58047ffbc08b0204 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Thu, 26 May 2022 10:56:28 -0700 Subject: [PATCH 05/17] item stats: Add mixed potions --- .../plugins/itemstats/ItemStatChanges.java | 77 ++++++++--- .../itemstats/potions/MixedPotion.java | 122 ++++++++++++++++++ .../plugins/itemstats/ItemStatEffectTest.java | 32 +++++ 3 files changed, 215 insertions(+), 16 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/MixedPotion.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java index 19bd488b39..e72982798c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java @@ -36,6 +36,7 @@ import net.runelite.client.plugins.itemstats.delta.DeltaPercentage; import net.runelite.client.plugins.itemstats.food.Anglerfish; import net.runelite.client.plugins.itemstats.potions.AncientBrew; import net.runelite.client.plugins.itemstats.potions.GauntletPotion; +import net.runelite.client.plugins.itemstats.potions.MixedPotion; import net.runelite.client.plugins.itemstats.potions.PrayerPotion; import net.runelite.client.plugins.itemstats.potions.SaradominBrew; import net.runelite.client.plugins.itemstats.potions.StaminaPotion; @@ -64,7 +65,8 @@ public class ItemStatChanges PINEAPPLE_RING, PINEAPPLE_CHUNKS, SPICY_SAUCE, CHEESE, SPINACH_ROLL, LEMON, LEMON_CHUNKS, LEMON_SLICES, LIME, LIME_CHUNKS, LIME_SLICES, DWELLBERRIES, KING_WORM, MINCED_MEAT, SPICY_TOMATO, WHITE_PEARL); add(food(3), SHRIMPS, COOKED_MEAT, COOKED_CHICKEN, ROE, CHOCOLATE_BAR, UGTHANKI_MEAT, TOADS_LEGS, ONION__TOMATO, - SPICY_MINCED_MEAT, SLICE_OF_BIRTHDAY_CAKE, LOCUST_MEAT); + SPICY_MINCED_MEAT, SLICE_OF_BIRTHDAY_CAKE, LOCUST_MEAT, RELICYMS_MIX1, RELICYMS_MIX2, ANTIPOISON_MIX1, + ANTIPOISON_MIX2); add(food(4), SARDINE, CAKE, _23_CAKE, SLICE_OF_CAKE, CHOCOLATEY_MILK, BAKED_POTATO, EDIBLE_SEAWEED, MOONLIGHT_MEAD, MOONLIGHT_MEAD4, MOONLIGHT_MEAD3, MOONLIGHT_MEAD2, MOONLIGHT_MEAD1, MONKEY_NUTS); add(food(5), BREAD, HERRING, CHOCOLATE_CAKE, _23_CHOCOLATE_CAKE, CHOCOLATE_SLICE, COOKED_RABBIT, CHILLI_CON_CARNE, @@ -72,7 +74,9 @@ public class ItemStatChanges SCRAMBLED_EGG, MONKEY_BAR, TCHIKI_MONKEY_NUTS, TCHIKI_NUT_PASTE, RED_BANANA, SLICED_RED_BANANA); add(food(6), CHOCICE, MACKEREL, MEAT_PIE, HALF_A_MEAT_PIE, GUANIC_BAT_0, ROAST_BIRD_MEAT, SQUARE_SANDWICH, ROLL, BAGUETTE, TRIANGLE_SANDWICH, GIANT_CARP, MOONLIGHT_MEADM, MOONLIGHT_MEADM4, MOONLIGHT_MEADM3, MOONLIGHT_MEADM2, - MOONLIGHT_MEADM1, STEAK_SANDWICH, GIANT_FROG_LEGS); + MOONLIGHT_MEADM1, STEAK_SANDWICH, GIANT_FROG_LEGS, ANTIFIRE_MIX1, ANTIFIRE_MIX2, EXTENDED_ANTIFIRE_MIX1, + EXTENDED_ANTIFIRE_MIX2, SUPER_ANTIFIRE_MIX1, SUPER_ANTIFIRE_MIX2, EXTENDED_SUPER_ANTIFIRE_MIX1, + EXTENDED_SUPER_ANTIFIRE_MIX2, ANTIPOISON_SUPERMIX1, ANTIPOISON_SUPERMIX2, ANTIDOTE_MIX1, ANTIDOTE_MIX2); add(food(7), TROUT, COD, PLAIN_PIZZA, _12_PLAIN_PIZZA, APPLE_PIE, HALF_AN_APPLE_PIE, ROAST_RABBIT, PREMADE_CH_CRUNCH, CHOCCHIP_CRUNCHIES, PREMADE_SY_CRUNCH, SPICY_CRUNCHIES); add(food(8), PIKE, ROAST_BEAST_MEAT, MEAT_PIZZA, _12_MEAT_PIZZA, PREMADE_WM_CRUN, WORM_CRUNCHIES, PREMADE_TD_CRUNCH, @@ -167,6 +171,9 @@ public class ItemStatChanges // Combat potions final SingleEffect attackPot = boost(ATTACK, perc(.10, 3)); final SingleEffect strengthPot = boost(STRENGTH, perc(.10, 3)); + final SingleEffect defencePot = boost(DEFENCE, perc(.10, 3)); + final Effect combatPot = combo(2, attackPot, strengthPot); + final Effect magicEssence = boost(MAGIC, 3); final SingleEffect magicPot = boost(MAGIC, 4); final SingleEffect imbuedHeart = boost(MAGIC, perc(.10, 1)); final SingleEffect rangingPot = boost(RANGED, perc(.10, 4)); @@ -176,20 +183,22 @@ public class ItemStatChanges final SingleEffect superMagicPot = boost(MAGIC, perc(.15, 5)); final SingleEffect superRangingPot = boost(RANGED, perc(.15, 5)); final SingleEffect divinePot = heal(HITPOINTS, -10); + final Effect zamorakBrew = combo(3, boost(ATTACK, perc(.20, 2)), boost(STRENGTH, perc(.12, 2)), heal(PRAYER, perc(.10, 0)), new BoostedStatBoost(DEFENCE, false, perc(.10, -2)), new BoostedStatBoost(HITPOINTS, false, perc(-.12, 0))); + final Effect ancientBrew = new AncientBrew(); add(attackPot, ATTACK_POTION1, ATTACK_POTION2, ATTACK_POTION3, ATTACK_POTION4); add(strengthPot, STRENGTH_POTION1, STRENGTH_POTION2, STRENGTH_POTION3, STRENGTH_POTION4); - add(boost(DEFENCE, perc(.10, 3)), DEFENCE_POTION1, DEFENCE_POTION2, DEFENCE_POTION3, DEFENCE_POTION4); + add(defencePot, DEFENCE_POTION1, DEFENCE_POTION2, DEFENCE_POTION3, DEFENCE_POTION4); add(magicPot, MAGIC_POTION1, MAGIC_POTION2, MAGIC_POTION3, MAGIC_POTION4); add(rangingPot, RANGING_POTION1, RANGING_POTION2, RANGING_POTION3, RANGING_POTION4, RANGING_POTION4_23551, RANGING_POTION3_23553, RANGING_POTION2_23555, RANGING_POTION1_23557 /* LMS */); - add(combo(2, attackPot, strengthPot), COMBAT_POTION1, COMBAT_POTION2, COMBAT_POTION3, COMBAT_POTION4, + add(combatPot, COMBAT_POTION1, COMBAT_POTION2, COMBAT_POTION3, COMBAT_POTION4, COMBAT_POTION4_26150, COMBAT_POTION3_26151, COMBAT_POTION2_26152, COMBAT_POTION1_26153 /* Deadman starter pack */); add(superAttackPot, SUPER_ATTACK1, SUPER_ATTACK2, SUPER_ATTACK3, SUPER_ATTACK4); add(superStrengthPot, SUPER_STRENGTH1, SUPER_STRENGTH2, SUPER_STRENGTH3, SUPER_STRENGTH4); add(superDefencePot, SUPER_DEFENCE1, SUPER_DEFENCE2, SUPER_DEFENCE3, SUPER_DEFENCE4); - add(boost(MAGIC, 3), MAGIC_ESSENCE1, MAGIC_ESSENCE2, MAGIC_ESSENCE3, MAGIC_ESSENCE4); + add(magicEssence, MAGIC_ESSENCE1, MAGIC_ESSENCE2, MAGIC_ESSENCE3, MAGIC_ESSENCE4); add(combo(3, superAttackPot, superStrengthPot, superDefencePot), SUPER_COMBAT_POTION1, SUPER_COMBAT_POTION2, SUPER_COMBAT_POTION3, SUPER_COMBAT_POTION4); - add(combo(3, boost(ATTACK, perc(.20, 2)), boost(STRENGTH, perc(.12, 2)), heal(PRAYER, perc(.10, 0)), new BoostedStatBoost(DEFENCE, false, perc(.10, -2)), new BoostedStatBoost(HITPOINTS, false, perc(-.12, 0))), ZAMORAK_BREW1, ZAMORAK_BREW2, ZAMORAK_BREW3, ZAMORAK_BREW4); + add(zamorakBrew, ZAMORAK_BREW1, ZAMORAK_BREW2, ZAMORAK_BREW3, ZAMORAK_BREW4); add(new SaradominBrew(0.15, 0.2, 0.1, 2, 2), SARADOMIN_BREW1, SARADOMIN_BREW2, SARADOMIN_BREW3, SARADOMIN_BREW4, SARADOMIN_BREW4_23575, SARADOMIN_BREW3_23577, SARADOMIN_BREW2_23579, SARADOMIN_BREW1_23581 /* LMS */); add(superRangingPot, SUPER_RANGING_1, SUPER_RANGING_2, SUPER_RANGING_3, SUPER_RANGING_4); @@ -208,7 +217,21 @@ public class ItemStatChanges CASTLEWARS_BREW4, CASTLEWARS_BREW3, CASTLEWARS_BREW2, CASTLEWARS_BREW1); add(combo(2, superAttackPot, superStrengthPot), SUPER_COMBAT_POTION4_23543, SUPER_COMBAT_POTION3_23545, SUPER_COMBAT_POTION2_23547, SUPER_COMBAT_POTION1_23549 /* LMS */); - add(new AncientBrew(), ANCIENT_BREW1, ANCIENT_BREW2, ANCIENT_BREW3, ANCIENT_BREW4); + add(ancientBrew, ANCIENT_BREW1, ANCIENT_BREW2, ANCIENT_BREW3, ANCIENT_BREW4); + + // Mixed combat potions + add(new MixedPotion(3, attackPot), ATTACK_MIX1, ATTACK_MIX2); + add(new MixedPotion(3, strengthPot), STRENGTH_MIX1, STRENGTH_MIX2); + add(new MixedPotion(6, defencePot), DEFENCE_MIX1, DEFENCE_MIX2); + add(new MixedPotion(6, magicPot), MAGIC_MIX1, MAGIC_MIX2); + add(new MixedPotion(6, rangingPot), RANGING_MIX1, RANGING_MIX2); + add(new MixedPotion(6, combatPot), COMBAT_MIX1, COMBAT_MIX2); + add(new MixedPotion(6, superAttackPot), SUPERATTACK_MIX1, SUPERATTACK_MIX2); + add(new MixedPotion(6, superStrengthPot), SUPER_STR_MIX1, SUPER_STR_MIX2); + add(new MixedPotion(6, superDefencePot), SUPER_DEF_MIX1, SUPER_DEF_MIX2); + add(new MixedPotion(6, magicEssence), MAGIC_ESSENCE_MIX1, MAGIC_ESSENCE_MIX2); + add(new MixedPotion(6, zamorakBrew), ZAMORAK_MIX1, ZAMORAK_MIX2); + add(new MixedPotion(6, ancientBrew), ANCIENT_MIX1, ANCIENT_MIX2); // Regular overload (NMZ) add(combo(5, superAttackPot, superStrengthPot, superDefencePot, superRangingPot, superMagicPot, heal(HITPOINTS, -50)), OVERLOAD_1, OVERLOAD_2, OVERLOAD_3, OVERLOAD_4); @@ -220,16 +243,30 @@ public class ItemStatChanges add(combo(8, food(20), heal(PRAYER, perc(0.25, 5)), heal(RUN_ENERGY, 20), boost(ATTACK, perc(0.15, 4)), boost(STRENGTH, perc(0.15, 4)), boost(DEFENCE, perc(0.15, 4)), rangingPot, magicPot), BANDAGES_25730); // Recovery potions - add(combo(5, heal(ATTACK, perc(.30, 10)), heal(STRENGTH, perc(.30, 10)), heal(DEFENCE, perc(.30, 10)), heal(RANGED, perc(.30, 10)), heal(MAGIC, perc(.30, 10))), RESTORE_POTION1, RESTORE_POTION2, RESTORE_POTION3, RESTORE_POTION4); - add(heal(RUN_ENERGY, 10), ENERGY_POTION1, ENERGY_POTION2, ENERGY_POTION3, ENERGY_POTION4); - add(new PrayerPotion(7), PRAYER_POTION1, PRAYER_POTION2, PRAYER_POTION3, PRAYER_POTION4); - add(heal(RUN_ENERGY, 20), SUPER_ENERGY1, SUPER_ENERGY2, SUPER_ENERGY3, SUPER_ENERGY4); - add(new SuperRestore(.25, 8), SUPER_RESTORE1, SUPER_RESTORE2, SUPER_RESTORE3, SUPER_RESTORE4, + final Effect restorePot = combo(5, heal(ATTACK, perc(.30, 10)), heal(STRENGTH, perc(.30, 10)), heal(DEFENCE, perc(.30, 10)), heal(RANGED, perc(.30, 10)), heal(MAGIC, perc(.30, 10))); + final Effect energyPot = heal(RUN_ENERGY, 10); + final Effect prayerPot = new PrayerPotion(7); + final Effect superEnergyPot = heal(RUN_ENERGY, 20); + final Effect superRestorePot = new SuperRestore(.25, 8); + final Effect staminaPot = new StaminaPotion(); + add(restorePot, RESTORE_POTION1, RESTORE_POTION2, RESTORE_POTION3, RESTORE_POTION4); + add(energyPot, ENERGY_POTION1, ENERGY_POTION2, ENERGY_POTION3, ENERGY_POTION4); + add(prayerPot, PRAYER_POTION1, PRAYER_POTION2, PRAYER_POTION3, PRAYER_POTION4); + add(superEnergyPot, SUPER_ENERGY1, SUPER_ENERGY2, SUPER_ENERGY3, SUPER_ENERGY4); + add(superRestorePot, SUPER_RESTORE1, SUPER_RESTORE2, SUPER_RESTORE3, SUPER_RESTORE4, BLIGHTED_SUPER_RESTORE1, BLIGHTED_SUPER_RESTORE2, BLIGHTED_SUPER_RESTORE3, BLIGHTED_SUPER_RESTORE4, SUPER_RESTORE4_23567, SUPER_RESTORE3_23569, SUPER_RESTORE2_23571, SUPER_RESTORE1_23573 /* LMS */); add(new SuperRestore(.30, 4), SANFEW_SERUM1, SANFEW_SERUM2, SANFEW_SERUM3, SANFEW_SERUM4, SANFEW_SERUM4_23559, SANFEW_SERUM3_23561, SANFEW_SERUM2_23563, SANFEW_SERUM1_23565 /* LMS */); - add(new StaminaPotion(), STAMINA_POTION1, STAMINA_POTION2, STAMINA_POTION3, STAMINA_POTION4); + add(staminaPot, STAMINA_POTION1, STAMINA_POTION2, STAMINA_POTION3, STAMINA_POTION4); + + // Mixed recovery potions + add(new MixedPotion(3, restorePot), RESTORE_MIX1, RESTORE_MIX2); + add(new MixedPotion(6, energyPot), ENERGY_MIX1, ENERGY_MIX2); + add(new MixedPotion(6, prayerPot), PRAYER_MIX1, PRAYER_MIX2); + add(new MixedPotion(6, superEnergyPot), SUPER_ENERGY_MIX1, SUPER_ENERGY_MIX2); + add(new MixedPotion(6, superRestorePot), SUPER_RESTORE_MIX1, SUPER_RESTORE_MIX2); + add(new MixedPotion(6, staminaPot), STAMINA_MIX1, STAMINA_MIX2); // Raids potions (+) final DeltaPercentage coxPlusPotionBoost = perc(.16, 6); @@ -255,11 +292,19 @@ public class ItemStatChanges add(combo(3, boost(MAGIC, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), KODAI_1, KODAI_2, KODAI_3, KODAI_4); // Skill potions - add(boost(AGILITY, 3), AGILITY_POTION1, AGILITY_POTION2, AGILITY_POTION3, AGILITY_POTION4); - add(boost(FISHING, 3), FISHING_POTION1, FISHING_POTION2, FISHING_POTION3, FISHING_POTION4); - add(boost(HUNTER, 3), HUNTER_POTION1, HUNTER_POTION2, HUNTER_POTION3, HUNTER_POTION4); + final Effect agilityPot = boost(AGILITY, 3); + final Effect fishingPot = boost(FISHING, 3); + final Effect hunterPot = boost(HUNTER, 3); + add(agilityPot, AGILITY_POTION1, AGILITY_POTION2, AGILITY_POTION3, AGILITY_POTION4); + add(fishingPot, FISHING_POTION1, FISHING_POTION2, FISHING_POTION3, FISHING_POTION4); + add(hunterPot, HUNTER_POTION1, HUNTER_POTION2, HUNTER_POTION3, HUNTER_POTION4); add(combo(2, boost(HITPOINTS, 5), heal(RUN_ENERGY, 5)), GUTHIX_REST1, GUTHIX_REST2, GUTHIX_REST3, GUTHIX_REST4); + // Mixed skill potions + add(new MixedPotion(6, agilityPot), AGILITY_MIX1, AGILITY_MIX2); + add(new MixedPotion(6, fishingPot), FISHING_MIX1, FISHING_MIX2); + add(new MixedPotion(6, hunterPot), HUNTING_MIX1, HUNTING_MIX2); + // Misc/run energy add(combo(food(3), range(heal(RUN_ENERGY, 5), heal(RUN_ENERGY, 10))), WHITE_TREE_FRUIT); add(heal(RUN_ENERGY, 30), STRANGE_FRUIT); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/MixedPotion.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/MixedPotion.java new file mode 100644 index 0000000000..e56f575315 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/MixedPotion.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2022, Jordan Atwood + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats.potions; + +import java.util.Comparator; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import lombok.RequiredArgsConstructor; +import net.runelite.api.Client; +import static net.runelite.client.plugins.itemstats.Builders.food; +import net.runelite.client.plugins.itemstats.Effect; +import net.runelite.client.plugins.itemstats.Positivity; +import net.runelite.client.plugins.itemstats.StatChange; +import static net.runelite.client.plugins.itemstats.stats.Stats.HITPOINTS; +import net.runelite.client.plugins.itemstats.StatsChanges; +import org.apache.commons.lang3.ArrayUtils; + +@RequiredArgsConstructor +public class MixedPotion implements Effect +{ + private final int heal; + + @Nonnull + private final Effect potion; + + @Override + public StatsChanges calculate(Client client) + { + final StatsChanges changes = new StatsChanges(0); + final StatChange mixedPotionHpBoost = food(heal).effect(client); + final StatsChanges potionChanges = potion.calculate(client); + final int mixedPotionHitpointsHealing = mixedPotionHpBoost.getRelative(); + + if (Stream.of(potionChanges.getStatChanges()).anyMatch(statChange -> statChange.getStat() == HITPOINTS)) + { + changes.setStatChanges(Stream.of(potionChanges.getStatChanges()) + .map(change -> + { + /* + * Mixed potions do not exist ingame for all types of potions. In fact, at the time of writing, the + * Zamorak mix is the only mixed potion which includes base potion effects which affect a player's + * Hitpoints. Working from what we know of how these behave, this code assumes that mixed potions + * including Hitpoints changes will only include negative HP effects as the + * absolute/relative/theoretical end values cannot be determined otherwise. For this reason, potions + * with positive HP effects will not have their stat changes affected here. + */ + if (change.getStat() != HITPOINTS || mixedPotionHitpointsHealing == 0 || change.getTheoretical() >= 0) + { + return change; + } + + /* + * Mixed potions apply two hitpoints changes, both based on the current hitpoints value. Because of + * this, the two effects are calculated independently of each other, both against the same starting + * hitpoints value and later combined. These effects are: + * 1. A food effect of `heal` amount + * 2. Deduct hitpoints equal to the potion's boost amount + */ + + final int max = HITPOINTS.getMaximum(client); + final int absolute = change.getAbsolute(); + final int relative = change.getRelative(); + + if (absolute + mixedPotionHitpointsHealing > max) + { + change.setPositivity(Positivity.BETTER_CAPPED); + } + else if (relative + mixedPotionHitpointsHealing > 0) + { + change.setPositivity(Positivity.BETTER_UNCAPPED); + } + else if (relative + mixedPotionHitpointsHealing == 0) + { + change.setPositivity(Positivity.NO_CHANGE); + } + else + { + change.setPositivity(Positivity.WORSE); + } + + change.setAbsolute(Math.min(max, absolute + mixedPotionHitpointsHealing)); + change.setRelative(change.getRelative() + mixedPotionHitpointsHealing); + change.setTheoretical(change.getTheoretical() + mixedPotionHitpointsHealing); + + return change; + }) + .toArray(StatChange[]::new)); + } + else + { + changes.setStatChanges(ArrayUtils.addAll(new StatChange[] { mixedPotionHpBoost }, potionChanges.getStatChanges())); + } + + changes.setPositivity(Stream.of(changes.getStatChanges()) + .map(StatChange::getPositivity) + .max(Comparator.naturalOrder()).get()); + + return changes; + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatEffectTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatEffectTest.java index b75313dd3e..c5d4535eb8 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatEffectTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatEffectTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, TheStonedTurtle + * Copyright (c) 2022, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -193,6 +194,37 @@ public class ItemStatEffectTest assertEquals(1, skillChange(Skill.PRAYER, 1, 0, ancientBrew)); } + @Test + public void testZamorakBrew() + { + final Effect zamorakBrew = new ItemStatChanges().get(ItemID.ZAMORAK_BREW4); + + assertEquals(-10, skillChange(Skill.HITPOINTS, 91, 91, zamorakBrew)); + assertEquals(-9, skillChange(Skill.HITPOINTS, 91, 81, zamorakBrew)); + assertEquals(-8, skillChange(Skill.HITPOINTS, 91, 72, zamorakBrew)); + assertEquals(-7, skillChange(Skill.HITPOINTS, 91, 64, zamorakBrew)); + assertEquals(-3, skillChange(Skill.HITPOINTS, 91, 31, zamorakBrew)); + assertEquals(-3, skillChange(Skill.HITPOINTS, 91, 28, zamorakBrew)); + assertEquals(-3, skillChange(Skill.HITPOINTS, 91, 25, zamorakBrew)); + assertEquals(-2, skillChange(Skill.HITPOINTS, 91, 22, zamorakBrew)); + } + + @Test + public void testZamorakMix() + { + final Effect zamorakMix = new ItemStatChanges().get(ItemID.ZAMORAK_MIX2); + + assertEquals(-10, skillChange(Skill.HITPOINTS, 91, 91, zamorakMix)); + assertEquals(-3, skillChange(Skill.HITPOINTS, 91, 81, zamorakMix)); + assertEquals(-3, skillChange(Skill.HITPOINTS, 91, 78, zamorakMix)); + assertEquals(-3, skillChange(Skill.HITPOINTS, 91, 75, zamorakMix)); + assertEquals(3, skillChange(Skill.HITPOINTS, 91, 31, zamorakMix)); + assertEquals(2, skillChange(Skill.HITPOINTS, 91, 34, zamorakMix)); + assertEquals(2, skillChange(Skill.HITPOINTS, 91, 36, zamorakMix)); + assertEquals(2, skillChange(Skill.HITPOINTS, 91, 38, zamorakMix)); + assertEquals(0, skillChange(Skill.HITPOINTS, 91, 50, zamorakMix)); + } + private int skillChange(Skill skill, int maxValue, int currentValue, Effect effect) { if (effect == null) From 840c3b264d174df01524e0714d5d30cb332a2c96 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Thu, 26 May 2022 11:20:03 -0700 Subject: [PATCH 06/17] item stats: Remove combo primaries This field never had any real use from the beginning, and has only caused confusion for contributors adding item stat change definitions. --- .../client/plugins/itemstats/Builders.java | 5 - .../client/plugins/itemstats/Combo.java | 19 +-- .../plugins/itemstats/ItemStatChanges.java | 146 +++++++++--------- 3 files changed, 76 insertions(+), 94 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Builders.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Builders.java index e5cee44b35..ff2d65faef 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Builders.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Builders.java @@ -40,11 +40,6 @@ public class Builders return new Food(p); } - public static Effect combo(int primaries, SingleEffect... effect) - { - return new Combo(primaries, effect); - } - public static Effect combo(SingleEffect... effect) { return new Combo(effect); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Combo.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Combo.java index 9749f1a17b..9248b0d202 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Combo.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Combo.java @@ -24,36 +24,23 @@ */ package net.runelite.client.plugins.itemstats; +import lombok.AllArgsConstructor; import net.runelite.api.Client; +@AllArgsConstructor public class Combo implements Effect { private final SingleEffect[] calcs; - private final int numPrimaries; - - public Combo(SingleEffect[] calcs) - { - this(1, calcs); - } - - public Combo(int numPrimaries, SingleEffect[] calcs) - { - this.numPrimaries = numPrimaries; - this.calcs = calcs; - } @Override public StatsChanges calculate(Client client) { StatsChanges out = new StatsChanges(calcs.length); StatChange[] statChanges = out.getStatChanges(); + Positivity positivity = Positivity.NO_CHANGE; for (int i = 0; i < calcs.length; i++) { statChanges[i] = calcs[i].effect(client); - } - Positivity positivity = Positivity.NO_CHANGE; - for (int i = 0; i < numPrimaries; i++) - { if (positivity.ordinal() < statChanges[i].getPositivity().ordinal()) { positivity = statChanges[i].getPositivity(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java index e72982798c..ef0cc5708d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java @@ -106,9 +106,9 @@ public class ItemStatChanges add(food(maxHP -> (int) Math.ceil(maxHP * .05)), WATERMELON_SLICE); add(food(perc(.1, 1)), COOKED_SWEETCORN, SWEETCORN_7088 /* Bowl of cooked sweetcorn */); add(combo(food(1), boost(DEFENCE, perc(.02, 1))), CABBAGE_1967 /* Draynor Manor */); - add(combo(2, food(8), heal(RUN_ENERGY, 5)), PAPAYA_FRUIT); - add(combo(2, food(3), boost(ATTACK, perc(.02, 2))), CUP_OF_TEA_1978 /* Standard tea */); - add(combo(2, food(3), new NettleTeaRunEnergy()), NETTLE_TEA, NETTLE_TEA_4240 /* Milky */, CUP_OF_TEA_4242 /* Nettle */, CUP_OF_TEA_4243 /* Milky nettle */); + add(combo(food(8), heal(RUN_ENERGY, 5)), PAPAYA_FRUIT); + add(combo(food(3), boost(ATTACK, perc(.02, 2))), CUP_OF_TEA_1978 /* Standard tea */); + add(combo(food(3), new NettleTeaRunEnergy()), NETTLE_TEA, NETTLE_TEA_4240 /* Milky */, CUP_OF_TEA_4242 /* Nettle */, CUP_OF_TEA_4243 /* Milky nettle */); add(range(food(5), food(7)), THIN_SNAIL_MEAT); add(range(food(5), food(8)), LEAN_SNAIL_MEAT); add(range(food(7), food(9)), FAT_SNAIL_MEAT); @@ -128,39 +128,39 @@ public class ItemStatChanges add(combo(food(11), dec(ATTACK, 2)), JUG_OF_WINE); add(combo(food(14), dec(ATTACK, 3)), BOTTLE_OF_WINE); add(combo(food(7), dec(ATTACK, 2)), HALF_FULL_WINE_JUG); - add(combo(dec(ATTACK, 3)), JUG_OF_BAD_WINE); - add(combo(3, food(5), new SimpleStatBoost(STRENGTH, true, perc(.05, 1)), new BoostedStatBoost(ATTACK, false, perc(.02, -3))), PREMADE_SGG, SHORT_GREEN_GUY, BRANDY, GIN, VODKA, WHISKY); - add(combo(3, food(7), new SimpleStatBoost(STRENGTH, true, perc(.05, 2)), new BoostedStatBoost(ATTACK, false, perc(.02, -3))), PREMADE_BLURB_SP, BLURBERRY_SPECIAL); - add(combo(3, food(5), new SimpleStatBoost(STRENGTH, true, perc(.05, 2)), new BoostedStatBoost(ATTACK, false, perc(.02, -3))), PREMADE_DR_DRAGON, DRUNK_DRAGON, PREMADE_CHOC_SDY, CHOC_SATURDAY); - add(combo(3, food(5), new SimpleStatBoost(STRENGTH, true, perc(.06, 1)), new BoostedStatBoost(ATTACK, false, perc(.02, -3))), PREMADE_WIZ_BLZD, WIZARD_BLIZZARD); - add(combo(3, food(3), new SimpleStatBoost(STRENGTH, true, perc(.04, 1)), new BoostedStatBoost(ATTACK, false, perc(.05, -3))), GROG); - add(combo(3, food(1), boost(STRENGTH, perc(.02, 1)), new BoostedStatBoost(ATTACK, false, perc(.06, -1))), BEER, BEER_7740); - add(combo(3, food(4), boost(STRENGTH, perc(.04, 2)), new BoostedStatBoost(ATTACK, false, perc(.1, -2))), BEER_TANKARD); - add(combo(3, food(15), boost(STRENGTH, perc(.1, 2)), new BoostedStatBoost(ATTACK, false, perc(.5, -4))), KEG_OF_BEER_3801 /* Non-quest version */); - add(combo(4, boost(ATTACK, 5), boost(STRENGTH, 5), heal(MAGIC, -5), heal(PRAYER, -5)), BLOOD_PINT); - add(combo(3, food(1), boost(STRENGTH, 2), new BoostedStatBoost(ATTACK, false, perc(.05, -2))), ASGARNIAN_ALE, ASGARNIAN_ALE1, ASGARNIAN_ALE2, ASGARNIAN_ALE3, ASGARNIAN_ALE4, ASGARNIAN_ALE_7744); - add(combo(3, food(1), boost(STRENGTH, 3), new BoostedStatBoost(ATTACK, false, perc(.05, -3))), ASGARNIAN_ALEM, ASGARNIAN_ALEM1, ASGARNIAN_ALEM2, ASGARNIAN_ALEM3, ASGARNIAN_ALEM4); - add(combo(4, food(1), boost(WOODCUTTING, 1), new BoostedStatBoost(ATTACK, false, perc(.02, -2)), new BoostedStatBoost(STRENGTH, false, perc(.02, -2))), AXEMANS_FOLLY, AXEMANS_FOLLY1, AXEMANS_FOLLY2, AXEMANS_FOLLY3, AXEMANS_FOLLY4); - add(combo(4, food(2), boost(WOODCUTTING, 2), new BoostedStatBoost(ATTACK, false, perc(.02, -3)), new BoostedStatBoost(STRENGTH, false, perc(.02, -3))), AXEMANS_FOLLYM, AXEMANS_FOLLYM1, AXEMANS_FOLLYM2, AXEMANS_FOLLYM3, AXEMANS_FOLLYM4); - add(combo(5, food(1), boost(THIEVING, 1), boost(ATTACK, 1), new BoostedStatBoost(DEFENCE, false, perc(.06, -3)), new BoostedStatBoost(STRENGTH, false, perc(.06, -3))), BANDITS_BREW); - add(combo(4, food(1), new SimpleStatBoost(COOKING, true, perc(.05, 1)), new BoostedStatBoost(ATTACK, false, perc(.05, -2)), new BoostedStatBoost(STRENGTH, false, perc(.05, -2))), CHEFS_DELIGHT, CHEFS_DELIGHT1, CHEFS_DELIGHT2, CHEFS_DELIGHT3, CHEFS_DELIGHT4, CHEFS_DELIGHT_7754); - add(combo(4, food(2), new SimpleStatBoost(COOKING, true, perc(.05, 2)), new BoostedStatBoost(ATTACK, false, perc(.05, -3)), new BoostedStatBoost(STRENGTH, false, perc(.05, -3))), CHEFS_DELIGHTM, CHEFS_DELIGHTM1, CHEFS_DELIGHTM2, CHEFS_DELIGHTM3, CHEFS_DELIGHTM4); - add(combo(4, food(1), boost(FARMING, 1), new BoostedStatBoost(ATTACK, false, perc(.02, -2)), new BoostedStatBoost(STRENGTH, false, perc(.02, -2))), CIDER, CIDER1, CIDER2, CIDER3, CIDER4, CIDER_7752); - add(combo(4, food(2), boost(FARMING, 2), new BoostedStatBoost(ATTACK, false, perc(.02, -3)), new BoostedStatBoost(STRENGTH, false, perc(.02, -3))), MATURE_CIDER, CIDERM1, CIDERM2, CIDERM3, CIDERM4); - add(combo(3, food(1), boost(STRENGTH, 2), new BoostedStatBoost(ATTACK, false, perc(.05, -2))), DRAGON_BITTER, DRAGON_BITTER1, DRAGON_BITTER2, DRAGON_BITTER3, DRAGON_BITTER4, DRAGON_BITTER_7748); - add(combo(3, food(2), boost(STRENGTH, 3), new BoostedStatBoost(ATTACK, false, perc(.05, -2))), DRAGON_BITTERM, DRAGON_BITTERM1, DRAGON_BITTERM2, DRAGON_BITTERM3, DRAGON_BITTERM4); - add(combo(6, food(1), boost(MINING, 1), boost(SMITHING, 1), new BoostedStatBoost(ATTACK, false, perc(.04, -2)), new BoostedStatBoost(DEFENCE, false, perc(.04, -2)), new BoostedStatBoost(STRENGTH, false, perc(.04, -2))), DWARVEN_STOUT, DWARVEN_STOUT1, DWARVEN_STOUT2, DWARVEN_STOUT3, DWARVEN_STOUT4); - add(combo(6, food(2), boost(MINING, 2), boost(SMITHING, 2), new BoostedStatBoost(ATTACK, false, perc(.04, -3)), new BoostedStatBoost(DEFENCE, false, perc(.04, -3)), new BoostedStatBoost(STRENGTH, false, perc(.04, -3))), DWARVEN_STOUTM, DWARVEN_STOUTM1, DWARVEN_STOUTM2, DWARVEN_STOUTM3, DWARVEN_STOUTM4); - add(combo(5, food(1), boost(HERBLORE, 1), new BoostedStatBoost(ATTACK, false, perc(.04, -2)), new BoostedStatBoost(DEFENCE, false, perc(.04, -2)), new BoostedStatBoost(STRENGTH, false, perc(.04, -2))), GREENMANS_ALE, GREENMANS_ALE1, GREENMANS_ALE2, GREENMANS_ALE3, GREENMANS_ALE4, GREENMANS_ALE_7746); - add(combo(5, food(2), boost(HERBLORE, 2), new BoostedStatBoost(ATTACK, false, perc(.04, -3)), new BoostedStatBoost(DEFENCE, false, perc(.04, -3)), new BoostedStatBoost(STRENGTH, false, perc(.04, -3))), GREENMANS_ALEM, GREENMANS_ALEM1, GREENMANS_ALEM2, GREENMANS_ALEM3, GREENMANS_ALEM4); - add(combo(5, food(1), boost(SLAYER, 2), new BoostedStatBoost(ATTACK, false, perc(.02, -2)), new BoostedStatBoost(DEFENCE, false, perc(.02, -2)), new BoostedStatBoost(STRENGTH, false, perc(.02, -2))), SLAYERS_RESPITE, SLAYERS_RESPITE1, SLAYERS_RESPITE2, SLAYERS_RESPITE3, SLAYERS_RESPITE4); - add(combo(5, food(2), boost(SLAYER, 4), new BoostedStatBoost(ATTACK, false, perc(.02, -3)), new BoostedStatBoost(DEFENCE, false, perc(.02, -3)), new BoostedStatBoost(STRENGTH, false, perc(.02, -3))), SLAYERS_RESPITEM, SLAYERS_RESPITEM1, SLAYERS_RESPITEM2, SLAYERS_RESPITEM3, SLAYERS_RESPITEM4); - add(combo(5, food(1), new SimpleStatBoost(MAGIC, true, perc(.02, 2)), new BoostedStatBoost(ATTACK, false, perc(.05, -1)), new BoostedStatBoost(DEFENCE, false, perc(.05, -1)), new BoostedStatBoost(STRENGTH, false, perc(.05, -1))), WIZARDS_MIND_BOMB, MIND_BOMB1, MIND_BOMB2, MIND_BOMB3, MIND_BOMB4); - add(combo(5, food(2), new SimpleStatBoost(MAGIC, true, perc(.02, 3)), new BoostedStatBoost(ATTACK, false, perc(.05, -2)), new BoostedStatBoost(DEFENCE, false, perc(.05, -2)), new BoostedStatBoost(STRENGTH, false, perc(.05, -2))), MATURE_WMB, MIND_BOMBM1, MIND_BOMBM2, MIND_BOMBM3, MIND_BOMBM4); - add(combo(10, food(14), boost(STRENGTH, 3), boost(MINING, 1), heal(PRAYER, perc(.06, -1)), new BoostedStatBoost(AGILITY, false, perc(.09, -3)), new BoostedStatBoost(ATTACK, false, perc(.06, -1)), new BoostedStatBoost(DEFENCE, false, perc(.08, -2)), new BoostedStatBoost(HERBLORE, false, perc(.06, -1)), new BoostedStatBoost(MAGIC, false, perc(.05, -1)), new BoostedStatBoost(RANGED, false, perc(.06, -1))), BRAINDEATH_RUM); - add(combo(2, food(2), heal(PRAYER, perc(.04, -2))), BLOODY_BRACER); - add(combo(3, food(1), boost(AGILITY, 1), heal(STRENGTH, -1)), ELVEN_DAWN); - add(combo(3, boost(RANGED, 4), new BoostedStatBoost(STRENGTH, false, perc(.04, -2)), new BoostedStatBoost(MAGIC, false, perc(.04, -2))), LIZARDKICKER); + add(dec(ATTACK, 3), JUG_OF_BAD_WINE); + add(combo(food(5), new SimpleStatBoost(STRENGTH, true, perc(.05, 1)), new BoostedStatBoost(ATTACK, false, perc(.02, -3))), PREMADE_SGG, SHORT_GREEN_GUY, BRANDY, GIN, VODKA, WHISKY); + add(combo(food(7), new SimpleStatBoost(STRENGTH, true, perc(.05, 2)), new BoostedStatBoost(ATTACK, false, perc(.02, -3))), PREMADE_BLURB_SP, BLURBERRY_SPECIAL); + add(combo(food(5), new SimpleStatBoost(STRENGTH, true, perc(.05, 2)), new BoostedStatBoost(ATTACK, false, perc(.02, -3))), PREMADE_DR_DRAGON, DRUNK_DRAGON, PREMADE_CHOC_SDY, CHOC_SATURDAY); + add(combo(food(5), new SimpleStatBoost(STRENGTH, true, perc(.06, 1)), new BoostedStatBoost(ATTACK, false, perc(.02, -3))), PREMADE_WIZ_BLZD, WIZARD_BLIZZARD); + add(combo(food(3), new SimpleStatBoost(STRENGTH, true, perc(.04, 1)), new BoostedStatBoost(ATTACK, false, perc(.05, -3))), GROG); + add(combo(food(1), boost(STRENGTH, perc(.02, 1)), new BoostedStatBoost(ATTACK, false, perc(.06, -1))), BEER, BEER_7740); + add(combo(food(4), boost(STRENGTH, perc(.04, 2)), new BoostedStatBoost(ATTACK, false, perc(.1, -2))), BEER_TANKARD); + add(combo(food(15), boost(STRENGTH, perc(.1, 2)), new BoostedStatBoost(ATTACK, false, perc(.5, -4))), KEG_OF_BEER_3801 /* Non-quest version */); + add(combo(boost(ATTACK, 5), boost(STRENGTH, 5), heal(MAGIC, -5), heal(PRAYER, -5)), BLOOD_PINT); + add(combo(food(1), boost(STRENGTH, 2), new BoostedStatBoost(ATTACK, false, perc(.05, -2))), ASGARNIAN_ALE, ASGARNIAN_ALE1, ASGARNIAN_ALE2, ASGARNIAN_ALE3, ASGARNIAN_ALE4, ASGARNIAN_ALE_7744); + add(combo(food(1), boost(STRENGTH, 3), new BoostedStatBoost(ATTACK, false, perc(.05, -3))), ASGARNIAN_ALEM, ASGARNIAN_ALEM1, ASGARNIAN_ALEM2, ASGARNIAN_ALEM3, ASGARNIAN_ALEM4); + add(combo(food(1), boost(WOODCUTTING, 1), new BoostedStatBoost(ATTACK, false, perc(.02, -2)), new BoostedStatBoost(STRENGTH, false, perc(.02, -2))), AXEMANS_FOLLY, AXEMANS_FOLLY1, AXEMANS_FOLLY2, AXEMANS_FOLLY3, AXEMANS_FOLLY4); + add(combo(food(2), boost(WOODCUTTING, 2), new BoostedStatBoost(ATTACK, false, perc(.02, -3)), new BoostedStatBoost(STRENGTH, false, perc(.02, -3))), AXEMANS_FOLLYM, AXEMANS_FOLLYM1, AXEMANS_FOLLYM2, AXEMANS_FOLLYM3, AXEMANS_FOLLYM4); + add(combo(food(1), boost(THIEVING, 1), boost(ATTACK, 1), new BoostedStatBoost(DEFENCE, false, perc(.06, -3)), new BoostedStatBoost(STRENGTH, false, perc(.06, -3))), BANDITS_BREW); + add(combo(food(1), new SimpleStatBoost(COOKING, true, perc(.05, 1)), new BoostedStatBoost(ATTACK, false, perc(.05, -2)), new BoostedStatBoost(STRENGTH, false, perc(.05, -2))), CHEFS_DELIGHT, CHEFS_DELIGHT1, CHEFS_DELIGHT2, CHEFS_DELIGHT3, CHEFS_DELIGHT4, CHEFS_DELIGHT_7754); + add(combo(food(2), new SimpleStatBoost(COOKING, true, perc(.05, 2)), new BoostedStatBoost(ATTACK, false, perc(.05, -3)), new BoostedStatBoost(STRENGTH, false, perc(.05, -3))), CHEFS_DELIGHTM, CHEFS_DELIGHTM1, CHEFS_DELIGHTM2, CHEFS_DELIGHTM3, CHEFS_DELIGHTM4); + add(combo(food(1), boost(FARMING, 1), new BoostedStatBoost(ATTACK, false, perc(.02, -2)), new BoostedStatBoost(STRENGTH, false, perc(.02, -2))), CIDER, CIDER1, CIDER2, CIDER3, CIDER4, CIDER_7752); + add(combo(food(2), boost(FARMING, 2), new BoostedStatBoost(ATTACK, false, perc(.02, -3)), new BoostedStatBoost(STRENGTH, false, perc(.02, -3))), MATURE_CIDER, CIDERM1, CIDERM2, CIDERM3, CIDERM4); + add(combo(food(1), boost(STRENGTH, 2), new BoostedStatBoost(ATTACK, false, perc(.05, -2))), DRAGON_BITTER, DRAGON_BITTER1, DRAGON_BITTER2, DRAGON_BITTER3, DRAGON_BITTER4, DRAGON_BITTER_7748); + add(combo(food(2), boost(STRENGTH, 3), new BoostedStatBoost(ATTACK, false, perc(.05, -2))), DRAGON_BITTERM, DRAGON_BITTERM1, DRAGON_BITTERM2, DRAGON_BITTERM3, DRAGON_BITTERM4); + add(combo(food(1), boost(MINING, 1), boost(SMITHING, 1), new BoostedStatBoost(ATTACK, false, perc(.04, -2)), new BoostedStatBoost(DEFENCE, false, perc(.04, -2)), new BoostedStatBoost(STRENGTH, false, perc(.04, -2))), DWARVEN_STOUT, DWARVEN_STOUT1, DWARVEN_STOUT2, DWARVEN_STOUT3, DWARVEN_STOUT4); + add(combo(food(2), boost(MINING, 2), boost(SMITHING, 2), new BoostedStatBoost(ATTACK, false, perc(.04, -3)), new BoostedStatBoost(DEFENCE, false, perc(.04, -3)), new BoostedStatBoost(STRENGTH, false, perc(.04, -3))), DWARVEN_STOUTM, DWARVEN_STOUTM1, DWARVEN_STOUTM2, DWARVEN_STOUTM3, DWARVEN_STOUTM4); + add(combo(food(1), boost(HERBLORE, 1), new BoostedStatBoost(ATTACK, false, perc(.04, -2)), new BoostedStatBoost(DEFENCE, false, perc(.04, -2)), new BoostedStatBoost(STRENGTH, false, perc(.04, -2))), GREENMANS_ALE, GREENMANS_ALE1, GREENMANS_ALE2, GREENMANS_ALE3, GREENMANS_ALE4, GREENMANS_ALE_7746); + add(combo(food(2), boost(HERBLORE, 2), new BoostedStatBoost(ATTACK, false, perc(.04, -3)), new BoostedStatBoost(DEFENCE, false, perc(.04, -3)), new BoostedStatBoost(STRENGTH, false, perc(.04, -3))), GREENMANS_ALEM, GREENMANS_ALEM1, GREENMANS_ALEM2, GREENMANS_ALEM3, GREENMANS_ALEM4); + add(combo(food(1), boost(SLAYER, 2), new BoostedStatBoost(ATTACK, false, perc(.02, -2)), new BoostedStatBoost(DEFENCE, false, perc(.02, -2)), new BoostedStatBoost(STRENGTH, false, perc(.02, -2))), SLAYERS_RESPITE, SLAYERS_RESPITE1, SLAYERS_RESPITE2, SLAYERS_RESPITE3, SLAYERS_RESPITE4); + add(combo(food(2), boost(SLAYER, 4), new BoostedStatBoost(ATTACK, false, perc(.02, -3)), new BoostedStatBoost(DEFENCE, false, perc(.02, -3)), new BoostedStatBoost(STRENGTH, false, perc(.02, -3))), SLAYERS_RESPITEM, SLAYERS_RESPITEM1, SLAYERS_RESPITEM2, SLAYERS_RESPITEM3, SLAYERS_RESPITEM4); + add(combo(food(1), new SimpleStatBoost(MAGIC, true, perc(.02, 2)), new BoostedStatBoost(ATTACK, false, perc(.05, -1)), new BoostedStatBoost(DEFENCE, false, perc(.05, -1)), new BoostedStatBoost(STRENGTH, false, perc(.05, -1))), WIZARDS_MIND_BOMB, MIND_BOMB1, MIND_BOMB2, MIND_BOMB3, MIND_BOMB4); + add(combo(food(2), new SimpleStatBoost(MAGIC, true, perc(.02, 3)), new BoostedStatBoost(ATTACK, false, perc(.05, -2)), new BoostedStatBoost(DEFENCE, false, perc(.05, -2)), new BoostedStatBoost(STRENGTH, false, perc(.05, -2))), MATURE_WMB, MIND_BOMBM1, MIND_BOMBM2, MIND_BOMBM3, MIND_BOMBM4); + add(combo(food(14), boost(STRENGTH, 3), boost(MINING, 1), heal(PRAYER, perc(.06, -1)), new BoostedStatBoost(AGILITY, false, perc(.09, -3)), new BoostedStatBoost(ATTACK, false, perc(.06, -1)), new BoostedStatBoost(DEFENCE, false, perc(.08, -2)), new BoostedStatBoost(HERBLORE, false, perc(.06, -1)), new BoostedStatBoost(MAGIC, false, perc(.05, -1)), new BoostedStatBoost(RANGED, false, perc(.06, -1))), BRAINDEATH_RUM); + add(combo(food(2), heal(PRAYER, perc(.04, -2))), BLOODY_BRACER); + add(combo(food(1), boost(AGILITY, 1), heal(STRENGTH, -1)), ELVEN_DAWN); + add(combo(boost(RANGED, 4), new BoostedStatBoost(STRENGTH, false, perc(.04, -2)), new BoostedStatBoost(MAGIC, false, perc(.04, -2))), LIZARDKICKER); // Sq'irk Juice add(heal(RUN_ENERGY, 5), WINTER_SQIRKJUICE); @@ -172,7 +172,7 @@ public class ItemStatChanges final SingleEffect attackPot = boost(ATTACK, perc(.10, 3)); final SingleEffect strengthPot = boost(STRENGTH, perc(.10, 3)); final SingleEffect defencePot = boost(DEFENCE, perc(.10, 3)); - final Effect combatPot = combo(2, attackPot, strengthPot); + final Effect combatPot = combo(attackPot, strengthPot); final Effect magicEssence = boost(MAGIC, 3); final SingleEffect magicPot = boost(MAGIC, 4); final SingleEffect imbuedHeart = boost(MAGIC, perc(.10, 1)); @@ -183,7 +183,7 @@ public class ItemStatChanges final SingleEffect superMagicPot = boost(MAGIC, perc(.15, 5)); final SingleEffect superRangingPot = boost(RANGED, perc(.15, 5)); final SingleEffect divinePot = heal(HITPOINTS, -10); - final Effect zamorakBrew = combo(3, boost(ATTACK, perc(.20, 2)), boost(STRENGTH, perc(.12, 2)), heal(PRAYER, perc(.10, 0)), new BoostedStatBoost(DEFENCE, false, perc(.10, -2)), new BoostedStatBoost(HITPOINTS, false, perc(-.12, 0))); + final Effect zamorakBrew = combo(boost(ATTACK, perc(.20, 2)), boost(STRENGTH, perc(.12, 2)), heal(PRAYER, perc(.10, 0)), new BoostedStatBoost(DEFENCE, false, perc(.10, -2)), new BoostedStatBoost(HITPOINTS, false, perc(-.12, 0))); final Effect ancientBrew = new AncientBrew(); add(attackPot, ATTACK_POTION1, ATTACK_POTION2, ATTACK_POTION3, ATTACK_POTION4); add(strengthPot, STRENGTH_POTION1, STRENGTH_POTION2, STRENGTH_POTION3, STRENGTH_POTION4); @@ -197,25 +197,25 @@ public class ItemStatChanges add(superStrengthPot, SUPER_STRENGTH1, SUPER_STRENGTH2, SUPER_STRENGTH3, SUPER_STRENGTH4); add(superDefencePot, SUPER_DEFENCE1, SUPER_DEFENCE2, SUPER_DEFENCE3, SUPER_DEFENCE4); add(magicEssence, MAGIC_ESSENCE1, MAGIC_ESSENCE2, MAGIC_ESSENCE3, MAGIC_ESSENCE4); - add(combo(3, superAttackPot, superStrengthPot, superDefencePot), SUPER_COMBAT_POTION1, SUPER_COMBAT_POTION2, SUPER_COMBAT_POTION3, SUPER_COMBAT_POTION4); + add(combo(superAttackPot, superStrengthPot, superDefencePot), SUPER_COMBAT_POTION1, SUPER_COMBAT_POTION2, SUPER_COMBAT_POTION3, SUPER_COMBAT_POTION4); add(zamorakBrew, ZAMORAK_BREW1, ZAMORAK_BREW2, ZAMORAK_BREW3, ZAMORAK_BREW4); add(new SaradominBrew(0.15, 0.2, 0.1, 2, 2), SARADOMIN_BREW1, SARADOMIN_BREW2, SARADOMIN_BREW3, SARADOMIN_BREW4, SARADOMIN_BREW4_23575, SARADOMIN_BREW3_23577, SARADOMIN_BREW2_23579, SARADOMIN_BREW1_23581 /* LMS */); add(superRangingPot, SUPER_RANGING_1, SUPER_RANGING_2, SUPER_RANGING_3, SUPER_RANGING_4); add(superMagicPot, SUPER_MAGIC_POTION_1, SUPER_MAGIC_POTION_2, SUPER_MAGIC_POTION_3, SUPER_MAGIC_POTION_4); - add(combo(2, rangingPot, superDefencePot), BASTION_POTION1, BASTION_POTION2, BASTION_POTION3, BASTION_POTION4); - add(combo(2, magicPot, superDefencePot), BATTLEMAGE_POTION1, BATTLEMAGE_POTION2, BATTLEMAGE_POTION3, BATTLEMAGE_POTION4); + add(combo(rangingPot, superDefencePot), BASTION_POTION1, BASTION_POTION2, BASTION_POTION3, BASTION_POTION4); + add(combo(magicPot, superDefencePot), BATTLEMAGE_POTION1, BATTLEMAGE_POTION2, BATTLEMAGE_POTION3, BATTLEMAGE_POTION4); add(combo(magicPot, divinePot), DIVINE_MAGIC_POTION1, DIVINE_MAGIC_POTION2, DIVINE_MAGIC_POTION3, DIVINE_MAGIC_POTION4); add(combo(rangingPot, divinePot), DIVINE_RANGING_POTION1, DIVINE_RANGING_POTION2, DIVINE_RANGING_POTION3, DIVINE_RANGING_POTION4); add(combo(superAttackPot, divinePot), DIVINE_SUPER_ATTACK_POTION1, DIVINE_SUPER_ATTACK_POTION2, DIVINE_SUPER_ATTACK_POTION3, DIVINE_SUPER_ATTACK_POTION4); add(combo(superStrengthPot, divinePot), DIVINE_SUPER_STRENGTH_POTION1, DIVINE_SUPER_STRENGTH_POTION2, DIVINE_SUPER_STRENGTH_POTION3, DIVINE_SUPER_STRENGTH_POTION4); add(combo(superDefencePot, divinePot), DIVINE_SUPER_DEFENCE_POTION1, DIVINE_SUPER_DEFENCE_POTION2, DIVINE_SUPER_DEFENCE_POTION3, DIVINE_SUPER_DEFENCE_POTION4); - add(combo(3, superAttackPot, superStrengthPot, superDefencePot, divinePot), DIVINE_SUPER_COMBAT_POTION1, DIVINE_SUPER_COMBAT_POTION2, DIVINE_SUPER_COMBAT_POTION3, DIVINE_SUPER_COMBAT_POTION4); - add(combo(2, rangingPot, superDefencePot, divinePot), DIVINE_BASTION_POTION1, DIVINE_BASTION_POTION2, DIVINE_BASTION_POTION3, DIVINE_BASTION_POTION4); - add(combo(2, magicPot, superDefencePot, divinePot), DIVINE_BATTLEMAGE_POTION1, DIVINE_BATTLEMAGE_POTION2, DIVINE_BATTLEMAGE_POTION3, DIVINE_BATTLEMAGE_POTION4); - add(combo(5, superAttackPot, superStrengthPot, superDefencePot, rangingPot, imbuedHeart), + add(combo(superAttackPot, superStrengthPot, superDefencePot, divinePot), DIVINE_SUPER_COMBAT_POTION1, DIVINE_SUPER_COMBAT_POTION2, DIVINE_SUPER_COMBAT_POTION3, DIVINE_SUPER_COMBAT_POTION4); + add(combo(rangingPot, superDefencePot, divinePot), DIVINE_BASTION_POTION1, DIVINE_BASTION_POTION2, DIVINE_BASTION_POTION3, DIVINE_BASTION_POTION4); + add(combo(magicPot, superDefencePot, divinePot), DIVINE_BATTLEMAGE_POTION1, DIVINE_BATTLEMAGE_POTION2, DIVINE_BATTLEMAGE_POTION3, DIVINE_BATTLEMAGE_POTION4); + add(combo(superAttackPot, superStrengthPot, superDefencePot, rangingPot, imbuedHeart), CASTLEWARS_BREW4, CASTLEWARS_BREW3, CASTLEWARS_BREW2, CASTLEWARS_BREW1); - add(combo(2, superAttackPot, superStrengthPot), + add(combo(superAttackPot, superStrengthPot), SUPER_COMBAT_POTION4_23543, SUPER_COMBAT_POTION3_23545, SUPER_COMBAT_POTION2_23547, SUPER_COMBAT_POTION1_23549 /* LMS */); add(ancientBrew, ANCIENT_BREW1, ANCIENT_BREW2, ANCIENT_BREW3, ANCIENT_BREW4); @@ -234,16 +234,16 @@ public class ItemStatChanges add(new MixedPotion(6, ancientBrew), ANCIENT_MIX1, ANCIENT_MIX2); // Regular overload (NMZ) - add(combo(5, superAttackPot, superStrengthPot, superDefencePot, superRangingPot, superMagicPot, heal(HITPOINTS, -50)), OVERLOAD_1, OVERLOAD_2, OVERLOAD_3, OVERLOAD_4); + add(combo(superAttackPot, superStrengthPot, superDefencePot, superRangingPot, superMagicPot, heal(HITPOINTS, -50)), OVERLOAD_1, OVERLOAD_2, OVERLOAD_3, OVERLOAD_4); // Bandages (Castle Wars) add(new CastleWarsBandage(), BANDAGES); // Bandages (Theatre of Blood entry mode) - add(combo(8, food(20), heal(PRAYER, perc(0.25, 5)), heal(RUN_ENERGY, 20), boost(ATTACK, perc(0.15, 4)), boost(STRENGTH, perc(0.15, 4)), boost(DEFENCE, perc(0.15, 4)), rangingPot, magicPot), BANDAGES_25730); + add(combo(food(20), heal(PRAYER, perc(0.25, 5)), heal(RUN_ENERGY, 20), boost(ATTACK, perc(0.15, 4)), boost(STRENGTH, perc(0.15, 4)), boost(DEFENCE, perc(0.15, 4)), rangingPot, magicPot), BANDAGES_25730); // Recovery potions - final Effect restorePot = combo(5, heal(ATTACK, perc(.30, 10)), heal(STRENGTH, perc(.30, 10)), heal(DEFENCE, perc(.30, 10)), heal(RANGED, perc(.30, 10)), heal(MAGIC, perc(.30, 10))); + final Effect restorePot = combo(heal(ATTACK, perc(.30, 10)), heal(STRENGTH, perc(.30, 10)), heal(DEFENCE, perc(.30, 10)), heal(RANGED, perc(.30, 10)), heal(MAGIC, perc(.30, 10))); final Effect energyPot = heal(RUN_ENERGY, 10); final Effect prayerPot = new PrayerPotion(7); final Effect superEnergyPot = heal(RUN_ENERGY, 20); @@ -270,26 +270,26 @@ public class ItemStatChanges // Raids potions (+) final DeltaPercentage coxPlusPotionBoost = perc(.16, 6); - add(combo(5, boost(ATTACK, coxPlusPotionBoost), boost(STRENGTH, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost), boost(RANGED, coxPlusPotionBoost), boost(MAGIC, coxPlusPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20993, OVERLOAD_2_20994, OVERLOAD_3_20995, OVERLOAD_4_20996); - add(combo(3, boost(ATTACK, coxPlusPotionBoost), boost(STRENGTH, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), ELDER_1_20921, ELDER_2_20922, ELDER_3_20923, ELDER_4_20924); - add(combo(2, boost(RANGED, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), TWISTED_1_20933, TWISTED_2_20934, TWISTED_3_20935, TWISTED_4_20936); - add(combo(2, boost(MAGIC, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), KODAI_1_20945, KODAI_2_20946, KODAI_3_20947, KODAI_4_20948); + add(combo(boost(ATTACK, coxPlusPotionBoost), boost(STRENGTH, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost), boost(RANGED, coxPlusPotionBoost), boost(MAGIC, coxPlusPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20993, OVERLOAD_2_20994, OVERLOAD_3_20995, OVERLOAD_4_20996); + add(combo(boost(ATTACK, coxPlusPotionBoost), boost(STRENGTH, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), ELDER_1_20921, ELDER_2_20922, ELDER_3_20923, ELDER_4_20924); + add(combo(boost(RANGED, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), TWISTED_1_20933, TWISTED_2_20934, TWISTED_3_20935, TWISTED_4_20936); + add(combo(boost(MAGIC, coxPlusPotionBoost), boost(DEFENCE, coxPlusPotionBoost)), KODAI_1_20945, KODAI_2_20946, KODAI_3_20947, KODAI_4_20948); add(new SuperRestore(.30, 11), REVITALISATION_1_20957, REVITALISATION_2_20958, REVITALISATION_3_20959, REVITALISATION_4_20960); add(new SaradominBrew(0.15, 0.2, 0.1, 5, 4), XERICS_AID_1_20981, XERICS_AID_2_20982, XERICS_AID_3_20983, XERICS_AID_4_20984); // Raids potions final DeltaPercentage coxPotionBoost = perc(.13, 5); - add(combo(5, boost(ATTACK, coxPotionBoost), boost(STRENGTH, coxPotionBoost), boost(DEFENCE, coxPotionBoost), boost(RANGED, coxPotionBoost), boost(MAGIC, coxPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20989, OVERLOAD_2_20990, OVERLOAD_3_20991, OVERLOAD_4_20992); - add(combo(3, boost(ATTACK, coxPotionBoost), boost(STRENGTH, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), ELDER_POTION_1, ELDER_POTION_2, ELDER_POTION_3, ELDER_POTION_4); - add(combo(2, boost(RANGED, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), TWISTED_POTION_1, TWISTED_POTION_2, TWISTED_POTION_3, TWISTED_POTION_4); - add(combo(2, boost(MAGIC, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), KODAI_POTION_1, KODAI_POTION_2, KODAI_POTION_3, KODAI_POTION_4); + add(combo(boost(ATTACK, coxPotionBoost), boost(STRENGTH, coxPotionBoost), boost(DEFENCE, coxPotionBoost), boost(RANGED, coxPotionBoost), boost(MAGIC, coxPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20989, OVERLOAD_2_20990, OVERLOAD_3_20991, OVERLOAD_4_20992); + add(combo(boost(ATTACK, coxPotionBoost), boost(STRENGTH, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), ELDER_POTION_1, ELDER_POTION_2, ELDER_POTION_3, ELDER_POTION_4); + add(combo(boost(RANGED, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), TWISTED_POTION_1, TWISTED_POTION_2, TWISTED_POTION_3, TWISTED_POTION_4); + add(combo(boost(MAGIC, coxPotionBoost), boost(DEFENCE, coxPotionBoost)), KODAI_POTION_1, KODAI_POTION_2, KODAI_POTION_3, KODAI_POTION_4); // Raids potions (-) final DeltaPercentage coxMinusPotionBoost = perc(.10, 4); - add(combo(5, boost(ATTACK, coxMinusPotionBoost), boost(STRENGTH, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost), boost(RANGED, coxMinusPotionBoost), boost(MAGIC, coxMinusPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20985, OVERLOAD_2_20986, OVERLOAD_3_20987, OVERLOAD_4_20988); - add(combo(3, boost(ATTACK, coxMinusPotionBoost), boost(STRENGTH, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), ELDER_1, ELDER_2, ELDER_3, ELDER_4); - add(combo(3, boost(RANGED, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), TWISTED_1, TWISTED_2, TWISTED_3, TWISTED_4); - add(combo(3, boost(MAGIC, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), KODAI_1, KODAI_2, KODAI_3, KODAI_4); + add(combo(boost(ATTACK, coxMinusPotionBoost), boost(STRENGTH, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost), boost(RANGED, coxMinusPotionBoost), boost(MAGIC, coxMinusPotionBoost), heal(HITPOINTS, -50)), OVERLOAD_1_20985, OVERLOAD_2_20986, OVERLOAD_3_20987, OVERLOAD_4_20988); + add(combo(boost(ATTACK, coxMinusPotionBoost), boost(STRENGTH, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), ELDER_1, ELDER_2, ELDER_3, ELDER_4); + add(combo(boost(RANGED, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), TWISTED_1, TWISTED_2, TWISTED_3, TWISTED_4); + add(combo(boost(MAGIC, coxMinusPotionBoost), boost(DEFENCE, coxMinusPotionBoost)), KODAI_1, KODAI_2, KODAI_3, KODAI_4); // Skill potions final Effect agilityPot = boost(AGILITY, 3); @@ -298,7 +298,7 @@ public class ItemStatChanges add(agilityPot, AGILITY_POTION1, AGILITY_POTION2, AGILITY_POTION3, AGILITY_POTION4); add(fishingPot, FISHING_POTION1, FISHING_POTION2, FISHING_POTION3, FISHING_POTION4); add(hunterPot, HUNTER_POTION1, HUNTER_POTION2, HUNTER_POTION3, HUNTER_POTION4); - add(combo(2, boost(HITPOINTS, 5), heal(RUN_ENERGY, 5)), GUTHIX_REST1, GUTHIX_REST2, GUTHIX_REST3, GUTHIX_REST4); + add(combo(boost(HITPOINTS, 5), heal(RUN_ENERGY, 5)), GUTHIX_REST1, GUTHIX_REST2, GUTHIX_REST3, GUTHIX_REST4); // Mixed skill potions add(new MixedPotion(6, agilityPot), AGILITY_MIX1, AGILITY_MIX2); @@ -312,20 +312,20 @@ public class ItemStatChanges add(combo(food(12), heal(RUN_ENERGY, 50)), GOUT_TUBER); // Pies - add(combo(2, heal(HITPOINTS, 6), boost(FARMING, 3)), GARDEN_PIE, HALF_A_GARDEN_PIE); - add(combo(2, heal(HITPOINTS, 6), boost(FISHING, 3)), FISH_PIE, HALF_A_FISH_PIE); - add(combo(2, heal(HITPOINTS, 7), boost(HERBLORE, 4)), BOTANICAL_PIE, HALF_A_BOTANICAL_PIE); - add(combo(2, heal(HITPOINTS, 8), boost(CRAFTING, 4)), MUSHROOM_PIE, HALF_A_MUSHROOM_PIE); - add(combo(2, heal(HITPOINTS, 8), boost(FISHING, 5)), ADMIRAL_PIE, HALF_AN_ADMIRAL_PIE); - add(combo(2, heal(HITPOINTS, 11), boost(SLAYER, 5), boost(RANGED, 4)), WILD_PIE, HALF_A_WILD_PIE); - add(combo(2, heal(HITPOINTS, 11), boost(AGILITY, 5), heal(RUN_ENERGY, 10)), SUMMER_PIE, HALF_A_SUMMER_PIE); - add(combo(2, heal(HITPOINTS, 10), boost(FLETCHING, 4)), DRAGONFRUIT_PIE, HALF_A_DRAGONFRUIT_PIE); + add(combo(heal(HITPOINTS, 6), boost(FARMING, 3)), GARDEN_PIE, HALF_A_GARDEN_PIE); + add(combo(heal(HITPOINTS, 6), boost(FISHING, 3)), FISH_PIE, HALF_A_FISH_PIE); + add(combo(heal(HITPOINTS, 7), boost(HERBLORE, 4)), BOTANICAL_PIE, HALF_A_BOTANICAL_PIE); + add(combo(heal(HITPOINTS, 8), boost(CRAFTING, 4)), MUSHROOM_PIE, HALF_A_MUSHROOM_PIE); + add(combo(heal(HITPOINTS, 8), boost(FISHING, 5)), ADMIRAL_PIE, HALF_AN_ADMIRAL_PIE); + add(combo(heal(HITPOINTS, 11), boost(SLAYER, 5), boost(RANGED, 4)), WILD_PIE, HALF_A_WILD_PIE); + add(combo(heal(HITPOINTS, 11), boost(AGILITY, 5), heal(RUN_ENERGY, 10)), SUMMER_PIE, HALF_A_SUMMER_PIE); + add(combo(heal(HITPOINTS, 10), boost(FLETCHING, 4)), DRAGONFRUIT_PIE, HALF_A_DRAGONFRUIT_PIE); // Other add(combo(range(food(1), food(3)), heal(RUN_ENERGY, 10)), PURPLE_SWEETS_10476); add(new SpicyStew(), SPICY_STEW); add(imbuedHeart, IMBUED_HEART); - add(combo(boost(ATTACK, 2), boost(STRENGTH, 1), heal(PRAYER, 1), heal(DEFENCE, -1)), JANGERBERRIES); + add(combo(boost(STRENGTH, 1), heal(PRAYER, 1), heal(DEFENCE, -1)), JANGERBERRIES); add(new CaveNightshade(), CAVE_NIGHTSHADE); // Gauntlet items @@ -334,8 +334,8 @@ public class ItemStatChanges add(new GauntletPotion(), EGNIOL_POTION_1, EGNIOL_POTION_2, EGNIOL_POTION_3, EGNIOL_POTION_4); // Soul Wars - add(combo(2, heal(HITPOINTS, perc(.15, 1)), heal(RUN_ENERGY, 100)), BANDAGES_25202); - add(combo(6, boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5)), boost(RANGED, perc(.15, 5)), boost(MAGIC, perc(.15, 5)), heal(PRAYER, perc(.25, 8))), POTION_OF_POWER1, POTION_OF_POWER2, POTION_OF_POWER3, POTION_OF_POWER4); + add(combo(heal(HITPOINTS, perc(.15, 1)), heal(RUN_ENERGY, 100)), BANDAGES_25202); + add(combo(boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5)), boost(RANGED, perc(.15, 5)), boost(MAGIC, perc(.15, 5)), heal(PRAYER, perc(.25, 8))), POTION_OF_POWER1, POTION_OF_POWER2, POTION_OF_POWER3, POTION_OF_POWER4); log.debug("{} items; {} behaviours loaded", effects.size(), new HashSet<>(effects.values()).size()); } From a830bc5572cd07e2f97df90ffb802a9f90f04545 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Thu, 26 May 2022 11:25:29 -0700 Subject: [PATCH 07/17] item stats: Fix jangerberries stats --- .../net/runelite/client/plugins/itemstats/ItemStatChanges.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java index ef0cc5708d..dd322cd3fc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java @@ -325,7 +325,7 @@ public class ItemStatChanges add(combo(range(food(1), food(3)), heal(RUN_ENERGY, 10)), PURPLE_SWEETS_10476); add(new SpicyStew(), SPICY_STEW); add(imbuedHeart, IMBUED_HEART); - add(combo(boost(STRENGTH, 1), heal(PRAYER, 1), heal(DEFENCE, -1)), JANGERBERRIES); + add(combo(boost(ATTACK, 2), boost(STRENGTH, 1), heal(PRAYER, 1), heal(DEFENCE, -1)), JANGERBERRIES); add(new CaveNightshade(), CAVE_NIGHTSHADE); // Gauntlet items From 88e39ab152dacf86457a51b84e6590e652fc93d4 Mon Sep 17 00:00:00 2001 From: superiorser9 <58041466+superiorser9@users.noreply.github.com> Date: Thu, 26 May 2022 23:33:10 +0100 Subject: [PATCH 08/17] timers: Track home and minigame teleports using vars (#14842) --- .../main/java/net/runelite/api/VarPlayer.java | 10 +++ .../client/plugins/timers/TeleportWidget.java | 68 -------------- .../client/plugins/timers/TimersPlugin.java | 89 +++++++++++++------ 3 files changed, 70 insertions(+), 97 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/timers/TeleportWidget.java diff --git a/runelite-api/src/main/java/net/runelite/api/VarPlayer.java b/runelite-api/src/main/java/net/runelite/api/VarPlayer.java index 6868dcd7c3..ce6ff390f7 100644 --- a/runelite-api/src/main/java/net/runelite/api/VarPlayer.java +++ b/runelite-api/src/main/java/net/runelite/api/VarPlayer.java @@ -221,6 +221,16 @@ public enum VarPlayer SETTINGS_TRANSPARENT_CHAT_TRADE_REQUEST(3006), SETTINGS_TRANSPARENT_CHAT_CHALLENGE_REQUEST(3007), + /** + * The difference, measured in minutes, between the time home teleport spell was last used and midnight, January 1, 1970 UTC. + */ + LAST_HOME_TELEPORT(892), + + /** + * The difference, measured in minutes, between the time minigame teleport was last used and midnight, January 1, 1970 UTC. + */ + LAST_MINIGAME_TELEPORT(888), + ; private final int id; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TeleportWidget.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TeleportWidget.java deleted file mode 100644 index 762d1d19be..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TeleportWidget.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018, Jordan Atwood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.timers; - -import com.google.common.collect.ImmutableList; -import java.util.Collection; -import javax.annotation.Nullable; -import net.runelite.api.widgets.WidgetInfo; - -enum TeleportWidget -{ - HOME_TELEPORT, - MINIGAME_TELEPORT, - TRAILBLAZER_AREA_TELEPORT, - ; - - private static final Collection HOME_TELEPORT_IDS = ImmutableList.of( - WidgetInfo.SPELL_LUMBRIDGE_HOME_TELEPORT.getId(), - WidgetInfo.SPELL_EDGEVILLE_HOME_TELEPORT.getId(), - WidgetInfo.SPELL_LUNAR_HOME_TELEPORT.getId(), - WidgetInfo.SPELL_ARCEUUS_HOME_TELEPORT.getId(), - WidgetInfo.SPELL_KOUREND_HOME_TELEPORT.getId(), - WidgetInfo.SPELL_CATHERBY_HOME_TELEPORT.getId() - ); - private static final Collection MINIGAME_TELEPORT_IDS = ImmutableList.of( - WidgetInfo.MINIGAME_TELEPORT_BUTTON.getId() - ); - - @Nullable - static TeleportWidget of(int widgetId) - { - if (HOME_TELEPORT_IDS.contains(widgetId)) - { - return HOME_TELEPORT; - } - else if (MINIGAME_TELEPORT_IDS.contains(widgetId)) - { - return MINIGAME_TELEPORT; - } - else if (widgetId == WidgetInfo.TRAILBLAZER_AREA_TELEPORT.getId()) - { - return TRAILBLAZER_AREA_TELEPORT; - } - return null; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java index d3dbcad8af..57da5b9b95 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java @@ -29,6 +29,7 @@ package net.runelite.client.plugins.timers; import com.google.inject.Provides; import java.time.Duration; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; @@ -45,7 +46,6 @@ import net.runelite.api.ItemContainer; import net.runelite.api.ItemID; import static net.runelite.api.ItemID.FIRE_CAPE; import static net.runelite.api.ItemID.INFERNAL_CAPE; -import net.runelite.api.MenuAction; import net.runelite.api.NPC; import net.runelite.api.NpcID; import net.runelite.api.Player; @@ -152,11 +152,12 @@ public class TimersPlugin extends Plugin private int lastPoisonVarp; private int lastPvpVarb; private int lastCorruptionVarb; + private int lastHomeTeleport; + private int lastMinigameTeleport; private int lastImbuedHeartVarb; private boolean imbuedHeartTimerActive; private int nextPoisonTick; private WorldPoint lastPoint; - private TeleportWidget lastTeleportClicked; private int lastAnimation; private boolean widgetHiddenChangedOnPvpWorld; private ElapsedTimer tzhaarTimer; @@ -185,6 +186,11 @@ public class TimersPlugin extends Plugin @Override public void startUp() { + if (config.showHomeMinigameTeleports()) + { + checkTeleport(VarPlayer.LAST_HOME_TELEPORT); + checkTeleport(VarPlayer.LAST_MINIGAME_TELEPORT); + } } @Override @@ -193,7 +199,6 @@ public class TimersPlugin extends Plugin infoBoxManager.removeIf(t -> t instanceof TimerTimer); lastRaidVarb = -1; lastPoint = null; - lastTeleportClicked = null; lastAnimation = -1; widgetHiddenChangedOnPvpWorld = false; lastPoisonVarp = 0; @@ -202,6 +207,8 @@ public class TimersPlugin extends Plugin staminaTimer = null; imbuedHeartTimerActive = false; lastImbuedHeartVarb = 0; + lastHomeTeleport = 0; + lastMinigameTeleport = 0; } @Subscribe @@ -214,6 +221,8 @@ public class TimersPlugin extends Plugin int pvpVarb = client.getVarbitValue(Varbits.PVP_SPEC_ORB); int corruptionCooldownVarb = client.getVarbitValue(Varbits.CORRUPTION_COOLDOWN); int imbuedHeartCooldownVarb = client.getVarbitValue(Varbits.IMBUED_HEART_COOLDOWN); + int homeTeleportVarp = client.getVar(VarPlayer.LAST_HOME_TELEPORT); + int minigameTeleportVarp = client.getVar(VarPlayer.LAST_MINIGAME_TELEPORT); if (lastRaidVarb != raidVarb) { @@ -320,6 +329,18 @@ public class TimersPlugin extends Plugin lastImbuedHeartVarb = imbuedHeartCooldownVarb; } + + if (lastHomeTeleport != homeTeleportVarp) + { + checkTeleport(VarPlayer.LAST_HOME_TELEPORT); + lastHomeTeleport = homeTeleportVarp; + } + + if (lastMinigameTeleport != minigameTeleportVarp) + { + checkTeleport(VarPlayer.LAST_MINIGAME_TELEPORT); + lastMinigameTeleport = minigameTeleportVarp; + } } @Subscribe @@ -335,6 +356,11 @@ public class TimersPlugin extends Plugin removeGameTimer(HOME_TELEPORT); removeGameTimer(MINIGAME_TELEPORT); } + else + { + checkTeleport(VarPlayer.LAST_HOME_TELEPORT); + checkTeleport(VarPlayer.LAST_MINIGAME_TELEPORT); + } if (!config.showAntiFire()) { @@ -491,15 +517,6 @@ public class TimersPlugin extends Plugin return; } } - - if (event.getMenuAction() == MenuAction.CC_OP) - { - TeleportWidget teleportWidget = TeleportWidget.of(event.getParam1()); - if (teleportWidget != null) - { - lastTeleportClicked = teleportWidget; - } - } } @Subscribe @@ -877,6 +894,37 @@ public class TimersPlugin extends Plugin } } + private void checkTeleport(VarPlayer varPlayer) + { + final GameTimer teleport; + switch (varPlayer) + { + case LAST_HOME_TELEPORT: + teleport = HOME_TELEPORT; + break; + case LAST_MINIGAME_TELEPORT: + teleport = MINIGAME_TELEPORT; + break; + default: + // Other var changes are not handled as teleports + return; + } + + int lastTeleport = client.getVar(varPlayer); + long lastTeleportSeconds = (long) lastTeleport * 60; + Instant teleportExpireInstant = Instant.ofEpochSecond(lastTeleportSeconds).plus(teleport.getDuration().getSeconds(), ChronoUnit.SECONDS); + Duration remainingTime = Duration.between(Instant.now(), teleportExpireInstant); + + if (remainingTime.getSeconds() > 0) + { + createGameTimer(teleport, remainingTime); + } + else + { + removeGameTimer(teleport); + } + } + @Subscribe public void onGameTick(GameTick event) { @@ -956,23 +1004,6 @@ public class TimersPlugin extends Plugin return; } - if (config.showHomeMinigameTeleports() - && client.getLocalPlayer().getAnimation() == AnimationID.IDLE - && (lastAnimation == AnimationID.BOOK_HOME_TELEPORT_5 - || lastAnimation == AnimationID.COW_HOME_TELEPORT_6 - || lastAnimation == AnimationID.LEAGUE_HOME_TELEPORT_6 - || lastAnimation == AnimationID.SHATTERED_LEAGUE_HOME_TELEPORT_6)) - { - if (lastTeleportClicked == TeleportWidget.HOME_TELEPORT) - { - createGameTimer(HOME_TELEPORT); - } - else if (lastTeleportClicked == TeleportWidget.MINIGAME_TELEPORT) - { - createGameTimer(MINIGAME_TELEPORT); - } - } - if (config.showDFSSpecial() && lastAnimation == AnimationID.DRAGONFIRE_SHIELD_SPECIAL) { createGameTimer(DRAGON_FIRE_SHIELD); From c7ea7a7e145467b0c50a619e10fbcbbcd105f0db Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Thu, 26 May 2022 15:21:55 -0700 Subject: [PATCH 09/17] status bars: Override hitpoints and prayer max values in LMS While playing Last Man Standing, your hitpoints and prayer values behave as though their maximum values were 99 instead of their actual max values. --- .../client/plugins/statusbars/StatusBarsOverlay.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsOverlay.java index e414b794d4..2b68c49eb5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsOverlay.java @@ -34,6 +34,7 @@ import java.util.EnumMap; import java.util.Map; import javax.inject.Inject; import net.runelite.api.Client; +import net.runelite.api.Experience; import net.runelite.api.MenuEntry; import net.runelite.api.Point; import net.runelite.api.Prayer; @@ -117,7 +118,7 @@ class StatusBarsOverlay extends Overlay { barRenderers.put(BarMode.DISABLED, null); barRenderers.put(BarMode.HITPOINTS, new BarRenderer( - () -> client.getRealSkillLevel(Skill.HITPOINTS), + () -> inLms() ? Experience.MAX_REAL_LEVEL : client.getRealSkillLevel(Skill.HITPOINTS), () -> client.getBoostedSkillLevel(Skill.HITPOINTS), () -> getRestoreValue(Skill.HITPOINTS.getName()), () -> @@ -170,7 +171,7 @@ class StatusBarsOverlay extends Overlay } )); barRenderers.put(BarMode.PRAYER, new BarRenderer( - () -> client.getRealSkillLevel(Skill.PRAYER), + () -> inLms() ? Experience.MAX_REAL_LEVEL : client.getRealSkillLevel(Skill.PRAYER), () -> client.getBoostedSkillLevel(Skill.PRAYER), () -> getRestoreValue(Skill.PRAYER.getName()), () -> @@ -349,4 +350,9 @@ class StatusBarsOverlay extends Overlay return ImageUtil.resizeCanvas(image, ICON_DIMENSIONS.width, ICON_DIMENSIONS.height); } + + private boolean inLms() + { + return client.getWidget(WidgetInfo.LMS_KDA) != null; + } } From 66f6dade342d0673507204604973a1d4e3d22e57 Mon Sep 17 00:00:00 2001 From: vmarlowe <77749581+vmarlowe@users.noreply.github.com> Date: Thu, 26 May 2022 18:48:40 -0400 Subject: [PATCH 10/17] fishing: Add frog spawn spot NPC (#14659) --- .../src/main/java/net/runelite/client/game/FishingSpot.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/game/FishingSpot.java b/runelite-client/src/main/java/net/runelite/client/game/FishingSpot.java index 6ab929d173..7fcb4fbf7a 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/FishingSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/game/FishingSpot.java @@ -94,8 +94,8 @@ public enum FishingSpot SACRED_EEL("Sacred eel", ItemID.SACRED_EEL, FISHING_SPOT_6488 ), - CAVE_EEL("Cave eel", ItemID.RAW_CAVE_EEL, - FISHING_SPOT_1497, FISHING_SPOT_1498, FISHING_SPOT_1499 + CAVE_EEL("Frog spawn, Cave eel", ItemID.RAW_CAVE_EEL, + FISHING_SPOT_1497, FISHING_SPOT_1498, FISHING_SPOT_1499, FISHING_SPOT_1500 ), SLIMY_EEL("Slimy eel", ItemID.RAW_SLIMY_EEL, FISHING_SPOT_2653, FISHING_SPOT_2654, FISHING_SPOT_2655 From ff210a6b4287bcc5276e7647725c4c363d9a146a Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 23 May 2022 22:43:30 -0400 Subject: [PATCH 11/17] party: remove Discord requirement Orginally the only way to form a party was via Discord invites. This has changed semi-recently to allow sharing party ids instead. The Discord invite system is finnicky since it doesn't work unless Discord is detected, doesn't work right with multiple clients, or multiple Discords. And, discord_rpc is deprecated without a suitable replacement. This changes the party system to instead always require sharing party ids instead. --- .../client/plugins/discord/DiscordPlugin.java | 78 ++------- .../client/plugins/discord/DiscordState.java | 46 +---- .../plugins/discord/DiscordUserInfo.java | 2 + .../plugins/dpscounter/DpsCounterPlugin.java | 4 +- .../client/plugins/party/PartyConfig.java | 22 --- .../client/plugins/party/PartyMemberBox.java | 32 ++-- .../client/plugins/party/PartyPanel.java | 29 ---- .../client/plugins/party/PartyPlugin.java | 162 +++--------------- .../client/plugins/party/PartyRequestBox.java | 111 ------------ .../plugins/party/PartyStatsOverlay.java | 12 +- .../plugins/party/PartyWorldMapPoint.java | 13 +- .../client/plugins/party/data/PartyData.java | 3 +- .../specialcounter/SpecialCounterPlugin.java | 2 +- .../net/runelite/client/ws/PartyMember.java | 2 + .../net/runelite/client/ws/PartyService.java | 37 ++-- 15 files changed, 84 insertions(+), 471 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyRequestBox.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java index 031ba10941..58cf1cad70 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java @@ -37,7 +37,6 @@ import java.time.temporal.ChronoUnit; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; -import java.util.UUID; import javax.imageio.ImageIO; import javax.inject.Named; import lombok.extern.slf4j.Slf4j; @@ -50,11 +49,8 @@ import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.StatChanged; import net.runelite.client.config.ConfigManager; import net.runelite.client.discord.DiscordService; -import net.runelite.client.discord.events.DiscordJoinGame; -import net.runelite.client.discord.events.DiscordReady; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; -import net.runelite.client.events.PartyChanged; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.task.Schedule; @@ -65,8 +61,7 @@ import net.runelite.client.util.LinkBrowser; import net.runelite.client.ws.PartyMember; import net.runelite.client.ws.PartyService; import net.runelite.client.ws.WSClient; -import net.runelite.http.api.ws.messages.party.UserJoin; -import net.runelite.http.api.ws.messages.party.UserPart; +import net.runelite.discord.DiscordUser; import net.runelite.http.api.ws.messages.party.UserSync; import okhttp3.Call; import okhttp3.Callback; @@ -137,11 +132,6 @@ public class DiscordPlugin extends Plugin checkForGameStateUpdate(); checkForAreaUpdate(); - if (discordService.getCurrentUser() != null) - { - partyService.setUsername(discordService.getCurrentUser().username + "#" + discordService.getCurrentUser().discriminator); - } - wsClient.registerMessage(DiscordUserInfo.class); } @@ -150,7 +140,6 @@ public class DiscordPlugin extends Plugin { clientToolbar.removeNavigation(discordButton); resetState(); - partyService.changeParty(null); wsClient.unregisterMessage(DiscordUserInfo.class); } @@ -209,30 +198,9 @@ public class DiscordPlugin extends Plugin } } - @Subscribe - public void onDiscordReady(DiscordReady event) - { - partyService.setUsername(event.getUsername() + "#" + event.getDiscriminator()); - } - - @Subscribe - public void onDiscordJoinGame(DiscordJoinGame joinGame) - { - UUID partyId = UUID.fromString(joinGame.getJoinSecret()); - partyService.changeParty(partyId); - updatePresence(); - } - @Subscribe public void onDiscordUserInfo(final DiscordUserInfo event) { - final PartyMember memberById = partyService.getMemberById(event.getMemberId()); - - if (memberById == null || memberById.getAvatar() != null) - { - return; - } - final CharMatcher matcher = CharMatcher.anyOf("abcdef0123456789"); // animated avatars contain a_ as prefix so we need to get rid of that first to check against matcher @@ -246,13 +214,7 @@ public class DiscordPlugin extends Plugin if (Strings.isNullOrEmpty(event.getAvatarId())) { - final String[] split = memberById.getName().split("#", 2); - if (split.length != 2) - { - return; - } - - int disc = Integer.parseInt(split[1]); + int disc = Integer.parseInt(event.getDiscriminator()); int avatarId = disc % 5; url = "https://cdn.discordapp.com/embed/avatars/" + avatarId + ".png"; } @@ -292,7 +254,7 @@ public class DiscordPlugin extends Plugin image = ImageIO.read(inputStream); } - partyService.setPartyMemberAvatar(memberById.getMemberId(), image); + partyService.setPartyMemberAvatar(event.getMemberId(), image); } finally { @@ -302,12 +264,6 @@ public class DiscordPlugin extends Plugin }); } - @Subscribe - public void onUserJoin(final UserJoin event) - { - updatePresence(); - } - @Subscribe public void onUserSync(final UserSync event) { @@ -315,30 +271,21 @@ public class DiscordPlugin extends Plugin if (localMember != null) { - if (discordService.getCurrentUser() != null) + final DiscordUser discordUser = discordService.getCurrentUser(); + if (discordUser != null) { final DiscordUserInfo userInfo = new DiscordUserInfo( - discordService.getCurrentUser().userId, - discordService.getCurrentUser().avatar); - + discordUser.userId, + discordUser.username, + discordUser.discriminator, + discordUser.avatar + ); userInfo.setMemberId(localMember.getMemberId()); wsClient.send(userInfo); } } } - @Subscribe - public void onUserPart(final UserPart event) - { - updatePresence(); - } - - @Subscribe - public void onPartyChanged(final PartyChanged event) - { - updatePresence(); - } - @Schedule( period = 1, unit = ChronoUnit.MINUTES @@ -348,11 +295,6 @@ public class DiscordPlugin extends Plugin discordState.checkForTimeout(); } - private void updatePresence() - { - discordState.refresh(); - } - private void resetState() { discordState.reset(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordState.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordState.java index 0fc41574cb..e2740e3c5e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordState.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordState.java @@ -38,8 +38,6 @@ import javax.inject.Named; import lombok.Data; import net.runelite.client.discord.DiscordPresence; import net.runelite.client.discord.DiscordService; -import net.runelite.client.ws.PartyService; -import static net.runelite.client.ws.PartyService.PARTY_MAX; /** * This class contains data about currently active discord state. @@ -57,7 +55,6 @@ class DiscordState private final List events = new ArrayList<>(); private final DiscordService discordService; private final DiscordConfig config; - private final PartyService party; private final String runeliteTitle; private final String runeliteVersion; private DiscordPresence lastPresence; @@ -66,14 +63,12 @@ class DiscordState private DiscordState( final DiscordService discordService, final DiscordConfig config, - final PartyService party, @Named("runelite.title") final String runeliteTitle, @Named("runelite.version") final String runeliteVersion ) { this.discordService = discordService; this.config = config; - this.party = party; this.runeliteTitle = runeliteTitle; this.runeliteVersion = runeliteVersion; } @@ -88,30 +83,6 @@ class DiscordState lastPresence = null; } - /** - * Force refresh discord presence - */ - void refresh() - { - if (lastPresence == null) - { - return; - } - - final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder() - .state(lastPresence.getState()) - .details(lastPresence.getDetails()) - .largeImageText(lastPresence.getLargeImageText()) - .startTimestamp(lastPresence.getStartTimestamp()) - .smallImageKey(lastPresence.getSmallImageKey()) - .partyMax(lastPresence.getPartyMax()); - - - setPresencePartyInfo(presenceBuilder); - - discordService.updatePresence(presenceBuilder.build()); - } - /** * Trigger new discord state update. * @@ -197,8 +168,7 @@ class DiscordState .state(MoreObjects.firstNonNull(state, "")) .details(MoreObjects.firstNonNull(details, "")) .largeImageText(runeliteTitle + " v" + versionShortHand) - .smallImageKey(imageKey) - .partyMax(PARTY_MAX); + .smallImageKey(imageKey); final Instant startTime; switch (config.elapsedTimeType()) @@ -225,8 +195,6 @@ class DiscordState presenceBuilder.startTimestamp(startTime); - setPresencePartyInfo(presenceBuilder); - final DiscordPresence presence = presenceBuilder.build(); // This is to reduce amount of RPC calls @@ -263,16 +231,4 @@ class DiscordState updatePresenceWithLatestEvent(); } } - - private void setPresencePartyInfo(DiscordPresence.DiscordPresenceBuilder presenceBuilder) - { - if (party.isInParty()) - { - presenceBuilder.partySize(party.getMembers().size()); - - // Set public party id and secret - presenceBuilder.partyId(party.getPublicPartyId().toString()); - presenceBuilder.joinSecret(party.getPartyId().toString()); - } - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordUserInfo.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordUserInfo.java index 360d58652e..1f96e67051 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordUserInfo.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordUserInfo.java @@ -33,5 +33,7 @@ import net.runelite.http.api.ws.messages.party.PartyMemberMessage; class DiscordUserInfo extends PartyMemberMessage { private final String userId; + private final String username; + private final String discriminator; private final String avatarId; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java index d158b151a7..ecd962ce85 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java @@ -208,7 +208,7 @@ public class DpsCounterPlugin extends Plugin } // If not in a party, user local player name - final String name = localMember == null ? player.getName() : localMember.getName(); + final String name = localMember == null ? player.getName() : localMember.getDisplayName(); DpsMember dpsMember = members.computeIfAbsent(name, DpsMember::new); dpsMember.addDamage(hit); @@ -240,7 +240,7 @@ public class DpsCounterPlugin extends Plugin return; } - String name = partyService.getMemberById(dpsUpdate.getMemberId()).getName(); + String name = partyService.getMemberById(dpsUpdate.getMemberId()).getDisplayName(); if (name == null) { return; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java index 4d484f4cdc..885f25b80d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java @@ -56,17 +56,6 @@ public interface PartyConfig extends Config return true; } - @ConfigItem( - keyName = "messages", - name = "Join messages", - description = "Enables members join/leave game messages", - position = 3 - ) - default boolean messages() - { - return true; - } - @ConfigItem( keyName = "recolorNames", name = "Recolor names", @@ -85,17 +74,6 @@ public interface PartyConfig extends Config position = 5 ) default boolean autoOverlay() - { - return true; - } - - @ConfigItem( - keyName = "includeSelf", - name = "Include yourself", - description = "Shows yourself in the panel as part of the party", - position = 6 - ) - default boolean includeSelf() { return false; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyMemberBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyMemberBox.java index 7b3839b406..04bea7d2d6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyMemberBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyMemberBox.java @@ -40,6 +40,7 @@ import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import lombok.AccessLevel; import lombok.Getter; +import net.runelite.client.ws.PartyMember; import net.runelite.client.plugins.party.data.PartyData; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.DynamicGridLayout; @@ -61,9 +62,7 @@ class PartyMemberBox extends JPanel private final ProgressBar hpBar = new ProgressBar(); private final ProgressBar prayerBar = new ProgressBar(); - private final JLabel topName = new JLabel(); - private final JLabel bottomName = new JLabel(); - + private final JLabel name = new JLabel(); private final JLabel avatar = new JLabel(); private final PartyConfig config; @@ -113,14 +112,10 @@ class PartyMemberBox extends JPanel namesPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); namesPanel.setBorder(new EmptyBorder(2, 5, 2, 5)); - topName.setFont(FontManager.getRunescapeSmallFont()); - bottomName.setFont(FontManager.getRunescapeSmallFont()); + name.setFont(FontManager.getRunescapeSmallFont()); + name.putClientProperty("html.disable", Boolean.TRUE); - topName.putClientProperty("html.disable", Boolean.TRUE); - bottomName.putClientProperty("html.disable", Boolean.TRUE); - - namesPanel.add(topName); // top - namesPanel.add(bottomName); // bottom + namesPanel.add(name); headerPanel.add(avatar, BorderLayout.WEST); headerPanel.add(namesPanel, BorderLayout.CENTER); @@ -155,10 +150,12 @@ class PartyMemberBox extends JPanel void update() { + final PartyMember member = memberPartyData.getMember(); + // Avatar - if (!avatarSet && memberPartyData.getMember().getAvatar() != null) + if (!avatarSet && member.getAvatar() != null) { - ImageIcon icon = new ImageIcon(ImageUtil.resizeImage(memberPartyData.getMember().getAvatar(), 32, 32)); + ImageIcon icon = new ImageIcon(ImageUtil.resizeImage(member.getAvatar(), 32, 32)); icon.getImage().flush(); avatar.setIcon(icon); @@ -174,15 +171,12 @@ class PartyMemberBox extends JPanel prayerBar.setMaximumValue(memberPartyData.getMaxPrayer()); prayerBar.setCenterLabel(progressBarLabel(memberPartyData.getPrayer(), memberPartyData.getMaxPrayer())); - // Update name labels + // Update name label Color playerColor = config.recolorNames() ? memberPartyData.getColor() : Color.WHITE; - boolean isLoggedIn = !memberPartyData.getCharacterName().isEmpty(); + boolean isLoggedIn = member.isLoggedIn(); - topName.setForeground(playerColor); - topName.setText(memberPartyData.getMember().getName()); - - bottomName.setForeground(isLoggedIn ? playerColor : Color.GRAY); - bottomName.setText(isLoggedIn ? memberPartyData.getCharacterName() : "Logged out"); + name.setForeground(isLoggedIn ? playerColor : Color.GRAY); + name.setText(member.getDisplayName()); } private static String progressBarLabel(int current, int max) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPanel.java index 52d4799e95..590424eaf8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPanel.java @@ -57,7 +57,6 @@ class PartyPanel extends PluginPanel private final PartyService party; private final PartyConfig config; - private final Map requestBoxes = new HashMap<>(); private final Map memberBoxes = new HashMap<>(); private final JButton startButton = new JButton(); @@ -68,7 +67,6 @@ class PartyPanel extends PluginPanel private final PluginErrorPanel noPartyPanel = new PluginErrorPanel(); private final PluginErrorPanel partyEmptyPanel = new PluginErrorPanel(); private final JComponent memberBoxPanel = new DragAndDropReorderPane(); - private final JComponent requestBoxPanel = new DragAndDropReorderPane(); @Inject PartyPanel(final PartyPlugin plugin, final PartyConfig config, final PartyService party) @@ -113,7 +111,6 @@ class PartyPanel extends PluginPanel topPanel.add(rejoinPartyButton, c); layoutPanel.add(topPanel); - layoutPanel.add(requestBoxPanel); layoutPanel.add(memberBoxPanel); startButton.setText(party.isInParty() ? BTN_LEAVE_TEXT : BTN_CREATE_TEXT); @@ -280,30 +277,4 @@ class PartyPanel extends PluginPanel { memberBoxes.forEach((key, value) -> value.update()); } - - void addRequest(String userId, String userName) - { - PartyRequestBox partyRequestBox = new PartyRequestBox(plugin, requestBoxPanel, userId, userName); - requestBoxes.put(userId, partyRequestBox); - requestBoxPanel.add(partyRequestBox); - requestBoxPanel.revalidate(); - } - - void removeAllRequests() - { - requestBoxes.forEach((key, value) -> requestBoxPanel.remove(value)); - requestBoxPanel.revalidate(); - requestBoxes.clear(); - } - - void removeRequest(String userId) - { - final PartyRequestBox requestBox = requestBoxes.remove(userId); - - if (requestBox != null) - { - requestBoxPanel.remove(requestBox); - requestBoxPanel.revalidate(); - } - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java index ae13a4a22f..c833be1e98 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java @@ -58,13 +58,9 @@ import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.MenuOptionClicked; import net.runelite.client.callback.ClientThread; -import net.runelite.client.chat.ChatColorType; -import net.runelite.client.chat.ChatMessageBuilder; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.ConfigManager; -import net.runelite.client.discord.DiscordService; -import net.runelite.client.discord.events.DiscordJoinRequest; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; import net.runelite.client.events.OverlayMenuClicked; @@ -138,9 +134,6 @@ public class PartyPlugin extends Plugin @Inject private ClientToolbar clientToolbar; - @Inject - private DiscordService discordService; - @Inject @Named("developerMode") boolean developerMode; @@ -157,7 +150,6 @@ public class PartyPlugin extends Plugin private int lastHp, lastPray; private String lastCharacterName = ""; private WorldPoint lastLocation; - private boolean sendAlert; @Override public void configure(Binder binder) @@ -207,7 +199,6 @@ public class PartyPlugin extends Plugin wsClient.unregisterMessage(TilePing.class); wsClient.unregisterMessage(LocationUpdate.class); wsClient.unregisterMessage(CharacterNameUpdate.class); - sendAlert = false; lastLocation = null; } @@ -231,21 +222,6 @@ public class PartyPlugin extends Plugin void leaveParty() { party.changeParty(null); - - if (!config.messages()) - { - return; - } - - final String leaveMessage = new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append("You have left the party.") - .build(); - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(leaveMessage) - .build()); } @Subscribe @@ -253,22 +229,6 @@ public class PartyPlugin extends Plugin { if (event.getGroup().equals(PartyConfig.GROUP)) { - final PartyMember localMember = party.getLocalMember(); - - if (localMember != null) - { - if (config.includeSelf()) - { - final PartyData partyData = getPartyData(localMember.getMemberId()); - assert partyData != null; - SwingUtilities.invokeLater(() -> panel.addMember(partyData)); - } - else - { - SwingUtilities.invokeLater(() -> panel.removeMember(localMember.getMemberId())); - } - } - // rebuild the panel in the event the "Recolor names" option changes SwingUtilities.invokeLater(panel::updateAll); } @@ -314,35 +274,12 @@ public class PartyPlugin extends Plugin wsClient.send(tilePing); } - @Subscribe - public void onDiscordJoinRequest(DiscordJoinRequest request) - { - final String requestMessage = new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append("New join request received. Check your Party panel.") - .build(); - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(requestMessage) - .build()); - - String userName = request.getUsername() + "#" + request.getDiscriminator(); - SwingUtilities.invokeLater(() -> panel.addRequest(request.getUserId(), userName)); - } - @Subscribe public void onGameStateChanged(GameStateChanged event) { checkStateChanged(false); } - public void replyToRequest(String userId, int reply) - { - discordService.respondToRequest(userId, reply); - panel.removeRequest(userId); - } - @Subscribe public void onTilePing(TilePing event) { @@ -400,12 +337,6 @@ public class PartyPlugin extends Plugin @Subscribe public void onGameTick(final GameTick event) { - if (sendAlert && client.getGameState() == GameState.LOGGED_IN) - { - sendAlert = false; - sendInstructionMessage(); - } - checkStateChanged(false); } @@ -430,11 +361,22 @@ public class PartyPlugin extends Plugin return; } - String name = event.getCharacterName(); - name = Text.removeTags(Text.toJagexName(name)); + final String name = Text.removeTags(Text.toJagexName(event.getCharacterName())); + final PartyMember member = partyData.getMember(); - partyData.setCharacterName(name); - SwingUtilities.invokeLater(() -> panel.updateMember(partyData.getMember().getMemberId())); + if (!name.isEmpty()) + { + member.setDisplayName(name); + member.setLoggedIn(true); + partyData.setColor(ColorUtil.fromObject(name)); + } + else + { + member.setLoggedIn(false); + partyData.setColor(Color.WHITE); + } + + SwingUtilities.invokeLater(() -> panel.updateMember(member.getMemberId())); } @Subscribe @@ -477,30 +419,8 @@ public class PartyPlugin extends Plugin @Subscribe public void onUserJoin(final UserJoin event) { - final PartyData partyData = getPartyData(event.getMemberId()); - - if (partyData == null || !config.messages()) - { - return; - } - - final String joinMessage = new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append(partyData.getMember().getName()) - .append(" has joined the party!") - .build(); - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(joinMessage) - .build()); - - final PartyMember localMember = party.getLocalMember(); - - if (localMember != null && partyData.getMember().getMemberId().equals(localMember.getMemberId())) - { - sendAlert = true; - } + // this has a side effect of creating the party data + getPartyData(event.getMemberId()); } @Subscribe @@ -557,20 +477,6 @@ public class PartyPlugin extends Plugin if (removed != null) { - if (config.messages()) - { - final String joinMessage = new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append(removed.getMember().getName()) - .append(" has left the party!") - .build(); - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(joinMessage) - .build()); - } - worldMapManager.remove(removed.getWorldMapPoint()); SwingUtilities.invokeLater(() -> panel.removeMember(event.getMemberId())); @@ -590,11 +496,7 @@ public class PartyPlugin extends Plugin config.setPreviousPartyId(String.valueOf(event.getPartyId())); } - SwingUtilities.invokeLater(() -> - { - panel.removeAllMembers(); - panel.removeAllRequests(); - }); + SwingUtilities.invokeLater(panel::removeAllMembers); } @Subscribe @@ -610,7 +512,7 @@ public class PartyPlugin extends Plugin chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Local ID " + party.getLocalMember().getMemberId()).build()); for (PartyMember partyMember : party.getMembers()) { - chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value(" " + partyMember.getName() + " " + partyMember.getMemberId()).build()); + chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Member " + partyMember.getName() + " " + partyMember.getDisplayName() + " " + partyMember.getMemberId()).build()); } } @@ -636,7 +538,6 @@ public class PartyPlugin extends Plugin return partyDataMap.computeIfAbsent(uuid, (u) -> { final WorldMapPoint worldMapPoint = new PartyWorldMapPoint(new WorldPoint(0, 0, 0), memberById); - worldMapPoint.setTooltip(memberById.getName()); // When first joining a party, other members can join before getting a join for self PartyMember partyMember = party.getLocalMember(); @@ -648,32 +549,11 @@ public class PartyPlugin extends Plugin worldMapManager.add(worldMapPoint); } - PartyData partyData = new PartyData(memberById, worldMapPoint, ColorUtil.fromObject(memberById.getName())); + PartyData partyData = new PartyData(memberById, worldMapPoint); partyData.setShowOverlay(config.autoOverlay()); - if (config.includeSelf() || !isSelf) - { - SwingUtilities.invokeLater(() -> panel.addMember(partyData)); - } - else - { - SwingUtilities.invokeLater(panel::updateParty); - } - + SwingUtilities.invokeLater(() -> panel.addMember(partyData)); return partyData; }); } - - private void sendInstructionMessage() - { - final String helpMessage = new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append("To leave the party, click \"Leave party\" on the party panel.") - .build(); - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(helpMessage) - .build()); - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyRequestBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyRequestBox.java deleted file mode 100644 index f36b262285..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyRequestBox.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2021, Jonathan Rousseau - * 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.party; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.GridLayout; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.border.EmptyBorder; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.DynamicGridLayout; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.components.MouseDragEventForwarder; -import net.runelite.client.ui.components.shadowlabel.JShadowedLabel; -import net.runelite.client.util.ImageUtil; -import net.runelite.client.util.SwingUtil; -import net.runelite.discord.DiscordRPC; - -class PartyRequestBox extends JPanel -{ - private static final ImageIcon CONFIRM_ICON = new ImageIcon(ImageUtil.loadImageResource(PartyPlugin.class, "confirm_icon.png")); - private static final ImageIcon CONFIRM_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.bufferedImageFromImage(CONFIRM_ICON.getImage()), 0.54f)); - private static final ImageIcon CANCEL_ICON = new ImageIcon(ImageUtil.loadImageResource(PartyPlugin.class, "cancel_icon.png")); - private static final ImageIcon CANCEL_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.bufferedImageFromImage(CANCEL_ICON.getImage()), 0.6f)); - - PartyRequestBox(final PartyPlugin plugin, final JComponent panel, String userId, String userName) - { - setLayout(new BorderLayout()); - setBorder(new EmptyBorder(5, 0, 0, 0)); - - /* The box's wrapping container */ - final JPanel container = new JPanel(); - container.setLayout(new BorderLayout()); - container.setBackground(ColorScheme.DARKER_GRAY_COLOR); - container.setBorder(new EmptyBorder(5, 5, 5, 5)); - - JPanel namesPanel = new JPanel(); - namesPanel.setLayout(new DynamicGridLayout(2, 1)); - namesPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); - namesPanel.setBorder(new EmptyBorder(2, 5, 2, 5)); - - JShadowedLabel nameLabel = new JShadowedLabel(); - nameLabel.setFont(FontManager.getRunescapeSmallFont()); - nameLabel.setForeground(Color.WHITE); - nameLabel.setText(userName); - - JShadowedLabel messageLabel = new JShadowedLabel(); - messageLabel.setFont(FontManager.getRunescapeSmallFont()); - messageLabel.setForeground(Color.WHITE); - messageLabel.setText("Wants to join your party!"); - - namesPanel.add(nameLabel); - namesPanel.add(messageLabel); - - JPanel actionsContainer = new JPanel(new GridLayout(1, 2, 8, 0)); - actionsContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); - - JButton confirmButton = new JButton(CONFIRM_ICON); - SwingUtil.removeButtonDecorations(confirmButton); - confirmButton.setToolTipText("Invite"); - confirmButton.setRolloverIcon(CONFIRM_HOVER_ICON); - confirmButton.addActionListener(e -> plugin.replyToRequest(userId, DiscordRPC.DISCORD_REPLY_YES)); - confirmButton.setPreferredSize(new Dimension(18, 18)); - - JButton cancelButton = new JButton(CANCEL_ICON); - SwingUtil.removeButtonDecorations(cancelButton); - cancelButton.setToolTipText("Reject"); - cancelButton.setRolloverIcon(CANCEL_HOVER_ICON); - cancelButton.addActionListener(e -> plugin.replyToRequest(userId, DiscordRPC.DISCORD_REPLY_NO)); - cancelButton.setPreferredSize(new Dimension(18, 18)); - - actionsContainer.add(confirmButton); - actionsContainer.add(cancelButton); - - container.add(namesPanel, BorderLayout.WEST); - container.add(actionsContainer, BorderLayout.EAST); - - // forward mouse drag events to parent panel for drag and drop reordering - MouseDragEventForwarder mouseDragEventForwarder = new MouseDragEventForwarder(panel); - container.addMouseListener(mouseDragEventForwarder); - container.addMouseMotionListener(mouseDragEventForwarder); - - add(container, BorderLayout.NORTH); - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java index e103649d35..501ae38682 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java @@ -41,7 +41,7 @@ import net.runelite.client.ui.overlay.components.ComponentConstants; import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.ProgressBarComponent; import net.runelite.client.ui.overlay.components.TitleComponent; -import net.runelite.client.ws.PartyService; +import net.runelite.client.ws.PartyMember; public class PartyStatsOverlay extends OverlayPanel { @@ -51,15 +51,13 @@ public class PartyStatsOverlay extends OverlayPanel private static final Color PRAY_BG = Color.black; private final PartyPlugin plugin; - private final PartyService party; private final PartyConfig config; @Inject - private PartyStatsOverlay(final PartyPlugin plugin, final PartyService party, final PartyConfig config) + private PartyStatsOverlay(final PartyPlugin plugin, final PartyConfig config) { super(plugin); this.plugin = plugin; - this.party = party; this.config = config; panelComponent.setBorder(new Rectangle()); panelComponent.setGap(new Point(0, ComponentConstants.STANDARD_BORDER / 2)); @@ -81,9 +79,9 @@ public class PartyStatsOverlay extends OverlayPanel { partyDataMap.forEach((k, v) -> { - boolean isSelf = party.getLocalMember() != null && party.getLocalMember().getMemberId().equals(k); + final PartyMember member = v.getMember(); - if (!v.isShowOverlay() || (!config.includeSelf() && isSelf)) + if (!v.isShowOverlay()) { return; } @@ -92,7 +90,7 @@ public class PartyStatsOverlay extends OverlayPanel panel.getChildren().clear(); final TitleComponent name = TitleComponent.builder() - .text(v.getCharacterName().isEmpty() ? v.getMember().getName() : v.getCharacterName()) + .text(member.getDisplayName()) .color(config.recolorNames() ? v.getColor() : Color.WHITE) .build(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java index 1c2bfd5b86..e85e32430c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java @@ -45,12 +45,23 @@ class PartyWorldMapPoint extends WorldMapPoint this.member = member; this.setSnapToEdge(true); this.setJumpOnClick(true); - this.setName(member.getName()); this.setImagePoint(new Point( ARROW.getWidth() / 2, ARROW.getHeight())); } + @Override + public String getName() + { + return member.getDisplayName(); + } + + @Override + public String getTooltip() + { + return member.getDisplayName(); + } + @Override public BufferedImage getImage() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java index f61a3b8866..053a16f5e6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java @@ -41,12 +41,11 @@ public class PartyData private final PartyMember member; private final WorldMapPoint worldMapPoint; private final PanelComponent panel = new PanelComponent(); - private final Color color; + private Color color = Color.WHITE; private int hitpoints; private int maxHitpoints; private int prayer; private int maxPrayer; - private String characterName = ""; private boolean showOverlay; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java index c1f72e1b42..78fadb0242 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java @@ -315,7 +315,7 @@ public class SpecialCounterPlugin extends Plugin return; } - String name = party.getMemberById(event.getMemberId()).getName(); + String name = party.getMemberById(event.getMemberId()).getDisplayName(); if (name == null) { return; diff --git a/runelite-client/src/main/java/net/runelite/client/ws/PartyMember.java b/runelite-client/src/main/java/net/runelite/client/ws/PartyMember.java index a5e6cc3275..cdc6ac1033 100644 --- a/runelite-client/src/main/java/net/runelite/client/ws/PartyMember.java +++ b/runelite-client/src/main/java/net/runelite/client/ws/PartyMember.java @@ -33,5 +33,7 @@ public class PartyMember { private final UUID memberId; private final String name; + private String displayName = ""; + private boolean loggedIn; private BufferedImage avatar; } diff --git a/runelite-client/src/main/java/net/runelite/client/ws/PartyService.java b/runelite-client/src/main/java/net/runelite/client/ws/PartyService.java index dc00df2e4d..d9f82836e0 100644 --- a/runelite-client/src/main/java/net/runelite/client/ws/PartyService.java +++ b/runelite-client/src/main/java/net/runelite/client/ws/PartyService.java @@ -25,18 +25,16 @@ */ package net.runelite.client.ws; -import com.google.common.base.Charsets; -import com.google.common.hash.Hashing; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Random; import java.util.UUID; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import lombok.Getter; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.client.account.AccountSession; @@ -46,8 +44,8 @@ import net.runelite.client.chat.QueuedMessage; import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.PartyChanged; -import net.runelite.client.util.Text; import net.runelite.client.events.PartyMemberAvatar; +import net.runelite.client.util.Text; import static net.runelite.client.util.Text.JAGEX_PRINTABLE_CHAR_MATCHER; import net.runelite.http.api.ws.messages.party.Join; import net.runelite.http.api.ws.messages.party.Part; @@ -60,9 +58,9 @@ import net.runelite.http.api.ws.messages.party.UserSync; @Singleton public class PartyService { - public static final int PARTY_MAX = 15; private static final int MAX_MESSAGE_LEN = 150; private static final int MAX_USERNAME_LEN = 32; // same as Discord + private static final String USERNAME = "rluser-" + new Random().nextInt(Integer.MAX_VALUE); private final WSClient wsClient; private final SessionManager sessionManager; @@ -73,15 +71,9 @@ public class PartyService @Getter private UUID localPartyId = UUID.randomUUID(); - @Getter - private UUID publicPartyId; // public party id, for advertising on discord, derived from the secret - @Getter private UUID partyId; // secret party id - @Setter - private String username; - @Inject private PartyService(final WSClient wsClient, final SessionManager sessionManager, final EventBus eventBus, final ChatMessageManager chat) { @@ -94,12 +86,6 @@ public class PartyService public void changeParty(@Nullable UUID newParty) { - if (username == null) - { - log.warn("Tried to join a party with no username"); - return; - } - if (wsClient.sessionExists()) { wsClient.send(new Part()); @@ -108,8 +94,6 @@ public class PartyService log.debug("Party change to {}", newParty); members.clear(); partyId = newParty; - // The public party ID needs to be consistent across party members, but not a secret - publicPartyId = newParty != null ? UUID.nameUUIDFromBytes(Hashing.sha256().hashString(newParty.toString(), Charsets.UTF_8).asBytes()) : null; if (partyId == null) { @@ -135,7 +119,7 @@ public class PartyService } eventBus.post(new PartyChanged(partyId)); - wsClient.send(new Join(partyId, username)); + wsClient.send(new Join(partyId, USERNAME)); } @Subscribe(priority = 1) // run prior to plugins so that the member is joined by the time the plugins see it. @@ -171,11 +155,18 @@ public class PartyService @Subscribe public void onPartyChatMessage(final PartyChatMessage message) { + final PartyMember member = getMemberById(message.getMemberId()); + if (member == null || !member.isLoggedIn()) + { + log.debug("Dropping party chat from non logged-in member"); + return; + } + // Remove non-printable characters, and tags from message String sentMesage = JAGEX_PRINTABLE_CHAR_MATCHER.retainFrom(message.getValue()) .replaceAll("", ""); - // Cap the mesage length + // Cap the message length if (sentMesage.length() > MAX_MESSAGE_LEN) { sentMesage = sentMesage.substring(0, MAX_MESSAGE_LEN); @@ -184,14 +175,14 @@ public class PartyService chat.queue(QueuedMessage.builder() .type(ChatMessageType.FRIENDSCHAT) .sender("Party") - .name(getMemberById(message.getMemberId()).getName()) + .name(member.getDisplayName()) .runeLiteFormattedMessage(sentMesage) .build()); } public PartyMember getLocalMember() { - return getMemberByName(username); + return getMemberByName(USERNAME); } public PartyMember getMemberById(final UUID id) From eb0cbd5f49ebdc5425bef5cae62ff3f91ea7a669 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 25 May 2022 20:13:37 -0400 Subject: [PATCH 12/17] party: use passphrases for party ids These are easier to type and share than uuids. --- .../runelite/client/events/PartyChanged.java | 1 + .../client/plugins/party/PartyPanel.java | 40 ++----- .../client/plugins/party/PartyPlugin.java | 5 +- .../net/runelite/client/ws/PartyService.java | 106 +++++++++++++++--- 4 files changed, 105 insertions(+), 47 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/events/PartyChanged.java b/runelite-client/src/main/java/net/runelite/client/events/PartyChanged.java index 0cb8a94c3e..be8bd63a9b 100644 --- a/runelite-client/src/main/java/net/runelite/client/events/PartyChanged.java +++ b/runelite-client/src/main/java/net/runelite/client/events/PartyChanged.java @@ -30,5 +30,6 @@ import lombok.Value; @Value public class PartyChanged { + private final String passphrase; private final UUID partyId; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPanel.java index 590424eaf8..2affaf1214 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPanel.java @@ -41,6 +41,7 @@ import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; +import net.runelite.client.callback.ClientThread; import net.runelite.client.plugins.party.data.PartyData; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.PluginPanel; @@ -51,7 +52,7 @@ import net.runelite.client.ws.PartyService; class PartyPanel extends PluginPanel { private static final String BTN_CREATE_TEXT = "Create party"; - private static final String BTN_LEAVE_TEXT = "Leave party"; + private static final String BTN_LEAVE_TEXT = "Leave"; private final PartyPlugin plugin; private final PartyService party; @@ -69,7 +70,7 @@ class PartyPanel extends PluginPanel private final JComponent memberBoxPanel = new DragAndDropReorderPane(); @Inject - PartyPanel(final PartyPlugin plugin, final PartyConfig config, final PartyService party) + PartyPanel(final ClientThread clientThread, final PartyPlugin plugin, final PartyConfig config, final PartyService party) { this.plugin = plugin; this.party = party; @@ -122,7 +123,7 @@ class PartyPanel extends PluginPanel rejoinPartyButton.setText("Join previous party"); rejoinPartyButton.setFocusable(false); - copyPartyIdButton.setText("Copy party id"); + copyPartyIdButton.setText("Copy passphrase"); copyPartyIdButton.setFocusable(false); startButton.addActionListener(e -> @@ -143,7 +144,7 @@ class PartyPanel extends PluginPanel else { // Create party - party.changeParty(party.getLocalPartyId()); + clientThread.invokeLater(() -> party.changeParty(party.generatePasspharse())); } }); @@ -153,8 +154,8 @@ class PartyPanel extends PluginPanel { String s = (String) JOptionPane.showInputDialog( joinPartyButton, - "Please enter the party id:", - "Party Id", + "Please enter the party passphrase:", + "Party Passphrase", JOptionPane.PLAIN_MESSAGE, null, null, @@ -165,15 +166,7 @@ class PartyPanel extends PluginPanel return; } - try - { - party.changeParty(UUID.fromString(s)); - } - catch (IllegalArgumentException ex) - { - JOptionPane.showMessageDialog(joinPartyButton, "You have entered an invalid party id.", "Invalid Party Id", - JOptionPane.ERROR_MESSAGE); - } + party.changeParty(s); } }); @@ -181,17 +174,7 @@ class PartyPanel extends PluginPanel { if (!party.isInParty()) { - try - { - party.changeParty(UUID.fromString(config.previousPartyId())); - } - catch (IllegalArgumentException ex) - { - JOptionPane.showMessageDialog(rejoinPartyButton, - "Failed to join your previous party, create a new party or join a new one.", - "Failed to Join Party", - JOptionPane.ERROR_MESSAGE); - } + party.changeParty(config.previousPartyId()); } }); @@ -200,12 +183,11 @@ class PartyPanel extends PluginPanel if (party.isInParty()) { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(new StringSelection(String.valueOf(party.getPartyId())), null); + clipboard.setContents(new StringSelection(party.getPartyPassphrase()), null); } }); noPartyPanel.setContent("Not in a party", "Create a party to begin."); - partyEmptyPanel.setContent("Party created", "You can now invite friends!"); updateParty(); } @@ -226,6 +208,8 @@ class PartyPanel extends PluginPanel } else if (plugin.getPartyDataMap().size() <= 1) { + partyEmptyPanel.setContent("Party created", "You can now invite friends!
" + + "Your party passphrase is: " + party.getPartyPassphrase() + "."); add(partyEmptyPanel); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java index c833be1e98..38fdba6e23 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java @@ -493,7 +493,7 @@ public class PartyPlugin extends Plugin if (event.getPartyId() != null) { - config.setPreviousPartyId(String.valueOf(event.getPartyId())); + config.setPreviousPartyId(event.getPassphrase()); } SwingUtilities.invokeLater(panel::removeAllMembers); @@ -507,8 +507,7 @@ public class PartyPlugin extends Plugin return; } - chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Party " + party.getPartyId()).build()); - chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Local Party " + party.getLocalPartyId()).build()); + chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Party " + party.getPartyPassphrase() + " ID " + party.getPartyId()).build()); chatMessageManager.queue(QueuedMessage.builder().type(ChatMessageType.GAMEMESSAGE).value("Local ID " + party.getLocalMember().getMemberId()).build()); for (PartyMember partyMember : party.getMembers()) { diff --git a/runelite-client/src/main/java/net/runelite/client/ws/PartyService.java b/runelite-client/src/main/java/net/runelite/client/ws/PartyService.java index d9f82836e0..123a172a0b 100644 --- a/runelite-client/src/main/java/net/runelite/client/ws/PartyService.java +++ b/runelite-client/src/main/java/net/runelite/client/ws/PartyService.java @@ -25,10 +25,14 @@ */ package net.runelite.client.ws; +import com.google.common.base.CharMatcher; +import com.google.common.hash.Hashing; import java.awt.image.BufferedImage; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Random; import java.util.UUID; import javax.annotation.Nullable; @@ -37,6 +41,9 @@ import javax.inject.Singleton; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.ItemComposition; import net.runelite.client.account.AccountSession; import net.runelite.client.account.SessionManager; import net.runelite.client.chat.ChatMessageManager; @@ -61,22 +68,24 @@ public class PartyService private static final int MAX_MESSAGE_LEN = 150; private static final int MAX_USERNAME_LEN = 32; // same as Discord private static final String USERNAME = "rluser-" + new Random().nextInt(Integer.MAX_VALUE); + private static final String ALPHABET = "bcdfghjklmnpqrstvwxyz"; + private final Client client; private final WSClient wsClient; private final SessionManager sessionManager; private final EventBus eventBus; private final ChatMessageManager chat; private final List members = new ArrayList<>(); - @Getter - private UUID localPartyId = UUID.randomUUID(); - @Getter private UUID partyId; // secret party id + @Getter + private String partyPassphrase; @Inject - private PartyService(final WSClient wsClient, final SessionManager sessionManager, final EventBus eventBus, final ChatMessageManager chat) + private PartyService(final Client client, final WSClient wsClient, final SessionManager sessionManager, final EventBus eventBus, final ChatMessageManager chat) { + this.client = client; this.wsClient = wsClient; this.sessionManager = sessionManager; this.eventBus = eventBus; @@ -84,28 +93,89 @@ public class PartyService eventBus.register(this); } - public void changeParty(@Nullable UUID newParty) + public String generatePasspharse() + { + assert client.isClientThread(); + + Random r = new Random(); + StringBuilder sb = new StringBuilder(); + + if (client.getGameState().getState() >= GameState.LOGIN_SCREEN.getState()) + { + int len = 0; + final CharMatcher matcher = CharMatcher.javaLetter(); + do + { + final int itemId = r.nextInt(client.getItemCount()); + final ItemComposition def = client.getItemDefinition(itemId); + final String name = def.getName(); + if (name == null || name.isEmpty() || name.equals("null")) + { + continue; + } + + final String[] split = name.split(" "); + final String token = split[r.nextInt(split.length)]; + if (!matcher.matchesAllOf(token) || token.length() <= 2) + { + continue; + } + + if (sb.length() > 0) + { + sb.append('-'); + } + sb.append(token.toLowerCase(Locale.US)); + ++len; + } + while (len < 4); + } + else + { + int len = 0; + do + { + if (sb.length() > 0) + { + sb.append('-'); + } + for (int i = 0; i < 5; ++i) + { + sb.append(ALPHABET.charAt(r.nextInt(ALPHABET.length()))); + } + ++len; + } + while (len < 4); + } + + String partyPassphrase = sb.toString(); + log.debug("Generated party passpharse {}", partyPassphrase); + return partyPassphrase; + } + + public void changeParty(@Nullable String passphrase) { if (wsClient.sessionExists()) { wsClient.send(new Part()); } - log.debug("Party change to {}", newParty); + UUID id = passphrase != null ? passphraseToId(passphrase) : null; + + log.debug("Party change to {} (id {})", passphrase, id); members.clear(); - partyId = newParty; + partyId = id; + partyPassphrase = passphrase; if (partyId == null) { - localPartyId = UUID.randomUUID(); // cycle local party id so that a new party is created now - // close the websocket if the session id isn't for an account if (sessionManager.getAccountSession() == null) { wsClient.changeSession(null); } - eventBus.post(new PartyChanged(partyId)); + eventBus.post(new PartyChanged(partyPassphrase, partyId)); return; } @@ -118,7 +188,7 @@ public class PartyService wsClient.changeSession(uuid); } - eventBus.post(new PartyChanged(partyId)); + eventBus.post(new PartyChanged(partyPassphrase, partyId)); wsClient.send(new Join(partyId, USERNAME)); } @@ -221,11 +291,6 @@ public class PartyService return partyId != null; } - public boolean isPartyOwner() - { - return localPartyId.equals(partyId); - } - public void setPartyMemberAvatar(UUID memberID, BufferedImage image) { final PartyMember memberById = getMemberById(memberID); @@ -246,4 +311,13 @@ public class PartyService } return s; } + + private static UUID passphraseToId(String passphrase) + { + return UUID.nameUUIDFromBytes( + Hashing.sha256().hashBytes( + passphrase.getBytes(StandardCharsets.UTF_8) + ).asBytes() + ); + } } From 9fe186cad22033484b4d81b800a24c1c47e35c99 Mon Sep 17 00:00:00 2001 From: Hexagon Date: Thu, 26 May 2022 21:02:21 -0300 Subject: [PATCH 13/17] spec counter: add spec drops Co-authored-by: Adam --- .../specialcounter/PlayerInfoDrop.java | 85 +++++++++++ .../specialcounter/PlayerInfoDropOverlay.java | 137 ++++++++++++++++++ .../specialcounter/SpecialCounterConfig.java | 31 +++- .../specialcounter/SpecialCounterPlugin.java | 51 ++++++- .../specialcounter/SpecialCounterUpdate.java | 2 + .../SpecialCounterPluginTest.java | 14 ++ 6 files changed, 315 insertions(+), 5 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/PlayerInfoDrop.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/PlayerInfoDropOverlay.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/PlayerInfoDrop.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/PlayerInfoDrop.java new file mode 100644 index 0000000000..09b95d7111 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/PlayerInfoDrop.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022, Hexagon + * 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.specialcounter; + +import java.awt.Color; +import java.awt.Font; +import java.awt.image.BufferedImage; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import net.runelite.client.ui.FontManager; + +@Data +@AllArgsConstructor(access = AccessLevel.PRIVATE) +class PlayerInfoDrop +{ + private final int startCycle; + private final int endCycle; + private final int playerIdx; + private final String text; + private final int startHeightOffset; + private final int endHeightOffset; + private final Font font; + private final Color color; + private final BufferedImage image; + + public static Builder builder(int startCycle, int endCycle, int playerIdx, String text) + { + return new Builder(startCycle, endCycle, playerIdx, text); + } + + @RequiredArgsConstructor + @Accessors(fluent = true) + @Setter + static class Builder + { + private final int startCycle; + private final int endCycle; + private final int playerIdx; + private final String text; + private int startHeightOffset = 0; + private int endHeightOffset = 200; + private Font font = FontManager.getRunescapeBoldFont(); + private Color color = Color.WHITE; + private BufferedImage image; + + public PlayerInfoDrop build() + { + if (startCycle > endCycle) + { + throw new IllegalArgumentException("endCycle must be after startCycle"); + } + if (playerIdx < 0 || playerIdx > 2047) + { + throw new IllegalArgumentException("playerIdx must be between 0-2047"); + } + return new PlayerInfoDrop(startCycle, endCycle, playerIdx, text, startHeightOffset, endHeightOffset, font, color, image); + } + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/PlayerInfoDropOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/PlayerInfoDropOverlay.java new file mode 100644 index 0000000000..497eb0d3d5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/PlayerInfoDropOverlay.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2022, Hexagon + * 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.specialcounter; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.Iterator; +import java.util.List; +import javax.inject.Inject; +import javax.inject.Singleton; +import net.runelite.api.Client; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.ImageUtil; + +@Singleton +class PlayerInfoDropOverlay extends Overlay +{ + private final SpecialCounterPlugin plugin; + private final SpecialCounterConfig config; + private final Client client; + + @Inject + private PlayerInfoDropOverlay(SpecialCounterPlugin plugin, SpecialCounterConfig config, Client client) + { + this.plugin = plugin; + this.config = config; + this.client = client; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.MED); + } + + @Override + public Dimension render(Graphics2D graphics) + { + final List infoDrops = plugin.getPlayerInfoDrops(); + if (infoDrops.isEmpty()) + { + return null; + } + + final int cycle = client.getGameCycle(); + for (Iterator iterator = infoDrops.iterator(); iterator.hasNext();) + { + PlayerInfoDrop infoDrop = iterator.next(); + + if (cycle < infoDrop.getStartCycle()) + { + continue; + } + + if (cycle > infoDrop.getEndCycle()) + { + iterator.remove(); + continue; + } + + if (!config.specDrops()) + { + continue; + } + + Player player = client.getCachedPlayers()[infoDrop.getPlayerIdx()]; + if (player == null) + { + continue; + } + + int elapsed = cycle - infoDrop.getStartCycle(); + int percent = elapsed * 100 / (infoDrop.getEndCycle() - infoDrop.getStartCycle()); + int currentHeight = infoDrop.getEndHeightOffset() * percent / 100; + String text = infoDrop.getText(); + + graphics.setFont(infoDrop.getFont()); + Point textLocation = player.getCanvasTextLocation(graphics, text, player.getLogicalHeight() + infoDrop.getStartHeightOffset() + currentHeight); + if (textLocation == null) + { + continue; + } + + int alpha = 255 - (255 * percent / 100); + BufferedImage image = infoDrop.getImage(); + if (image != null) + { + int textHeight = graphics.getFontMetrics().getHeight() - graphics.getFontMetrics().getMaxDescent(); + int textMargin = image.getWidth() / 2; + int x = textLocation.getX() - textMargin - 1; + int y = textLocation.getY() - textHeight / 2 - image.getHeight() / 2; + Point imageLocation = new Point(x, y); + + textLocation = new Point(textLocation.getX() + textMargin, textLocation.getY()); + + OverlayUtil.renderImageLocation(graphics, imageLocation, ImageUtil.alphaOffset(image, alpha - 255)); + } + + drawText(graphics, textLocation, text, infoDrop.getColor(), alpha); + } + return null; + } + + private static void drawText(Graphics2D g, Point point, String text, Color color, int colorAlpha) + { + g.setColor(ColorUtil.colorWithAlpha(Color.BLACK, colorAlpha)); + g.drawString(text, point.getX() + 1, point.getY() + 1); + g.setColor(ColorUtil.colorWithAlpha(color, colorAlpha)); + g.drawString(text, point.getX(), point.getY()); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterConfig.java index 7eb596275a..4249fa3be8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterConfig.java @@ -25,6 +25,7 @@ */ package net.runelite.client.plugins.specialcounter; +import java.awt.Color; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; @@ -45,6 +46,28 @@ public interface SpecialCounterConfig extends Config @ConfigItem( position = 1, + keyName = "specDrops", + name = "Spec Drops", + description = "Draws an overlay over the player when a special attack hits" + ) + default boolean specDrops() + { + return true; + } + + @ConfigItem( + position = 2, + keyName = "specDropColor", + name = "Spec Drop Color", + description = "Text color for spec drops" + ) + default Color specDropColor() + { + return Color.WHITE; + } + + @ConfigItem( + position = 10, keyName = "dragonWarhammerThreshold", name = "Dragon Warhammer", description = "Threshold for Dragon Warhammer (0 to disable)" @@ -55,7 +78,7 @@ public interface SpecialCounterConfig extends Config } @ConfigItem( - position = 2, + position = 20, keyName = "arclightThreshold", name = "Arclight", description = "Threshold for Arclight (0 to disable)" @@ -66,7 +89,7 @@ public interface SpecialCounterConfig extends Config } @ConfigItem( - position = 3, + position = 30, keyName = "darklightThreshold", name = "Darklight", description = "Threshold for Darklight (0 to disable)" @@ -77,7 +100,7 @@ public interface SpecialCounterConfig extends Config } @ConfigItem( - position = 4, + position = 40, keyName = "bandosGodswordThreshold", name = "Bandos Godsword", description = "Threshold for Bandos Godsword (0 to disable)" @@ -88,7 +111,7 @@ public interface SpecialCounterConfig extends Config } @ConfigItem( - position = 5, + position = 50, keyName = "bulwarkThreshold", name = "Dinh's Bulwark", description = "Threshold for Dinh's Bulwark (0 to disable)" diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java index 78fadb0242..b55c8c16b5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java @@ -26,11 +26,16 @@ package net.runelite.client.plugins.specialcounter; import com.google.common.collect.ImmutableSet; import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; import net.runelite.api.Client; @@ -44,6 +49,7 @@ import net.runelite.api.NPC; import net.runelite.api.NpcID; import net.runelite.api.VarPlayer; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.CommandExecuted; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.HitsplatApplied; @@ -57,7 +63,9 @@ import net.runelite.client.eventbus.Subscribe; import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.util.ImageUtil; import net.runelite.client.ws.PartyService; import net.runelite.client.ws.WSClient; @@ -95,6 +103,9 @@ public class SpecialCounterPlugin extends Plugin private final Set interactedNpcIds = new HashSet<>(); private final SpecialCounter[] specialCounter = new SpecialCounter[SpecialWeapon.values().length]; + @Getter(AccessLevel.PACKAGE) + private final List playerInfoDrops = new ArrayList<>(); + @Inject private Client client; @@ -119,6 +130,12 @@ public class SpecialCounterPlugin extends Plugin @Inject private SpecialCounterConfig config; + @Inject + private OverlayManager overlayManager; + + @Inject + private PlayerInfoDropOverlay playerInfoDropOverlay; + @Provides SpecialCounterConfig getConfig(ConfigManager configManager) { @@ -128,6 +145,7 @@ public class SpecialCounterPlugin extends Plugin @Override protected void startUp() { + overlayManager.add(playerInfoDropOverlay); wsClient.registerMessage(SpecialCounterUpdate.class); currentWorld = -1; specialPercentage = -1; @@ -140,6 +158,7 @@ public class SpecialCounterPlugin extends Plugin protected void shutDown() { removeCounters(); + overlayManager.remove(playerInfoDropOverlay); wsClient.unregisterMessage(SpecialCounterUpdate.class); } @@ -267,15 +286,18 @@ public class SpecialCounterPlugin extends Plugin if (wasSpec && specialWeapon != null && hitsplat.getAmount() > 0) { int hit = getHit(specialWeapon, hitsplat); + int localPlayerId = client.getLocalPlayer().getId(); updateCounter(specialWeapon, null, hit); if (!party.getMembers().isEmpty()) { - final SpecialCounterUpdate specialCounterUpdate = new SpecialCounterUpdate(interactingId, specialWeapon, hit); + final SpecialCounterUpdate specialCounterUpdate = new SpecialCounterUpdate(interactingId, specialWeapon, hit, client.getWorld(), localPlayerId); specialCounterUpdate.setMemberId(party.getLocalMember().getMemberId()); wsClient.send(specialCounterUpdate); } + + playerInfoDrops.add(createSpecInfoDrop(specialWeapon, hit, localPlayerId)); } } @@ -334,9 +356,23 @@ public class SpecialCounterPlugin extends Plugin { updateCounter(event.getWeapon(), name, event.getHit()); } + + if (event.getWorld() == client.getWorld()) + { + playerInfoDrops.add(createSpecInfoDrop(event.getWeapon(), event.getHit(), event.getPlayerId())); + } }); } + @Subscribe + public void onCommandExecuted(CommandExecuted commandExecuted) + { + if (commandExecuted.getCommand().equals("spec")) + { + playerInfoDrops.add(createSpecInfoDrop(SpecialWeapon.BANDOS_GODSWORD, 42, client.getLocalPlayer().getId())); + } + } + private SpecialWeapon usedSpecialWeapon() { ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); @@ -424,4 +460,17 @@ public class SpecialCounterPlugin extends Plugin { return specialWeapon.isDamage() ? hitsplat.getAmount() : 1; } + + private PlayerInfoDrop createSpecInfoDrop(SpecialWeapon weapon, int hit, int playerId) + { + int cycle = client.getGameCycle(); + BufferedImage image = ImageUtil.resizeImage(itemManager.getImage(weapon.getItemID()[0]), 24, 24); + + return PlayerInfoDrop.builder(cycle, cycle + 100, playerId, Integer.toString(hit)) + .color(config.specDropColor()) + .startHeightOffset(100) + .endHeightOffset(400) + .image(image) + .build(); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java index 16eff1af25..2c7bcbe21b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterUpdate.java @@ -35,4 +35,6 @@ public class SpecialCounterUpdate extends PartyMemberMessage private final int npcId; private final SpecialWeapon weapon; private final int hit; + private final int world; + private final int playerId; } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java index 977e379a9a..43241d448c 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java @@ -28,6 +28,7 @@ import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.testing.fieldbinder.Bind; import com.google.inject.testing.fieldbinder.BoundFieldModule; +import java.awt.image.BufferedImage; import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.EquipmentInventorySlot; @@ -44,13 +45,16 @@ import net.runelite.api.events.InteractingChanged; import net.runelite.api.events.VarbitChanged; import net.runelite.client.Notifier; import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.util.AsyncBufferedImage; import net.runelite.client.ws.PartyService; import net.runelite.client.ws.WSClient; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import org.mockito.Mock; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; @@ -90,6 +94,14 @@ public class SpecialCounterPluginTest @Bind private SpecialCounterConfig specialCounterConfig; + @Mock + @Bind + private OverlayManager overlayManager; + + @Mock + @Bind + private PlayerInfoDropOverlay playerInfoDropOverlay; + @Inject private SpecialCounterPlugin specialCounterPlugin; @@ -107,6 +119,8 @@ public class SpecialCounterPluginTest when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(100); specialCounterPlugin.onVarbitChanged(new VarbitChanged()); + // Set up item image for spec info drop + when(itemManager.getImage(anyInt())).thenReturn(new AsyncBufferedImage(24, 24, BufferedImage.TYPE_INT_ARGB)); } private static HitsplatApplied hitsplat(Actor target, Hitsplat.HitsplatType type) From 282eab1a4c6f3133635ed4a1c7b594bb254ea0bf Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 27 May 2022 14:34:07 -0400 Subject: [PATCH 14/17] party: remove overlay This is rarely used because the information is duplicated in the panel, and not very useful. Also the toggling behavior is confusing to people. --- .../client/plugins/party/PartyConfig.java | 11 -- .../client/plugins/party/PartyMemberBox.java | 15 +-- .../client/plugins/party/PartyPlugin.java | 6 - .../plugins/party/PartyStatsOverlay.java | 127 ------------------ .../client/plugins/party/data/PartyData.java | 1 - 5 files changed, 1 insertion(+), 159 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java index 885f25b80d..fd8553ad5a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java @@ -67,17 +67,6 @@ public interface PartyConfig extends Config return true; } - @ConfigItem( - keyName = "autoOverlay", - name = "Auto overlay", - description = "Automatically add an overlay with player data when a member joins", - position = 5 - ) - default boolean autoOverlay() - { - return false; - } - @ConfigItem( keyName = "previousPartyId", name = "", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyMemberBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyMemberBox.java index 04bea7d2d6..832989f5a5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyMemberBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyMemberBox.java @@ -32,15 +32,12 @@ import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; -import javax.swing.JMenuItem; import javax.swing.JPanel; -import javax.swing.JPopupMenu; import javax.swing.SwingConstants; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import lombok.AccessLevel; import lombok.Getter; -import net.runelite.client.ws.PartyMember; import net.runelite.client.plugins.party.data.PartyData; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.DynamicGridLayout; @@ -48,6 +45,7 @@ import net.runelite.client.ui.FontManager; import net.runelite.client.ui.components.MouseDragEventForwarder; import net.runelite.client.ui.components.ProgressBar; import net.runelite.client.util.ImageUtil; +import net.runelite.client.ws.PartyMember; class PartyMemberBox extends JPanel { @@ -83,15 +81,6 @@ class PartyMemberBox extends JPanel container.setBackground(ColorScheme.DARKER_GRAY_COLOR); container.setBorder(new EmptyBorder(5, 5, 5, 5)); - // Create Toggle overlay - final JMenuItem overlay = new JMenuItem("Toggle overlay"); - overlay.addActionListener(e -> memberPartyData.setShowOverlay(!memberPartyData.isShowOverlay())); - - // Create popup menu - final JPopupMenu popupMenu = new JPopupMenu(); - popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); - popupMenu.add(overlay); - // create a line border with the specified color and width Border border = BorderFactory.createLineBorder(Color.gray, 1); avatar.setBorder(border); @@ -136,8 +125,6 @@ class PartyMemberBox extends JPanel container.add(headerPanel, BorderLayout.NORTH); container.add(progressWrapper, BorderLayout.SOUTH); - container.setComponentPopupMenu(popupMenu); - // forward mouse drag events to parent panel for drag and drop reordering MouseDragEventForwarder mouseDragEventForwarder = new MouseDragEventForwarder(panel); container.addMouseListener(mouseDragEventForwarder); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java index 38fdba6e23..927f575b9d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java @@ -110,9 +110,6 @@ public class PartyPlugin extends Plugin @Inject private OverlayManager overlayManager; - @Inject - private PartyStatsOverlay partyStatsOverlay; - @Inject private PartyPingOverlay partyPingOverlay; @@ -173,7 +170,6 @@ public class PartyPlugin extends Plugin clientToolbar.addNavigation(navButton); - overlayManager.add(partyStatsOverlay); overlayManager.add(partyPingOverlay); wsClient.registerMessage(SkillUpdate.class); wsClient.registerMessage(TilePing.class); @@ -193,7 +189,6 @@ public class PartyPlugin extends Plugin partyDataMap.clear(); pendingTilePings.clear(); worldMapManager.removeIf(PartyWorldMapPoint.class::isInstance); - overlayManager.remove(partyStatsOverlay); overlayManager.remove(partyPingOverlay); wsClient.unregisterMessage(SkillUpdate.class); wsClient.unregisterMessage(TilePing.class); @@ -549,7 +544,6 @@ public class PartyPlugin extends Plugin } PartyData partyData = new PartyData(memberById, worldMapPoint); - partyData.setShowOverlay(config.autoOverlay()); SwingUtilities.invokeLater(() -> panel.addMember(partyData)); return partyData; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java deleted file mode 100644 index 501ae38682..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2019, Tomas Slusny - * Copyright (c) 2021, Jonathan Rousseau - * 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.party; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.util.Map; -import java.util.UUID; -import javax.inject.Inject; -import net.runelite.api.MenuAction; -import net.runelite.client.plugins.party.data.PartyData; -import net.runelite.client.ui.overlay.OverlayMenuEntry; -import net.runelite.client.ui.overlay.OverlayPanel; -import net.runelite.client.ui.overlay.components.ComponentConstants; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.ProgressBarComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; -import net.runelite.client.ws.PartyMember; - -public class PartyStatsOverlay extends OverlayPanel -{ - private static final Color HP_FG = new Color(0, 146, 54, 230); - private static final Color HP_BG = new Color(102, 15, 16, 230); - private static final Color PRAY_FG = new Color(0, 149, 151); - private static final Color PRAY_BG = Color.black; - - private final PartyPlugin plugin; - private final PartyConfig config; - - @Inject - private PartyStatsOverlay(final PartyPlugin plugin, final PartyConfig config) - { - super(plugin); - this.plugin = plugin; - this.config = config; - panelComponent.setBorder(new Rectangle()); - panelComponent.setGap(new Point(0, ComponentConstants.STANDARD_BORDER / 2)); - getMenuEntries().add(new OverlayMenuEntry(MenuAction.RUNELITE_OVERLAY, "Leave", "Party")); - } - - @Override - public Dimension render(Graphics2D graphics) - { - final Map partyDataMap = plugin.getPartyDataMap(); - if (partyDataMap.isEmpty()) - { - return null; - } - - panelComponent.setBackgroundColor(null); - - synchronized (plugin.getPartyDataMap()) - { - partyDataMap.forEach((k, v) -> - { - final PartyMember member = v.getMember(); - - if (!v.isShowOverlay()) - { - return; - } - - final PanelComponent panel = v.getPanel(); - panel.getChildren().clear(); - - final TitleComponent name = TitleComponent.builder() - .text(member.getDisplayName()) - .color(config.recolorNames() ? v.getColor() : Color.WHITE) - .build(); - - panel.getChildren().add(name); - - if (v.getMaxHitpoints() > 0) - { - final ProgressBarComponent hpBar = new ProgressBarComponent(); - hpBar.setBackgroundColor(HP_BG); - hpBar.setForegroundColor(HP_FG); - hpBar.setMaximum(v.getMaxHitpoints()); - hpBar.setValue(v.getHitpoints()); - hpBar.setLabelDisplayMode(ProgressBarComponent.LabelDisplayMode.FULL); - panel.getChildren().add(hpBar); - } - - if (v.getMaxPrayer() > 0) - { - final ProgressBarComponent prayBar = new ProgressBarComponent(); - prayBar.setBackgroundColor(PRAY_BG); - prayBar.setForegroundColor(PRAY_FG); - prayBar.setMaximum(v.getMaxPrayer()); - prayBar.setValue(v.getPrayer()); - prayBar.setLabelDisplayMode(ProgressBarComponent.LabelDisplayMode.FULL); - panel.getChildren().add(prayBar); - } - - panelComponent.getChildren().add(panel); - }); - } - - return super.render(graphics); - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java index 053a16f5e6..b821420a68 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java @@ -47,5 +47,4 @@ public class PartyData private int maxHitpoints; private int prayer; private int maxPrayer; - private boolean showOverlay; } From 5fa08751a1206a61b4fb8d717ca10fab36d247d3 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 27 May 2022 14:52:59 -0400 Subject: [PATCH 15/17] spec counter: add devmode check for spec command --- .../plugins/specialcounter/SpecialCounterPlugin.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java index b55c8c16b5..9391d82ee6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; +import javax.inject.Named; import lombok.AccessLevel; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -136,6 +137,10 @@ public class SpecialCounterPlugin extends Plugin @Inject private PlayerInfoDropOverlay playerInfoDropOverlay; + @Inject + @Named("developerMode") + boolean developerMode; + @Provides SpecialCounterConfig getConfig(ConfigManager configManager) { @@ -367,7 +372,7 @@ public class SpecialCounterPlugin extends Plugin @Subscribe public void onCommandExecuted(CommandExecuted commandExecuted) { - if (commandExecuted.getCommand().equals("spec")) + if (developerMode && commandExecuted.getCommand().equals("spec")) { playerInfoDrops.add(createSpecInfoDrop(SpecialWeapon.BANDOS_GODSWORD, 42, client.getLocalPlayer().getId())); } From 491c23fd7416c73a3f0e8e7e043aed7c6085e20a Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Fri, 27 May 2022 13:24:29 -0700 Subject: [PATCH 16/17] special counter: Fix test --- .../plugins/specialcounter/SpecialCounterPluginTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java index 43241d448c..4846efdd9a 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java @@ -26,6 +26,7 @@ package net.runelite.client.plugins.specialcounter; import com.google.inject.Guice; import com.google.inject.Inject; +import com.google.inject.name.Named; import com.google.inject.testing.fieldbinder.Bind; import com.google.inject.testing.fieldbinder.BoundFieldModule; import java.awt.image.BufferedImage; @@ -70,6 +71,10 @@ public class SpecialCounterPluginTest @Bind private Client client; + @Bind + @Named("developerMode") + boolean developerMode; + @Mock @Bind private InfoBoxManager infoBoxManager; From e8c7e782b34486ee58f7fd7d2e5dfcbf40d39559 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Fri, 27 May 2022 13:45:05 -0700 Subject: [PATCH 17/17] hunter: Remove unused lastActionTime field This field was originally used to show a catch rate overlay, but all its uses were removed in 76fbab60fc742c95c526ce0cb8a371f8d5d65369 when the overlay was removed due to unreliable behavior. --- .../net/runelite/client/plugins/hunter/HunterPlugin.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java index 4c5a3c310a..22813a8c43 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java @@ -76,9 +76,6 @@ public class HunterPlugin extends Plugin @Getter private final Map traps = new HashMap<>(); - @Getter - private Instant lastActionTime = Instant.ofEpochMilli(0); - private WorldPoint lastTickLocalPlayerLocation; @Provides @@ -98,7 +95,6 @@ public class HunterPlugin extends Plugin protected void shutDown() throws Exception { overlayManager.remove(overlay); - lastActionTime = Instant.ofEpochMilli(0); traps.clear(); } @@ -124,7 +120,6 @@ public class HunterPlugin extends Plugin { log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), trapLocation); traps.put(trapLocation, new HunterTrap(gameObject)); - lastActionTime = Instant.now(); } break; @@ -140,7 +135,6 @@ public class HunterPlugin extends Plugin { log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), localPlayer.getWorldLocation()); traps.put(trapLocation, new HunterTrap(gameObject)); - lastActionTime = Instant.now(); } break; @@ -168,7 +162,6 @@ public class HunterPlugin extends Plugin log.debug("Trap placed by \"{}\" on {} facing {}", localPlayer.getName(), translatedTrapLocation, trapOrientation); traps.put(translatedTrapLocation, new HunterTrap(gameObject)); - lastActionTime = Instant.now(); } break; @@ -201,7 +194,6 @@ public class HunterPlugin extends Plugin { myTrap.setState(HunterTrap.State.FULL); myTrap.resetTimer(); - lastActionTime = Instant.now(); if (config.maniacalMonkeyNotify() && myTrap.getObjectId() == ObjectID.MONKEY_TRAP) { @@ -222,7 +214,6 @@ public class HunterPlugin extends Plugin { myTrap.setState(HunterTrap.State.EMPTY); myTrap.resetTimer(); - lastActionTime = Instant.now(); } break;