diff options
11 files changed, 264 insertions, 95 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0a496..3f9bc56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Added quick lookup for item prices and wiki: - wiki: hypixel-skyblock.fandom.com (default key: `I` = info) - item prices: stonks.gg (default key: `P` = price) +- Display pet exp in pet tooltips ### Changed - Item age: show timestamp in the local timezone instead of "SkyBlock"-timezone (Eastern Time; also fixed the incorrect 12h ↔ 24h clock conversion) @@ -30,9 +31,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Dungeon Party Finder (overlay): - Made party indicators clearer (current, suitable, unideal, unjoinable party) - Show sizes of parties - - Mark parties with 'carry' in their notes + - Mark parties with 'carry' or 'hyperion' in their notes (disabled by default) + - Lookup info when dungeon party is full - Lookup info when joining another party via Dungeon Party Finder - - Added active pet + found dungeon secrets to dungeon player lookup + - Added active pet + found dungeon secrets + dungeon types (currently only Catacombs) level to dungeon player lookup ### Fixed - Fixed some possible problems with bad server connection diff --git a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java index 2510820..cd7279e 100644 --- a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java +++ b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java @@ -73,6 +73,7 @@ public class MooConfig { private static String tooltipItemAge; public static boolean tooltipItemAgeShortened; private static String tooltipItemTimestamp; + private static String showPetExp; private static String numeralSystem; private static String tooltipAuctionHousePriceEach; private static String bazaarConnectGraphsNodes; @@ -91,10 +92,12 @@ public class MooConfig { public static int dungOverlayGuiScale; public static boolean dungOverlayTextShadow; private static String dungPartyFinderPlayerLookup; + public static boolean dungPartyFullLookup; public static boolean dungPartyFinderPartyLookup; public static boolean dungPartiesSize; public static int dungClassMin; - public static boolean dungFilterPartiesWithCarry; + private static String dungMarkPartiesWithCarry; + private static String dungMarkPartiesWithHyperion; private static boolean dungFilterPartiesWithArcherDupes; private static boolean dungFilterPartiesWithBerserkDupes; private static boolean dungFilterPartiesWithHealerDupes; @@ -345,6 +348,9 @@ public class MooConfig { Property propTooltipItemTimestamp = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "tooltipItemTimestamp", "key press", "Show item creation date", new String[]{"always", "key press", "never"})); + Property propShowPetExp = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "showPetExp", "always", "Show pet exp", new String[]{"always", "key press", "never"})); + Property propNumeralSystem = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "numeralSystem", "Arabic: 1, 4, 10", "Use Roman or Arabic numeral system?", new String[]{"Arabic: 1, 4, 10", "Roman: I, IV, X"})); @@ -463,12 +469,14 @@ public class MooConfig { " ‣ that do not meet all your criteria: " + EnumChatFormatting.GOLD + "⬛", " ‣ with someone below a certain class level: " + EnumChatFormatting.RED + EnumChatFormatting.BOLD + "ᐯ" + EnumChatFormatting.RESET, " ‣ with duplicated roles you specify below: " + EnumChatFormatting.GOLD + "²⁺", - " ‣ with 'carry' in their notes: " + EnumChatFormatting.AQUA + "carry", " ‣ that match your criteria: " + EnumChatFormatting.GREEN + "⬛"); Property propDungPartyFinderPlayerLookup = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "dungPartyFinderPlayerLookup", "as a tooltip", "Show armor + dungeons stats of player joining via party finder as a tooltip or in chat?", new String[]{"as a tooltip", "in chat", "disabled"})); + Property propDungPartyFullLookup = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungPartyFullLookup", true, "Lookup info when party full?")); + Property propDungPartyFinderPartyLookup = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "dungPartyFinderPartyLookup", true, "Lookup info when joining another party?")); @@ -481,11 +489,17 @@ public class MooConfig { .setMinValue(0).setMaxValue(50), new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.RED + EnumChatFormatting.BOLD + "ᐯ").gray())); - Property propDungFilterPartiesWithCarry = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), - "dungFilterPartiesWithCarry", true, "Mark parties with carry in the notes"), + Property propDungMarkPartiesWithCarry = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungMarkPartiesWithCarry", "do not mark", "Mark parties with carry in the notes", + new String[]{"suitable " + EnumChatFormatting.GREEN + "⬛", "unideal " + EnumChatFormatting.GOLD + "⬛", "block " + EnumChatFormatting.RED + "⬛", "do not mark"}), new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.AQUA + "carry" + EnumChatFormatting.GRAY + " or " + EnumChatFormatting.GREEN + "carry " + EnumChatFormatting.GRAY + "('free' carries)").gray())); + Property propDungMarkPartiesWithHyperion = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungMarkPartiesWithHyperion", "do not mark", "Mark parties with hyperion in the notes", + new String[]{"suitable " + EnumChatFormatting.GREEN + "⬛", "unideal " + EnumChatFormatting.GOLD + "⬛", "block " + EnumChatFormatting.RED + "⬛", "do not mark"}), + new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.AQUA + "hyper").gray())); + Property propDungFilterPartiesWithArcherDupes = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "dungFilterPartiesWithArcherDupes", true, "Mark parties with duplicated Archer class?"), new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.GOLD + "²⁺" + EnumChatFormatting.YELLOW + "A").gray())); @@ -535,6 +549,7 @@ public class MooConfig { tooltipItemAge = propTooltipItemAge.getString(); tooltipItemAgeShortened = propTooltipItemAgeShortened.getBoolean(); tooltipItemTimestamp = propTooltipItemTimestamp.getString(); + showPetExp = propShowPetExp.getString(); numeralSystem = propNumeralSystem.getString(); tooltipAuctionHousePriceEach = propTooltipAuctionHousePriceEach.getString(); bazaarConnectGraphsNodes = propBazaarConnectGraphsNodes.getString(); @@ -553,10 +568,12 @@ public class MooConfig { dungOverlayGuiScale = propDungOverlayGuiScale.getInt(); dungOverlayTextShadow = propDungOverlayTextShadow.getBoolean(); dungPartyFinderPlayerLookup = propDungPartyFinderPlayerLookup.getString(); + dungPartyFullLookup = propDungPartyFullLookup.getBoolean(); dungPartyFinderPartyLookup = propDungPartyFinderPartyLookup.getBoolean(); dungPartiesSize = propDungPartiesSize.getBoolean(); dungClassMin = propDungClassMin.getInt(); - dungFilterPartiesWithCarry = propDungFilterPartiesWithCarry.getBoolean(); + dungMarkPartiesWithCarry = propDungMarkPartiesWithCarry.getString(); + dungMarkPartiesWithHyperion = propDungMarkPartiesWithHyperion.getString(); dungFilterPartiesWithArcherDupes = propDungFilterPartiesWithArcherDupes.getBoolean(); dungFilterPartiesWithBerserkDupes = propDungFilterPartiesWithBerserkDupes.getBoolean(); dungFilterPartiesWithHealerDupes = propDungFilterPartiesWithHealerDupes.getBoolean(); @@ -596,6 +613,7 @@ public class MooConfig { propTooltipItemAge.set(tooltipItemAge); propTooltipItemAgeShortened.set(tooltipItemAgeShortened); propTooltipItemTimestamp.set(tooltipItemTimestamp); + propShowPetExp.set(showPetExp); propNumeralSystem.set(numeralSystem); propTooltipAuctionHousePriceEach.set(tooltipAuctionHousePriceEach); propBazaarConnectGraphsNodes.set(bazaarConnectGraphsNodes); @@ -614,10 +632,12 @@ public class MooConfig { propDungOverlayGuiScale.set(dungOverlayGuiScale); propDungOverlayTextShadow.set(dungOverlayTextShadow); propDungPartyFinderPlayerLookup.set(dungPartyFinderPlayerLookup); + propDungPartyFullLookup.set(dungPartyFullLookup); propDungPartyFinderPartyLookup.set(dungPartyFinderPartyLookup); propDungPartiesSize.set(dungPartiesSize); propDungClassMin.set(dungClassMin); - propDungFilterPartiesWithCarry.set(dungFilterPartiesWithCarry); + propDungMarkPartiesWithCarry.set(dungMarkPartiesWithCarry); + propDungMarkPartiesWithHyperion.set(dungMarkPartiesWithHyperion); propDungFilterPartiesWithArcherDupes.set(dungFilterPartiesWithArcherDupes); propDungFilterPartiesWithBerserkDupes.set(dungFilterPartiesWithBerserkDupes); propDungFilterPartiesWithHealerDupes.set(dungFilterPartiesWithHealerDupes); @@ -740,6 +760,10 @@ public class MooConfig { return Setting.get(tooltipItemTimestamp); } + public static Setting getTooltipPetExpDisplay() { + return Setting.get(showPetExp); + } + public static boolean useRomanNumerals() { return numeralSystem.startsWith("Roman"); } @@ -773,6 +797,28 @@ public class MooConfig { return Setting.get(dungPartyFinderPlayerLookup); } + public static DataHelper.PartyType getDungPartyFinderMarkCarry() { + return getPartyType(dungMarkPartiesWithCarry); + } + + public static DataHelper.PartyType getDungPartyFinderMarkHyperion() { + return getPartyType(dungMarkPartiesWithHyperion); + } + + private static DataHelper.PartyType getPartyType(String configValue) { + String configValueBeginning = configValue.length() >= 5 ? configValue.substring(0, 5) : "invalid"; + switch (configValueBeginning) { + case "suita": // "suitable " + EnumChatFormatting.GREEN + "⬛" + return DataHelper.PartyType.SUITABLE; + case "unide": // "unideal " + EnumChatFormatting.GOLD + "⬛" + return DataHelper.PartyType.UNIDEAL; + case "block": // "block " + EnumChatFormatting.RED + "⬛" + return DataHelper.PartyType.UNJOINABLE; + default: // "do not mark" + return DataHelper.PartyType.NONE; + } + } + public static boolean filterDungPartiesWithDupes(DataHelper.DungeonClass dungeonClass) { switch (dungeonClass) { case ARCHER: diff --git a/src/main/java/de/cowtipper/cowlection/data/DataHelper.java b/src/main/java/de/cowtipper/cowlection/data/DataHelper.java index 028fe62..75c49b0 100644 --- a/src/main/java/de/cowtipper/cowlection/data/DataHelper.java +++ b/src/main/java/de/cowtipper/cowlection/data/DataHelper.java @@ -32,6 +32,19 @@ public final class DataHelper { return Arrays.stream(values(), 0, 5).toArray(SkyBlockRarity[]::new); } + public static SkyBlockRarity getPetRarityByColorCode(String colorCode) { + if (MYTHIC.rarityColor.toString().equals(colorCode)) { + // special case: Mystic Bat + return LEGENDARY; + } + for (SkyBlockRarity petRarity : getPetRarities()) { + if (petRarity.rarityColor.toString().equals(colorCode)) { + return petRarity; + } + } + return null; + } + public EnumChatFormatting getColor() { return rarityColor; } @@ -93,6 +106,30 @@ public final class DataHelper { } } + public enum PartyType { + SUITABLE(0xff22B14C, 240), + UNIDEAL(0xffCD8032, 240), + UNJOINABLE(0xffEB6E6E, 279), + CURRENT(0xff5FDE6C, 240), + NONE(0xffFF0000, 279); + + private final float zIndex; + private final int color; + + PartyType(int color, float zIndex) { + this.color = color; + this.zIndex = zIndex; + } + + public float getZIndex() { + return zIndex; + } + + public int getColor() { + return color; + } + } + public enum DungeonClass { @SerializedName("archer") ARCHER('A'), @SerializedName("berserk") BERSERK('B'), diff --git a/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java b/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java index 242c0c3..b65e48c 100644 --- a/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java +++ b/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java @@ -338,6 +338,23 @@ public class HySkyBlockStats { return output; } + public String getDungeonTypesLevels() { + StringBuilder dungeonTypesLevels = new StringBuilder(); + if (dungeon_types != null && !dungeon_types.isEmpty()) { + for (Map.Entry<String, HySkyBlockStats.Profile.Dungeons.Type> dungeonType : dungeon_types.entrySet()) { + if (dungeonTypesLevels.length() == 0) { + dungeonTypesLevels.append(EnumChatFormatting.DARK_GRAY).append(" [").append(EnumChatFormatting.GRAY); + } else { + dungeonTypesLevels.append(EnumChatFormatting.DARK_GRAY).append(", ").append(EnumChatFormatting.GRAY); + } + int dungeonTypeLevel = dungeonType.getValue().getLevel(); + dungeonTypesLevels.append(Utils.fancyCase(dungeonType.getKey().substring(0, 4))).append(" ").append(MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(dungeonTypeLevel) : dungeonTypeLevel); + } + dungeonTypesLevels.append(EnumChatFormatting.DARK_GRAY).append("]"); + } + return dungeonTypesLevels.toString(); + } + public static class Type { private Map<String, Integer> times_played; private Map<String, Integer> tier_completions; diff --git a/src/main/java/de/cowtipper/cowlection/data/XpTables.java b/src/main/java/de/cowtipper/cowlection/data/XpTables.java index 391f90a..158fb66 100644 --- a/src/main/java/de/cowtipper/cowlection/data/XpTables.java +++ b/src/main/java/de/cowtipper/cowlection/data/XpTables.java @@ -249,6 +249,18 @@ public class XpTables { return -1; } } + + public static int getTotalExp(DataHelper.SkyBlockRarity rarity, int level, int exp) { + TreeSet<Integer> xpToLevels = PET_XP.get(rarity); + if (xpToLevels != null) { + for (int xpToLevel : xpToLevels) { + if (level-- <= 1) { + return xpToLevel + exp; + } + } + } + return -1; + } } public enum Dungeoneering { diff --git a/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java b/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java index cfacd9d..df3d08f 100644 --- a/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java +++ b/src/main/java/de/cowtipper/cowlection/handler/DungeonCache.java @@ -27,7 +27,7 @@ public class DungeonCache { private final Set<String> deadPlayers; private final Set<String> failedPuzzles; private final Set<UUID> destroyedCrypts; - private int cryptsOffset; + private int destroyedCryptsInTabList; private boolean isInDungeon; private int elapsedMinutes; @@ -43,7 +43,7 @@ public class DungeonCache { deadPlayers = new HashSet<>(); failedPuzzles = new HashSet<>(); destroyedCrypts = new HashSet<>(); - cryptsOffset = 0; + destroyedCryptsInTabList = 0; } public boolean isInDungeon() { @@ -147,8 +147,7 @@ public class DungeonCache { String tabListEntry = EnumChatFormatting.getTextWithoutFormattingCodes(tabList.getPlayerName(playerInfo)); if (tabListEntry != null && tabListEntry.startsWith(" Crypts: ")) { try { - int cryptsFromTabList = Integer.parseInt(tabListEntry.substring(" Crypts: ".length()).trim()); - cryptsOffset = cryptsFromTabList - destroyedCrypts.size(); + destroyedCryptsInTabList = Integer.parseInt(tabListEntry.substring(" Crypts: ".length()).trim()); } catch (NumberFormatException | IndexOutOfBoundsException ex) { // couldn't parse crypts count from tab list ex.printStackTrace(); @@ -235,7 +234,7 @@ public class DungeonCache { } public int getDestroyedCrypts() { - return destroyedCrypts.size() + cryptsOffset; + return destroyedCryptsInTabList > 0 ? destroyedCryptsInTabList : destroyedCrypts.size(); } public int getElapsedMinutes() { @@ -248,7 +247,7 @@ public class DungeonCache { deadPlayers.clear(); failedPuzzles.clear(); destroyedCrypts.clear(); - cryptsOffset = 0; + destroyedCryptsInTabList = 0; elapsedMinutes = 0; classMilestone = 0; nextPerformanceSend = 0; diff --git a/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java b/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java index 0240938..45b99a7 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java @@ -17,6 +17,7 @@ import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.IChatComponent; import net.minecraft.util.StringUtils; +import net.minecraftforge.client.ClientCommandHandler; import net.minecraftforge.client.event.ClientChatReceivedEvent; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiScreenEvent; @@ -187,6 +188,9 @@ public class ChatListener { main.getDungeonCache().lookupPartyMembers(); } } + } else if (CredentialStorage.isMooValid && MooConfig.dungPartyFullLookup && message.equals("Dungeon Finder > Your dungeon group is full! Click here to warp to the dungeon!") + && (Minecraft.getMinecraft().currentScreen == null || Minecraft.getMinecraft().currentScreen instanceof GuiChat)) { + ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/moo dp"); } if (messageSender != null) { @@ -210,13 +214,16 @@ public class ChatListener { HySkyBlockStats.Profile.Member member = activeProfile.getMember(stalkedPlayer.getUuid()); String armorLookupPrefix = " ❈ " + EnumChatFormatting.DARK_GREEN + playerName; String delimiter = "\n" + (outputAsChatMessages ? " " : ""); - String armorLookupResult = EnumChatFormatting.LIGHT_PURPLE + " ➜ " + EnumChatFormatting.GRAY + dungeonClass + delimiter + String.join(delimiter, member.getArmor()); + + HySkyBlockStats.Profile.Dungeons dungeons = member.getDungeons(); + String dungeonTypesLevels = dungeons != null ? dungeons.getDungeonTypesLevels() : ""; + + String armorLookupResult = EnumChatFormatting.LIGHT_PURPLE + " ➜ " + EnumChatFormatting.GRAY + dungeonClass + dungeonTypesLevels + delimiter + String.join(delimiter, member.getArmor()); // active pet: HySkyBlockStats.Profile.Pet activePet = member.getActivePet(); String petInfo = (outputAsChatMessages ? "\n " : "\n\n") + EnumChatFormatting.GRAY + "Active pet: " + (activePet != null ? activePet.toFancyString() : "" + EnumChatFormatting.DARK_GRAY + EnumChatFormatting.ITALIC + "none"); - HySkyBlockStats.Profile.Dungeons dungeons = member.getDungeons(); String highestFloorCompletions = "\n" + (outputAsChatMessages ? " " : "") + EnumChatFormatting.GRAY + "Completed no dungeons yet"; String skyBlockDetails; diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java index 27da9f0..5f25fa7 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java @@ -5,6 +5,7 @@ import de.cowtipper.cowlection.Cowlection; import de.cowtipper.cowlection.config.CredentialStorage; import de.cowtipper.cowlection.config.MooConfig; import de.cowtipper.cowlection.config.gui.MooConfigGui; +import de.cowtipper.cowlection.data.DataHelper; import de.cowtipper.cowlection.data.DataHelper.DungeonClass; import de.cowtipper.cowlection.handler.DungeonCache; import de.cowtipper.cowlection.util.GuiHelper; @@ -283,7 +284,7 @@ public class DungeonsListener { // not a player skull, don't draw party status indicator return; } - PartyType partyType = PartyType.NONE; + DataHelper.PartyType partyType = DataHelper.PartyType.NONE; List<String> itemTooltip = item.getTooltip(Minecraft.getMinecraft().thePlayer, false); if (itemTooltip.size() < 5) { @@ -295,9 +296,9 @@ public class DungeonsListener { || lastToolTipLine.startsWith("Requires a Class at Level") || lastToolTipLine.startsWith("Requires Catacombs Level")) { // cannot enter dungeon - partyType = PartyType.UNJOINABLE; + partyType = DataHelper.PartyType.UNJOINABLE; } else if (lastToolTipLine.endsWith("You are in this party!")) { - partyType = PartyType.CURRENT; + partyType = DataHelper.PartyType.CURRENT; } else { Map<DungeonClass, AtomicInteger> dungClassesInParty = new LinkedHashMap<>(); AtomicInteger classCounter = new AtomicInteger(); @@ -305,8 +306,8 @@ public class DungeonsListener { dungClassesInParty.put(activeDungeonClass, classCounter); // add our own class int partySize = 5; - String isCarry = null; boolean memberTooLowLevel = false; + String middleText = null; for (String toolTipLine : itemTooltip) { String toolTipLineWithoutFormatting = EnumChatFormatting.getTextWithoutFormattingCodes(toolTipLine); @@ -323,63 +324,73 @@ public class DungeonsListener { } } else if (" Empty".equals(toolTipLineWithoutFormatting)) { --partySize; - } else if (MooConfig.dungFilterPartiesWithCarry && toolTipLineWithoutFormatting.startsWith("Note: ")) { + } else if (toolTipLineWithoutFormatting.startsWith("Note: ")) { String partyNote = toolTipLineWithoutFormatting.toLowerCase(); - if (partyNote.contains("carry") || partyNote.contains("carries")) { - partyType = PartyType.UNIDEAL; - isCarry = partyNote.contains("free") ? "free" : "paid"; + DataHelper.PartyType partyTypeCarry = MooConfig.getDungPartyFinderMarkCarry(); + DataHelper.PartyType partyTypeHyperion = MooConfig.getDungPartyFinderMarkHyperion(); + if (partyTypeCarry != DataHelper.PartyType.NONE && (partyNote.contains("carry") || partyNote.contains("carries"))) { + partyType = partyTypeCarry; + if (partyTypeCarry != DataHelper.PartyType.UNJOINABLE) { + middleText = (partyNote.contains("free") ? EnumChatFormatting.GREEN : "") + "carry"; + } + } else if (partyTypeHyperion != DataHelper.PartyType.NONE && partyNote.contains("hyp")) { + partyType = partyTypeHyperion; + if (partyTypeHyperion != DataHelper.PartyType.UNJOINABLE) { + middleText = "hyper"; + } } } } FontRenderer font = Minecraft.getMinecraft().fontRendererObj; - if (MooConfig.dungFilterPartiesWithCarry && isCarry != null) { + if (partyType != DataHelper.PartyType.UNJOINABLE && middleText != null) { GlStateManager.pushMatrix(); GlStateManager.translate(0, 0, 281); double scaleFactor = 0.5; GlStateManager.scale(scaleFactor, scaleFactor, 0); - int carryColor = "free".equals(isCarry) ? new Color(85, 240, 85, 255).getRGB() : new Color(85, 240, 240, 255).getRGB(); - font.drawStringWithShadow("carry", (float) ((x + 1) / scaleFactor), (float) ((y + 5) / scaleFactor), carryColor); + font.drawStringWithShadow(middleText, (float) ((x + 1) / scaleFactor), (float) ((y + 5) / scaleFactor), new Color(85, 240, 240, 255).getRGB()); GlStateManager.popMatrix(); } - if (memberTooLowLevel) { - // at least one party member is lower than the min class level - partyType = PartyType.UNIDEAL; - GlStateManager.pushMatrix(); - GlStateManager.translate(0, 0, 280); - font.drawStringWithShadow(EnumChatFormatting.BOLD + "ᐯ", x + 1, y + 8, new Color(220, 20, 20, 255).getRGB()); - GlStateManager.popMatrix(); - } - StringBuilder dupedClasses = new StringBuilder(); - for (Map.Entry<DungeonClass, AtomicInteger> partyClassInfo : dungClassesInParty.entrySet()) { - if (partyClassInfo.getValue().get() > 1 && MooConfig.filterDungPartiesWithDupes(partyClassInfo.getKey())) { - dupedClasses.append(partyClassInfo.getKey().getShortName()); + if (partyType != DataHelper.PartyType.UNJOINABLE) { + if (memberTooLowLevel) { + // at least one party member is lower than the min class level + partyType = DataHelper.PartyType.UNIDEAL; + GlStateManager.pushMatrix(); + GlStateManager.translate(0, 0, 280); + font.drawStringWithShadow(EnumChatFormatting.BOLD + "ᐯ", x + 1, y + 8, new Color(220, 20, 20, 255).getRGB()); + GlStateManager.popMatrix(); + } + StringBuilder dupedClasses = new StringBuilder(); + for (Map.Entry<DungeonClass, AtomicInteger> partyClassInfo : dungClassesInParty.entrySet()) { + if (partyClassInfo.getValue().get() > 1 && MooConfig.filterDungPartiesWithDupes(partyClassInfo.getKey())) { + dupedClasses.append(partyClassInfo.getKey().getShortName()); + } + } + if (dupedClasses.length() > 0) { + // party has class duplicates + partyType = DataHelper.PartyType.UNIDEAL; + dupedClasses.insert(0, EnumChatFormatting.YELLOW).insert(0, "²⁺"); // 2+ + + GlStateManager.pushMatrix(); + GlStateManager.translate(0, 0, 280); + double scaleFactor = 0.8; + GlStateManager.scale(scaleFactor, scaleFactor, 0); + font.drawStringWithShadow(dupedClasses.toString(), (float) (x / scaleFactor), (float) (y / scaleFactor), new Color(255, 170, 0, 255).getRGB()); + GlStateManager.popMatrix(); + } else if (!memberTooLowLevel && middleText == null) { + // party matches our criteria! + partyType = DataHelper.PartyType.SUITABLE; + } + // add party size indicator + if (MooConfig.dungPartiesSize && partySize > 0) { + GlStateManager.pushMatrix(); + GlStateManager.translate(0, 0, 280); + String partySizeIndicator = String.valueOf(partySize); + font.drawStringWithShadow(partySizeIndicator, x + 17 - font.getStringWidth(partySizeIndicator), y + 9, 0xffFFFFFF); + GlStateManager.popMatrix(); } - } - if (dupedClasses.length() > 0) { - // party has class duplicates - partyType = PartyType.UNIDEAL; - dupedClasses.insert(0, EnumChatFormatting.YELLOW).insert(0, "²⁺"); // 2+ - - GlStateManager.pushMatrix(); - GlStateManager.translate(0, 0, 280); - double scaleFactor = 0.8; - GlStateManager.scale(scaleFactor, scaleFactor, 0); - font.drawStringWithShadow(dupedClasses.toString(), (float) (x / scaleFactor), (float) (y / scaleFactor), new Color(255, 170, 0, 255).getRGB()); - GlStateManager.popMatrix(); - } else if (!memberTooLowLevel && isCarry == null) { - // party matches our criteria! - partyType = PartyType.SUITABLE; - } - // add party size indicator - if (MooConfig.dungPartiesSize && partySize > 0) { - GlStateManager.pushMatrix(); - GlStateManager.translate(0, 0, 280); - String partySizeIndicator = String.valueOf(partySize); - font.drawStringWithShadow(partySizeIndicator, x + 17 - font.getStringWidth(partySizeIndicator), y + 9, 0xffFFFFFF); - GlStateManager.popMatrix(); } } - if (partyType != PartyType.CURRENT + if (partyType != DataHelper.PartyType.CURRENT || (/*partyType == PartyType.CURRENT &&*/ Minecraft.getSystemTime() % 1000 < 600)) { GlStateManager.pushMatrix(); GlStateManager.translate(0, 0, partyType.getZIndex()); @@ -623,28 +634,4 @@ public class DungeonsListener { } } } - - private enum PartyType { - SUITABLE(0xff32CD32, 240), - UNIDEAL(0xffCD8032, 240), - UNJOINABLE(0xffD75B5B, 279), - CURRENT(0xff5FDE6C, 240), - NONE(0xffFF0000, 279); - - private final float zIndex; - private final int color; - - PartyType(int color, float zIndex) { - this.color = color; - this.zIndex = zIndex; - } - - public float getZIndex() { - return zIndex; - } - - public int getColor() { - return color; - } - } } diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java index 84a58ee..a0162d3 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java @@ -246,12 +246,13 @@ public class DungeonsPartyListener { DataHelper.DungeonClass selectedClass = dungeons.getSelectedClass(); int selectedClassLevel = dungeons.getSelectedClassLevel(); - String classInfo = selectedClass.getName() + " " + (MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(selectedClassLevel) : selectedClassLevel); - playerEntry.append(classInfo); - // insert class data into str: + String classAndDungeonTypeInfo = selectedClass.getName() + " " + (MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(selectedClassLevel) : selectedClassLevel) + + dungeons.getDungeonTypesLevels(); + playerEntry.append(classAndDungeonTypeInfo); + // insert class + dungeon type data into str: String noClassSelected = EnumChatFormatting.ITALIC + "no class selected"; int start = playerTooltip.indexOf(noClassSelected); - playerTooltip.replace(start, start + noClassSelected.length(), classInfo); + playerTooltip.replace(start, start + noClassSelected.length(), classAndDungeonTypeInfo); // highest floor completions: playerTooltip.append(dungeons.getHighestFloorCompletions(3, false)); 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 5093e9a..524a0c1 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java @@ -4,6 +4,8 @@ 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.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; @@ -51,6 +53,7 @@ public class SkyBlockListener { private static final Set<String> blackList = new HashSet<>(Arrays.asList("ENCHANTED_BOOK", "RUNE", "PET", "POTION")); // + minions (_GENERATOR_) 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 final NumberFormat numberFormatter; private final Cowlection main; @@ -163,6 +166,59 @@ public class SkyBlockListener { } } + // show total pet exp + NBTTagCompound extraAttributes = e.itemStack.getSubCompound("ExtraAttributes", false); + if ((MooConfig.getTooltipPetExpDisplay() == MooConfig.Setting.ALWAYS + || MooConfig.getTooltipPetExpDisplay() == MooConfig.Setting.SPECIAL && MooConfig.isTooltipToggleKeyBindingPressed()) + && e.itemStack.getItem() == Items.skull) { + if (extraAttributes != null && extraAttributes.hasKey("petInfo")) { + // pet in inventory, auction house or similar + String petInfo = extraAttributes.getString("petInfo"); + String expSubstr = "\"exp\":"; + int beginPetExp = petInfo.indexOf(expSubstr); + int endPetExp = petInfo.indexOf(',', beginPetExp); + if (beginPetExp > 0 && endPetExp > 0) { + try { + long petExp = (long) Double.parseDouble(petInfo.substring(beginPetExp + expSubstr.length(), endPetExp)); + int index = Math.max(0, e.toolTip.size() - (e.showAdvancedItemTooltips ? /* item name & nbt info */ 2 : 0)); + e.toolTip.add(index, EnumChatFormatting.GRAY + "Pet exp: " + EnumChatFormatting.GOLD + numberFormatter.format(petExp)); + } catch (NumberFormatException ignored) { + // do nothing + } + } + } else if (e.itemStack.getDisplayName().contains("[Lvl ")) { + // pet in pets menu + for (int i = e.toolTip.size() - 1; i >= 0; i--) { + String loreLine = EnumChatFormatting.getTextWithoutFormattingCodes(e.toolTip.get(i)); + if (loreLine.startsWith("--------------------")) { // exp bar to next level + int beginPetExp = loreLine.indexOf(' '); + int endPetExp = loreLine.indexOf('/'); + if (beginPetExp < 0 || endPetExp < 0) { + // didn't find pet exp, abort + break; + } + try { + int petExp = numberFormatter.parse(loreLine.substring(beginPetExp + 1, endPetExp)).intValue(); + + Matcher petNameMatcher = PET_NAME_PATTERN.matcher(e.itemStack.getDisplayName()); + if (petNameMatcher.find()) { + int petLevel = Integer.parseInt(petNameMatcher.group(1)); + DataHelper.SkyBlockRarity petRarity = DataHelper.SkyBlockRarity.getPetRarityByColorCode(petNameMatcher.group(2)); + if (petRarity == null) { + break; + } + int totalPetExp = XpTables.Pet.getTotalExp(petRarity, petLevel, petExp); + e.toolTip.add(i + 1, EnumChatFormatting.GRAY + "Total pet exp: " + EnumChatFormatting.GOLD + numberFormatter.format(totalPetExp)); + } + } catch (ParseException | NumberFormatException ignored) { + // do nothing + } + break; + } + } + } + } + // remove unnecessary tooltip entries: dyed leather armor NBTTagCompound nbtDisplay = e.itemStack.getSubCompound("display", false); if (!Minecraft.getMinecraft().gameSettings.advancedItemTooltips @@ -187,7 +243,6 @@ public class SkyBlockListener { MooConfig.Setting tooltipItemTimestampDisplay = MooConfig.getTooltipItemTimestampDisplay(); // add item age to tooltip - NBTTagCompound extraAttributes = e.itemStack.getSubCompound("ExtraAttributes", false); if (extraAttributes != null && extraAttributes.hasKey("timestamp") && (tooltipItemAgeDisplay != MooConfig.Setting.DISABLED || tooltipItemTimestampDisplay != MooConfig.Setting.DISABLED)) { LocalDateTime skyBlockDateTime; @@ -198,7 +253,7 @@ public class SkyBlockListener { skyBlockDateTime = LocalDateTime.parse(timestamp, DateTimeFormatter.ofPattern("M/d/yy h:mm a", Locale.US)); } else { // format: day > month > year + 24 hour clock (very, very rare) - skyBlockDateTime = LocalDateTime.parse(timestamp, DateTimeFormatter.ofPattern("d/M/yy hh:mm", Locale.US)); + skyBlockDateTime = LocalDateTime.parse(timestamp, DateTimeFormatter.ofPattern("d/M/yy HH:mm", Locale.US)); } } catch (DateTimeParseException ignored) { // unknown/invalid timestamp format diff --git a/src/main/resources/assets/cowlection/lang/en_US.lang b/src/main/resources/assets/cowlection/lang/en_US.lang index 53af4a0..93fef62 100644 --- a/src/main/resources/assets/cowlection/lang/en_US.lang +++ b/src/main/resources/assets/cowlection/lang/en_US.lang @@ -46,6 +46,8 @@ cowlection.config.tooltipItemAgeShortened=Shorten 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.tooltip=Show item creation date? Only works for non-stackable items +cowlection.config.showPetExp=Show 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 cowlection.config.tooltipAuctionHousePriceEach=§7Auction house: §rprice per item @@ -80,14 +82,18 @@ cowlection.config.dungOverlayTextShadow=Add text shadow cowlection.config.dungOverlayTextShadow.tooltip=Enable or disable text shadow cowlection.config.dungPartyFinderPlayerLookup=Show info of joining players §d§l⚷ cowlection.config.dungPartyFinderPlayerLookup.tooltip=Show armor and dungeons stats of player joining via party finder as a tooltip or in chat?\n§d§l⚷ §eRequires a valid API key! +cowlection.config.dungPartyFullLookup=Lookup info when party full? §d§l⚷ +cowlection.config.dungPartyFullLookup.tooltip=Lookup armor and dungeons stats of each party member when your party is full?\n§7Alternatively: §e/moo dungeon party §7or §e/m dp\n§d§l⚷ §eRequires a valid API key! cowlection.config.dungPartyFinderPartyLookup=Lookup info when joining another party? §d§l⚷ cowlection.config.dungPartyFinderPartyLookup.tooltip=Lookup armor and dungeons stats of each party member when joining via party finder?\n§7Alternatively: §e/moo dungeon party §7or §e/m dp\n§d§l⚷ §eRequires a valid API key! cowlection.config.dungPartiesSize=Show party sizes? cowlection.config.dungPartiesSize.tooltip=Show sizes of parties? cowlection.config.dungClassMin=Minimum preferred class level cowlection.config.dungClassMin.tooltip=Marks parties with members with lower class level than this value -cowlection.config.dungFilterPartiesWithCarry=Mark 'carry' parties? -cowlection.config.dungFilterPartiesWithCarry.tooltip=Mark parties that have 'carry' in their notes? +cowlection.config.dungMarkPartiesWithCarry=Mark 'carry' parties? +cowlection.config.dungMarkPartiesWithCarry.tooltip=Mark parties that have 'carry' in their notes? +cowlection.config.dungMarkPartiesWithHyperion=Mark 'hyperion' parties? +cowlection.config.dungMarkPartiesWithHyperion.tooltip=Mark parties that have 'hyperion' in their notes? cowlection.config.dungFilterPartiesWithArcherDupes=Mark duplicated Archer class? cowlection.config.dungFilterPartiesWithArcherDupes.tooltip=Mark parties with duplicated Archer class? cowlection.config.dungFilterPartiesWithBerserkDupes=Mark duplicated Berserk class? |