diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index b2d321d827..f1dbef7b29 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -570,6 +570,13 @@ public class WidgetID static final int ROLE_SPRITE = 11; static final int ROLE = 12; } + static class HLR + { + static final int TEAMMATE1 = 18; + static final int TEAMMATE2 = 22; + static final int TEAMMATE3 = 26; + static final int TEAMMATE4 = 30; + } static final int CORRECT_STYLE = 3; static final int CURRENT_WAVE_WIDGET = 4; static final int CURRENT_WAVE = 5; diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index c7e3efb585..d0fd4a8c5b 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -353,6 +353,11 @@ public enum WidgetInfo BA_HEAL_ROLE_TEXT(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.ROLE), BA_HEAL_ROLE_SPRITE(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.ROLE_SPRITE), + BA_HEAL_TEAMMATE1(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE1), + BA_HEAL_TEAMMATE2(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE2), + BA_HEAL_TEAMMATE3(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE3), + BA_HEAL_TEAMMATE4(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE4), + BA_COLL_WAVE_TEXT(WidgetID.BA_COLLECTOR_GROUP_ID, WidgetID.BarbarianAssault.CURRENT_WAVE), BA_COLL_CALL_TEXT(WidgetID.BA_COLLECTOR_GROUP_ID, WidgetID.BarbarianAssault.TO_CALL), BA_COLL_LISTEN_TEXT(WidgetID.BA_COLLECTOR_GROUP_ID, WidgetID.BarbarianAssault.CORRECT_STYLE), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultConfig.java index 52d6a18af5..a2353866f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultConfig.java @@ -42,6 +42,16 @@ public interface BarbarianAssaultConfig extends Config return true; } + @ConfigItem( + keyName = "showHealerBars", + name = "Show health bars for teammates when healer", + description = "Displays team health for healer" + ) + default boolean showHealerBars() + { + return true; + } + @ConfigItem( keyName = "waveTimes", name = "Show wave and game duration", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java index 448efc3d15..7536a009c8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java @@ -29,6 +29,7 @@ import com.google.inject.Provides; import java.awt.Font; import java.awt.Image; import javax.inject.Inject; +import lombok.Getter; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.Varbits; @@ -67,6 +68,9 @@ public class BarbarianAssaultPlugin extends Plugin private String currentWave = START_WAVE; private GameTimer gameTime; + @Getter + private Round currentRound; + @Inject private Client client; @@ -80,7 +84,10 @@ public class BarbarianAssaultPlugin extends Plugin private BarbarianAssaultConfig config; @Inject - private BarbarianAssaultOverlay overlay; + private TimerOverlay timerOverlay; + + @Inject + private HealerOverlay healerOverlay; @Provides BarbarianAssaultConfig provideConfig(ConfigManager configManager) @@ -91,7 +98,8 @@ public class BarbarianAssaultPlugin extends Plugin @Override protected void startUp() throws Exception { - overlayManager.add(overlay); + overlayManager.add(timerOverlay); + overlayManager.add(healerOverlay); font = FontManager.getRunescapeFont() .deriveFont(Font.BOLD, 24); @@ -101,7 +109,8 @@ public class BarbarianAssaultPlugin extends Plugin @Override protected void shutDown() throws Exception { - overlayManager.remove(overlay); + overlayManager.remove(timerOverlay); + overlayManager.remove(healerOverlay); gameTime = null; currentWave = START_WAVE; inGameBit = 0; @@ -126,22 +135,22 @@ public class BarbarianAssaultPlugin extends Plugin } case WidgetID.BA_ATTACKER_GROUP_ID: { - setOverlayRound(Role.ATTACKER); + setRound(Role.ATTACKER); break; } case WidgetID.BA_DEFENDER_GROUP_ID: { - setOverlayRound(Role.DEFENDER); + setRound(Role.DEFENDER); break; } case WidgetID.BA_HEALER_GROUP_ID: { - setOverlayRound(Role.HEALER); + setRound(Role.HEALER); break; } case WidgetID.BA_COLLECTOR_GROUP_ID: { - setOverlayRound(Role.COLLECTOR); + setRound(Role.COLLECTOR); break; } } @@ -176,7 +185,7 @@ public class BarbarianAssaultPlugin extends Plugin { if (inGameBit == 1) { - overlay.setCurrentRound(null); + currentRound = null; // Use an instance check to determine if this is exiting a game or a tutorial // After exiting tutorials there is a small delay before changing IN_GAME_BA back to @@ -191,17 +200,15 @@ public class BarbarianAssaultPlugin extends Plugin inGameBit = inGame; } - private void setOverlayRound(Role role) + private void setRound(Role role) { - // Prevent changing roles when a role is already set, as widgets can be + // Prevent changing rounds when a round is already set, as widgets can be // loaded multiple times in game from eg. opening and closing the horn // of glory. - if (overlay.getCurrentRound() != null) + if (currentRound == null) { - return; + currentRound = new Round(role); } - - overlay.setCurrentRound(new Round(role)); } private void announceTime(String preText, String time) @@ -228,4 +235,4 @@ public class BarbarianAssaultPlugin extends Plugin { return clockImage; } -} \ No newline at end of file +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/HealerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/HealerOverlay.java new file mode 100644 index 0000000000..7a04cfb288 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/HealerOverlay.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2019, whartd + * 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.barbarianassault; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.Client; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; +import net.runelite.client.ui.overlay.OverlayMenuEntry; +import net.runelite.client.ui.overlay.OverlayPosition; + +class HealerOverlay extends Overlay +{ + @Getter + @AllArgsConstructor + private enum HealerTeam + { + TEAMMATE1(WidgetInfo.BA_HEAL_TEAMMATE1, 28, 2, 115), + TEAMMATE2(WidgetInfo.BA_HEAL_TEAMMATE2, 26, 2, 115), + TEAMMATE3(WidgetInfo.BA_HEAL_TEAMMATE3, 26, 2, 115), + TEAMMATE4(WidgetInfo.BA_HEAL_TEAMMATE4, 25, 2, 115); + + private WidgetInfo teammate; + private int offsetX; + private int offsetY; + private int width; + } + + private static final Color HP_HIGH = new Color(10, 146, 5, 125); + private static final Color HP_MID = new Color(146, 146, 0, 230); + private static final Color HP_LOW = new Color(225, 35, 0, 125); + + private final Client client; + private final BarbarianAssaultPlugin plugin; + private final BarbarianAssaultConfig config; + + @Inject + private HealerOverlay(Client client, BarbarianAssaultPlugin plugin, BarbarianAssaultConfig config) + { + super(plugin); + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.UNDER_WIDGETS); + this.client = client; + this.plugin = plugin; + this.config = config; + getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "B.A. overlay")); + } + + @Override + public Dimension render(Graphics2D graphics) + { + Round round = plugin.getCurrentRound(); + if (round == null) + { + return null; + } + + Role role = round.getRoundRole(); + if (role == null) + { + return null; + } + + if (config.showHealerBars() && role == Role.HEALER) + { + for (HealerTeam teammate : HealerTeam.values()) + { + Widget widget = client.getWidget(teammate.getTeammate()); + if (widget == null) + { + continue; + } + + String[] teammateHealth = widget.getText().split(" / "); + int curHealth = Integer.parseInt(teammateHealth[0]); + int maxHealth = Integer.parseInt(teammateHealth[1]); + + int width = teammate.getWidth(); + double hpRatio = (double) curHealth / maxHealth; + int filledWidth = getBarWidth(hpRatio, width); + Color barColor = getBarColor(hpRatio); + + int offsetX = teammate.getOffsetX(); + int offsetY = teammate.getOffsetY(); + int x = widget.getCanvasLocation().getX() - offsetX; + int y = widget.getCanvasLocation().getY() - offsetY; + + graphics.setColor(barColor); + graphics.fillRect(x, y, filledWidth, 20); + } + } + + return null; + } + + private int getBarWidth(double ratio, int size) + { + if (ratio >= 1) + { + return size; + } + + return (int) Math.round(ratio * size); + } + + private Color getBarColor(double ratio) + { + if (ratio <= 0.33) + { + return HP_LOW; + } + + if (ratio <= 0.66) + { + return HP_MID; + } + + return HP_HIGH; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Role.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Role.java index 64cf11fa8b..58b047c829 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Role.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Role.java @@ -56,4 +56,4 @@ enum Role { return name(); } -} \ No newline at end of file +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/TimerOverlay.java similarity index 85% rename from runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultOverlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/TimerOverlay.java index 0fdf9edc2e..ecaa420ff7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/TimerOverlay.java @@ -28,10 +28,7 @@ import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; import javax.inject.Inject; -import lombok.Getter; -import lombok.Setter; import net.runelite.api.Client; -import net.runelite.api.GameState; import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; import net.runelite.api.widgets.Widget; import net.runelite.client.ui.overlay.Overlay; @@ -40,19 +37,14 @@ import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.OverlayPosition; -class BarbarianAssaultOverlay extends Overlay +class TimerOverlay extends Overlay { private final Client client; private final BarbarianAssaultPlugin plugin; private final BarbarianAssaultConfig config; - @Getter - @Setter - private Round currentRound; - - @Inject - private BarbarianAssaultOverlay(Client client, BarbarianAssaultPlugin plugin, BarbarianAssaultConfig config) + private TimerOverlay(Client client, BarbarianAssaultPlugin plugin, BarbarianAssaultConfig config) { super(plugin); setPosition(OverlayPosition.DYNAMIC); @@ -66,12 +58,13 @@ class BarbarianAssaultOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - if (client.getGameState() != GameState.LOGGED_IN || currentRound == null) + Round round = plugin.getCurrentRound(); + if (round == null) { return null; } - Role role = currentRound.getRoundRole(); + Role role = round.getRoundRole(); if (role == null) { return null; @@ -82,7 +75,7 @@ class BarbarianAssaultOverlay extends Overlay if (config.showTimer() && roleText != null && roleSprite != null) { - roleText.setText(String.format("00:%02d", currentRound.getTimeToChange())); + roleText.setText(String.format("00:%02d", round.getTimeToChange())); Rectangle spriteBounds = roleSprite.getBounds(); roleSprite.setHidden(true); graphics.drawImage(plugin.getClockImage(), spriteBounds.x, spriteBounds.y, null);