Skip to content

Commit

Permalink
Add goal tracking infoboxes
Browse files Browse the repository at this point in the history
This adds a config section for picking an item goal
and shows an infobox for the 3 components to
show how much you have left to reach your goal
  • Loading branch information
BlueSoapTurtle committed Oct 2, 2024
1 parent b2dbe6c commit d0c5ad6
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,60 @@ default int highlightBorderWidth() {
default int highlightFeather() {
return 1;
}

@ConfigSection(
name = "Reward Tracking",
description = "Track your progress towards rewards",
position = 13
)
String rewardTracking = "RewardTracking";

@ConfigItem(
section = rewardTracking,
keyName = "selectedReward",
name = "Selected Reward",
description = "Select a reward to track resin for",
position = 14
)
default RewardItem selectedReward() {
return RewardItem.NONE;
}

@ConfigItem(
section = rewardTracking,
keyName = "showGoalTrackingInfobox",
name = "Show Goal Tracking Infobox",
description = "Displays an infobox tracking your progress towards the selected reward",
position = 15
)
default boolean showGoalTrackingInfobox() {
return false;
}

@ConfigItem(
section = rewardTracking,
keyName = "showResinInfoboxes",
name = "Show Resin Infoboxes",
description = "Displays infoboxes for each resin type",
position = 16
)
default boolean showResinInfoboxes() {
return false;
}

@ConfigItem(
section = rewardTracking,
keyName = "resinInfoboxDisplayType",
name = "Resin Infobox Display Type",
description = "Select what to display in the resin infoboxes",
position = 17
)
default ResinInfoboxDisplayType resinInfoboxDisplayType() {
return ResinInfoboxDisplayType.PERCENTAGE_COMPLETE;
}

enum ResinInfoboxDisplayType {
PERCENTAGE_COMPLETE,
AMOUNT_LEFT
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,20 @@
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import work.fking.masteringmixology.evaluator.PotionOrderEvaluator.EvaluatorContext;
import work.fking.masteringmixology.ui.GoalTrackingInfobox;
import work.fking.masteringmixology.ui.OrdersFulfilledInfoBox;
import work.fking.masteringmixology.ui.ResinGoalTrackingInfobox;

import javax.inject.Inject;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;

@PluginDescriptor(name = "Mastering Mixology")
public class MasteringMixologyPlugin extends Plugin {
Expand Down Expand Up @@ -84,12 +83,16 @@ public class MasteringMixologyPlugin extends Plugin {

@Inject
ItemManager itemManager;
@Inject
SpriteManager spriteManager;

@Inject
private MasteringMixologyOverlay overlay;
@Inject
private InfoBoxManager infoBoxManager;
private OrdersFulfilledInfoBox ordersFulfilledInfoBox;
private final Map<PotionComponent, ResinGoalTrackingInfobox> resinTrackingInfoboxes = new HashMap<>();
private GoalTrackingInfobox goalTrackingInfobox;

private final Map<AlchemyObject, HighlightedObject> highlightedObjects = new LinkedHashMap<>();
private List<PotionOrder> potionOrders = Collections.emptyList();
Expand Down Expand Up @@ -428,6 +431,64 @@ private void updateInfoboxes() {
infoBoxManager.removeInfoBox(ordersFulfilledInfoBox);
ordersFulfilledInfoBox = null;
}

// Setup the goal tracking infobox
if (config.showGoalTrackingInfobox() && config.selectedReward() != RewardItem.NONE) {
RewardItem rewardItem = config.selectedReward();
int moxResin = client.getVarpValue(VARP_MOX_RESIN);
int agaResin = client.getVarpValue(VARP_AGA_RESIN);
int lyeResin = client.getVarpValue(VARP_LYE_RESIN);

if (goalTrackingInfobox == null) {
BufferedImage image = itemManager.getImage(rewardItem.itemId());
goalTrackingInfobox = new GoalTrackingInfobox(this, image, rewardItem, moxResin, agaResin, lyeResin);
infoBoxManager.addInfoBox(goalTrackingInfobox);
} else {
goalTrackingInfobox.setResinBalance(moxResin, agaResin, lyeResin);
goalTrackingInfobox.setRewardItem(rewardItem);
}
} else if (goalTrackingInfobox != null) {
infoBoxManager.removeInfoBox(goalTrackingInfobox);
goalTrackingInfobox = null;
}

// Setup an infobox for each resin to track progress towards a goal
if (config.showResinInfoboxes() && config.selectedReward() != RewardItem.NONE) {
RewardItem rewardItem = config.selectedReward();
MasteringMixologyConfig.ResinInfoboxDisplayType displayType = config.resinInfoboxDisplayType();
Map<PotionComponent, Integer> resinBalance = new HashMap<>();
resinBalance.put(PotionComponent.AGA, client.getVarpValue(VARP_AGA_RESIN));
resinBalance.put(PotionComponent.LYE, client.getVarpValue(VARP_LYE_RESIN));
resinBalance.put(PotionComponent.MOX, client.getVarpValue(VARP_MOX_RESIN));

for (PotionComponent component : PotionComponent.values()) {
int balance = resinBalance.get(component);
int goalCost = rewardItem.componentCost(component);

ResinGoalTrackingInfobox infobox = resinTrackingInfoboxes.get(component);
if (infobox == null) {
BufferedImage image = itemManager.getImage(ItemID.MOX_PASTE);
infobox = new ResinGoalTrackingInfobox(this, image, balance, goalCost, displayType);
resinTrackingInfoboxes.put(component, infobox);
infoBoxManager.addInfoBox(infobox);

// Load the sprite async and set it once it loads
spriteManager.getSpriteAsync(component.spriteId(), 0, sprite ->
resinTrackingInfoboxes.get(component).setImage(sprite));
} else {
infobox.setCurrentAmount(balance);
infobox.setGoalAmount(goalCost);
infobox.setDisplayType(displayType);
}
}
} else if (!resinTrackingInfoboxes.isEmpty()){
for (PotionComponent component : PotionComponent.values()) {
if (resinTrackingInfoboxes.containsKey(component)) {
ResinGoalTrackingInfobox infobox = resinTrackingInfoboxes.remove(component);
infoBoxManager.removeInfoBox(infobox);
}
}
}
}

public static class HighlightedObject {
Expand Down
14 changes: 10 additions & 4 deletions src/main/java/work/fking/masteringmixology/PotionComponent.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package work.fking.masteringmixology;

public enum PotionComponent {
AGA('A', "00e676", 850),
LYE('L', "e91e63", 1250),
MOX('M', "03a9f4", 450);
AGA('A', "00e676", 5667, 850),
LYE('L', "e91e63", 5668, 1250),
MOX('M', "03a9f4", 5666, 450);

private final char character;
private final String color;
private final int spriteId;
private final int experience;

PotionComponent(char character, String color, int experience) {
PotionComponent(char character, String color, int spriteId, int experience) {
this.character = character;
this.color = color;
this.spriteId = spriteId;
this.experience = experience;
}

Expand All @@ -23,6 +25,10 @@ public String color() {
return color;
}

public int spriteId() {
return spriteId;
}

public int experience() {
return experience;
}
Expand Down
52 changes: 52 additions & 0 deletions src/main/java/work/fking/masteringmixology/RewardItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package work.fking.masteringmixology;

import net.runelite.api.ItemID;

import java.util.HashMap;
import java.util.Map;

@SuppressWarnings("unused") // The items are used in the config
public enum RewardItem {
NONE("None", 0, 0, 0, 0),

APPRENTICE_POTION_PACK("Apprentice Potion Pack", ItemID.APPRENTICE_POTION_PACK, 420, 70, 30),
ADEPT_POTION_PACK("Adept Potion Pack", ItemID.ADEPT_POTION_PACK, 180, 440, 70),
EXPERT_POTION_PACK("Expert Potion Pack", ItemID.EXPERT_POTION_PACK, 410, 320, 480),
PRESCRIPTION_GOGGLES("Prescription Goggles", ItemID.PRESCRIPTION_GOGGLES, 8600, 7000, 9350),
ALCHEMIST_LABCOAT("Alchemist Labcoat", ItemID.ALCHEMIST_LABCOAT, 2250, 2800, 3700),
ALCHEMIST_PANTS("Alchemist Pants", ItemID.ALCHEMIST_PANTS, 2250, 2800, 3700),
ALCHEMIST_GLOVES("Alchemist Gloves", ItemID.ALCHEMIST_GLOVES, 2250, 2800, 3700),
REAGENT_POUCH("Reagent Pouch", ItemID.REAGENT_POUCH, 13800, 12200, 15100),
POTION_STORAGE("Potion Storage", ItemID.POTION_STORAGE, 7750, 6300, 8950),
CHUGGING_BARREL("Chugging Barrel", ItemID.PREPOT_DEVICE, 17250, 14000, 18600),
ALCHEMISTS_AMULET("Alchemist's Amulet", ItemID.ALCHEMISTS_AMULET, 6900, 5650, 7400),
ALDARIUM("Aldarium", ItemID.ALDARIUM, 80, 60, 90);

private final String itemName;
private final int itemId;
private final Map<PotionComponent, Integer> componentCost = new HashMap<>();

RewardItem(String itemName, int itemId, int moxResinCost, int agaResinCost, int lyeResinCost) {
this.itemName = itemName;
this.itemId = itemId;
this.componentCost.put(PotionComponent.MOX, moxResinCost);
this.componentCost.put(PotionComponent.AGA, agaResinCost);
this.componentCost.put(PotionComponent.LYE, lyeResinCost);
}

public String itemName() {
return itemName;
}

public int itemId() {
return itemId;
}

public Map<PotionComponent, Integer> componentCost() {
return componentCost;
}

public int componentCost(PotionComponent component) {
return componentCost.get(component);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package work.fking.masteringmixology.ui;

import net.runelite.client.ui.overlay.infobox.InfoBox;
import net.runelite.client.util.QuantityFormatter;
import work.fking.masteringmixology.MasteringMixologyPlugin;
import work.fking.masteringmixology.PotionComponent;
import work.fking.masteringmixology.RewardItem;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;


public class GoalTrackingInfobox extends InfoBox {
private RewardItem rewardItem;
private final Map<PotionComponent, Integer> resinBalance = new HashMap<>();

public GoalTrackingInfobox(MasteringMixologyPlugin plugin, BufferedImage image, RewardItem rewardItem,
int mox, int aga, int lye) {
super(image, plugin);
this.rewardItem = rewardItem;
resinBalance.put(PotionComponent.MOX, mox);
resinBalance.put(PotionComponent.AGA, aga);
resinBalance.put(PotionComponent.LYE, lye);
}

@Override
public String getText() {
double percentageCompleted = getPercentageCompleted();
return (int) (percentageCompleted * 100) + "%";
}

private double getPercentageCompleted() {
int currentAmount = resinBalance.values().stream().mapToInt(Integer::intValue).sum();
int goalAmount = rewardItem.componentCost().values().stream().mapToInt(Integer::intValue).sum();
return currentAmount >= goalAmount ? 1 : ((double) currentAmount / goalAmount);
}

@Override
public Color getTextColor() {
double percentageCompleted = getPercentageCompleted();
if (percentageCompleted >= 1) {
return Color.GREEN;
} else {
return Color.WHITE;
}
}

@Override
public String getTooltip() {
StringBuilder goal = new StringBuilder(rewardItem.itemName() + "</br>");
for (PotionComponent component : PotionComponent.values()) {
int current = resinBalance.get(component);
int goalAmount = rewardItem.componentCost(component);
goal.append(component.name())
.append(": ")
.append(QuantityFormatter.quantityToRSDecimalStack(current))
.append("/")
.append(QuantityFormatter.quantityToRSDecimalStack(goalAmount))
.append("</br>");
}
int currentBalance = resinBalance.values().stream().mapToInt(Integer::intValue).sum();
int goalCost = rewardItem.componentCost().values().stream().mapToInt(Integer::intValue).sum();
// Round up
int potionsLeft = (int) Math.ceil((double) (goalCost - currentBalance) / 30);
if (potionsLeft > 0) {
goal.append("~")
.append(potionsLeft)
.append(" potions left</br>");
}
return goal.toString();
}

public void setRewardItem(RewardItem rewardItem) {
this.rewardItem = rewardItem;
}

public void setResinBalance(int mox, int aga, int lye) {
resinBalance.put(PotionComponent.MOX, mox);
resinBalance.put(PotionComponent.AGA, aga);
resinBalance.put(PotionComponent.LYE, lye);
}
}
Loading

0 comments on commit d0c5ad6

Please sign in to comment.