diff options
10 files changed, 355 insertions, 32 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a4c51f2..95a5da9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [1.8.9-0.13.0] - unreleased ### Added +- Bestiary Overview: enhances tooltips of `/bestiary` ⬌ `/be` + - hover over one of the area/location-items in a *sub*-category of the Bestiary to see an overview of the tiers upgrades you are closest to + - can be ordered by fewest kills or lowest % to next tier by clicking on the area/location item - SkyBlock Dwarven Mines update: - Added new minions to `/m analyzeIslands` (Mithril + t12) - `/moo stalkskyblock` additions: - - Added 'last profile save' - - Added Enchanting, Farming and Mining 51-60 + - Added 'last profile save' (= last time user played SkyBlock) + - Added Enchanting, Farming, Mining, and Combat 51-60 - Added missing Runecrafting 25 ### Changed @@ -29,7 +29,7 @@ It is a collection of different features mainly focused on Hypixel SkyBlock. | Dungeon interfaces enhancements (normalize dungeon item stats, improved party finder) | Hold <kbd>shift</kbd> (configurable) while viewing a dungeon item tooltip | | Dungeon performance tracker and overlay: Skill score calculation, class milestone tracker, destroyed crypts tracker, and elapsed time indicator | automatically; or with `/moo dungeon` | | Check how long current world has been loaded (≈ when the server was last restarted) | `/moo worldage` + `/moo config` → SkyBlock | -| Additional info in various tooltips (e.g. show item age, display pet exp, price per item in an auction) | `/moo config` → SkyBlock → Tooltip enhancements | +| Additional info in various tooltips (e.g. show item age, display pet exp, price per item in an auction, Bestiary overview) | `/moo config` → SkyBlock → Tooltip enhancements | | Quick lookup for item prices and wiki articles | Wiki: <kbd>I</kbd> *(= Info)*, Prices: <kbd>P</kbd> | ## Download diff --git a/src/main/java/de/cowtipper/cowlection/Cowlection.java b/src/main/java/de/cowtipper/cowlection/Cowlection.java index 92a6397..5e0e7bb 100644 --- a/src/main/java/de/cowtipper/cowlection/Cowlection.java +++ b/src/main/java/de/cowtipper/cowlection/Cowlection.java @@ -64,7 +64,7 @@ public class Cowlection { friendsHandler = new FriendsHandler(this, new File(configDir, "friends.json")); moo = new CredentialStorage(new Configuration(new File(configDir, "do-not-share-me-with-other-players.cfg"))); - config = new MooConfig(this, new Configuration(new File(configDir, MODID + ".cfg"), "0.12.0")); + config = new MooConfig(this, new Configuration(new File(configDir, MODID + ".cfg"), "0.13.0-pre")); } @EventHandler diff --git a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java index c422236..caa392a 100644 --- a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java +++ b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java @@ -78,6 +78,8 @@ public class MooConfig { private static String tooltipAuctionHousePriceEach; private static String bazaarConnectGraphsNodes; public static int bazaarConnectGraphsLineWidth; + public static String bestiaryOverviewOrder; + private String[] bestiaryOverviewOrderDefaultValues; private static int lookupWikiKeyBinding; private static int lookupPriceKeyBinding; public static boolean lookupItemDirectly; @@ -387,7 +389,7 @@ public class MooConfig { "numeralSystem", "Arabic: 1, 4, 10", "Use Roman or Arabic numeral system?", new String[]{"Arabic: 1, 4, 10", "Roman: I, IV, X"})); Map<String, NBTBase> demoAhItemExtraAttributes = new HashMap<>(); - demoItemExtraAttributes.put("id", new NBTTagString("BEACON")); + demoAhItemExtraAttributes.put("id", new NBTTagString("BEACON")); ItemStack demoAhItem = MooConfigPreview.createDemoItem("beacon", "§764x §fB§8e§facon Block", new String[]{"§f§lCOMMON", "§8§m-----------------", "§7Seller: §6[MVP§0++§6] Enlightener", "§7Buy it now: §63,900,000 coins", "", "§7Ends in: §e13h 33m 37s", "", "§eDon't click to inspect!"}, demoAhItemExtraAttributes); demoAhItem.stackSize = 64; MooConfigPreview ahItemPreview = new MooConfigPreview(demoAhItem); @@ -409,6 +411,16 @@ public class MooConfig { Property propBazaarConnectGraphsLineWidth = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "bazaarConnectGraphsLineWidth", 3, "Line width of bazaar graph", 1, 10)); + bestiaryOverviewOrderDefaultValues = new String[]{"fewest kills", "lowest %", "hidden"}; + MooConfigPreview bestiaryOverviewPreview = new MooConfigPreview(MooConfigPreview.createDemoItem("wheat", "§a§3The Barn", new String[]{ + "§7View all of the mobs that you've", + "§7found and killed in §3The Barn§7.", + "", + "§7Families Found: §e75§6%", "§3---------------§f----- §b3§3/§b4"}, Maps.newHashMap())); + Property propBestiaryOverviewOrder = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "bestiaryOverviewOrder", "fewest kills", "Order of the Bestiary overview?", bestiaryOverviewOrderDefaultValues), + bestiaryOverviewPreview); + // Sub-Category: Item lookup subCat = configCat.addSubCategory("Item lookup"); subCat.addExplanations("Lookup item prices or wiki articles for any SkyBlock item in any inventory."); @@ -586,6 +598,7 @@ public class MooConfig { tooltipAuctionHousePriceEach = propTooltipAuctionHousePriceEach.getString(); bazaarConnectGraphsNodes = propBazaarConnectGraphsNodes.getString(); bazaarConnectGraphsLineWidth = propBazaarConnectGraphsLineWidth.getInt(); + bestiaryOverviewOrder = propBestiaryOverviewOrder.getString(); lookupWikiKeyBinding = propLookupWikiKeyBinding.getInt(); lookupPriceKeyBinding = propLookupPriceKeyBinding.getInt(); lookupItemDirectly = propLookupItemDirectly.getBoolean(); @@ -650,6 +663,7 @@ public class MooConfig { propTooltipAuctionHousePriceEach.set(tooltipAuctionHousePriceEach); propBazaarConnectGraphsNodes.set(bazaarConnectGraphsNodes); propBazaarConnectGraphsLineWidth.set(bazaarConnectGraphsLineWidth); + propBestiaryOverviewOrder.set(bestiaryOverviewOrder); propLookupWikiKeyBinding.set(lookupWikiKeyBinding); propLookupPriceKeyBinding.set(lookupPriceKeyBinding); propLookupItemDirectly.set(lookupItemDirectly); @@ -800,6 +814,19 @@ public class MooConfig { return numeralSystem.startsWith("Roman"); } + public void cycleBestiaryOverviewOrder() { + String oldValue = bestiaryOverviewOrder; + int currentIndex = -1; + for (int i = 0; i < bestiaryOverviewOrderDefaultValues.length; i++) { + if (oldValue.equals(bestiaryOverviewOrderDefaultValues[i])) { + currentIndex = i; + break; + } + } + bestiaryOverviewOrder = bestiaryOverviewOrderDefaultValues[(currentIndex + 1) % bestiaryOverviewOrderDefaultValues.length]; + syncFromFields(); + } + public static boolean isTooltipToggleKeyBindingPressed() { return tooltipToggleKeyBinding > 0 && Keyboard.isKeyDown(tooltipToggleKeyBinding); } diff --git a/src/main/java/de/cowtipper/cowlection/data/BestiaryEntry.java b/src/main/java/de/cowtipper/cowlection/data/BestiaryEntry.java new file mode 100644 index 0000000..a6c78e7 --- /dev/null +++ b/src/main/java/de/cowtipper/cowlection/data/BestiaryEntry.java @@ -0,0 +1,151 @@ +package de.cowtipper.cowlection.data; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import org.apache.commons.lang3.StringUtils; + +import java.text.NumberFormat; +import java.util.Locale; + +public class BestiaryEntry { + public static ItemStack triggerItem; + + public static int highestKillsToGo; + public static int highestKillGoal; + public static int highestPercentageToGo; + public static int widestMobNameWidth; + + private static int widestKillsToGoWidth; + private static int widestKillGoalToGoWidth; + private static int widestPercentageToGoWidth; + + private static final NumberFormat numberFormatter; + private static final char dashSpacerChar; + private static final char spacerChar; + private static int dashSpacerWidth; + private static int spacerWidth; + + private final String mobName; + private final int mobNameWidth; + private final int killsToGo; + private final int killsGoal; + private final int percentageToGo; + + static { + numberFormatter = NumberFormat.getNumberInstance(Locale.US); + numberFormatter.setMaximumFractionDigits(0); + dashSpacerChar = '·'; + spacerChar = ' '; + } + + public BestiaryEntry(String mobName, int currentKills, int killsGoal) { + this.mobName = mobName; + this.killsToGo = killsGoal - currentKills; + this.killsGoal = killsGoal; + this.percentageToGo = 100 - (currentKills * 100 / killsGoal); + if (killsToGo > highestKillsToGo) { + highestKillsToGo = killsToGo; + } + if (killsGoal > highestKillGoal) { + highestKillGoal = killsGoal; + } + if (percentageToGo > highestPercentageToGo) { + highestPercentageToGo = percentageToGo; + } + this.mobNameWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(mobName); + if (mobNameWidth > widestMobNameWidth) { + widestMobNameWidth = mobNameWidth; + } + } + + /** + * Bestiary not unlocked yet + */ + public BestiaryEntry(String mobName) { + this.mobName = mobName; + mobNameWidth = -1; + killsToGo = Integer.MAX_VALUE; + killsGoal = -1; + percentageToGo = Integer.MAX_VALUE; + } + + public static void reinitialize(ItemStack triggerItem) { + BestiaryEntry.triggerItem = triggerItem; + + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; + dashSpacerWidth = fontRenderer.getCharWidth(dashSpacerChar); + spacerWidth = fontRenderer.getCharWidth(spacerChar); + + highestKillsToGo = 0; + highestKillGoal = 0; + highestPercentageToGo = 0; + widestMobNameWidth = 0; + } + + public static void calculateWidestEntries() { + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; + widestKillsToGoWidth = fontRenderer.getStringWidth(numberFormatter.format(highestKillsToGo)); + widestKillGoalToGoWidth = fontRenderer.getStringWidth(numberFormatter.format(highestKillGoal)); + widestPercentageToGoWidth = fontRenderer.getStringWidth(numberFormatter.format(highestPercentageToGo)); + } + + public static boolean isDifferentTriggerItem(ItemStack triggerItem) { + return BestiaryEntry.triggerItem == null || !BestiaryEntry.triggerItem.getIsItemStackEqual(triggerItem); + } + + public String getFormattedOutput(boolean sortBestiaryOverviewByKills) { + if (percentageToGo == Integer.MAX_VALUE) { + return mobName + EnumChatFormatting.GRAY + ": not unlocked yet"; + } + + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; + StringBuilder currentEntry = new StringBuilder(); + String formattedKillsToGo = numberFormatter.format(killsToGo); + String formattedKillsGoal = numberFormatter.format(killsGoal); + String formattedPercentageToGo = numberFormatter.format(percentageToGo); + + int gapSize = (widestMobNameWidth - mobNameWidth) + (sortBestiaryOverviewByKills + ? widestKillsToGoWidth - fontRenderer.getStringWidth(formattedKillsToGo) + : widestPercentageToGoWidth - fontRenderer.getStringWidth(formattedPercentageToGo)); + int amountOfSpacerChars = Math.max(gapSize, 0) / dashSpacerWidth; + + currentEntry.append(mobName).append(EnumChatFormatting.RESET).append(EnumChatFormatting.DARK_GRAY).append(StringUtils.repeat(dashSpacerChar, amountOfSpacerChars)).append(' '); + int remainingGap = gapSize % dashSpacerWidth; + if (remainingGap >= 3) { + // quite a large gap left = add another smaller spacer + currentEntry.append(spacerChar); + remainingGap -= spacerWidth; + } + + StringBuilder killsInfo = new StringBuilder().append(sortBestiaryOverviewByKills ? EnumChatFormatting.AQUA : EnumChatFormatting.DARK_AQUA) + .append(formattedKillsToGo).append(EnumChatFormatting.DARK_GRAY).append('/').append(formattedKillsGoal).append(EnumChatFormatting.GRAY).append(" kills"); + StringBuilder percentageInfo = new StringBuilder().append(sortBestiaryOverviewByKills ? EnumChatFormatting.DARK_AQUA : EnumChatFormatting.AQUA) + .append(formattedPercentageToGo).append(EnumChatFormatting.DARK_GRAY).append("%"); + String spacer = EnumChatFormatting.DARK_GRAY + " ⬌ "; + + currentEntry.append(sortBestiaryOverviewByKills ? killsInfo : percentageInfo).append(spacer); + int gapSize2 = ((sortBestiaryOverviewByKills + ? (widestPercentageToGoWidth - fontRenderer.getStringWidth(formattedPercentageToGo) + widestKillGoalToGoWidth - fontRenderer.getStringWidth(formattedKillsGoal)) + : (widestKillsToGoWidth - fontRenderer.getStringWidth(formattedKillsToGo))) + + remainingGap); + int amountOf2ndSpacerChars = Math.max(gapSize2, 0) / spacerWidth; + currentEntry.append(StringUtils.repeat(spacerChar, amountOf2ndSpacerChars)); + + currentEntry.append(sortBestiaryOverviewByKills ? percentageInfo : killsInfo).append(EnumChatFormatting.GRAY).append(" to go"); + return currentEntry.toString(); + } + + public int getKillsToGo() { + return killsToGo; + } + + public int getPercentageToGo() { + return percentageToGo; + } + + public String getMobName() { + return mobName; + } +} diff --git a/src/main/java/de/cowtipper/cowlection/data/DataHelper.java b/src/main/java/de/cowtipper/cowlection/data/DataHelper.java index e491867..9f529a4 100644 --- a/src/main/java/de/cowtipper/cowlection/data/DataHelper.java +++ b/src/main/java/de/cowtipper/cowlection/data/DataHelper.java @@ -164,7 +164,7 @@ public final class DataHelper { public static Map<String, String> getMinions() { // key = skin id, value = minion type and tier Map<String, String> minions = new HashMap<>(); - // TODO currently Fishing VI + VII use the same skull texture (server-side) - thus can't be distinguished + // TODO currently Fishing VI + VII and Revenant I + XII use the same skull texture (server-side) - thus can't be distinguished minions.put("2f93289a82bd2a06cbbe61b733cfdc1f1bd93c4340f7a90abd9bdda774109071", "Cobblestone I"); minions.put("3fd87486dc94cb8cd04a3d7d06f191f027f38dad7b4ed34c6681fb4d08834c06", "Cobblestone II"); minions.put("cc088ed6bb8763af4eb7d006e00fda7dc11d7681e97c983b7011c3e872f6aab9", "Cobblestone III"); diff --git a/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java b/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java index fb9fcff..98fab87 100644 --- a/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java +++ b/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java @@ -160,7 +160,7 @@ public class HySkyBlockStats { skills.put(XpTables.Skill.MINING, XpTables.Skill.MINING.getLevel(experience_skill_mining, 60)); } if (experience_skill_combat >= 0) { - skills.put(XpTables.Skill.COMBAT, XpTables.Skill.COMBAT.getLevel(experience_skill_combat)); + skills.put(XpTables.Skill.COMBAT, XpTables.Skill.COMBAT.getLevel(experience_skill_combat, 60)); } if (experience_skill_foraging >= 0) { skills.put(XpTables.Skill.FORAGING, XpTables.Skill.FORAGING.getLevel(experience_skill_foraging)); @@ -428,26 +428,12 @@ public class HySkyBlockStats { public static class Banking { private double balance; - // private List<Transaction> transactions; /** * No-args constructor for GSON */ private Banking() { } - - // private class Transaction { - // private int amount; - // private long timestamp; - // private Transaction.Action action; - // private String initiator_name; - // - // /** - // * No-args constructor for GSON - // */ - // private Transaction() { - // } - // } } } } diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java index 12f5e48..1555e2d 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java @@ -4,34 +4,41 @@ import com.mojang.realmsclient.util.Pair; import de.cowtipper.cowlection.Cowlection; import de.cowtipper.cowlection.config.MooConfig; import de.cowtipper.cowlection.config.gui.MooConfigGui; +import de.cowtipper.cowlection.data.BestiaryEntry; import de.cowtipper.cowlection.data.DataHelper; import de.cowtipper.cowlection.data.XpTables; import de.cowtipper.cowlection.util.GuiHelper; import de.cowtipper.cowlection.util.MooChatComponent; import de.cowtipper.cowlection.util.Utils; import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.audio.SoundCategory; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.inventory.GuiChest; import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.command.NumberInvalidException; import net.minecraft.enchantment.Enchantment; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.ContainerChest; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; +import net.minecraft.item.EnumDyeColor; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; +import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.util.Constants; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.apache.commons.lang3.StringUtils; import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; import java.awt.*; import java.io.UnsupportedEncodingException; @@ -54,6 +61,8 @@ public class SkyBlockListener { private static final Pattern ITEM_COUNT_PREFIXED_PATTERN = Pattern.compile("^(?:§[0-9a-fl-or])*[\\d]+x "); private static final Pattern ITEM_COUNT_SUFFIXED_PATTERN = Pattern.compile(" (?:§[0-9a-fl-or])*x[\\d]+$"); private static final Pattern PET_NAME_PATTERN = Pattern.compile("^§7\\[Lvl (\\d+)] (§[0-9a-f])"); + private static final Pattern TIER_SUFFIX_PATTERN = Pattern.compile(" [IVX0-9]+$"); + List<BestiaryEntry> bestiaryOverview = null; private final NumberFormat numberFormatter; private final Cowlection main; @@ -304,6 +313,88 @@ public class SkyBlockListener { } } + // bestiary overview: + String bestiaryOverviewOrder = MooConfig.bestiaryOverviewOrder; + boolean isBestiaryOverviewVisible = !"hidden".equals(bestiaryOverviewOrder); + // either use cached bestiary overview or generate overview if trigger item is different + boolean isDifferentTriggerItem = BestiaryEntry.isDifferentTriggerItem(e.itemStack); + GuiScreen currentScreen = Minecraft.getMinecraft().currentScreen; + if (currentScreen instanceof GuiChest && isBestiaryOverviewVisible && isBestiaryGui((GuiChest) currentScreen, e.itemStack)) { + if (isDifferentTriggerItem) { + BestiaryEntry.reinitialize(e.itemStack); + bestiaryOverview = new ArrayList<>(); + + ContainerChest chestContainer = (ContainerChest) ((GuiChest) currentScreen).inventorySlots; + IInventory inventory = chestContainer.getLowerChestInventory(); + for (int slot = 0; slot < inventory.getSizeInventory(); slot++) { + ItemStack item = inventory.getStackInSlot(slot); + if (item != null) { + // slot + item + NBTTagCompound itemNbtDisplay = item.getSubCompound("display", false); + if (itemNbtDisplay != null && itemNbtDisplay.hasKey("Lore", Constants.NBT.TAG_LIST)) { + NBTTagList loreList = itemNbtDisplay.getTagList("Lore", Constants.NBT.TAG_STRING); + + if (loreList.tagCount() < 10 || !"§eClick to view!".equals(loreList.getStringTagAt(loreList.tagCount() - 1))) { + if (item.getItem() == Items.dye && item.getMetadata() == EnumDyeColor.GRAY.getDyeDamage()) { + // mob hasn't been killed yet + bestiaryOverview.add(new BestiaryEntry(item.getDisplayName())); + } + // not a bestiary icon with additional data + continue; + } + + for (int loreLineNr = 0; loreLineNr < loreList.tagCount(); ++loreLineNr) { + String loreLineFormatted = loreList.getStringTagAt(loreLineNr); + String loreLine = EnumChatFormatting.getTextWithoutFormattingCodes(loreLineFormatted); + if (loreLine.startsWith("-------------------- ")) { + try { + String progress = loreLine.substring("-------------------- ".length()); + int divider = progress.indexOf('/'); + if (divider > 0) { + bestiaryOverview.add(new BestiaryEntry(TIER_SUFFIX_PATTERN.matcher(item.getDisplayName()).replaceFirst(""), + abbreviatedToLongNumber(progress.substring(0, divider)), + abbreviatedToLongNumber(progress.substring(divider + 1)))); + break; + } + } catch (NumberInvalidException ignored) { + } + } + } + } + } + } + } + } else if (currentScreen instanceof MooConfigGui && isBestiaryOverviewVisible && e.itemStack.getItem() == Items.wheat) { + if (isDifferentTriggerItem) { + // bestiary overview preview in config gui + BestiaryEntry.reinitialize(e.itemStack); + bestiaryOverview = new ArrayList<>(); + bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.GREEN + "Cow", 1, 2)); + bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.GREEN + "Pig", 1163, 2500)); + bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.GREEN + "Chicken", 10800, 15000)); + bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.RED + "Farmhand")); + } + } else { + isBestiaryOverviewVisible = false; + } + if (bestiaryOverview != null && isBestiaryOverviewVisible) { + e.toolTip.add(""); + e.toolTip.add("" + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + EnumChatFormatting.UNDERLINE + "Bestiary Overview:" + EnumChatFormatting.RESET + EnumChatFormatting.YELLOW + " (ordered by: " + bestiaryOverviewOrder + " to next tier)"); + + if (bestiaryOverview.size() == 0) { + e.toolTip.add(EnumChatFormatting.GREEN + "All mobs max tier " + EnumChatFormatting.DARK_GREEN + "✔"); + } else { + boolean sortBestiaryOverviewByKills = "fewest kills".equals(bestiaryOverviewOrder); + // sort by <kills|percentage> left, then alphabetically by mob name + bestiaryOverview.sort(Comparator.<BestiaryEntry>comparingInt(entry -> (sortBestiaryOverviewByKills) ? entry.getKillsToGo() : entry.getPercentageToGo()).thenComparing(BestiaryEntry::getMobName)); + BestiaryEntry.calculateWidestEntries(); + + for (BestiaryEntry bestiaryEntry : bestiaryOverview) { + e.toolTip.add(bestiaryEntry.getFormattedOutput(sortBestiaryOverviewByKills)); + } + } + } + // for auction house: show price for each item if multiple items are sold at once MooConfig.Setting tooltipAuctionHousePriceEachDisplay = MooConfig.getTooltipAuctionHousePriceEachDisplay(); if ((tooltipAuctionHousePriceEachDisplay == MooConfig.Setting.ALWAYS || tooltipAuctionHousePriceEachDisplay == MooConfig.Setting.SPECIAL && MooConfig.isTooltipToggleKeyBindingPressed()) @@ -352,6 +443,75 @@ public class SkyBlockListener { } } + @SubscribeEvent + public void onGuiClose(GuiOpenEvent e) { + if (e.gui == null && this.bestiaryOverview != null) { + this.bestiaryOverview = null; + BestiaryEntry.reinitialize(null); + } + } + + @SubscribeEvent + public void onMouseInteractionInGui(GuiScreenEvent.MouseInputEvent.Pre e) { + int clickedMouseButton = Mouse.getEventButton(); + if (clickedMouseButton < 0) { + // no button press, just mouse-hover + return; + } + if (Mouse.getEventButtonState() && e.gui instanceof GuiChest) { + GuiChest guiChest = (GuiChest) e.gui; + Slot hoveredSlot = GuiHelper.getSlotUnderMouse(guiChest); + if (hoveredSlot != null && hoveredSlot.getHasStack() && hoveredSlot.getStack().hasDisplayName()) { + if (clickedMouseButton == 0 && isBestiaryGui(guiChest, hoveredSlot.getStack())) { + // cycle bestiary order on left click + main.getConfig().cycleBestiaryOverviewOrder(); + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F)); + } else if (this.bestiaryOverview != null && clickedMouseButton <= 3 && hoveredSlot.getStack().getItem() == Items.arrow) { + // reset bestiary overview cache on page switch via left, middle or right click on arrow + this.bestiaryOverview = null; + BestiaryEntry.reinitialize(null); + } + } + } + } + + private boolean isBestiaryGui(GuiChest guiChest, ItemStack hoveredItem) { + IInventory inventory = guiChest.inventorySlots.getSlot(0).inventory; + String inventoryName = (inventory.hasCustomName() ? EnumChatFormatting.getTextWithoutFormattingCodes(inventory.getDisplayName().getUnformattedTextForChat()) : inventory.getName()); + String hoveredItemName = EnumChatFormatting.getTextWithoutFormattingCodes(hoveredItem.getDisplayName()); + if (inventoryName.startsWith("Bestiary ➜ ") && inventoryName.endsWith(hoveredItemName)) { + // bestiary overview is enabled and mouse is hovering over bestiary category item (with same name as category) + BestiaryEntry.triggerItem = hoveredItem; + return true; + } else if (inventoryName.equals("Search Results") && hoveredItem.getItem() == Items.sign && "Search Results".equals(hoveredItemName)) { + NBTTagCompound itemNbtDisplay = hoveredItem.getSubCompound("display", false); + if (itemNbtDisplay != null && itemNbtDisplay.hasKey("Lore", Constants.NBT.TAG_LIST)) { + NBTTagList loreList = itemNbtDisplay.getTagList("Lore", Constants.NBT.TAG_STRING); + if (loreList.tagCount() >= 2 + && loreList.getStringTagAt(0).startsWith("§7Query: §a") + && loreList.getStringTagAt(1).startsWith("§7Results: §a")) { + // hovering over bestiary search result item + BestiaryEntry.triggerItem = hoveredItem; + return true; + } + } + } + return false; + } + + private int abbreviatedToLongNumber(String number) throws NumberInvalidException { + try { + number = number.replace(",", ""); + if (number.endsWith("k")) { + return (int) (Double.parseDouble(number.substring(0, number.length() - 1)) * 1000); + } else { + return Integer.parseInt(number); + } + } catch (NumberFormatException | IndexOutOfBoundsException e) { + throw new NumberInvalidException("commands.generic.num.invalid", number); + } + } + private String buildLink(String itemName, ItemLookupType itemLookupType) { try { return itemLookupType.getBaseUrl() + URLEncoder.encode(itemName, "UTF-8"); @@ -371,7 +531,7 @@ public class SkyBlockListener { } private boolean isSubmitBidItem(ItemStack itemStack) { - return ((itemStack.getItem().equals(Items.gold_nugget) || itemStack.getItem().equals(Item.getItemFromBlock(Blocks.gold_block))) + return ((itemStack.getItem() == Items.gold_nugget || itemStack.getItem() == Item.getItemFromBlock(Blocks.gold_block)) && (itemStack.hasDisplayName() && (itemStack.getDisplayName().endsWith("Submit Bid") || itemStack.getDisplayName().endsWith("Collect Auction")))) || (/* green hardened clay + */ itemStack.hasDisplayName() && (itemStack.getDisplayName().endsWith("Create BIN Auction") || itemStack.getDisplayName().endsWith("Create Auction"))); } diff --git a/src/main/java/de/cowtipper/cowlection/util/MooChatComponent.java b/src/main/java/de/cowtipper/cowlection/util/MooChatComponent.java index 4694fee..95415d3 100644 --- a/src/main/java/de/cowtipper/cowlection/util/MooChatComponent.java +++ b/src/main/java/de/cowtipper/cowlection/util/MooChatComponent.java @@ -165,12 +165,6 @@ public class MooChatComponent extends ChatComponentText { return this; } - @Deprecated - public MooChatComponent appendKeyValue(String key, String value) { - appendSibling(new MooChatComponent("\n").appendFreshSibling(new KeyValueChatComponent(key, value))); - return this; - } - public static class KeyValueChatComponent extends MooChatComponent { public KeyValueChatComponent(String key, String value) { this(key, value, ": "); diff --git a/src/main/resources/assets/cowlection/lang/en_US.lang b/src/main/resources/assets/cowlection/lang/en_US.lang index bcb84d7..5acf252 100644 --- a/src/main/resources/assets/cowlection/lang/en_US.lang +++ b/src/main/resources/assets/cowlection/lang/en_US.lang @@ -40,13 +40,13 @@ cowlection.config.notifyServerAge=Show server age notifications? cowlection.config.notifyServerAge.tooltip=Overrides the two settings above.\n§7This setting can also be changed with §e/moo worldage <on|off> cowlection.config.tooltipToggleKeyBinding=Key binding: toggle tooltip cowlection.config.tooltipToggleKeyBinding.tooltip=Hold down this key to toggle tooltip if one of the following settings is set to 'key press'\n\n§7§odisable key binding: §e§oset key binding to §lESC -cowlection.config.tooltipItemAge=Show item age +cowlection.config.tooltipItemAge=§7Items: §rShow item age cowlection.config.tooltipItemAge.tooltip=Show item age? Only works for non-stackable items -cowlection.config.tooltipItemAgeShortened=Shorten item age? +cowlection.config.tooltipItemAgeShortened=§7Items: §rShorten item age? cowlection.config.tooltipItemAgeShortened.tooltip=Show shortened (5.8 months) or detailed item age (5 months 24 days)? -cowlection.config.tooltipItemTimestamp=Show item creation date +cowlection.config.tooltipItemTimestamp=§7Items: §rShow item creation date cowlection.config.tooltipItemTimestamp.tooltip=Show item creation date? Only works for non-stackable items -cowlection.config.showPetExp=Show pet exp +cowlection.config.showPetExp=§7Pets: §rShow pet exp cowlection.config.showPetExp.tooltip=Show pet exp?\n§7§oExp for max level pets §f§odon't §7§owork inside the pets menu (but in every other GUI)! cowlection.config.numeralSystem=Numeral system cowlection.config.numeralSystem.tooltip=Use Roman or Arabic numeral system?\nThis is currently used to display numbers in the commands /moo stalkSkyBlock and /moo analyzeIsland @@ -56,6 +56,8 @@ cowlection.config.bazaarConnectGraphsNodes=§7Bazaar: §rconnect the graph nodes cowlection.config.bazaarConnectGraphsNodes.tooltip=Draw a line through the nodes of the bazaar graphs?\n§7§oThis also (tries to) fix the graphs when using the MC unicode font. cowlection.config.bazaarConnectGraphsLineWidth=§7Bazaar: §rline width cowlection.config.bazaarConnectGraphsLineWidth.tooltip=Width of the line drawn through the nodes of the bazaar graphs? +cowlection.config.bestiaryOverviewOrder=§7Bestiary: §roverview order by... +cowlection.config.bestiaryOverviewOrder.tooltip=Add §6§lBestiary Overview§r to the SkyBlock Bestiary (§e/bestiary§7 or §e/be§r).\nThis setting changes the order of the Bestiary Overview entries, §7which can also be changed by left-clicking the area/location icon in the Bestiary GUI §7(§e/be§7). cowlection.config.lookupWikiKeyBinding=Key binding: lookup item wiki cowlection.config.lookupWikiKeyBinding.tooltip=Hover over an item in any inventory and press keybinding to open the item's wiki article.\n§7§oAccesses §e§ohypixel-skyblock.fandom.com\n§7§odefault key: §e§oI = info\n\n§7§odisable key binding: §e§oset key binding to §lESC cowlection.config.lookupPriceKeyBinding=Key binding: lookup item price |