spec counter: add spec threshold notifications
This allows configuring spec thresholds which a notification will be sent for when reached. Additionally it colors the infobox text red or green based on if the threshold has been reached. Co-authored-by: Dylan <dylanhe@gmail.com> Co-authored-by: jgozon <47003557+jgozon@users.noreply.github.com>
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.specialcounter;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -34,13 +35,15 @@ import net.runelite.client.ui.overlay.infobox.Counter;
|
||||
class SpecialCounter extends Counter
|
||||
{
|
||||
private final SpecialWeapon weapon;
|
||||
private final SpecialCounterConfig config;
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final Map<String, Integer> partySpecs = new HashMap<>();
|
||||
|
||||
SpecialCounter(BufferedImage image, SpecialCounterPlugin plugin, int hitValue, SpecialWeapon weapon)
|
||||
SpecialCounter(BufferedImage image, SpecialCounterPlugin plugin, SpecialCounterConfig config, int hitValue, SpecialWeapon weapon)
|
||||
{
|
||||
super(image, plugin, hitValue);
|
||||
this.weapon = weapon;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
void addHits(double hit)
|
||||
@@ -90,4 +93,16 @@ class SpecialCounter extends Counter
|
||||
return weapon.getName() + " special has hit " + hitValue + " total.";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getTextColor()
|
||||
{
|
||||
int threshold = weapon.getThreshold().apply(config);
|
||||
if (threshold > 0)
|
||||
{
|
||||
int count = getCount();
|
||||
return count >= threshold ? Color.GREEN : Color.RED;
|
||||
}
|
||||
return super.getTextColor();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Dylan <dylanhe@umich.edu>
|
||||
* Copyright (c) 2020, Jacob <jgozon@umich.edu>
|
||||
* 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 net.runelite.client.config.Config;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
|
||||
@ConfigGroup("specialcounter")
|
||||
public interface SpecialCounterConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
position = 0,
|
||||
keyName = "thresholdNotification",
|
||||
name = "Threshold Notifications",
|
||||
description = "Sends a notification when your special attack counter exceeds the threshold"
|
||||
)
|
||||
default boolean thresholdNotification()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 1,
|
||||
keyName = "dragonWarhammerThreshold",
|
||||
name = "Dragon Warhammer",
|
||||
description = "Threshold for Dragon Warhammer (0 to disable)"
|
||||
)
|
||||
default int dragonWarhammerThreshold()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 2,
|
||||
keyName = "arclightThreshold",
|
||||
name = "Arclight",
|
||||
description = "Threshold for Arclight (0 to disable)"
|
||||
)
|
||||
default int arclightThreshold()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 3,
|
||||
keyName = "darklightThreshold",
|
||||
name = "Darklight",
|
||||
description = "Threshold for Darklight (0 to disable)"
|
||||
)
|
||||
default int darklightThreshold()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 4,
|
||||
keyName = "bandosGodswordThreshold",
|
||||
name = "Bandos Godsword",
|
||||
description = "Threshold for Bandos Godsword (0 to disable)"
|
||||
)
|
||||
default int bandosGodswordThreshold()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
package net.runelite.client.plugins.specialcounter;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Provides;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -46,7 +47,9 @@ import net.runelite.api.events.HitsplatApplied;
|
||||
import net.runelite.api.events.InteractingChanged;
|
||||
import net.runelite.api.events.NpcDespawned;
|
||||
import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
@@ -96,6 +99,18 @@ public class SpecialCounterPlugin extends Plugin
|
||||
@Inject
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Inject
|
||||
private Notifier notifier;
|
||||
|
||||
@Inject
|
||||
private SpecialCounterConfig config;
|
||||
|
||||
@Provides
|
||||
SpecialCounterConfig getConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(SpecialCounterConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp()
|
||||
{
|
||||
@@ -313,7 +328,7 @@ public class SpecialCounterPlugin extends Plugin
|
||||
|
||||
if (counter == null)
|
||||
{
|
||||
counter = new SpecialCounter(itemManager.getImage(specialWeapon.getItemID()), this,
|
||||
counter = new SpecialCounter(itemManager.getImage(specialWeapon.getItemID()), this, config,
|
||||
hit, specialWeapon);
|
||||
infoBoxManager.addInfoBox(counter);
|
||||
specialCounter[specialWeapon.ordinal()] = counter;
|
||||
@@ -323,6 +338,9 @@ public class SpecialCounterPlugin extends Plugin
|
||||
counter.addHits(hit);
|
||||
}
|
||||
|
||||
// Display a notification if special attack thresholds are met
|
||||
sendNotification(specialWeapon, counter);
|
||||
|
||||
// If in a party, add hit to partySpecs for the infobox tooltip
|
||||
Map<String, Integer> partySpecs = counter.getPartySpecs();
|
||||
if (!party.getMembers().isEmpty())
|
||||
@@ -338,6 +356,15 @@ public class SpecialCounterPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
private void sendNotification(SpecialWeapon weapon, SpecialCounter counter)
|
||||
{
|
||||
int threshold = weapon.getThreshold().apply(config);
|
||||
if (threshold > 0 && counter.getCount() >= threshold && config.thresholdNotification())
|
||||
{
|
||||
notifier.notify(weapon.getName() + " special attack threshold reached!");
|
||||
}
|
||||
}
|
||||
|
||||
private void removeCounters()
|
||||
{
|
||||
interactedNpcIds.clear();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.specialcounter;
|
||||
|
||||
import java.util.function.Function;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.ItemID;
|
||||
@@ -32,13 +33,14 @@ import net.runelite.api.ItemID;
|
||||
@Getter
|
||||
enum SpecialWeapon
|
||||
{
|
||||
DRAGON_WARHAMMER("Dragon Warhammer", ItemID.DRAGON_WARHAMMER, false),
|
||||
ARCLIGHT("Arclight", ItemID.ARCLIGHT, false),
|
||||
DARKLIGHT("Darklight", ItemID.DARKLIGHT, false),
|
||||
BANDOS_GODSWORD("Bandos Godsword", ItemID.BANDOS_GODSWORD, true),
|
||||
BANDOS_GODSWORD_OR("Bandos Godsword", ItemID.BANDOS_GODSWORD_OR, true);
|
||||
DRAGON_WARHAMMER("Dragon Warhammer", ItemID.DRAGON_WARHAMMER, false, SpecialCounterConfig::dragonWarhammerThreshold),
|
||||
ARCLIGHT("Arclight", ItemID.ARCLIGHT, false, SpecialCounterConfig::arclightThreshold),
|
||||
DARKLIGHT("Darklight", ItemID.DARKLIGHT, false, SpecialCounterConfig::darklightThreshold),
|
||||
BANDOS_GODSWORD("Bandos Godsword", ItemID.BANDOS_GODSWORD, true, SpecialCounterConfig::bandosGodswordThreshold),
|
||||
BANDOS_GODSWORD_OR("Bandos Godsword", ItemID.BANDOS_GODSWORD_OR, true, SpecialCounterConfig::bandosGodswordThreshold);
|
||||
|
||||
private final String name;
|
||||
private final int itemID;
|
||||
private final boolean damage;
|
||||
private final Function<SpecialCounterConfig, Integer> threshold;
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import net.runelite.api.VarPlayer;
|
||||
import net.runelite.api.events.HitsplatApplied;
|
||||
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.infobox.InfoBoxManager;
|
||||
import net.runelite.client.ws.PartyService;
|
||||
@@ -76,6 +77,14 @@ public class SpecialCounterPluginTest
|
||||
@Bind
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private Notifier notifier;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private SpecialCounterConfig specialCounterConfig;
|
||||
|
||||
@Inject
|
||||
private SpecialCounterPlugin specialCounterPlugin;
|
||||
|
||||
@@ -227,4 +236,62 @@ public class SpecialCounterPluginTest
|
||||
|
||||
verify(infoBoxManager).removeInfoBox(any(SpecialCounter.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotification()
|
||||
{
|
||||
// Create an enemy
|
||||
NPC target = mock(NPC.class);
|
||||
|
||||
// Create player
|
||||
Player player = mock(Player.class);
|
||||
when(client.getLocalPlayer()).thenReturn(player);
|
||||
when(specialCounterConfig.bandosGodswordThreshold()).thenReturn(2);
|
||||
when(specialCounterConfig.thresholdNotification()).thenReturn(true);
|
||||
|
||||
// Attack enemy
|
||||
when(player.getInteracting()).thenReturn(target);
|
||||
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, target));
|
||||
|
||||
// First special attack
|
||||
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
|
||||
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
|
||||
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
|
||||
|
||||
// Second special attack
|
||||
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(0);
|
||||
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
|
||||
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
|
||||
|
||||
verify(notifier).notify("Bandos Godsword special attack threshold reached!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotificationNotThreshold()
|
||||
{
|
||||
// Create an enemy
|
||||
NPC target = mock(NPC.class);
|
||||
|
||||
// Create player
|
||||
Player player = mock(Player.class);
|
||||
when(client.getLocalPlayer()).thenReturn(player);
|
||||
when(specialCounterConfig.bandosGodswordThreshold()).thenReturn(3);
|
||||
lenient().when(specialCounterConfig.thresholdNotification()).thenReturn(true);
|
||||
|
||||
// Attack enemy
|
||||
when(player.getInteracting()).thenReturn(target);
|
||||
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, target));
|
||||
|
||||
// First special attack
|
||||
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
|
||||
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
|
||||
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
|
||||
|
||||
// Second special attack
|
||||
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(0);
|
||||
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
|
||||
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
|
||||
|
||||
verify(notifier, never()).notify(any());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user