Show opponents hp in menu, your target colored, targeting you *
This commit is contained in:
@@ -64,8 +64,11 @@ public interface Actor extends Entity, Locatable
|
|||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @return the actor, null if no interaction is occurring
|
* @return the actor, null if no interaction is occurring
|
||||||
|
*
|
||||||
|
* (getRSInteracting returns the npc/player index, useful for menus)
|
||||||
*/
|
*/
|
||||||
Actor getInteracting();
|
Actor getInteracting();
|
||||||
|
int getRSInteracting();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the health ratio of the actor.
|
* Gets the health ratio of the actor.
|
||||||
|
|||||||
@@ -341,9 +341,12 @@ public interface Client extends GameShell
|
|||||||
* Gets the logged in player instance.
|
* Gets the logged in player instance.
|
||||||
*
|
*
|
||||||
* @return the logged in player
|
* @return the logged in player
|
||||||
|
*
|
||||||
|
* (getLocalPlayerIndex returns the local index, useful for menus/interacting)
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Player getLocalPlayer();
|
Player getLocalPlayer();
|
||||||
|
int getLocalPlayerIndex();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the item composition corresponding to an items ID.
|
* Gets the item composition corresponding to an items ID.
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ public class MenuManager
|
|||||||
private MenuEntry leftClickEntry = null;
|
private MenuEntry leftClickEntry = null;
|
||||||
private MenuEntry firstEntry = null;
|
private MenuEntry firstEntry = null;
|
||||||
|
|
||||||
|
private int playerAttackIdx = -1;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private MenuManager(Client client, EventBus eventBus)
|
private MenuManager(Client client, EventBus eventBus)
|
||||||
{
|
{
|
||||||
@@ -500,6 +502,29 @@ public class MenuManager
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getPlayerAttackOpcode()
|
||||||
|
{
|
||||||
|
final String[] playerMenuOptions = client.getPlayerOptions();
|
||||||
|
|
||||||
|
if (playerAttackIdx != -1 && playerMenuOptions[playerAttackIdx].equals("Attack"))
|
||||||
|
{
|
||||||
|
return client.getPlayerMenuTypes()[playerAttackIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
playerAttackIdx = -1;
|
||||||
|
|
||||||
|
for (int i = IDX_LOWER; i < IDX_UPPER; i++)
|
||||||
|
{
|
||||||
|
if ("Attack".equals(playerMenuOptions[i]))
|
||||||
|
{
|
||||||
|
playerAttackIdx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerAttackIdx >= 0 ? client.getPlayerMenuTypes()[playerAttackIdx] : -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds to the set of menu entries which when present, will remove all entries except for this one
|
* Adds to the set of menu entries which when present, will remove all entries except for this one
|
||||||
*/
|
*/
|
||||||
@@ -522,7 +547,7 @@ public class MenuManager
|
|||||||
|
|
||||||
AbstractComparableEntry entry = newBaseComparableEntry(option, target);
|
AbstractComparableEntry entry = newBaseComparableEntry(option, target);
|
||||||
|
|
||||||
priorityEntries.removeIf(entry::equals);
|
priorityEntries.remove(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -562,7 +587,7 @@ public class MenuManager
|
|||||||
|
|
||||||
public void removePriorityEntry(AbstractComparableEntry entry)
|
public void removePriorityEntry(AbstractComparableEntry entry)
|
||||||
{
|
{
|
||||||
priorityEntries.removeIf(entry::equals);
|
priorityEntries.remove(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePriorityEntry(String option)
|
public void removePriorityEntry(String option)
|
||||||
@@ -571,7 +596,7 @@ public class MenuManager
|
|||||||
|
|
||||||
AbstractComparableEntry entry = newBaseComparableEntry(option, "", false);
|
AbstractComparableEntry entry = newBaseComparableEntry(option, "", false);
|
||||||
|
|
||||||
priorityEntries.removeIf(entry::equals);
|
priorityEntries.remove(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePriorityEntry(String option, boolean strictOption)
|
public void removePriorityEntry(String option, boolean strictOption)
|
||||||
@@ -581,7 +606,17 @@ public class MenuManager
|
|||||||
AbstractComparableEntry entry =
|
AbstractComparableEntry entry =
|
||||||
newBaseComparableEntry(option, "", -1, -1, false, strictOption);
|
newBaseComparableEntry(option, "", -1, -1, false, strictOption);
|
||||||
|
|
||||||
priorityEntries.removeIf(entry::equals);
|
priorityEntries.remove(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPriorityEntries(Collection<AbstractComparableEntry> entries)
|
||||||
|
{
|
||||||
|
priorityEntries.addAll(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePriorityEntries(Collection<AbstractComparableEntry> entries)
|
||||||
|
{
|
||||||
|
priorityEntries.removeAll(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.opponentinfo;
|
package net.runelite.client.plugins.opponentinfo;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
import net.runelite.client.config.Config;
|
import net.runelite.client.config.Config;
|
||||||
import net.runelite.client.config.ConfigGroup;
|
import net.runelite.client.config.ConfigGroup;
|
||||||
import net.runelite.client.config.ConfigItem;
|
import net.runelite.client.config.ConfigItem;
|
||||||
@@ -65,12 +66,47 @@ public interface OpponentInfoConfig extends Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "showOpponentsInMenu",
|
keyName = "showAttackersMenu",
|
||||||
name = "Show opponents in menu",
|
name = "Show attackers in menu",
|
||||||
description = "Marks opponents names in the menu which you are attacking or are attacking you (NPC only)",
|
description = "Marks attackers' names in menus with a *<br>",
|
||||||
position = 3
|
position = 3,
|
||||||
|
warning = "NOTE: This'll also mark people who are following you/interacting with you in any other way. Don't blindly trust this in pvp!"
|
||||||
)
|
)
|
||||||
default boolean showOpponentsInMenu()
|
default boolean showAttackersMenu()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "showAttackingMenu",
|
||||||
|
name = "Green main target",
|
||||||
|
description = "Display main target's name colored in menus (Players and NPCs)",
|
||||||
|
position = 4,
|
||||||
|
warning = "NOTE: This'll also show green when following/interacting in any other way. Don't blindly trust this in pvp!"
|
||||||
|
)
|
||||||
|
default boolean showAttackingMenu()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "attackingColor",
|
||||||
|
name = "Target color",
|
||||||
|
description = "The color your target will be highlighted with",
|
||||||
|
position = 5
|
||||||
|
)
|
||||||
|
default Color attackingColor()
|
||||||
|
{
|
||||||
|
return Color.GREEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "showHitpointsMenu",
|
||||||
|
name = "Show NPC hp in menu",
|
||||||
|
description = "Show NPC hp in menu. Useful when barraging",
|
||||||
|
position = 6
|
||||||
|
)
|
||||||
|
default boolean showHitpointsMenu()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,11 +36,7 @@ import javax.inject.Singleton;
|
|||||||
import net.runelite.api.Actor;
|
import net.runelite.api.Actor;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import static net.runelite.api.MenuOpcode.RUNELITE_OVERLAY_CONFIG;
|
import static net.runelite.api.MenuOpcode.RUNELITE_OVERLAY_CONFIG;
|
||||||
import net.runelite.api.NPC;
|
|
||||||
import net.runelite.api.Player;
|
|
||||||
import net.runelite.api.Varbits;
|
import net.runelite.api.Varbits;
|
||||||
import net.runelite.client.game.HiscoreManager;
|
|
||||||
import net.runelite.client.game.NPCManager;
|
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
|
import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
|
||||||
import net.runelite.client.ui.overlay.OverlayMenuEntry;
|
import net.runelite.client.ui.overlay.OverlayMenuEntry;
|
||||||
@@ -51,7 +47,6 @@ import net.runelite.client.ui.overlay.components.PanelComponent;
|
|||||||
import net.runelite.client.ui.overlay.components.ProgressBarComponent;
|
import net.runelite.client.ui.overlay.components.ProgressBarComponent;
|
||||||
import net.runelite.client.ui.overlay.components.TitleComponent;
|
import net.runelite.client.ui.overlay.components.TitleComponent;
|
||||||
import net.runelite.api.util.Text;
|
import net.runelite.api.util.Text;
|
||||||
import net.runelite.http.api.hiscore.HiscoreResult;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class OpponentInfoOverlay extends Overlay
|
class OpponentInfoOverlay extends Overlay
|
||||||
@@ -61,8 +56,6 @@ class OpponentInfoOverlay extends Overlay
|
|||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final OpponentInfoPlugin opponentInfoPlugin;
|
private final OpponentInfoPlugin opponentInfoPlugin;
|
||||||
private final HiscoreManager hiscoreManager;
|
|
||||||
private final NPCManager npcManager;
|
|
||||||
|
|
||||||
private final PanelComponent panelComponent = new PanelComponent();
|
private final PanelComponent panelComponent = new PanelComponent();
|
||||||
|
|
||||||
@@ -75,15 +68,11 @@ class OpponentInfoOverlay extends Overlay
|
|||||||
@Inject
|
@Inject
|
||||||
private OpponentInfoOverlay(
|
private OpponentInfoOverlay(
|
||||||
final Client client,
|
final Client client,
|
||||||
final OpponentInfoPlugin opponentInfoPlugin,
|
final OpponentInfoPlugin opponentInfoPlugin)
|
||||||
final HiscoreManager hiscoreManager,
|
|
||||||
final NPCManager npcManager)
|
|
||||||
{
|
{
|
||||||
super(opponentInfoPlugin);
|
super(opponentInfoPlugin);
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.opponentInfoPlugin = opponentInfoPlugin;
|
this.opponentInfoPlugin = opponentInfoPlugin;
|
||||||
this.hiscoreManager = hiscoreManager;
|
|
||||||
this.npcManager = npcManager;
|
|
||||||
|
|
||||||
setPosition(OverlayPosition.TOP_LEFT);
|
setPosition(OverlayPosition.TOP_LEFT);
|
||||||
setPriority(OverlayPriority.HIGH);
|
setPriority(OverlayPriority.HIGH);
|
||||||
@@ -110,23 +99,7 @@ class OpponentInfoOverlay extends Overlay
|
|||||||
lastHealthScale = opponent.getHealth();
|
lastHealthScale = opponent.getHealth();
|
||||||
opponentName = Text.removeTags(opponent.getName());
|
opponentName = Text.removeTags(opponent.getName());
|
||||||
|
|
||||||
lastMaxHealth = -1;
|
lastMaxHealth = opponentInfoPlugin.getMaxHp(opponent);
|
||||||
if (opponent instanceof NPC)
|
|
||||||
{
|
|
||||||
lastMaxHealth = npcManager.getHealth(((NPC) opponent).getId());
|
|
||||||
}
|
|
||||||
else if (opponent instanceof Player)
|
|
||||||
{
|
|
||||||
final HiscoreResult hiscoreResult = hiscoreManager.lookupAsync(opponentName, opponentInfoPlugin.getHiscoreEndpoint());
|
|
||||||
if (hiscoreResult != null)
|
|
||||||
{
|
|
||||||
final int hp = hiscoreResult.getHitpoints().getLevel();
|
|
||||||
if (hp > 0)
|
|
||||||
{
|
|
||||||
lastMaxHealth = hp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Actor opponentsOpponent = opponent.getInteracting();
|
final Actor opponentsOpponent = opponent.getInteracting();
|
||||||
if (opponentsOpponent != null
|
if (opponentsOpponent != null
|
||||||
@@ -168,37 +141,7 @@ class OpponentInfoOverlay extends Overlay
|
|||||||
if ((displayStyle == HitpointsDisplayStyle.HITPOINTS || displayStyle == HitpointsDisplayStyle.BOTH)
|
if ((displayStyle == HitpointsDisplayStyle.HITPOINTS || displayStyle == HitpointsDisplayStyle.BOTH)
|
||||||
&& lastMaxHealth != -1)
|
&& lastMaxHealth != -1)
|
||||||
{
|
{
|
||||||
// This is the reverse of the calculation of healthRatio done by the server
|
int health = getExactHp(lastRatio, lastHealthScale, lastMaxHealth);
|
||||||
// which is: healthRatio = 1 + (healthScale - 1) * health / maxHealth (if health > 0, 0 otherwise)
|
|
||||||
// It's able to recover the exact health if maxHealth <= healthScale.
|
|
||||||
int health = 0;
|
|
||||||
if (lastRatio > 0)
|
|
||||||
{
|
|
||||||
int minHealth = 1;
|
|
||||||
int maxHealth;
|
|
||||||
if (lastHealthScale > 1)
|
|
||||||
{
|
|
||||||
if (lastRatio > 1)
|
|
||||||
{
|
|
||||||
// This doesn't apply if healthRatio = 1, because of the special case in the server calculation that
|
|
||||||
// health = 0 forces healthRatio = 0 instead of the expected healthRatio = 1
|
|
||||||
minHealth = (lastMaxHealth * (lastRatio - 1) + lastHealthScale - 2) / (lastHealthScale - 1);
|
|
||||||
}
|
|
||||||
maxHealth = (lastMaxHealth * lastRatio - 1) / (lastHealthScale - 1);
|
|
||||||
if (maxHealth > lastMaxHealth)
|
|
||||||
{
|
|
||||||
maxHealth = lastMaxHealth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If healthScale is 1, healthRatio will always be 1 unless health = 0
|
|
||||||
// so we know nothing about the upper limit except that it can't be higher than maxHealth
|
|
||||||
maxHealth = lastMaxHealth;
|
|
||||||
}
|
|
||||||
// Take the average of min and max possible healths
|
|
||||||
health = (minHealth + maxHealth + 1) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show both the hitpoint and percentage values if enabled in the config
|
// Show both the hitpoint and percentage values if enabled in the config
|
||||||
final ProgressBarComponent.LabelDisplayMode progressBarDisplayMode = displayStyle == HitpointsDisplayStyle.BOTH ?
|
final ProgressBarComponent.LabelDisplayMode progressBarDisplayMode = displayStyle == HitpointsDisplayStyle.BOTH ?
|
||||||
@@ -229,4 +172,47 @@ class OpponentInfoOverlay extends Overlay
|
|||||||
|
|
||||||
return panelComponent.render(graphics);
|
return panelComponent.render(graphics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int getExactHp(int ratio, int health, int maxHp)
|
||||||
|
{
|
||||||
|
if (ratio < 0 || health <= 0 || maxHp == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exactHealth = 0;
|
||||||
|
|
||||||
|
// This is the reverse of the calculation of healthRatio done by the server
|
||||||
|
// which is: healthRatio = 1 + (healthScale - 1) * health / maxHealth (if health > 0, 0 otherwise)
|
||||||
|
// It's able to recover the exact health if maxHealth <= healthScale.
|
||||||
|
if (ratio > 0)
|
||||||
|
{
|
||||||
|
int minHealth = 1;
|
||||||
|
int maxHealth;
|
||||||
|
if (health > 1)
|
||||||
|
{
|
||||||
|
if (ratio > 1)
|
||||||
|
{
|
||||||
|
// This doesn't apply if healthRatio = 1, because of the special case in the server calculation that
|
||||||
|
// health = 0 forces healthRatio = 0 instead of the expected healthRatio = 1
|
||||||
|
minHealth = (maxHp * (ratio - 1) + health - 2) / (health - 1);
|
||||||
|
}
|
||||||
|
maxHealth = (maxHp * ratio - 1) / (health - 1);
|
||||||
|
if (maxHealth > maxHp)
|
||||||
|
{
|
||||||
|
maxHealth = maxHp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If healthScale is 1, healthRatio will always be 1 unless health = 0
|
||||||
|
// so we know nothing about the upper limit except that it can't be higher than maxHealth
|
||||||
|
maxHealth = maxHp;
|
||||||
|
}
|
||||||
|
// Take the average of min and max possible healths
|
||||||
|
exactHealth = (minHealth + maxHealth + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exactHealth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,24 +33,33 @@ import javax.inject.Inject;
|
|||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.Actor;
|
import net.runelite.api.Actor;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.GameState;
|
import net.runelite.api.GameState;
|
||||||
import net.runelite.api.MenuEntry;
|
import net.runelite.api.MenuEntry;
|
||||||
import net.runelite.api.MenuOpcode;
|
import net.runelite.api.MenuOpcode;
|
||||||
import net.runelite.api.NPC;
|
import net.runelite.api.NPC;
|
||||||
|
import net.runelite.api.Player;
|
||||||
import net.runelite.api.WorldType;
|
import net.runelite.api.WorldType;
|
||||||
|
import net.runelite.api.events.BeforeRender;
|
||||||
import net.runelite.api.events.ConfigChanged;
|
import net.runelite.api.events.ConfigChanged;
|
||||||
import net.runelite.api.events.GameStateChanged;
|
import net.runelite.api.events.GameStateChanged;
|
||||||
import net.runelite.api.events.GameTick;
|
import net.runelite.api.events.GameTick;
|
||||||
import net.runelite.api.events.InteractingChanged;
|
import net.runelite.api.events.InteractingChanged;
|
||||||
import net.runelite.api.events.MenuEntryAdded;
|
import net.runelite.api.events.MenuOpened;
|
||||||
|
import net.runelite.api.util.Text;
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.EventBus;
|
import net.runelite.client.eventbus.EventBus;
|
||||||
|
import net.runelite.client.game.HiscoreManager;
|
||||||
|
import net.runelite.client.game.NPCManager;
|
||||||
|
import net.runelite.client.menus.MenuManager;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
import net.runelite.client.ui.overlay.OverlayManager;
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
|
import net.runelite.client.util.ColorUtil;
|
||||||
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
||||||
|
import net.runelite.http.api.hiscore.HiscoreResult;
|
||||||
|
|
||||||
@PluginDescriptor(
|
@PluginDescriptor(
|
||||||
name = "Opponent Information",
|
name = "Opponent Information",
|
||||||
@@ -58,9 +67,12 @@ import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
|||||||
tags = {"combat", "health", "hitpoints", "npcs", "overlay"}
|
tags = {"combat", "health", "hitpoints", "npcs", "overlay"}
|
||||||
)
|
)
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@Slf4j
|
||||||
public class OpponentInfoPlugin extends Plugin
|
public class OpponentInfoPlugin extends Plugin
|
||||||
{
|
{
|
||||||
private static final Duration WAIT = Duration.ofSeconds(5);
|
private static final Duration WAIT = Duration.ofSeconds(5);
|
||||||
|
private static final Object MENU = new Object();
|
||||||
|
private static final int COLOR_TAG_LENGTH = 12;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Client client;
|
private Client client;
|
||||||
@@ -80,6 +92,15 @@ public class OpponentInfoPlugin extends Plugin
|
|||||||
@Inject
|
@Inject
|
||||||
private EventBus eventBus;
|
private EventBus eventBus;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private HiscoreManager hiscoreManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private MenuManager menuManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private NPCManager npcManager;
|
||||||
|
|
||||||
@Getter(AccessLevel.PACKAGE)
|
@Getter(AccessLevel.PACKAGE)
|
||||||
private HiscoreEndpoint hiscoreEndpoint = HiscoreEndpoint.NORMAL;
|
private HiscoreEndpoint hiscoreEndpoint = HiscoreEndpoint.NORMAL;
|
||||||
|
|
||||||
@@ -95,6 +116,11 @@ public class OpponentInfoPlugin extends Plugin
|
|||||||
@Getter(AccessLevel.PACKAGE)
|
@Getter(AccessLevel.PACKAGE)
|
||||||
private boolean showOpponentsOpponent;
|
private boolean showOpponentsOpponent;
|
||||||
|
|
||||||
|
private String attackingColTag;
|
||||||
|
private boolean showAttackers;
|
||||||
|
private boolean showAttacking;
|
||||||
|
private boolean showHitpoints;
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
OpponentInfoConfig provideConfig(ConfigManager configManager)
|
OpponentInfoConfig provideConfig(ConfigManager configManager)
|
||||||
{
|
{
|
||||||
@@ -104,6 +130,11 @@ public class OpponentInfoPlugin extends Plugin
|
|||||||
@Override
|
@Override
|
||||||
protected void startUp() throws Exception
|
protected void startUp() throws Exception
|
||||||
{
|
{
|
||||||
|
this.attackingColTag = ColorUtil.colorTag(config.attackingColor());
|
||||||
|
this.showAttackers = config.showAttackersMenu();
|
||||||
|
this.showAttacking = config.showAttackingMenu();
|
||||||
|
this.showHitpoints = config.showHitpointsMenu();
|
||||||
|
|
||||||
updateConfig();
|
updateConfig();
|
||||||
addSubscriptions();
|
addSubscriptions();
|
||||||
|
|
||||||
@@ -115,6 +146,7 @@ public class OpponentInfoPlugin extends Plugin
|
|||||||
protected void shutDown() throws Exception
|
protected void shutDown() throws Exception
|
||||||
{
|
{
|
||||||
eventBus.unregister(this);
|
eventBus.unregister(this);
|
||||||
|
eventBus.unregister(MENU);
|
||||||
|
|
||||||
lastOpponent = null;
|
lastOpponent = null;
|
||||||
lastTime = null;
|
lastTime = null;
|
||||||
@@ -128,7 +160,20 @@ public class OpponentInfoPlugin extends Plugin
|
|||||||
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
|
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
|
||||||
eventBus.subscribe(InteractingChanged.class, this, this::onInteractingChanged);
|
eventBus.subscribe(InteractingChanged.class, this, this::onInteractingChanged);
|
||||||
eventBus.subscribe(GameTick.class, this, this::onGameTick);
|
eventBus.subscribe(GameTick.class, this, this::onGameTick);
|
||||||
eventBus.subscribe(MenuEntryAdded.class, this, this::onMenuEntryAdded);
|
updateMenuSubs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMenuSubs()
|
||||||
|
{
|
||||||
|
if (showAttackers || showAttacking || showHitpoints)
|
||||||
|
{
|
||||||
|
eventBus.subscribe(BeforeRender.class, MENU, this::onBeforeRender);
|
||||||
|
eventBus.subscribe(MenuOpened.class, MENU, this::onMenuOpened);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eventBus.unregister(MENU);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onGameStateChanged(GameStateChanged gameStateChanged)
|
private void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||||
@@ -194,6 +239,25 @@ public class OpponentInfoPlugin extends Plugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (event.getKey())
|
||||||
|
{
|
||||||
|
case "showAttackersMenu":
|
||||||
|
this.showAttackers = config.showAttackersMenu();
|
||||||
|
updateMenuSubs();
|
||||||
|
break;
|
||||||
|
case "showAttackingMenu":
|
||||||
|
this.showAttacking = config.showAttackingMenu();
|
||||||
|
updateMenuSubs();
|
||||||
|
break;
|
||||||
|
case "showHitpointsMenu":
|
||||||
|
this.showHitpoints = config.showHitpointsMenu();
|
||||||
|
updateMenuSubs();
|
||||||
|
break;
|
||||||
|
case "attackingColor":
|
||||||
|
attackingColTag = ColorUtil.colorTag(config.attackingColor());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
updateConfig();
|
updateConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,27 +268,253 @@ public class OpponentInfoPlugin extends Plugin
|
|||||||
this.showOpponentsOpponent = config.showOpponentsOpponent();
|
this.showOpponentsOpponent = config.showOpponentsOpponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onMenuEntryAdded(MenuEntryAdded menuEntryAdded)
|
private void onBeforeRender(BeforeRender event)
|
||||||
{
|
{
|
||||||
if (menuEntryAdded.getOpcode() != MenuOpcode.NPC_SECOND_OPTION.getId()
|
if (client.getMenuOptionCount() <= 0)
|
||||||
|| !menuEntryAdded.getOption().equals("Attack")
|
|
||||||
|| !config.showOpponentsInMenu())
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (client.isMenuOpen())
|
||||||
int npcIndex = menuEntryAdded.getIdentifier();
|
|
||||||
NPC npc = client.getCachedNPCs()[npcIndex];
|
|
||||||
if (npc == null)
|
|
||||||
{
|
{
|
||||||
|
boolean changed = false;
|
||||||
|
final MenuEntry[] entries = client.getMenuEntries();
|
||||||
|
for (final MenuEntry entry : entries)
|
||||||
|
{
|
||||||
|
changed |= fixup(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
client.setMenuEntries(entries);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (npc.getInteracting() == client.getLocalPlayer() || lastOpponent == npc)
|
final MenuEntry entry = client.getLeftClickMenuEntry();
|
||||||
|
if (modify(entry))
|
||||||
{
|
{
|
||||||
MenuEntry[] menuEntries = client.getMenuEntries();
|
client.setLeftClickMenuEntry(entry);
|
||||||
menuEntries[menuEntries.length - 1].setTarget("*" + menuEntryAdded.getTarget());
|
}
|
||||||
client.setMenuEntries(menuEntries);
|
}
|
||||||
|
|
||||||
|
private void onMenuOpened(MenuOpened event)
|
||||||
|
{
|
||||||
|
boolean changed = false;
|
||||||
|
for (MenuEntry entry : event.getMenuEntries())
|
||||||
|
{
|
||||||
|
changed |= modify(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
event.setModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean modify(MenuEntry entry)
|
||||||
|
{
|
||||||
|
if (isNotAttackEntry(entry))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean changed = false;
|
||||||
|
|
||||||
|
int index = entry.getIdentifier();
|
||||||
|
Actor actor = getActorFromIndex(index);
|
||||||
|
|
||||||
|
if (actor == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor instanceof Player)
|
||||||
|
{
|
||||||
|
index -= 32768;
|
||||||
|
}
|
||||||
|
|
||||||
|
String target = entry.getTarget();
|
||||||
|
|
||||||
|
if (showAttacking &&
|
||||||
|
client.getLocalPlayer().getRSInteracting() == index)
|
||||||
|
{
|
||||||
|
target = attackingColTag + target.substring(COLOR_TAG_LENGTH);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showAttackers &&
|
||||||
|
actor.getRSInteracting() - 32768 == client.getLocalPlayerIndex())
|
||||||
|
{
|
||||||
|
target = '*' + target;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showHitpoints &&
|
||||||
|
actor.getHealth() > 0)
|
||||||
|
{
|
||||||
|
int lvlIndex = target.lastIndexOf("(level-");
|
||||||
|
if (lvlIndex != -1)
|
||||||
|
{
|
||||||
|
String levelReplacement = getHpString(actor, true);
|
||||||
|
|
||||||
|
target = target.substring(0, lvlIndex) + levelReplacement;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
entry.setTarget(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean fixup(MenuEntry entry)
|
||||||
|
{
|
||||||
|
if (isNotAttackEntry(entry))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = entry.getIdentifier();
|
||||||
|
|
||||||
|
Actor actor = getActorFromIndex(index);
|
||||||
|
|
||||||
|
if (actor == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor instanceof Player)
|
||||||
|
{
|
||||||
|
index -= 32768;
|
||||||
|
}
|
||||||
|
|
||||||
|
String target = entry.getTarget();
|
||||||
|
|
||||||
|
boolean hasAggro = actor.getRSInteracting() - 32768 == client.getLocalPlayerIndex();
|
||||||
|
boolean hadAggro = target.charAt(0) == '*';
|
||||||
|
boolean isTarget = client.getLocalPlayer().getRSInteracting() == index;
|
||||||
|
boolean hasHp = showHitpoints && actor instanceof NPC && actor.getHealth() > 0;
|
||||||
|
|
||||||
|
boolean aggroChanged = showAttackers && hasAggro != hadAggro;
|
||||||
|
boolean targetChanged = showAttacking && isTarget != target.startsWith(attackingColTag, aggroChanged ? 1 : 0);
|
||||||
|
boolean hpChanged = showHitpoints && hasHp == target.contains("(level-");
|
||||||
|
|
||||||
|
if (!aggroChanged &&
|
||||||
|
!targetChanged &&
|
||||||
|
!hasHp &&
|
||||||
|
!hpChanged)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetChanged)
|
||||||
|
{
|
||||||
|
boolean player = actor instanceof Player;
|
||||||
|
final int start = hadAggro ? 1 + COLOR_TAG_LENGTH : COLOR_TAG_LENGTH;
|
||||||
|
target =
|
||||||
|
(hasAggro ? '*' : "") +
|
||||||
|
(isTarget ? attackingColTag :
|
||||||
|
player ? ColorUtil.colorStartTag(0xffffff) : ColorUtil.colorStartTag(0xffff00)) +
|
||||||
|
target.substring(start);
|
||||||
|
}
|
||||||
|
else if (aggroChanged)
|
||||||
|
{
|
||||||
|
if (hasAggro)
|
||||||
|
{
|
||||||
|
target = '*' + target;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target = target.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hpChanged || hasHp)
|
||||||
|
{
|
||||||
|
final int braceIdx;
|
||||||
|
|
||||||
|
if (!hasHp)
|
||||||
|
{
|
||||||
|
braceIdx = target.lastIndexOf("<col=ff0000>(");
|
||||||
|
if (braceIdx != -1)
|
||||||
|
{
|
||||||
|
target = target.substring(0, braceIdx - 1) + "(level-" + actor.getCombatLevel() + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((braceIdx = target.lastIndexOf('(')) != -1)
|
||||||
|
{
|
||||||
|
final String hpString = getHpString(actor, hpChanged);
|
||||||
|
|
||||||
|
target = target.substring(0, braceIdx) + hpString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.setTarget(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNotAttackEntry(MenuEntry entry)
|
||||||
|
{
|
||||||
|
return entry.getOpcode() != MenuOpcode.NPC_SECOND_OPTION.getId() &&
|
||||||
|
entry.getOpcode() != menuManager.getPlayerAttackOpcode()
|
||||||
|
|| !entry.getOption().equals("Attack");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getHpString(Actor actor, boolean withColorTag)
|
||||||
|
{
|
||||||
|
int maxHp = getMaxHp(actor);
|
||||||
|
int health = actor.getHealth();
|
||||||
|
int ratio = actor.getHealthRatio();
|
||||||
|
|
||||||
|
final String result;
|
||||||
|
if (maxHp != -1)
|
||||||
|
{
|
||||||
|
final int exactHealth = OpponentInfoOverlay.getExactHp(ratio, health, maxHp);
|
||||||
|
result = "(" + exactHealth + "/" + maxHp + ")";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = "(" + (100 * ratio) / health + "%)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return withColorTag ? ColorUtil.colorStartTag(0xff0000) + result : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMaxHp(Actor actor)
|
||||||
|
{
|
||||||
|
if (actor instanceof NPC)
|
||||||
|
{
|
||||||
|
return npcManager.getHealth(((NPC) actor).getId());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
final HiscoreResult hiscoreResult = hiscoreManager.lookupAsync(Text.removeTags(actor.getName()), getHiscoreEndpoint());
|
||||||
|
if (hiscoreResult != null)
|
||||||
|
{
|
||||||
|
final int hp = hiscoreResult.getHitpoints().getLevel();
|
||||||
|
if (hp > 0)
|
||||||
|
{
|
||||||
|
return hp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Actor getActorFromIndex(int index)
|
||||||
|
{
|
||||||
|
if (index < 32768)
|
||||||
|
{
|
||||||
|
return client.getCachedNPCs()[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return client.getCachedPlayers()[index - 32768];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import net.runelite.mapping.Import;
|
|||||||
public interface RSActor extends RSEntity, Actor
|
public interface RSActor extends RSEntity, Actor
|
||||||
{
|
{
|
||||||
@Import("targetIndex")
|
@Import("targetIndex")
|
||||||
|
@Override
|
||||||
int getRSInteracting();
|
int getRSInteracting();
|
||||||
|
|
||||||
// Overhead text
|
// Overhead text
|
||||||
|
|||||||
@@ -208,6 +208,10 @@ public interface RSClient extends RSGameShell, Client
|
|||||||
@Override
|
@Override
|
||||||
RSPlayer getLocalPlayer();
|
RSPlayer getLocalPlayer();
|
||||||
|
|
||||||
|
@Import("localPlayerIndex")
|
||||||
|
@Override
|
||||||
|
int getLocalPlayerIndex();
|
||||||
|
|
||||||
@Import("npcCount")
|
@Import("npcCount")
|
||||||
int getNpcIndexesCount();
|
int getNpcIndexesCount();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user