Add item overlay to show when monsters are weak enough to finish off (#6710)
Current behaviour shows the required item to finish an NPC off above it's head when it's health is below the required threshold. Works for Rockslugs, Gargoyles, Desert Lizards and Zygomites Fixes: #784
This commit is contained in:
committed by
Tomas Slusny
parent
a771a49ab2
commit
c8105908c0
@@ -99,6 +99,17 @@ public interface SlayerConfig extends Config
|
||||
return Color.RED;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 7,
|
||||
keyName = "weaknessPrompt",
|
||||
name = "Show Monster Weakness",
|
||||
description = "Show an overlay on a monster when it is weak enough to finish off (Only Lizards, Gargoyles & Rockslugs)"
|
||||
)
|
||||
default boolean weaknessPrompt()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stored data
|
||||
@ConfigItem(
|
||||
keyName = "taskName",
|
||||
|
||||
@@ -138,6 +138,9 @@ public class SlayerPlugin extends Plugin
|
||||
@Inject
|
||||
private TargetClickboxOverlay targetClickboxOverlay;
|
||||
|
||||
@Inject
|
||||
private TargetWeaknessOverlay targetWeaknessOverlay;
|
||||
|
||||
@Inject
|
||||
private TargetMinimapOverlay targetMinimapOverlay;
|
||||
|
||||
@@ -181,6 +184,7 @@ public class SlayerPlugin extends Plugin
|
||||
{
|
||||
overlayManager.add(overlay);
|
||||
overlayManager.add(targetClickboxOverlay);
|
||||
overlayManager.add(targetWeaknessOverlay);
|
||||
overlayManager.add(targetMinimapOverlay);
|
||||
|
||||
if (client.getGameState() == GameState.LOGGED_IN
|
||||
@@ -200,6 +204,7 @@ public class SlayerPlugin extends Plugin
|
||||
{
|
||||
overlayManager.remove(overlay);
|
||||
overlayManager.remove(targetClickboxOverlay);
|
||||
overlayManager.remove(targetWeaknessOverlay);
|
||||
overlayManager.remove(targetMinimapOverlay);
|
||||
removeCounter();
|
||||
highlightedTargets.clear();
|
||||
@@ -557,7 +562,8 @@ public class SlayerPlugin extends Plugin
|
||||
if (name.contains(target))
|
||||
{
|
||||
NPCComposition composition = npc.getTransformedComposition();
|
||||
if (composition != null && Arrays.asList(composition.getActions()).contains("Attack"))
|
||||
List actions = Arrays.asList(composition.getActions());
|
||||
if (composition != null && (actions.contains("Attack") || actions.contains("Pick"))) //Pick action is for zygomite-fungi
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam "Berry" Beresford <seb1g13@soton.ac.uk>
|
||||
* 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.slayer;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.Perspective;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.NPCManager;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
import net.runelite.client.ui.overlay.OverlayUtil;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
class TargetWeaknessOverlay extends Overlay
|
||||
{
|
||||
private final Client client;
|
||||
private final SlayerConfig config;
|
||||
private final SlayerPlugin plugin;
|
||||
private final ItemManager itemManager;
|
||||
private final NPCManager npcManager;
|
||||
|
||||
@Inject
|
||||
private TargetWeaknessOverlay(Client client, SlayerConfig config, SlayerPlugin plugin, ItemManager itemManager, NPCManager npcManager)
|
||||
{
|
||||
this.client = client;
|
||||
this.config = config;
|
||||
this.plugin = plugin;
|
||||
this.itemManager = itemManager;
|
||||
this.npcManager = npcManager;
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
setLayer(OverlayLayer.ABOVE_SCENE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
if (!config.weaknessPrompt())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
final Task curTask = Task.getTask(plugin.getTaskName());
|
||||
if (curTask == null || curTask.getWeaknessThreshold() < 0 || curTask.getWeaknessItem() < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
final int threshold = curTask.getWeaknessThreshold();
|
||||
final BufferedImage image = itemManager.getImage(curTask.getWeaknessItem());
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<NPC> targets = plugin.getHighlightedTargets();
|
||||
for (NPC target : targets)
|
||||
{
|
||||
final int currentHealth = calculateHealth(target);
|
||||
|
||||
if (currentHealth >= 0 && currentHealth <= threshold)
|
||||
{
|
||||
renderTargetItem(graphics, target, image);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int calculateHealth(NPC target)
|
||||
{
|
||||
// Based on OpponentInfoOverlay HP calculation
|
||||
if (target == null || target.getName() == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
final int healthScale = target.getHealth();
|
||||
final int healthRatio = target.getHealthRatio();
|
||||
final String targetName = Text.removeTags(target.getName());
|
||||
final Integer maxHealth = npcManager.getHealth(targetName, target.getCombatLevel());
|
||||
|
||||
if (healthRatio < 0 || healthScale <= 0 || maxHealth == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)((maxHealth * healthRatio / healthScale) + 0.5f);
|
||||
}
|
||||
|
||||
private void renderTargetItem(Graphics2D graphics, NPC actor, BufferedImage image)
|
||||
{
|
||||
final LocalPoint actorPosition = actor.getLocalLocation();
|
||||
final int offset = actor.getLogicalHeight() + 40;
|
||||
|
||||
if (actorPosition == null || image == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Point imageLoc = Perspective.getCanvasImageLocation(client, actorPosition, image, offset);
|
||||
|
||||
if (imageLoc != null)
|
||||
{
|
||||
OverlayUtil.renderImageLocation(graphics, imageLoc, image);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ enum Task
|
||||
DARK_BEASTS("Dark beasts", ItemID.DARK_BEAST, "Night beast"),
|
||||
DARK_WARRIORS("Dark warriors", ItemID.BLACK_MED_HELM, "Dark warrior"),
|
||||
DERANGED_ARCHAEOLOGIST("Deranged Archaeologist", ItemID.ARCHAEOLOGISTS_DIARY),
|
||||
DESERT_LIZARDS("Desert lizards", ItemID.DESERT_LIZARD, "Small lizard", "Lizard"),
|
||||
DESERT_LIZARDS("Desert lizards", ItemID.DESERT_LIZARD, 4, ItemID.ICE_COOLER, "Small lizard", "Lizard"),
|
||||
DOGS("Dogs", ItemID.GUARD_DOG, "Jackal"),
|
||||
DUST_DEVILS("Dust devils", ItemID.DUST_DEVIL, "Choke devil"),
|
||||
DWARVES("Dwarves", ItemID.DWARVEN_HELMET, "Dwarf"),
|
||||
@@ -86,7 +86,7 @@ enum Task
|
||||
REVENANTS("Revenants", ItemID.REVENANT_ETHER, "Revenant imp", "Revenant goblin", "Revenant pyrefiend", "Revenant hobgoblin", "Revenant cyclops", "Revenant hellhound", "Revenant demon", "Revenant ork", "Revenant dark beast", "Revenant knight", "Revenant dragon"),
|
||||
FLESH_CRAWLERS("Flesh crawlers", ItemID.ENSOULED_SCORPION_HEAD),
|
||||
FOSSIL_ISLAND_WYVERNS("Fossil island wyverns", ItemID.FOSSIL_ISLAND_WYVERN, "Ancient wyvern", "Long-tailed wyvern", "Spitting wyvern", "Taloned wyvern"),
|
||||
GARGOYLES("Gargoyles", ItemID.GARGOYLE),
|
||||
GARGOYLES("Gargoyles", ItemID.GARGOYLE, 9, ItemID.ROCK_HAMMER),
|
||||
GENERAL_GRAARDOR("General Graardor", ItemID.PET_GENERAL_GRAARDOR),
|
||||
GHOSTS("Ghosts", ItemID.GHOSTSPEAK_AMULET, "Tortured soul"),
|
||||
GIANT_MOLE("Giant Mole", ItemID.BABY_MOLE),
|
||||
@@ -94,7 +94,7 @@ enum Task
|
||||
GOBLINS("Goblins", ItemID.ENSOULED_GOBLIN_HEAD),
|
||||
GREATER_DEMONS("Greater demons", ItemID.GREATER_DEMON_MASK),
|
||||
GREEN_DRAGONS("Green dragons", ItemID.GREEN_DRAGON_MASK),
|
||||
GROTESQUE_GUARDIANS("Grotesque Guardians", ItemID.MIDNIGHT),
|
||||
GROTESQUE_GUARDIANS("Grotesque Guardians", ItemID.MIDNIGHT, 0, ItemID.ROCK_HAMMER, "Dusk", "Dawn"),
|
||||
HARPIE_BUG_SWARMS("Harpie bug swarms", ItemID.SWARM),
|
||||
HELLHOUNDS("Hellhounds", ItemID.HELLHOUND),
|
||||
HILL_GIANTS("Hill giants", ItemID.ENSOULED_GIANT_HEAD),
|
||||
@@ -126,14 +126,14 @@ enum Task
|
||||
MOLANISKS("Molanisks", ItemID.MOLANISK),
|
||||
MONKEYS("Monkeys", ItemID.ENSOULED_MONKEY_HEAD),
|
||||
MOSS_GIANTS("Moss giants", ItemID.HILL_GIANT_CLUB),
|
||||
MUTATED_ZYGOMITES("Mutated zygomites", ItemID.MUTATED_ZYGOMITE),
|
||||
MUTATED_ZYGOMITES("Mutated zygomites", ItemID.MUTATED_ZYGOMITE, 0, ItemID.FUNGICIDE_SPRAY_0, "Zygomite", "Fungi"),
|
||||
NECHRYAEL("Nechryael", ItemID.NECHRYAEL, "Nechryarch"),
|
||||
OGRES("Ogres", ItemID.ENSOULED_OGRE_HEAD),
|
||||
OTHERWORLDLY_BEING("Otherworldly beings", ItemID.GHOSTLY_HOOD),
|
||||
PYREFIENDS("Pyrefiends", ItemID.PYREFIEND, "Flaming pyrelord"),
|
||||
RATS("Rats", ItemID.RATS_TAIL),
|
||||
RED_DRAGONS("Red dragons", ItemID.BABY_RED_DRAGON),
|
||||
ROCKSLUGS("Rockslugs", ItemID.ROCKSLUG),
|
||||
ROCKSLUGS("Rockslugs", ItemID.ROCKSLUG, 4, ItemID.BAG_OF_SALT),
|
||||
RUNE_DRAGONS("Rune dragons", ItemID.RUNITE_BAR),
|
||||
SCORPIA("Scorpia", ItemID.SCORPIAS_OFFSPRING),
|
||||
CHAOS_DRUIDS("Chaos druids", ItemID.ELDER_CHAOS_HOOD, "Elder Chaos druid", "Chaos druid"),
|
||||
@@ -174,6 +174,8 @@ enum Task
|
||||
private final String name;
|
||||
private final int itemSpriteId;
|
||||
private final String[] targetNames;
|
||||
private final int weaknessThreshold;
|
||||
private final int weaknessItem;
|
||||
|
||||
static
|
||||
{
|
||||
@@ -188,6 +190,18 @@ enum Task
|
||||
Preconditions.checkArgument(itemSpriteId >= 0);
|
||||
this.name = name;
|
||||
this.itemSpriteId = itemSpriteId;
|
||||
this.weaknessThreshold = -1;
|
||||
this.weaknessItem = -1;
|
||||
this.targetNames = targetNames;
|
||||
}
|
||||
|
||||
Task(String name, int itemSpriteId, int weaknessThreshold, int weaknessItem, String... targetNames)
|
||||
{
|
||||
Preconditions.checkArgument(itemSpriteId >= 0);
|
||||
this.name = name;
|
||||
this.itemSpriteId = itemSpriteId;
|
||||
this.weaknessThreshold = weaknessThreshold;
|
||||
this.weaknessItem = weaknessItem;
|
||||
this.targetNames = targetNames;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user