aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/hysky/skyblocker/skyblock
diff options
context:
space:
mode:
authorKevin <92656833+kevinthegreat1@users.noreply.github.com>2024-06-10 12:12:29 +0800
committerGitHub <noreply@github.com>2024-06-10 12:12:29 +0800
commitc29b55bc64fdf8717b42f1a5f7e0d18895007fb3 (patch)
tree382a7d4f3fa4b40fcbfe2c752cf581c36382bc52 /src/main/java/de/hysky/skyblocker/skyblock
parentec1c0104a17d9e3a5741efa38528d628b53d940d (diff)
parent48430e36a87c09e033c0bd43e65b70bbac0e2664 (diff)
downloadSkyblocker-c29b55bc64fdf8717b42f1a5f7e0d18895007fb3.tar.gz
Skyblocker-c29b55bc64fdf8717b42f1a5f7e0d18895007fb3.tar.bz2
Skyblocker-c29b55bc64fdf8717b42f1a5f7e0d18895007fb3.zip
Merge pull request #735 from Emirlol/tooltips-galore
Tooltip refactors
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock')
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java320
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotText.java21
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextAdder.java64
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextManager.java68
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/TextPosition.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/AttributeShardAdder.java (renamed from src/main/java/de/hysky/skyblocker/skyblock/item/AttributeShards.java)48
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CatacombsLevelAdder.java92
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EnchantmentLevelAdder.java46
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/MinionLevelAdder.java31
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PetLevelAdder.java28
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PrehistoricEggAdder.java34
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/RancherBootsSpeedAdder.java36
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkillLevelAdder.java34
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkyblockLevelAdder.java29
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorDeletorPreview.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ExoticTooltip.java96
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java355
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipAdder.java48
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java72
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AccessoryTooltip.java43
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AvgBinTooltip.java63
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java57
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java135
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/DungeonQualityTooltip.java57
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java40
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LineSmoothener.java32
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java50
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java49
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java28
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java72
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SupercraftReminder.java30
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/itemlist/ResultButtonWidget.java34
36 files changed, 1497 insertions, 642 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java
index 7b36dd78..908525e1 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java
@@ -79,7 +79,7 @@ public class ChestValue {
}
String name = stack.getName().getString();
- String id = ItemTooltip.getInternalNameFromNBT(stack, false);
+ String id = stack.getSkyblockApiId();
//Regular item price
if (id != null) {
@@ -158,7 +158,7 @@ public class ChestValue {
continue;
}
- String id = ItemTooltip.getInternalNameFromNBT(stack, false);
+ String id = stack.getSkyblockApiId();
if (id != null) {
DoubleBooleanPair priceData = ItemUtils.getItemPrice(id);
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java
index 042b126b..a8155b43 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java
@@ -1,7 +1,6 @@
package de.hysky.skyblocker.skyblock;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.render.RenderHelper;
@@ -27,7 +26,7 @@ public class TeleportOverlay {
private static void render(WorldRenderContext wrc) {
if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().uiAndVisuals.teleportOverlay.enableTeleportOverlays && client.player != null && client.world != null) {
ItemStack heldItem = client.player.getMainHandStack();
- String itemId = ItemTooltip.getInternalNameFromNBT(heldItem, true);
+ String itemId = heldItem.getSkyblockId();
NbtCompound customData = ItemUtils.getCustomData(heldItem);
if (itemId != null) {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java
index fd69d886..557cb6c9 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java
@@ -295,8 +295,8 @@ public class AuctionBrowserScreen extends AbstractCustomHypixelGUI<AuctionHouseS
String coins = split[1].replace(",", "").replace("coins", "").trim();
try {
long parsed = Long.parseLong(coins);
- String name = ItemTooltip.getInternalNameFromNBT(stack, false);
- String internalID = ItemTooltip.getInternalNameFromNBT(stack, true);
+ String name = stack.getSkyblockApiId();
+ String internalID = stack.getSkyblockId();
String neuName = name;
if (name == null || internalID == null) break;
if (name.startsWith("ISSHINY_")) {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java
index e04e632a..d33a83e9 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java
@@ -1,20 +1,18 @@
package de.hysky.skyblocker.skyblock.chocolatefactory;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
+import de.hysky.skyblocker.skyblock.item.tooltip.adders.LineSmoothener;
+import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RegexUtils;
+import de.hysky.skyblocker.utils.RomanNumerals;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
-import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
-import net.minecraft.client.item.TooltipType;
-import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
+import net.minecraft.screen.slot.Slot;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
@@ -46,10 +44,27 @@ public class ChocolateFactorySolver extends ContainerSolver {
private static boolean canPrestige = false;
private static boolean reachedMaxPrestige = false;
private static double timeTowerMultiplier = -1.0;
+ private static boolean isTimeTowerMaxed = false;
private static boolean isTimeTowerActive = false;
+ private static int bestUpgrade = -1;
+ private static int bestAffordableUpgrade = -1;
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,###.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
- private static ItemStack bestUpgrade = null;
- private static ItemStack bestAffordableUpgrade = null;
+
+ @Override
+ protected void reset() {
+ cpsIncreaseFactors.clear();
+ totalChocolate = -1L;
+ totalCps = -1.0;
+ totalCpsMultiplier = -1.0;
+ requiredUntilNextPrestige = -1L;
+ canPrestige = false;
+ reachedMaxPrestige = false;
+ timeTowerMultiplier = -1.0;
+ isTimeTowerMaxed = false;
+ isTimeTowerActive = false;
+ bestUpgrade = -1;
+ bestAffordableUpgrade = -1;
+ }
//Slots, for ease of maintenance rather than using magic numbers everywhere.
private static final byte RABBITS_START = 28;
@@ -63,8 +78,7 @@ public class ChocolateFactorySolver extends ContainerSolver {
private static final byte STRAY_RABBIT_END = 26;
public ChocolateFactorySolver() {
- super("^Chocolate Factory$");
- ItemTooltipCallback.EVENT.register(ChocolateFactorySolver::handleTooltip);
+ super("^Chocolate Factory$"); //There are multiple screens that fit the pattern `^Chocolate Factory`, so the $ is required
}
@Override
@@ -82,7 +96,7 @@ public class ChocolateFactorySolver extends ContainerSolver {
if (totalChocolate <= 0 || cpsIncreaseFactors.isEmpty()) return highlights; //Something went wrong or there's nothing we can afford.
Rabbit bestRabbit = cpsIncreaseFactors.getFirst();
- bestUpgrade = bestRabbit.itemStack;
+ bestUpgrade = bestRabbit.slot;
if (bestRabbit.cost <= totalChocolate) {
highlights.add(ColorHighlight.green(bestRabbit.slot));
return highlights;
@@ -91,7 +105,7 @@ public class ChocolateFactorySolver extends ContainerSolver {
for (Rabbit rabbit : cpsIncreaseFactors.subList(1, cpsIncreaseFactors.size())) {
if (rabbit.cost <= totalChocolate) {
- bestAffordableUpgrade = rabbit.itemStack;
+ bestAffordableUpgrade = rabbit.slot;
highlights.add(ColorHighlight.green(rabbit.slot));
break;
}
@@ -143,7 +157,8 @@ public class ChocolateFactorySolver extends ContainerSolver {
}
//Time Tower is in slot 39
- timeTowerMultiplier = romanToDecimal(StringUtils.substringAfterLast(slots.get(TIME_TOWER_SLOT).getName().getString(), ' ')) / 10.0; //The name holds the level, which is multiplier * 10 in roman numerals
+ isTimeTowerMaxed = StringUtils.substringAfterLast(slots.get(TIME_TOWER_SLOT).getName().getString(), ' ').equals("XV");
+ timeTowerMultiplier = RomanNumerals.romanToDecimal(StringUtils.substringAfterLast(slots.get(TIME_TOWER_SLOT).getName().getString(), ' ')) / 10.0; //The name holds the level, which is multiplier * 10 in roman numerals
Matcher timeTowerStatusMatcher = TIME_TOWER_STATUS_PATTERN.matcher(getConcatenatedLore(slots.get(TIME_TOWER_SLOT)));
if (timeTowerStatusMatcher.find()) {
isTimeTowerActive = timeTowerStatusMatcher.group(1).equals("ACTIVE");
@@ -153,130 +168,6 @@ public class ChocolateFactorySolver extends ContainerSolver {
cpsIncreaseFactors.sort(Comparator.comparingDouble(rabbit -> rabbit.cost() / rabbit.cpsIncrease())); //Ascending order, lower = better
}
- private static void handleTooltip(ItemStack stack, Item.TooltipContext tooltipContext, TooltipType tooltipType, List<Text> lines) {
- if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableChocolateFactoryHelper) return;
- if (!(MinecraftClient.getInstance().currentScreen instanceof GenericContainerScreen screen) || !screen.getTitle().getString().equals("Chocolate Factory")) return;
-
- int lineIndex = lines.size();
- //This boolean is used to determine if we should add a smooth line to separate the added information from the rest of the tooltip.
- //It should be set to true if there's any information added, false otherwise.
- boolean shouldAddLine = false;
-
- String lore = concatenateLore(lines);
- Matcher costMatcher = COST_PATTERN.matcher(lore);
- OptionalLong cost = RegexUtils.getLongFromMatcher(costMatcher);
- //Available on all items with a chocolate cost
- if (cost.isPresent()) shouldAddLine = addUpgradeTimerToLore(lines, cost.getAsLong());
-
- //Prestige item
- if (stack.isOf(Items.DROPPER)) {
- shouldAddLine = addPrestigeTimerToLore(lines) || shouldAddLine;
- }
- //Time tower
- else if (stack.isOf(Items.CLOCK)) {
- shouldAddLine = addTimeTowerStatsToLore(lines) || shouldAddLine;
- }
- //Rabbits
- else if (stack.isOf(Items.PLAYER_HEAD)) {
- shouldAddLine = addRabbitStatsToLore(lines, stack) || shouldAddLine;
- }
-
- //This is an ArrayList, so this operation is probably not very efficient, but logically it's pretty much the only way I can think of
- if (shouldAddLine) lines.add(lineIndex, ItemTooltip.createSmoothLine());
- }
-
- private static boolean addUpgradeTimerToLore(List<Text> lines, long cost) {
- if (totalChocolate < 0L || totalCps < 0.0) return false;
- lines.add(Text.empty()
- .append(Text.literal("Time until upgrade: ").formatted(Formatting.GRAY))
- .append(formatTime((cost - totalChocolate) / totalCps)));
- return true;
- }
-
- private static boolean addPrestigeTimerToLore(List<Text> lines) {
- if (totalCps < 0.0 || reachedMaxPrestige) return false;
- if (requiredUntilNextPrestige > 0 && !canPrestige) {
- lines.add(Text.empty()
- .append(Text.literal("Chocolate until next prestige: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(requiredUntilNextPrestige)).formatted(Formatting.GOLD)));
- }
- lines.add(Text.empty() //Keep this outside of the `if` to match the format of the upgrade tooltips, that say "Time until upgrade: Now" when it's possible
- .append(Text.literal("Time until next prestige: ").formatted(Formatting.GRAY))
- .append(formatTime(requiredUntilNextPrestige / totalCps)));
- return true;
- }
-
- private static boolean addTimeTowerStatsToLore(List<Text> lines) {
- if (totalCps < 0.0 || totalCpsMultiplier < 0.0 || timeTowerMultiplier < 0.0) return false;
- lines.add(Text.literal("Current stats:").formatted(Formatting.GRAY));
- lines.add(Text.empty()
- .append(Text.literal(" CPS increase: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(totalCps / totalCpsMultiplier * timeTowerMultiplier)).formatted(Formatting.GOLD)));
- lines.add(Text.empty()
- .append(Text.literal(" CPS when active: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(isTimeTowerActive ? totalCps : totalCps / totalCpsMultiplier * (timeTowerMultiplier + totalCpsMultiplier))).formatted(Formatting.GOLD)));
- if (timeTowerMultiplier < 1.5) {
- lines.add(Text.literal("Stats after upgrade:").formatted(Formatting.GRAY));
- lines.add(Text.empty()
- .append(Text.literal(" CPS increase: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(totalCps / (totalCpsMultiplier) * (timeTowerMultiplier + 0.1))).formatted(Formatting.GOLD)));
- lines.add(Text.empty()
- .append(Text.literal(" CPS when active: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(isTimeTowerActive ? totalCps / totalCpsMultiplier * (totalCpsMultiplier + 0.1) : totalCps / totalCpsMultiplier * (timeTowerMultiplier + 0.1 + totalCpsMultiplier))).formatted(Formatting.GOLD)));
- }
- return true;
- }
-
- private static boolean addRabbitStatsToLore(List<Text> lines, ItemStack stack) {
- if (cpsIncreaseFactors.isEmpty()) return false;
- boolean changed = false;
- for (Rabbit rabbit : cpsIncreaseFactors) {
- if (rabbit.itemStack != stack) continue;
- changed = true;
- lines.add(Text.empty()
- .append(Text.literal("CPS Increase: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cpsIncrease)).formatted(Formatting.GOLD)));
-
- lines.add(Text.empty()
- .append(Text.literal("Cost per CPS: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cost / rabbit.cpsIncrease)).formatted(Formatting.GOLD)));
-
- if (rabbit.itemStack == bestUpgrade) {
- if (rabbit.cost <= totalChocolate) {
- lines.add(Text.literal("Best upgrade").formatted(Formatting.GREEN));
- } else {
- lines.add(Text.literal("Best upgrade, can't afford").formatted(Formatting.YELLOW));
- }
- } else if (rabbit.itemStack == bestAffordableUpgrade && rabbit.cost <= totalChocolate) {
- lines.add(Text.literal("Best upgrade you can afford").formatted(Formatting.GREEN));
- }
- }
- return changed;
- }
-
- private static MutableText formatTime(double seconds) {
- seconds = Math.ceil(seconds);
- if (seconds <= 0) return Text.literal("Now").formatted(Formatting.GREEN);
-
- StringBuilder builder = new StringBuilder();
- if (seconds >= 86400) {
- builder.append((int) (seconds / 86400)).append("d ");
- seconds %= 86400;
- }
- if (seconds >= 3600) {
- builder.append((int) (seconds / 3600)).append("h ");
- seconds %= 3600;
- }
- if (seconds >= 60) {
- builder.append((int) (seconds / 60)).append("m ");
- seconds %= 60;
- }
- if (seconds >= 1) {
- builder.append((int) seconds).append("s");
- }
- return Text.literal(builder.toString()).formatted(Formatting.GOLD);
- }
-
/**
* Utility method.
*/
@@ -317,7 +208,7 @@ public class ChocolateFactorySolver extends ContainerSolver {
OptionalInt cost = RegexUtils.getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.hasMatch() ? multiplierIncreaseMatcher.end() : 0); //Cost comes after the multiplier line
if (cost.isEmpty()) return Optional.empty();
- return Optional.of(new Rabbit(totalCps / totalCpsMultiplier * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt(), COACH_SLOT, coachItem));
+ return Optional.of(new Rabbit(totalCps / totalCpsMultiplier * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt(), COACH_SLOT));
}
private static Optional<Rabbit> getRabbit(ItemStack item, int slot) {
@@ -334,7 +225,7 @@ public class ChocolateFactorySolver extends ContainerSolver {
Matcher costMatcher = COST_PATTERN.matcher(lore);
OptionalInt cost = RegexUtils.getIntFromMatcher(costMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0); //Cost comes after the cps line
if (cost.isEmpty()) return Optional.empty();
- return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt(), slot, item));
+ return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt(), slot));
}
private static Optional<ColorHighlight> getPrestigeHighlight() {
@@ -356,28 +247,137 @@ public class ChocolateFactorySolver extends ContainerSolver {
return highlights;
}
- private record Rabbit(double cpsIncrease, int cost, int slot, ItemStack itemStack) {
- }
+ private record Rabbit(double cpsIncrease, int cost, int slot) { }
+
+ public static final class Tooltip extends TooltipAdder {
+ public Tooltip() {
+ super("^Chocolate Factory$", 0); //The priority doesn't really matter here as this is the only tooltip adder for the Chocolate Factory.
+ }
+
+ @Override
+ public void addToTooltip(List<Text> lines, Slot focusedSlot) {
+ if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableChocolateFactoryHelper) return;
+
+ int lineIndex = lines.size();
+ //This boolean is used to determine if we should add a smooth line to separate the added information from the rest of the tooltip.
+ //It should be set to true if there's any information added, false otherwise.
+ boolean shouldAddLine = false;
+
+ String lore = concatenateLore(lines);
+ Matcher costMatcher = COST_PATTERN.matcher(lore);
+ OptionalLong cost = RegexUtils.getLongFromMatcher(costMatcher);
+ //Available on all items with a chocolate cost
+ if (cost.isPresent()) shouldAddLine |= addUpgradeTimerToLore(lines, cost.getAsLong());
+
+ int index = focusedSlot.id;
+
+ //Prestige item
+ if (index == PRESTIGE_SLOT) {
+ shouldAddLine |= addPrestigeTimerToLore(lines);
+ }
+ //Time tower
+ else if (index == TIME_TOWER_SLOT) {
+ shouldAddLine |= addTimeTowerStatsToLore(lines);
+ }
+ //Rabbits
+ else if (index == COACH_SLOT || (index >= RABBITS_START && index <= RABBITS_END)) {
+ shouldAddLine |= addRabbitStatsToLore(lines, index);
+ }
+
+ //This is an ArrayList, so this operation is probably not very efficient, but logically it's pretty much the only way I can think of
+ if (shouldAddLine) lines.add(lineIndex, LineSmoothener.createSmoothLine());
+ }
+
+ private static boolean addUpgradeTimerToLore(List<Text> lines, long cost) {
+ if (totalChocolate < 0L || totalCps < 0.0) return false;
+ lines.add(Text.empty()
+ .append(Text.literal("Time until upgrade: ").formatted(Formatting.GRAY))
+ .append(formatTime((cost - totalChocolate) / totalCps)));
+ return true;
+ }
- //Perhaps the part below can go to a separate file later on, but I couldn't find a proper name for the class, so they're staying here.
- private static final Map<Character, Integer> romanMap = Map.of(
- 'I', 1,
- 'V', 5,
- 'X', 10,
- 'L', 50,
- 'C', 100,
- 'D', 500,
- 'M', 1000
- );
-
- public static int romanToDecimal(String romanNumeral) {
- int decimal = 0;
- int lastNumber = 0;
- for (int i = romanNumeral.length() - 1; i >= 0; i--) {
- char ch = romanNumeral.charAt(i);
- decimal = romanMap.get(ch) >= lastNumber ? decimal + romanMap.get(ch) : decimal - romanMap.get(ch);
- lastNumber = romanMap.get(ch);
+ private static boolean addPrestigeTimerToLore(List<Text> lines) {
+ if (totalCps < 0.0 || reachedMaxPrestige) return false;
+ if (requiredUntilNextPrestige > 0 && !canPrestige) {
+ lines.add(Text.empty()
+ .append(Text.literal("Chocolate until next prestige: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(requiredUntilNextPrestige)).formatted(Formatting.GOLD)));
+ }
+ lines.add(Text.empty() //Keep this outside of the `if` to match the format of the upgrade tooltips, that say "Time until upgrade: Now" when it's possible
+ .append(Text.literal("Time until next prestige: ").formatted(Formatting.GRAY))
+ .append(formatTime(requiredUntilNextPrestige / totalCps)));
+ return true;
+ }
+
+ private static boolean addTimeTowerStatsToLore(List<Text> lines) {
+ if (totalCps < 0.0 || totalCpsMultiplier < 0.0 || timeTowerMultiplier < 0.0) return false;
+ lines.add(Text.literal("Current stats:").formatted(Formatting.GRAY));
+ lines.add(Text.empty()
+ .append(Text.literal(" CPS increase: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(totalCps / totalCpsMultiplier * timeTowerMultiplier)).formatted(Formatting.GOLD)));
+ lines.add(Text.empty()
+ .append(Text.literal(" CPS when active: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(isTimeTowerActive ? totalCps : totalCps / totalCpsMultiplier * (timeTowerMultiplier + totalCpsMultiplier))).formatted(Formatting.GOLD)));
+ if (!isTimeTowerMaxed) {
+ lines.add(Text.literal("Stats after upgrade:").formatted(Formatting.GRAY));
+ lines.add(Text.empty()
+ .append(Text.literal(" CPS increase: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(totalCps / (totalCpsMultiplier) * (timeTowerMultiplier + 0.1))).formatted(Formatting.GOLD)));
+ lines.add(Text.empty()
+ .append(Text.literal(" CPS when active: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(isTimeTowerActive ? totalCps / totalCpsMultiplier * (totalCpsMultiplier + 0.1) : totalCps / totalCpsMultiplier * (timeTowerMultiplier + 0.1 + totalCpsMultiplier))).formatted(Formatting.GOLD)));
+ }
+ return true;
+ }
+
+ private static boolean addRabbitStatsToLore(List<Text> lines, int slot) {
+ if (cpsIncreaseFactors.isEmpty()) return false;
+ for (Rabbit rabbit : cpsIncreaseFactors) {
+ if (rabbit.slot == slot) {
+ lines.add(Text.empty()
+ .append(Text.literal("CPS Increase: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cpsIncrease)).formatted(Formatting.GOLD)));
+
+ lines.add(Text.empty()
+ .append(Text.literal("Cost per CPS: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cost / rabbit.cpsIncrease)).formatted(Formatting.GOLD)));
+
+ if (rabbit.slot == bestUpgrade) {
+ if (rabbit.cost <= totalChocolate) {
+ lines.add(Text.literal("Best upgrade").formatted(Formatting.GREEN));
+ } else {
+ lines.add(Text.literal("Best upgrade, can't afford").formatted(Formatting.YELLOW));
+ }
+ } else if (rabbit.slot == bestAffordableUpgrade && rabbit.cost <= totalChocolate) {
+ lines.add(Text.literal("Best upgrade you can afford").formatted(Formatting.GREEN));
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static MutableText formatTime(double seconds) {
+ seconds = Math.ceil(seconds);
+ if (seconds <= 0) return Text.literal("Now").formatted(Formatting.GREEN);
+
+ StringBuilder builder = new StringBuilder();
+ if (seconds >= 86400) {
+ builder.append((int) (seconds / 86400)).append("d ");
+ seconds %= 86400;
+ }
+ if (seconds >= 3600) {
+ builder.append((int) (seconds / 3600)).append("h ");
+ seconds %= 3600;
+ }
+ if (seconds >= 60) {
+ builder.append((int) (seconds / 60)).append("m ");
+ seconds %= 60;
+ }
+ if (seconds >= 1) {
+ builder.append((int) seconds).append("s");
+ }
+ return Text.literal(builder.toString()).formatted(Formatting.GOLD);
}
- return decimal;
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotText.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotText.java
new file mode 100644
index 00000000..66c02ca1
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotText.java
@@ -0,0 +1,21 @@
+package de.hysky.skyblocker.skyblock.item.slottext;
+
+import net.minecraft.text.Text;
+
+public record SlotText(Text text, TextPosition position) {
+ public static SlotText bottomLeft(Text text) {
+ return new SlotText(text, TextPosition.BOTTOM_LEFT);
+ }
+
+ public static SlotText bottomRight(Text text) {
+ return new SlotText(text, TextPosition.BOTTOM_RIGHT);
+ }
+
+ public static SlotText topLeft(Text text) {
+ return new SlotText(text, TextPosition.TOP_LEFT);
+ }
+
+ public static SlotText topRight(Text text) {
+ return new SlotText(text, TextPosition.TOP_RIGHT);
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextAdder.java
new file mode 100644
index 00000000..18bf1dc1
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextAdder.java
@@ -0,0 +1,64 @@
+package de.hysky.skyblocker.skyblock.item.slottext;
+
+import de.hysky.skyblocker.skyblock.ChestValue;
+import net.minecraft.screen.slot.Slot;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Extend this class and add it to {@link SlotTextManager#adders} to add text to any arbitrary slot.
+ */
+public abstract class SlotTextAdder {
+ /**
+ * The title of the screen must match this pattern for this adder to be applied. Null means it will be applied to all screens.
+ * @implNote Don't end your regex with a {@code $} as {@link ChestValue} appends text to the end