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) {