From 335479d097c09a0c76bc38c36fbc9fbdf832a005 Mon Sep 17 00:00:00 2001
From: conker-rsc <16803725+conker-rsc@users.noreply.github.com>
Date: Thu, 6 Feb 2025 16:28:01 -0600
Subject: [PATCH] Implement healing item overlay
---
src/Client/ConfigWindow.java | 22 ++--
src/Client/Settings.java | 7 +-
src/Game/ConsumableHeals.java | 199 ++++++++++++++++++++++++++++++++++
src/Game/Renderer.java | 88 ++++++++++++++-
4 files changed, 300 insertions(+), 16 deletions(-)
create mode 100644 src/Game/ConsumableHeals.java
diff --git a/src/Client/ConfigWindow.java b/src/Client/ConfigWindow.java
index f14aab37..015837c4 100644
--- a/src/Client/ConfigWindow.java
+++ b/src/Client/ConfigWindow.java
@@ -2625,6 +2625,11 @@ public void actionPerformed(ActionEvent e) {
SearchUtils.addSearchMetadata(
overlayPanelInvCountColoursCheckbox, CommonMetadata.COLOUR.getText());
+ overlayPanelFoodHealingCheckbox = addCheckbox("Show food healing overlay", overlayPanel);
+ overlayPanelFoodHealingCheckbox.setToolTipText(
+ "When hovering on food in your inventory, shows the HP a consumable recovers");
+ SearchUtils.addSearchMetadata(overlayPanelFoodHealingCheckbox, CommonMetadata.HP.getText());
+
overlayPanelRemoveReportAbuseButtonHbarCheckbox =
addCheckbox("Remove Report Abuse Button (Similar to prior to 2002-09-11)", overlayPanel);
overlayPanelRemoveReportAbuseButtonHbarCheckbox.setToolTipText(
@@ -2654,14 +2659,6 @@ public void actionPerformed(ActionEvent e) {
+ Launcher.appName
+ " will tell you in the bottom right");
- overlayPanelFoodHealingCheckbox =
- addCheckbox("Show food healing overlay (Not implemented yet)", overlayPanel);
- overlayPanelFoodHealingCheckbox.setToolTipText(
- "When hovering on food, shows the HP a consumable recovers");
- SearchUtils.addSearchMetadata(overlayPanelFoodHealingCheckbox, CommonMetadata.HP.getText());
- // TODO: Remove this line when food healing overlay is implemented
- overlayPanelFoodHealingCheckbox.setEnabled(false);
-
overlayPanelHPRegenTimerCheckbox =
addCheckbox("Display time until next HP regeneration (Not implemented yet)", overlayPanel);
overlayPanelHPRegenTimerCheckbox.setToolTipText(
@@ -4410,6 +4407,12 @@ public void actionPerformed(ActionEvent e) {
KeyModifier.ALT,
KeyEvent.VK_T,
"colors");
+ addKeybindSet(
+ keybindContainerPanel,
+ "Toggle food healing overlay",
+ "toggle_food_heal_overlay",
+ KeyModifier.ALT,
+ KeyEvent.VK_O);
addKeybindSet(
keybindContainerPanel,
"Toggle position overlay",
@@ -6444,8 +6447,7 @@ private void executeSynchronizeGuiValues() {
overlayPanelLagIndicatorCheckbox.setSelected(
Settings.LAG_INDICATOR.get(Settings.currentProfile));
overlayPanelFoodHealingCheckbox.setSelected(
- Settings.SHOW_FOOD_HEAL_OVERLAY.get(
- Settings.currentProfile)); // TODO: Implement this feature
+ Settings.SHOW_FOOD_HEAL_OVERLAY.get(Settings.currentProfile));
overlayPanelHPRegenTimerCheckbox.setSelected(
Settings.SHOW_TIME_UNTIL_HP_REGEN.get(
Settings.currentProfile)); // TODO: Implement this feature
diff --git a/src/Client/Settings.java b/src/Client/Settings.java
index f5bbdd0c..9e8652de 100644
--- a/src/Client/Settings.java
+++ b/src/Client/Settings.java
@@ -3215,7 +3215,7 @@ private static void resolveNewDefaults() {
}
}
- // 08/16/2023 - toggle_food_heal_overlay was removed
+ // 08/16/2023 - Original toggle_food_heal_overlay was removed
if (keybind.getCommandName().equals("toggle_food_heal_overlay")) {
if (keybind.getModifier().equals(KeyModifier.CTRL) && keybind.getKey() == KeyEvent.VK_G) {
keybind.setModifier(null);
@@ -4806,13 +4806,12 @@ public static void checkSoftwareCursor() {
}
private static void toggleFoodOverlay() {
- // TODO: This toggles the variable but does nothing yet
SHOW_FOOD_HEAL_OVERLAY.put(currentProfile, !SHOW_FOOD_HEAL_OVERLAY.get(currentProfile));
if (SHOW_FOOD_HEAL_OVERLAY.get(currentProfile)) {
- Client.displayMessage("@cya@Not yet implemented, sorry!", Client.CHAT_NONE);
+ Client.displayMessage("@cya@Showing item heal amounts on hover", Client.CHAT_NONE);
} else {
- Client.displayMessage("@cya@Not yet implemented, sorry!", Client.CHAT_NONE);
+ Client.displayMessage("@cya@No longer showing item heal amounts on hover", Client.CHAT_NONE);
}
save();
diff --git a/src/Game/ConsumableHeals.java b/src/Game/ConsumableHeals.java
new file mode 100644
index 00000000..3a81a9e7
--- /dev/null
+++ b/src/Game/ConsumableHeals.java
@@ -0,0 +1,199 @@
+/**
+ * rscplus
+ *
+ *
This file is part of rscplus.
+ *
+ *
rscplus is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ *
rscplus is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ *
You should have received a copy of the GNU General Public License along with rscplus. If not,
+ * see .
+ *
+ *
Authors: see
+ */
+package Game;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** Cache for consumable item healing values */
+public class ConsumableHeals {
+ private static final Map consumableDB = new HashMap<>();
+
+ static {
+ /* "Eat" commands */
+ consumableDB.put(18, "1");
+ consumableDB.put(132, "3");
+ consumableDB.put(138, "4");
+ consumableDB.put(179, "2");
+ consumableDB.put(210, "?"); // Kebab
+ consumableDB.put(228, "1");
+ consumableDB.put(249, "2");
+ consumableDB.put(257, "5");
+ consumableDB.put(258, "3");
+ consumableDB.put(259, "4");
+ consumableDB.put(261, "4");
+ consumableDB.put(262, "3");
+ consumableDB.put(263, "5");
+ consumableDB.put(319, "2");
+ consumableDB.put(320, "2");
+ consumableDB.put(325, "11");
+ consumableDB.put(326, "7");
+ consumableDB.put(327, "8");
+ consumableDB.put(328, "7");
+ consumableDB.put(329, "8");
+ consumableDB.put(330, "4");
+ consumableDB.put(332, "5");
+ consumableDB.put(333, "4");
+ consumableDB.put(334, "5");
+ consumableDB.put(335, "4");
+ consumableDB.put(336, "5");
+ consumableDB.put(337, "3");
+ consumableDB.put(346, "9");
+ consumableDB.put(350, "3");
+ consumableDB.put(352, "1");
+ consumableDB.put(355, "4");
+ consumableDB.put(357, "9");
+ consumableDB.put(359, "7");
+ consumableDB.put(362, "5");
+ consumableDB.put(364, "8");
+ consumableDB.put(367, "10");
+ consumableDB.put(370, "14");
+ consumableDB.put(373, "12");
+ consumableDB.put(422, "14");
+ consumableDB.put(546, "20");
+ consumableDB.put(551, "7");
+ consumableDB.put(553, "6");
+ consumableDB.put(555, "13");
+ consumableDB.put(590, "11");
+ consumableDB.put(677, "14");
+ consumableDB.put(709, "19");
+ consumableDB.put(718, "6");
+ consumableDB.put(749, "2");
+ consumableDB.put(750, "10");
+ consumableDB.put(751, "10");
+ consumableDB.put(765, "2");
+ consumableDB.put(801, "0");
+ consumableDB.put(855, "2");
+ consumableDB.put(856, "2");
+ consumableDB.put(857, "2");
+ consumableDB.put(858, "2");
+ consumableDB.put(859, "2");
+ consumableDB.put(860, "2");
+ consumableDB.put(861, "2");
+ consumableDB.put(862, "2");
+ consumableDB.put(863, "2");
+ consumableDB.put(864, "2");
+ consumableDB.put(865, "2");
+ consumableDB.put(871, "2");
+ consumableDB.put(873, "1");
+ consumableDB.put(885, "2");
+ consumableDB.put(896, "3");
+ consumableDB.put(897, "2");
+ consumableDB.put(900, "2");
+ consumableDB.put(901, "11");
+ consumableDB.put(902, "11");
+ consumableDB.put(903, "11");
+ consumableDB.put(904, "11");
+ consumableDB.put(905, "11");
+ consumableDB.put(906, "11");
+ consumableDB.put(907, "15");
+ consumableDB.put(908, "12");
+ consumableDB.put(909, "12");
+ consumableDB.put(910, "15");
+ consumableDB.put(911, "7");
+ consumableDB.put(912, "8");
+ consumableDB.put(913, "8");
+ consumableDB.put(914, "7");
+ consumableDB.put(923, "19");
+ consumableDB.put(924, "19");
+ consumableDB.put(936, "2");
+ consumableDB.put(944, "11");
+ consumableDB.put(945, "11");
+ consumableDB.put(946, "11");
+ consumableDB.put(947, "11");
+ consumableDB.put(948, "11");
+ consumableDB.put(949, "11");
+ consumableDB.put(950, "15");
+ consumableDB.put(951, "12");
+ consumableDB.put(952, "12");
+ consumableDB.put(953, "11");
+ consumableDB.put(954, "7");
+ consumableDB.put(955, "8");
+ consumableDB.put(956, "8");
+ consumableDB.put(957, "7");
+ consumableDB.put(1061, "4");
+ consumableDB.put(1102, "19");
+ consumableDB.put(1103, "3");
+ consumableDB.put(1191, "20");
+ consumableDB.put(1193, "20");
+ consumableDB.put(1245, "4");
+ consumableDB.put(1269, "8");
+
+ /* "Drink" commands */
+ consumableDB.put(142, "11");
+ consumableDB.put(180, "0");
+ consumableDB.put(193, "1");
+ consumableDB.put(246, "5");
+ consumableDB.put(267, "1");
+ consumableDB.put(268, "1");
+ consumableDB.put(269, "1");
+ consumableDB.put(598, "3");
+ consumableDB.put(737, "?"); // Poison chalice
+ consumableDB.put(770, "4");
+ consumableDB.put(829, "1");
+ consumableDB.put(830, "1");
+ consumableDB.put(853, "0");
+ consumableDB.put(854, "0");
+ consumableDB.put(866, "8");
+ consumableDB.put(867, "0");
+ consumableDB.put(868, "4");
+ consumableDB.put(869, "4");
+ consumableDB.put(870, "4");
+ consumableDB.put(872, "5");
+ consumableDB.put(874, "5");
+ consumableDB.put(875, "5");
+ consumableDB.put(876, "4");
+ consumableDB.put(877, "5");
+ consumableDB.put(878, "5");
+ consumableDB.put(879, "9");
+ consumableDB.put(937, "8");
+ consumableDB.put(938, "5");
+ consumableDB.put(939, "5");
+ consumableDB.put(940, "8");
+ consumableDB.put(941, "5");
+ consumableDB.put(942, "5");
+ consumableDB.put(943, "5");
+
+ // Note: Not a lot of data is available about gnome cocktails,
+ // so values may not be authentic
+ }
+
+ /** @return Healing display value */
+ public static String getValue(int id) {
+ return consumableDB.get(id);
+ }
+
+ /** @return Damaging value for nightshade (1086) */
+ public static String getNightShadeValue() {
+ int amount = (int) (Client.current_level[Client.SKILL_HP] * 0.166666666D) + 14;
+ return String.valueOf(-1 * amount);
+ }
+
+ /** @return Damaging value for Zamorak potion (963,964,965) */
+ public static String getZamorakPotValue() {
+ int amount = (int) (Client.current_level[Client.SKILL_HP] * 0.1);
+ return String.valueOf(-1 * amount);
+ }
+
+ /** @return Healing value for tea (739) */
+ public static String getTeaValue() {
+ int amount = (int) (Client.base_level[Client.SKILL_HP] * 0.02) + 2;
+ return String.valueOf(amount);
+ }
+}
diff --git a/src/Game/Renderer.java b/src/Game/Renderer.java
index b37fe475..99a8268d 100644
--- a/src/Game/Renderer.java
+++ b/src/Game/Renderer.java
@@ -1554,6 +1554,12 @@ public static void present(Image image) {
false);
}
+ // Draw consumable healing amounts over inventory items
+ if (Settings.SHOW_FOOD_HEAL_OVERLAY.get(Settings.currentProfile)
+ && Client.onlyShowingInventory()) {
+ drawConsumableLabels(g2);
+ }
+
// Mouseover hover handling
if (Settings.SHOW_MOUSE_TOOLTIP.get(Settings.currentProfile)
&& !Client.isInterfaceOpen()
@@ -2606,9 +2612,11 @@ private static void drawDeathItems(Graphics2D g2) {
// Note: This function many not be entirely authentic because we don't
// currently know if certain items besides stackable items were
// always dropped on death, such as the quest item "Liquid Honey"
- Map inventoryValues = new HashMap<>();
+ if (Client.inventory_count < 1) {
+ return;
+ }
- if (Client.inventory_count < 1) return;
+ Map inventoryValues = new HashMap<>();
int protectItemOffset = Client.prayers_on[8] ? 1 : 0;
int numItemsToKeep = (Client.getPlayerSkulled() ? 0 : 3) + protectItemOffset;
@@ -2650,6 +2658,82 @@ private static void drawDeathItems(Graphics2D g2) {
});
}
+ /** Draws consumable item healing amounts over inventory items on hover */
+ private static void drawConsumableLabels(Graphics2D g2) {
+ if (Client.inventory_count < 1) {
+ return;
+ }
+
+ // Loop through inventory
+ for (int i = 0; i < Client.inventory_count; i++) {
+ // Only consider drawing when hovering over an inventory item
+ int x = width - 245 + ((i % 5) * 49);
+ int y = 47 + ((i / 5) * 34);
+
+ final Rectangle currentItem = new Rectangle(x - 2, y - 10, 47, 32);
+ if (!currentItem.contains(MouseHandler.x, MouseHandler.y)) {
+ continue;
+ }
+
+ // Set label properties
+ final Color labelColor;
+ final String healLabel;
+
+ final int itemID = Client.inventory_items[i];
+
+ /* Dynamic values */
+ if (itemID == 1086) {
+ // Nightshade
+ healLabel = ConsumableHeals.getNightShadeValue();
+ labelColor = color_low;
+ } else if (itemID == 963 || itemID == 964 || itemID == 965) {
+ // Zamorak potion
+ healLabel = ConsumableHeals.getZamorakPotValue();
+ labelColor = color_low;
+ } else if (itemID == 739) {
+ // Tea
+ healLabel = ConsumableHeals.getTeaValue();
+ labelColor = color_hp;
+ }
+ /* Static values */
+ else {
+ healLabel = ConsumableHeals.getValue(itemID);
+
+ // Determine color
+ if (itemID == 210 || itemID == 737) {
+ // Mystery items (kebab, poison chalice)
+ labelColor = Color.magenta;
+ } else {
+ // Everything else
+ labelColor = color_hp;
+ }
+ }
+
+ // No label found, exit
+ if (healLabel == null) {
+ continue;
+ }
+
+ // Don't draw if it overlaps with the right-click menu
+ if (showingRightClickMenu) {
+ final Dimension healBounds = Renderer.getStringBounds(g2, healLabel);
+ final Rectangle drawBounds =
+ new Rectangle(x, y - healBounds.height, healBounds.width, healBounds.height);
+
+ final Rectangle menuBounds =
+ new Rectangle(
+ rightClickMenuX, rightClickMenuY, rightClickMenuWidth, rightClickMenuHeight);
+
+ if (drawBounds.intersects(menuBounds)) {
+ continue;
+ }
+ }
+
+ // Draw the label
+ drawShadowText(g2, healLabel, x, y, labelColor, false);
+ }
+ }
+
private static Color getInventoryCountColor() {
if (Settings.SHOW_INVCOUNT_COLOURS.get(Settings.currentProfile)) {
if (Client.inventory_count == 0) {