aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md7
-rw-r--r--README.md2
-rw-r--r--src/main/java/de/cowtipper/cowlection/Cowlection.java2
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/MooConfig.java29
-rw-r--r--src/main/java/de/cowtipper/cowlection/data/BestiaryEntry.java151
-rw-r--r--src/main/java/de/cowtipper/cowlection/data/DataHelper.java2
-rw-r--r--src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java16
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java162
-rw-r--r--src/main/java/de/cowtipper/cowlection/util/MooChatComponent.java6
-rw-r--r--src/main/resources/assets/cowlection/lang/en_US.lang10
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
diff --git a/README.md b/README.md
index b746904..1a76670 100644
--- a/README.md
+++ b/README.md
@@ -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` &rarr; SkyBlock |
-| Additional info in various tooltips (e.g. show item age, display pet exp, price per item in an auction) | `/moo config` &rarr; SkyBlock &rarr; 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` &rarr; SkyBlock &rarr; 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