diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeConfig.java index 3d484d381e..b1eb1e212c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeConfig.java @@ -74,4 +74,26 @@ public interface GrandExchangeConfig extends Config { return true; } + + @ConfigItem( + position = 5, + keyName = "showTotal", + name = "Show grand exchange total", + description = "Show grand exchange total" + ) + default boolean showTotal() + { + return true; + } + + @ConfigItem( + position = 6, + keyName = "showExact", + name = "Show exact total value", + description = "Show exact total value" + ) + default boolean showExact() + { + return false; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index bcdaa20abe..1cec9f64f1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -58,6 +58,7 @@ import net.runelite.api.events.GameTick; import net.runelite.api.events.GrandExchangeOfferChanged; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; @@ -428,6 +429,49 @@ public class GrandExchangePlugin extends Plugin } } + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent event) + { + if (!event.getEventName().equals("setGETitle") || !config.showTotal()) + { + return; + } + + long total = 0; + GrandExchangeOffer[] offers = client.getGrandExchangeOffers(); + for (GrandExchangeOffer offer : offers) + { + if (offer != null) + { + total += offer.getPrice() * offer.getTotalQuantity(); + } + } + + if (total == 0L) + { + return; + } + + StringBuilder titleBuilder = new StringBuilder(" ("); + + if (config.showExact()) + { + titleBuilder.append(StackFormatter.formatNumber(total)); + } + else + { + titleBuilder.append(StackFormatter.quantityToStackSize(total)); + } + + titleBuilder.append(')'); + + // Append to title + String[] stringStack = client.getStringStack(); + int stringStackSize = client.getStringStackSize(); + + stringStack[stringStackSize - 1] += titleBuilder.toString(); + } + @Subscribe public void onGameTick(GameTick event) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningOverlay.java index 3ce12efcf7..fc673f2784 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningOverlay.java @@ -51,6 +51,7 @@ class MiningOverlay extends Overlay private static final int ORE_VEIN_MIN_RESPAWN_TIME = 90; private static final float ORE_VEIN_RANDOM_PERCENT_THRESHOLD = (float) ORE_VEIN_MIN_RESPAWN_TIME / ORE_VEIN_MAX_RESPAWN_TIME; private static final Color DARK_GREEN = new Color(0, 100, 0); + private static final int MOTHERLODE_UPPER_FLOOR_HEIGHT = -500; private final Client client; private final MiningPlugin plugin; @@ -95,8 +96,17 @@ class MiningOverlay extends Overlay continue; } + Rock rock = rockRespawn.getRock(); + + // Only draw timer for veins on the same level in motherlode mine + LocalPoint localLocation = client.getLocalPlayer().getLocalLocation(); + if (rock == Rock.ORE_VEIN && isUpstairsMotherlode(localLocation) != isUpstairsMotherlode(loc)) + { + continue; + } + // Recolour pie on motherlode veins during the portion of the timer where they may respawn - if (rockRespawn.getRock() == Rock.ORE_VEIN && percent > ORE_VEIN_RANDOM_PERCENT_THRESHOLD) + if (rock == Rock.ORE_VEIN && percent > ORE_VEIN_RANDOM_PERCENT_THRESHOLD) { pieFillColor = Color.GREEN; pieBorderColor = DARK_GREEN; @@ -111,4 +121,19 @@ class MiningOverlay extends Overlay } return null; } + + /** + * Checks if the given point is "upstairs" in the mlm. + * The upper floor is actually on z=0. + * + * This method assumes that the given point is already in the mlm + * and is not meaningful when outside the mlm. + * + * @param localPoint the LocalPoint to be tested + * @return true if localPoint is at same height as mlm upper floor + */ + private boolean isUpstairsMotherlode(LocalPoint localPoint) + { + return Perspective.getTileHeight(client, localPoint, 0) < MOTHERLODE_UPPER_FLOOR_HEIGHT; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java index 63ec966f6d..2e1d0cdfa4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java @@ -584,7 +584,16 @@ public class NpcIndicatorsPlugin extends Plugin if (mn.getDiedOnTick() != -1) { - mn.setRespawnTime(client.getTickCount() + 1 - mn.getDiedOnTick()); + final int respawnTime = client.getTickCount() + 1 - mn.getDiedOnTick(); + + // By killing a monster and leaving the area before seeing it again, an erroneously lengthy + // respawn time can be recorded. Thus, if the respawn time is already set and is greater than + // the observed time, assume that the lower observed respawn time is correct. + if (mn.getRespawnTime() == -1 || respawnTime < mn.getRespawnTime()) + { + mn.setRespawnTime(respawnTime); + } + mn.setDiedOnTick(-1); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerBarOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerBarOverlay.java index 18d28da696..5798698621 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerBarOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerBarOverlay.java @@ -28,6 +28,7 @@ package net.runelite.client.plugins.prayer; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.Client; @@ -35,11 +36,13 @@ import net.runelite.api.Perspective; import net.runelite.api.Player; import net.runelite.api.Point; import net.runelite.api.Skill; +import net.runelite.api.SpriteID; import net.runelite.api.coords.LocalPoint; 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.OverlayPriority; +import net.runelite.client.util.ImageUtil; @Singleton class PrayerBarOverlay extends Overlay @@ -48,6 +51,9 @@ class PrayerBarOverlay extends Overlay private static final Color BAR_BG_COLOR = Color.black; private static final Color FLICK_HELP_COLOR = Color.white; private static final Dimension PRAYER_BAR_SIZE = new Dimension(30, 5); + private static final int HD_PRAYER_BAR_PADDING = 1; + private static final BufferedImage HD_FRONT_BAR = ImageUtil.getResourceStreamFromClass(PrayerPlugin.class, "front.png"); + private static final BufferedImage HD_BACK_BAR = ImageUtil.getResourceStreamFromClass(PrayerPlugin.class, "back.png"); private final Client client; private final PrayerConfig config; @@ -79,12 +85,44 @@ class PrayerBarOverlay extends Overlay final LocalPoint localLocation = client.getLocalPlayer().getLocalLocation(); final Point canvasPoint = Perspective.localToCanvas(client, localLocation, client.getPlane(), height); + final float ratio = (float) client.getBoostedSkillLevel(Skill.PRAYER) / client.getRealSkillLevel(Skill.PRAYER); + + // Draw HD bar + if (client.getSpriteOverrides().containsKey(SpriteID.HEALTHBAR_DEFAULT_FRONT_30PX)) + { + final int barWidth = HD_FRONT_BAR.getWidth(); + final int barHeight = HD_FRONT_BAR.getHeight(); + final int barX = canvasPoint.getX() - barWidth / 2; + final int barY = canvasPoint.getY(); + + // Include padding so the bar doesn't show empty at very low prayer values + final int progressFill = (int) Math.ceil(Math.max(HD_PRAYER_BAR_PADDING * 2, Math.min((barWidth * ratio), barWidth))); + + graphics.drawImage(HD_BACK_BAR, barX, barY, barWidth, barHeight, null); + // Use a sub-image to create the same effect the HD Health Bar has + graphics.drawImage(HD_FRONT_BAR.getSubimage(0, 0, progressFill, barHeight), barX, barY, progressFill, barHeight, null); + + if ((plugin.isPrayersActive() || config.prayerFlickAlwaysOn()) + && (config.prayerFlickLocation().equals(PrayerFlickLocation.PRAYER_BAR) + || config.prayerFlickLocation().equals(PrayerFlickLocation.BOTH))) + { + final double t = plugin.getTickProgress(); + final int halfBarWidth = (barWidth / 2) - HD_PRAYER_BAR_PADDING; + + final int xOffset = (int) (-Math.cos(t) * halfBarWidth) + ((barWidth / 2) - halfBarWidth); + + graphics.setColor(FLICK_HELP_COLOR); + graphics.fillRect(barX + xOffset + HD_PRAYER_BAR_PADDING, barY + HD_PRAYER_BAR_PADDING, 1, barHeight - HD_PRAYER_BAR_PADDING * 2); + } + + return new Dimension(barWidth, barHeight); + } + // Draw bar final int barX = canvasPoint.getX() - 15; final int barY = canvasPoint.getY(); final int barWidth = PRAYER_BAR_SIZE.width; final int barHeight = PRAYER_BAR_SIZE.height; - final float ratio = (float) client.getBoostedSkillLevel(Skill.PRAYER) / client.getRealSkillLevel(Skill.PRAYER); // Restricted by the width to prevent the bar from being too long while you are boosted above your real prayer level. final int progressFill = (int) Math.ceil(Math.min((barWidth * ratio), barWidth)); @@ -100,7 +138,7 @@ class PrayerBarOverlay extends Overlay { double t = plugin.getTickProgress(); - int xOffset = (int) (-Math.cos(t) * barWidth / 2) + barWidth / 2; + final int xOffset = (int) (-Math.cos(t) * barWidth / 2) + barWidth / 2; graphics.setColor(FLICK_HELP_COLOR); graphics.fillRect(barX + xOffset, barY, 1, barHeight); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartLocation.java index 43f2f73a8a..cfa3d9fb12 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartLocation.java @@ -49,7 +49,8 @@ enum QuestStartLocation THE_RESTLESS_GHOST(Quest.THE_RESTLESS_GHOST, new WorldPoint(3240, 3210, 0)), RUNE_MYSTERIES(Quest.RUNE_MYSTERIES, new WorldPoint(3210, 3220, 0)), SHEEP_SHEARER(Quest.SHEEP_SHEARER, new WorldPoint(3190, 3272, 0)), - SHIELD_OF_ARRAV(Quest.SHIELD_OF_ARRAV, new WorldPoint(3208, 3495, 0)), + SHIELD_OF_ARRAV_PHOENIX_GANG(Quest.SHIELD_OF_ARRAV, new WorldPoint(3208, 3495, 0)), + SHIELD_OF_ARRAV_BLACK_ARM_GANG(Quest.SHIELD_OF_ARRAV, new WorldPoint(3208, 3392, 0)), VAMPIRE_SLAYER(Quest.VAMPIRE_SLAYER, new WorldPoint(3096, 3266, 0)), WITCHS_POTION(Quest.WITCHS_POTION, new WorldPoint(2967, 3203, 0)), X_MARKS_THE_SPOT(Quest.X_MARKS_THE_SPOT, new WorldPoint(3227, 3242, 0)), diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/prayer/back.png b/runelite-client/src/main/resources/net/runelite/client/plugins/prayer/back.png new file mode 100644 index 0000000000..76773682c4 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/prayer/back.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/prayer/front.png b/runelite-client/src/main/resources/net/runelite/client/plugins/prayer/front.png new file mode 100644 index 0000000000..d8df9d8bfe Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/prayer/front.png differ diff --git a/runelite-client/src/main/scripts/GELayout.hash b/runelite-client/src/main/scripts/GELayout.hash new file mode 100644 index 0000000000..dba0bed2f5 --- /dev/null +++ b/runelite-client/src/main/scripts/GELayout.hash @@ -0,0 +1 @@ +03E202EADA91DB0D5EE9B98E360685149F29B10A1C565B9BE65C2A50BD262BC3 \ No newline at end of file diff --git a/runelite-client/src/main/scripts/GELayout.rs2asm b/runelite-client/src/main/scripts/GELayout.rs2asm new file mode 100644 index 0000000000..5a75b20ffc --- /dev/null +++ b/runelite-client/src/main/scripts/GELayout.rs2asm @@ -0,0 +1,101 @@ +.id 806 +.int_stack_count 7 +.string_stack_count 0 +.int_var_count 9 +.string_var_count 0 + iload 6 + invoke 41 + get_varbit 4439 + iconst 1 + sub + istore 7 + iconst 105 + iconst 118 + iconst 150 + iload 7 + enum + istore 8 + iload 8 + iconst -1 + if_icmpeq LABEL16 + jump LABEL37 +LABEL16: + iconst 1 + iload 2 + if_sethide + iconst 0 + iload 3 + if_sethide + iconst 1 + iload 4 + if_sethide + iconst 1 + iload 5 + if_sethide + iload 0 + iload 1 + cc_find + iconst 1 + if_icmpeq LABEL34 + jump LABEL36 +LABEL34: + sconst "Grand Exchange" + sconst "setGETitle" ; + runelite_callback ; + cc_settext +LABEL36: + return +LABEL37: + iconst 0 + iload 2 + if_sethide + iconst 0 + iload 2 + if_settrans + iload 7 + stockmarket_isofferempty + iconst 1 + if_icmpeq LABEL48 + jump LABEL66 +LABEL48: + iconst 1 + iload 3 + if_sethide + iconst 1 + iload 4 + if_sethide + iconst 0 + iload 5 + if_sethide + iload 0 + iload 1 + cc_find + iconst 1 + if_icmpeq LABEL63 + jump LABEL65 +LABEL63: + sconst "Grand Exchange: Set up offer" + cc_settext +LABEL65: + return +LABEL66: + iconst 1 + iload 3 + if_sethide + iconst 0 + iload 4 + if_sethide + iconst 1 + iload 5 + if_sethide + iload 0 + iload 1 + cc_find + iconst 1 + if_icmpeq LABEL81 + jump LABEL83 +LABEL81: + sconst "Grand Exchange: Offer status" + cc_settext +LABEL83: + return