From 37a9fd7df3695fcc0fb4dd5427a91b73bdadefbb Mon Sep 17 00:00:00 2001 From: Luna Date: Fri, 3 May 2024 14:07:46 +0200 Subject: Feature: Add overflow crop milestones (#997) Co-authored-by: HiZe Co-authored-by: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt | 2 + .../hannibal2/skyhanni/config/commands/Commands.kt | 9 ++ .../cropmilestones/CropMilestonesConfig.java | 5 ++ .../CropMilestonesOverflowConfig.java | 38 +++++++++ .../config/storage/ProfileSpecificStorage.java | 3 + .../skyhanni/data/GardenCropMilestones.kt | 99 +++++++++++++++++++--- .../data/GardenCropMilestonesCommunityFix.kt | 16 +--- .../hannibal2/skyhanni/features/garden/CropType.kt | 2 +- .../features/garden/FarmingMilestoneCommand.kt | 50 ++++++++--- .../skyhanni/features/garden/GardenLevelDisplay.kt | 1 + .../features/garden/farming/GardenBestCropTime.kt | 15 ++-- .../garden/farming/GardenCropMilestoneDisplay.kt | 65 ++++++++++---- .../inventory/GardenCropMilestoneInventory.kt | 3 +- .../garden/inventory/GardenInventoryNumbers.kt | 3 +- .../inventory/GardenInventoryTooltipOverflow.kt | 93 ++++++++++++++++++++ .../features/misc/discordrpc/DiscordStatus.kt | 18 ++-- .../features/skillprogress/SkillTooltip.kt | 3 +- .../at/hannibal2/skyhanni/utils/LorenzUtils.kt | 1 + 18 files changed, 359 insertions(+), 67 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesOverflowConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryTooltipOverflow.kt (limited to 'src') diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 96d6c4af1..80dcc16f8 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -218,6 +218,7 @@ import at.hannibal2.skyhanni.features.garden.fortuneguide.CaptureFarmingGear import at.hannibal2.skyhanni.features.garden.inventory.AnitaExtraFarmingFortune import at.hannibal2.skyhanni.features.garden.inventory.GardenCropMilestoneInventory import at.hannibal2.skyhanni.features.garden.inventory.GardenInventoryNumbers +import at.hannibal2.skyhanni.features.garden.inventory.GardenInventoryTooltipOverflow import at.hannibal2.skyhanni.features.garden.inventory.LogBookStats import at.hannibal2.skyhanni.features.garden.inventory.SkyMartCopperPrice import at.hannibal2.skyhanni.features.garden.inventory.plots.GardenNextPlotPrice @@ -900,6 +901,7 @@ class SkyHanniMod { loadModule(VerminTracker) loadModule(VerminHighlighter()) loadModule(SkillProgress) + loadModule(GardenInventoryTooltipOverflow()) loadModule(SkillTooltip()) loadModule(MaxPurseItems()) loadModule(SuperCraftFeatures()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index b4a2c336e..faca8636b 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -7,6 +7,7 @@ import at.hannibal2.skyhanni.config.ConfigGuiManager import at.hannibal2.skyhanni.config.features.About.UpdateStream import at.hannibal2.skyhanni.data.ChatClickActionManager import at.hannibal2.skyhanni.data.ChatManager +import at.hannibal2.skyhanni.data.GardenCropMilestones import at.hannibal2.skyhanni.data.GardenCropMilestonesCommunityFix import at.hannibal2.skyhanni.data.GuiEditManager import at.hannibal2.skyhanni.data.PartyAPI @@ -291,6 +292,14 @@ object Commands { }, FarmingMilestoneCommand::onComplete ) + registerCommand0( + "shcropgoal", + "Define a custom milestone goal for a crop.", + { + FarmingMilestoneCommand.setGoal(it.getOrNull(0), it.getOrNull(1)) + }, + FarmingMilestoneCommand::onComplete + ) registerCommand0( "shskills", "Skills XP/Level related command", diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesConfig.java index ee47709a8..abc256c97 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesConfig.java @@ -36,6 +36,11 @@ public class CropMilestonesConfig { @FeatureToggle public boolean progress = true; + @Expose + @ConfigOption(name = "Overflow", desc = "") + @Accordion + public CropMilestonesOverflowConfig overflow = new CropMilestonesOverflowConfig(); + @Expose @ConfigOption( name = "Warn When Close", diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesOverflowConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesOverflowConfig.java new file mode 100644 index 000000000..acf588543 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesOverflowConfig.java @@ -0,0 +1,38 @@ +package at.hannibal2.skyhanni.config.features.garden.cropmilestones; + +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class CropMilestonesOverflowConfig { + + @Expose + @ConfigOption(name = "Crop Milestone Display", desc = "Show overflow levels in Crop Milestone display.") + @ConfigEditorBoolean + public boolean cropMilestoneDisplay = false; + + @Expose + @ConfigOption(name = "Best Crop Time", desc = "Show overflow levels in Best Crop Time Display.") + @ConfigEditorBoolean + public boolean bestCropTime = false; + + @Expose + @ConfigOption(name = "Inventory", desc = "Show overflow levels as stack size in the Crop Milestones inventory (will also change milestone average).") + @ConfigEditorBoolean + public boolean inventoryStackSize = false; + + @Expose + @ConfigOption(name = "Tooltip", desc = "Show overflow level progress in the item tooltip in the Crop Milestones inventory.") + @ConfigEditorBoolean + public boolean inventoryTooltip = false; + + @Expose + @ConfigOption(name = "Discord RPC", desc = "Show overflow levels in the Discord RPC milestone display.") + @ConfigEditorBoolean + public boolean discordRPC = false; + + @Expose + @ConfigOption(name = "Chat", desc = "Send a chat message when gaining an overflow milestone level.") + @ConfigEditorBoolean + public boolean chat = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java index 2638512d8..5487a3519 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -361,6 +361,9 @@ public class ProfileSpecificStorage { @Expose public Map npcVisitorLocations = new HashMap<>(); + @Expose + public Map customGoalMilestone = new HashMap<>(); + @Expose public PestProfitTracker.Data pestProfitTracker = new PestProfitTracker.Data(); diff --git a/src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestones.kt b/src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestones.kt index 0038f4448..8a3eef8cd 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestones.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestones.kt @@ -6,14 +6,18 @@ import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.features.garden.CropType import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.utils.ChatUtils.chat import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.NumberUtil.formatLong +import at.hannibal2.skyhanni.utils.SoundUtils +import at.hannibal2.skyhanni.utils.SoundUtils.playSound import at.hannibal2.skyhanni.utils.StringUtils.matchFirst import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object GardenCropMilestones { + private val patternGroup = RepoPattern.group("data.garden.milestone") private val cropPattern by patternGroup.pattern( "crop", @@ -24,6 +28,8 @@ object GardenCropMilestones { "§7Total: §a(?.*)" ) + private val config get() = GardenAPI.config.cropMilestones + fun getCropTypeByLore(itemStack: ItemStack): CropType? { itemStack.getLore().matchFirst(cropPattern) { val name = group("name") @@ -47,6 +53,42 @@ object GardenCropMilestones { GardenCropMilestonesCommunityFix.openInventory(event.inventoryItems) } + fun onOverflowLevelUp(crop: CropType, oldLevel: Int, newLevel: Int) { + val customGoalLevel = ProfileStorageData.profileSpecific?.garden?.customGoalMilestone?.get(crop) ?: 0 + val goalReached = newLevel == customGoalLevel + + // TODO utils function that is shared with Garden Level Display + val rewards = buildList { + add(" §r§8+§aRespect from Elite Farmers and SkyHanni members :)") + add(" §r§8+§b1 Flexing Point") + if (newLevel % 5 == 0) + add(" §r§7§8+§d2 SkyHanni User Luck") + } + + val messages = listOf( + "§r§3§l▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬§r", + " §r§b§lGARDEN MILESTONE §3${crop.cropName} §8$oldLevel➜§3$newLevel§r", + if (goalReached) + listOf( + "", + " §r§d§lGOAL REACHED!", + "", + ).joinToString("\n") + else + "", + " §r§a§lREWARDS§r", + rewards.joinToString("\n"), + "§r§3§l▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬§r" + ) + + chat(messages.joinToString("\n"), false) + + if (goalReached) + chat("§e§lYou have reached your milestone goal of §b§l${customGoalLevel} §e§lin the §b§l${crop.cropName} §e§lcrop!", false) + + SoundUtils.createSound("random.levelup", 1f, 1f).playSound() + } + var cropMilestoneData: Map> = emptyMap() val cropCounter: MutableMap? get() = GardenAPI.storage?.cropCounter @@ -58,50 +100,81 @@ object GardenCropMilestones { cropCounter?.set(this, counter) } - fun CropType.isMaxed(): Boolean { + fun CropType.isMaxed(useOverflow: Boolean): Boolean { + if (useOverflow) return false + // TODO change 1b val maxValue = cropMilestoneData[this]?.sum() ?: 1_000_000_000 // 1 bil for now return getCounter() >= maxValue } - fun getTierForCropCount(count: Long, crop: CropType): Int { + fun getTierForCropCount(count: Long, crop: CropType, allowOverflow: Boolean = false): Int { var tier = 0 var totalCrops = 0L val cropMilestone = cropMilestoneData[crop] ?: return 0 + val last = cropMilestone.last() + for (tierCrops in cropMilestone) { totalCrops += tierCrops - if (totalCrops > count) { + if (totalCrops >= count) { return tier } tier++ } + if (allowOverflow) { + while (totalCrops < count) { + totalCrops += last + if (totalCrops >= count) { + return tier + } + tier++ + } + } return tier } fun getMaxTier() = cropMilestoneData.values.firstOrNull()?.size ?: 0 - fun getCropsForTier(requestedTier: Int, crop: CropType): Long { + fun getCropsForTier(requestedTier: Int, crop: CropType, allowOverflow: Boolean = false): Long { var totalCrops = 0L var tier = 0 val cropMilestone = cropMilestoneData[crop] ?: return 0 + val definedTiers = cropMilestone.size + + if (requestedTier <= definedTiers || !allowOverflow) { + for (tierCrops in cropMilestone) { + totalCrops += tierCrops + tier++ + if (tier == requestedTier) { + return totalCrops + } + } + + return if (!allowOverflow) 0 else totalCrops + } + + for (tierCrops in cropMilestone) { totalCrops += tierCrops tier++ - if (tier == requestedTier) { - return totalCrops - } } - return 0 + val additionalTiers = requestedTier - definedTiers + + val lastIncrement = cropMilestone.last().toLong() + + totalCrops += lastIncrement * additionalTiers + + return totalCrops } - fun CropType.progressToNextLevel(): Double { + fun CropType.progressToNextLevel(allowOverflow: Boolean = false): Double { val progress = getCounter() - val startTier = getTierForCropCount(progress, this) - val startCrops = getCropsForTier(startTier, this) - val end = getCropsForTier(startTier + 1, this).toDouble() - return (progress - startCrops) / (end - startCrops) + val startTier = getTierForCropCount(progress, this, allowOverflow) + val startCrops = getCropsForTier(startTier, this, allowOverflow) + val end = getCropsForTier(startTier + 1, this, allowOverflow) + return (progress - startCrops).toDouble() / (end - startCrops) } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestonesCommunityFix.kt b/src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestonesCommunityFix.kt index c52878003..fdfd3ca96 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestonesCommunityFix.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestonesCommunityFix.kt @@ -91,10 +91,7 @@ object GardenCropMilestonesCommunityFix { // debug("crop: $crop") // debug("realTier: $realTier") - val guessNextMax = GardenCropMilestones.getCropsForTier( - realTier + 1, - crop - ) - GardenCropMilestones.getCropsForTier(realTier, crop) + val guessNextMax = GardenCropMilestones.getCropsForTier(realTier + 1, crop) - GardenCropMilestones.getCropsForTier(realTier, crop) // debug("guessNextMax: ${guessNextMax.addSeparators()}") val nextMax = amountPattern.matchMatcher(next) { group("max").formatLong() @@ -105,7 +102,7 @@ object GardenCropMilestonesCommunityFix { wrongData.add("$crop:$realTier:${nextMax.addSeparators()}") } - val guessTotalMax = GardenCropMilestones.getCropsForTier(46, crop) + val guessTotalMax = GardenCropMilestones.getCropsForTier(46, crop) // no need to overflow here // println("guessTotalMax: ${guessTotalMax.addSeparators()}") val totalMax = amountPattern.matchMatcher(total) { group("max").formatLong() @@ -163,13 +160,8 @@ object GardenCropMilestonesCommunityFix { } private fun tryFix(crop: CropType, tier: Int, amount: Int): Boolean { - val guessNextMax = GardenCropMilestones.getCropsForTier(tier + 1, crop) - GardenCropMilestones.getCropsForTier( - tier, - crop - ) - if (guessNextMax.toInt() == amount) { - return false - } + val guessNextMax = GardenCropMilestones.getCropsForTier(tier + 1, crop) - GardenCropMilestones.getCropsForTier(tier, crop) + if (guessNextMax.toInt() == amount) return false GardenCropMilestones.cropMilestoneData = GardenCropMilestones.cropMilestoneData.editCopy { fix(crop, this, tier, amount) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/CropType.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/CropType.kt index 968fb1b29..dc15f136a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/CropType.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/CropType.kt @@ -69,7 +69,7 @@ enum class CropType( fun getByNameOrNull(itemName: String): CropType? { if (itemName == "Red Mushroom" || itemName == "Brown Mushroom") return MUSHROOM if (itemName == "Seeds") return WHEAT - return entries.firstOrNull { it.cropName == itemName } + return entries.firstOrNull { it.cropName.equals(itemName, ignoreCase = true) } } fun getByName(name: String) = getByNameOrNull(name) ?: error("No valid crop type '$name'") diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingMilestoneCommand.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingMilestoneCommand.kt index 61e3d1caa..72f09be00 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingMilestoneCommand.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingMilestoneCommand.kt @@ -2,9 +2,11 @@ package at.hannibal2.skyhanni.features.garden import at.hannibal2.skyhanni.data.GardenCropMilestones import at.hannibal2.skyhanni.data.GardenCropMilestones.getCounter +import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.features.garden.farming.GardenCropSpeed.getSpeed import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.formatIntOrUserError import at.hannibal2.skyhanni.utils.TimeUtils import net.minecraft.command.CommandBase @@ -16,18 +18,18 @@ object FarmingMilestoneCommand { return } - val enteredCrop = CropType.entries.firstOrNull { it.simpleName == crop.lowercase() } ?: run { + val enteredCrop = CropType.getByName(crop) ?: run { ChatUtils.userError("Invalid crop type entered") return } - val currentMilestone = getValidNumber(current) - val targetMilestone = getValidNumber(target) + val currentMilestone = current?.toIntOrNull() + val targetMilestone = target?.toIntOrNull() if (currentMilestone == null) { val currentProgress = enteredCrop.getCounter() - val currentCropMilestone = GardenCropMilestones.getTierForCropCount(currentProgress, enteredCrop) + 1 - val cropsForTier = GardenCropMilestones.getCropsForTier(currentCropMilestone, enteredCrop) + val currentCropMilestone = GardenCropMilestones.getTierForCropCount(currentProgress, enteredCrop, allowOverflow = true) + 1 + val cropsForTier = GardenCropMilestones.getCropsForTier(currentCropMilestone, enteredCrop, allowOverflow = true) val output = (cropsForTier - currentProgress).formatOutput(needsTime, enteredCrop) ChatUtils.chat("§7$output needed to reach the next milestone") @@ -35,24 +37,52 @@ object FarmingMilestoneCommand { } if (targetMilestone == null) { - val cropsForTier = GardenCropMilestones.getCropsForTier(currentMilestone, enteredCrop) + val cropsForTier = GardenCropMilestones.getCropsForTier(currentMilestone, enteredCrop, allowOverflow = true) val output = cropsForTier.formatOutput(needsTime, enteredCrop) ChatUtils.chat("§7$output needed for milestone §7$currentMilestone") return } + if (currentMilestone >= targetMilestone) { ChatUtils.userError("Entered milestone is greater than or the same as target milestone") return } - val currentAmount = GardenCropMilestones.getCropsForTier(currentMilestone, enteredCrop) - val targetAmount = GardenCropMilestones.getCropsForTier(targetMilestone, enteredCrop) + val currentAmount = GardenCropMilestones.getCropsForTier(currentMilestone, enteredCrop, allowOverflow = true) + val targetAmount = GardenCropMilestones.getCropsForTier(targetMilestone, enteredCrop, allowOverflow = true) val output = (targetAmount - currentAmount).formatOutput(needsTime, enteredCrop) - ChatUtils.chat("§7$output needed for milestone §7$currentMilestone §a-> §7$targetMilestone") } + fun setGoal(crop: String?, target: String?) { + val storage = ProfileStorageData.profileSpecific?.garden?.customGoalMilestone ?: return + + if (crop == null) { + ChatUtils.userError("No crop type entered.") + return + } + + val enteredCrop = CropType.getByName(crop) ?: run { + ChatUtils.userError("Invalid crop type entered.") + return + } + + val targetLevel = target?.formatIntOrUserError() + if (targetLevel == null) { + ChatUtils.userError("$target is not a valid number.") + return + } + val counter = enteredCrop.getCounter() + val level = GardenCropMilestones.getTierForCropCount(counter, enteredCrop) + if (targetLevel <= level && targetLevel != 0) { + ChatUtils.userError("Custom goal milestone ($targetLevel) must be greater than your current milestone ($level).") + return + } + storage[enteredCrop] = targetLevel + ChatUtils.chat("Custom goal milestone for §b${enteredCrop.cropName} §eset to §b$targetLevel.") + } + fun onComplete(strings: Array): List { return if (strings.size <= 1) { CommandBase.getListOfStringsMatchingLastWord( @@ -62,8 +92,6 @@ object FarmingMilestoneCommand { } else listOf() } - private fun getValidNumber(entry: String?) = entry?.toIntOrNull()?.coerceIn(0, 46) - private fun Long.formatOutput(needsTime: Boolean, crop: CropType): String { if (!needsTime) return "${this.addSeparators()} §a${crop.cropName}" val speed = crop.getSpeed() ?: -1 diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenLevelDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenLevelDisplay.kt index 1196c82e1..e31b5fc3e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenLevelDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenLevelDisplay.kt @@ -92,6 +92,7 @@ class GardenLevelDisplay { val newLevel = GardenAPI.getGardenLevel() if (newLevel != oldLevel + 1 || newLevel <= 15) return LorenzUtils.runDelayed(50.milliseconds) { + // TODO utils function that is shared with Crop Milestone Display ChatUtils.clickableChat( " \n§b§lGARDEN LEVEL UP §8$oldLevel ➜ §b$newLevel\n" + " §8+§aRespect from Elite Farmers and SkyHanni members :)\n ", diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt index c5547fc9b..b1c2a3b82 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt @@ -33,12 +33,13 @@ class GardenBestCropTime { } fun updateTimeTillNextCrop() { + val useOverflow = config.overflow.bestCropTime for (crop in CropType.entries) { val speed = crop.getSpeed() ?: continue - if (crop.isMaxed()) continue + if (crop.isMaxed(useOverflow)) continue val counter = crop.getCounter() - val currentTier = GardenCropMilestones.getTierForCropCount(counter, crop) + val currentTier = GardenCropMilestones.getTierForCropCount(counter, crop, allowOverflow = true) val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier, crop) val nextTier = if (config.bestShowMaxedNeeded.get()) 46 else currentTier + 1 @@ -62,11 +63,13 @@ class GardenBestCropTime { } val gardenExp = config.next.bestType == NextConfig.BestTypeEntry.GARDEN_EXP + val useOverflow = config.overflow.bestCropTime val sorted = if (gardenExp) { val helpMap = mutableMapOf() for ((crop, time) in timeTillNextCrop) { - if (crop.isMaxed()) continue - val currentTier = GardenCropMilestones.getTierForCropCount(crop.getCounter(), crop) + if (crop.isMaxed(useOverflow)) continue + val currentTier = + GardenCropMilestones.getTierForCropCount(crop.getCounter(), crop, allowOverflow = true) val gardenExpForTier = getGardenExpForTier(currentTier + 1) val fakeTime = time / gardenExpForTier helpMap[crop] = fakeTime @@ -98,7 +101,7 @@ class GardenBestCropTime { var number = 0 for (crop in sorted.keys) { - if (crop.isMaxed()) continue + if (crop.isMaxed(useOverflow)) continue val millis = timeTillNextCrop[crop]!! // TODO, change functionality to use enum rather than ordinals val biggestUnit = TimeUnit.entries[config.highestTimeFormat.get().ordinal] @@ -115,7 +118,7 @@ class GardenBestCropTime { val color = if (isCurrent) "§e" else "§7" val contestFormat = if (GardenNextJacobContest.isNextCrop(crop)) "§n" else "" - val currentTier = GardenCropMilestones.getTierForCropCount(crop.getCounter(), crop) + val currentTier = GardenCropMilestones.getTierForCropCount(crop.getCounter(), crop, allowOverflow = true) val nextTier = if (config.bestShowMaxedNeeded.get()) 46 else currentTier + 1 val cropName = if (!config.next.bestCompact) crop.cropName + " " else "" diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt index 43b3f8ab7..9e10a8941 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt @@ -8,6 +8,7 @@ import at.hannibal2.skyhanni.data.GardenCropMilestones import at.hannibal2.skyhanni.data.GardenCropMilestones.getCounter import at.hannibal2.skyhanni.data.GardenCropMilestones.isMaxed import at.hannibal2.skyhanni.data.GardenCropMilestones.setCounter +import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.events.ConfigLoadEvent import at.hannibal2.skyhanni.events.CropMilestoneUpdateEvent import at.hannibal2.skyhanni.events.GuiRenderEvent @@ -41,11 +42,19 @@ object GardenCropMilestoneDisplay { private var mushroomCowPerkDisplay = emptyList>() private val cultivatingData = mutableMapOf() private val config get() = GardenAPI.config.cropMilestones + private val overflowConfig get() = config.overflow + private val storage get() = ProfileStorageData.profileSpecific?.garden?.customGoalMilestone private val bestCropTime = GardenBestCropTime() private var lastPlaySoundTime = 0L private var needsInventory = false + private var lastWarnedLevel = -1 + private var previousNext = 0 + + private var lastMushWarnedLevel = -1 + private var previousMushNext = 0 + @SubscribeEvent fun onConfigLoad(event: ConfigLoadEvent) { ConditionalUtils.onToggle( @@ -140,29 +149,36 @@ object GardenCropMilestoneDisplay { val lineMap = HashMap>() lineMap[0] = Collections.singletonList("§6Crop Milestones") - val currentTier = GardenCropMilestones.getTierForCropCount(counter, crop) - val nextTier = if (config.bestShowMaxedNeeded.get()) 46 else currentTier + 1 + val customTargetLevel = storage?.get(crop) ?: 0 + val overflowDisplay = overflowConfig.cropMilestoneDisplay + val allowOverflow = overflowDisplay || (customTargetLevel != 0) + val currentTier = GardenCropMilestones.getTierForCropCount(counter, crop, allowOverflow) + var nextTier = if (config.bestShowMaxedNeeded.get() && currentTier <= 46) 46 else currentTier + 1 + val nextRealTier = nextTier + val useCustomGoal = customTargetLevel != 0 && customTargetLevel > currentTier + nextTier = if (useCustomGoal) customTargetLevel else nextTier val list = mutableListOf() list.addCropIcon(crop) - if (crop.isMaxed()) { + if (crop.isMaxed(overflowDisplay)) { list.add("§7" + crop.cropName + " §eMAXED") } else { list.add("§7" + crop.cropName + " §8$currentTier➜§3$nextTier") } lineMap[1] = list - val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier, crop) - val (have, need) = if (config.bestShowMaxedNeeded.get()) { + val allowOverflowOrCustom = overflowDisplay || useCustomGoal + val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier, crop, allowOverflowOrCustom) + val (have, need) = if (config.bestShowMaxedNeeded.get() && !overflowDisplay) { Pair(counter, cropsForNextTier) } else { - val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier, crop) - val have = counter - cropsForCurrentTier - val need = cropsForNextTier - cropsForCurrentTier + val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier, crop, allowOverflowOrCustom) + val have = if (useCustomGoal) counter else counter - cropsForCurrentTier + val need = if (useCustomGoal) cropsForNextTier else cropsForNextTier - cropsForCurrentTier Pair(have, need) } - lineMap[2] = if (crop.isMaxed()) { + lineMap[2] = if (crop.isMaxed(overflowDisplay)) { val haveFormat = counter.addSeparators() Collections.singletonList("§7Counter: §e$haveFormat") } else { @@ -177,7 +193,7 @@ object GardenCropMilestoneDisplay { if (farmingFortuneSpeed > 0) { crop.setSpeed(farmingFortuneSpeed) - if (!crop.isMaxed()) { + if (!crop.isMaxed(overflowDisplay)) { val missing = need - have val missingTimeSeconds = missing / farmingFortuneSpeed val millis = missingTimeSeconds * 1000 @@ -186,6 +202,7 @@ object GardenCropMilestoneDisplay { val biggestUnit = TimeUnit.entries[config.highestTimeFormat.get().ordinal] val duration = TimeUtils.formatDuration(millis, biggestUnit) tryWarn(millis, "§b${crop.cropName} $nextTier in $duration") + val speedText = "§7In §b$duration" lineMap[3] = Collections.singletonList(speedText) GardenAPI.itemInHand?.let { @@ -202,16 +219,26 @@ object GardenCropMilestoneDisplay { } val percentageFormat = LorenzUtils.formatPercentage(have.toDouble() / need.toDouble()) - lineMap[6] = if (crop.isMaxed()) { + lineMap[6] = if (crop.isMaxed(overflowDisplay)) { Collections.singletonList("§7Percentage: §e100%") } else { Collections.singletonList("§7Percentage: §e$percentageFormat") } + + if (overflowConfig.chat) { + if (currentTier >= 46 && currentTier == previousNext && nextRealTier == currentTier + 1 && lastWarnedLevel != currentTier) { + GardenCropMilestones.onOverflowLevelUp(crop, currentTier - 1, nextRealTier - 1) + lastWarnedLevel = currentTier + } + } + if (GardenAPI.mushroomCowPet && crop != CropType.MUSHROOM) { addMushroomCowData() } + previousNext = nextRealTier + return formatDisplay(lineMap) } @@ -247,7 +274,8 @@ object GardenCropMilestoneDisplay { private fun addMushroomCowData() { val mushroom = CropType.MUSHROOM - if (mushroom.isMaxed()) { + val allowOverflow = overflowConfig.cropMilestoneDisplay + if (mushroom.isMaxed(allowOverflow)) { mushroomCowPerkDisplay = listOf( listOf("§6Mooshroom Cow Perk"), listOf("§eMushroom crop is maxed!"), @@ -258,11 +286,11 @@ object GardenCropMilestoneDisplay { val lineMap = HashMap>() val counter = mushroom.getCounter() - val currentTier = GardenCropMilestones.getTierForCropCount(counter, mushroom) + val currentTier = GardenCropMilestones.getTierForCropCount(counter, mushroom, allowOverflow) val nextTier = currentTier + 1 - val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier, mushroom) - val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier, mushroom) + val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier, mushroom, allowOverflow) + val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier, mushroom, allowOverflow) val have = counter - cropsForCurrentTier val need = cropsForNextTier - cropsForCurrentTier @@ -296,6 +324,11 @@ object GardenCropMilestoneDisplay { val percentageFormat = LorenzUtils.formatPercentage(have.toDouble() / need.toDouble()) lineMap[4] = Collections.singletonList("§7Percentage: §e$percentageFormat") + if (currentTier >= 46 && currentTier == previousMushNext && nextTier == currentTier + 1 && lastMushWarnedLevel != currentTier) { + GardenCropMilestones.onOverflowLevelUp(mushroom, currentTier - 1, nextTier - 1) + lastMushWarnedLevel = currentTier + } + val newList = mutableListOf>() for (index in config.mushroomPetPerk.text) { // TODO, change functionality to use enum rather than ordinals @@ -303,6 +336,8 @@ object GardenCropMilestoneDisplay { newList.add(it) } } + + previousMushNext = nextTier mushroomCowPerkDisplay = newList } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt index 414b18462..eb73cf85c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt @@ -29,7 +29,8 @@ class GardenCropMilestoneInventory { val tiers = mutableListOf() for (cropType in CropType.entries) { val counter = cropType.getCounter() - val tier = GardenCropMilestones.getTierForCropCount(counter, cropType) + val allowOverflow = config.cropMilestones.overflow.inventoryStackSize + val tier = GardenCropMilestones.getTierForCropCount(counter, cropType, allowOverflow) tiers.add(tier.toDouble()) } average = (tiers.sum() / CropType.entries.size).round(2) diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt index 86495cb24..ffd66364b 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt @@ -33,7 +33,8 @@ class GardenInventoryNumbers { val crop = GardenCropMilestones.getCropTypeByLore(event.stack) ?: return val counter = crop.getCounter() - val currentTier = GardenCropMilestones.getTierForCropCount(counter, crop) + val allowOverflow = GardenAPI.config.cropMilestones.overflow.inventoryStackSize + val currentTier = GardenCropMilestones.getTierForCropCount(counter, crop, allowOverflow) event.stackTip = "" + currentTier } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryTooltipOverflow.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryTooltipOverflow.kt new file mode 100644 index 000000000..b4f76c9f2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryTooltipOverflow.kt @@ -0,0 +1,93 @@ +package at.hannibal2.skyhanni.features.garden.inventory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.GardenCropMilestones +import at.hannibal2.skyhanni.data.GardenCropMilestones.getCounter +import at.hannibal2.skyhanni.events.LorenzToolTipEvent +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.cleanName +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.toRoman +import at.hannibal2.skyhanni.utils.StringUtils +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +// TODO: Merge common code with skill overflow +class GardenInventoryTooltipOverflow { + + private val config get() = SkyHanniMod.feature.garden.cropMilestones.overflow + + @SubscribeEvent + fun onTooltip(event: LorenzToolTipEvent) { + if (!isEnabled()) return + + val inventoryName = InventoryUtils.openInventoryName() + if (inventoryName != "Crop Milestones") return + + val stack = event.itemStack + if (!stack.getLore().any { it.contains("Max tier reached!") }) return + + val split = stack.cleanName().split(" ") + val crop = getCrop(split) + val counter = crop.getCounter() + + val currentTier = GardenCropMilestones.getTierForCropCount(counter, crop, allowOverflow = true) + val (have, need) = getHaveNeed(currentTier, crop, counter) + val (level, nextLevel) = getLevels(split, currentTier) + + var next = false + val iterator = event.toolTip.listIterator() + val percentage = have.toDouble() / need.toDouble() + for (line in iterator) { + val maxTierReached = "§7§8Max tier reached!" + if (line.contains(maxTierReached)) { + iterator.set("§7Progress to tier $nextLevel: §e${LorenzUtils.formatPercentage(percentage)}") + event.itemStack.name = "§a${crop.cropName} $level" + next = true + continue + } + if (next) { + val bar = " " + if (line.contains(bar)) { + val progressBar = StringUtils.progressBar(percentage) + iterator.set("$progressBar §e${have.addSeparators()}§6/§e${need.addSeparators()}") + } + } + } + } + + private fun getLevels( + split: List, + currentTier: Int, + ): Pair { + val nextTier = currentTier + 1 + val useRoman = split.last().toIntOrNull() == null + val level = if (useRoman) currentTier.toRoman() else "" + currentTier + val nextLevel = if (useRoman) nextTier.toRoman() else "" + nextTier + return Pair(level, nextLevel) + } + + private fun getHaveNeed( + currentTier: Int, + crop: CropType, + counter: Long, + ): Pair { + val nextTier = currentTier + 1 + val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier, crop, allowOverflow = true) + val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier, crop, allowOverflow = true) + val have = counter - cropsForCurrentTier + val need = cropsForNextTier - cropsForCurrentTier + return Pair(have, need) + } + + private fun getCrop(split: List): CropType { + val cropName = split.dropLast(1).joinToString(" ") + return CropType.getByName(cropName.removeColor()) + } + + fun isEnabled() = LorenzUtils.inSkyBlock && config.inventoryTooltip +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index 94e4d027b..ed89624e4 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -12,6 +12,7 @@ import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.features.dungeon.DungeonAPI +import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.features.garden.GardenAPI.getCropType import at.hannibal2.skyhanni.features.misc.compacttablist.AdvancedPlayerList import at.hannibal2.skyhanni.features.rift.RiftAPI @@ -64,15 +65,20 @@ fun getPetDisplay(): String = PetAPI.currentPet?.let { private fun getCropMilestoneDisplay(): String { val crop = InventoryUtils.getItemInHand()?.getCropType() val cropCounter = crop?.getCounter() - val tier = cropCounter?.let { getTierForCropCount(it, crop) } - + val allowOverflow = GardenAPI.config.cropMilestones.overflow.discordRPC + val tier = cropCounter?.let { getTierForCropCount(it, crop, allowOverflow) } val progress = tier?.let { - LorenzUtils.formatPercentage(crop.progressToNextLevel()) + LorenzUtils.formatPercentage(crop.progressToNextLevel(allowOverflow)) } ?: 100 // percentage to next milestone - return if (tier != null) { - "${crop.cropName}: ${if (!crop.isMaxed()) "Milestone $tier ($progress)" else "MAXED (${cropCounter.addSeparators()} crops)"}" - } else AutoStatus.CROP_MILESTONES.placeholderText + if (tier == null) return AutoStatus.CROP_MILESTONES.placeholderText + + val text = if (crop.isMaxed(allowOverflow)) { + "MAXED (${cropCounter.addSeparators()} crops)" + } else { + "Milestone $tier ($progress)" + } + return "${crop.cropName}: $text" } enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/skillprogress/SkillTooltip.kt b/src/main/java/at/hannibal2/skyhanni/features/skillprogress/SkillTooltip.kt index 75c69f491..691ed4498 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/skillprogress/SkillTooltip.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/skillprogress/SkillTooltip.kt @@ -12,6 +12,7 @@ import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.roundToPrecision import at.hannibal2.skyhanni.utils.NumberUtil.toRoman import at.hannibal2.skyhanni.utils.StringUtils +import at.hannibal2.skyhanni.utils.StringUtils.isRoman import net.minecraftforge.fml.common.eventhandler.SubscribeEvent class SkillTooltip { @@ -29,7 +30,7 @@ class SkillTooltip { val split = stack.cleanName().split(" ") val skillName = split.first() val skill = SkillType.getByNameOrNull(skillName) ?: return - val useRoman = split.last().toIntOrNull() == null + val useRoman = split.last().isRoman() val skillInfo = SkillAPI.storage?.get(skill) ?: return val showCustomGoal = skillInfo.customGoalLevel != 0 && customGoalConfig.enableInSkillMenuTooltip var next = false diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt index 63c2e4c67..cb5099ebe 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt @@ -129,6 +129,7 @@ object LorenzUtils { val EntityLivingBase.baseMaxHealth: Int get() = this.getEntityAttribute(SharedMonsterAttributes.maxHealth).baseValue.toInt() + // TODO create extenstion function fun formatPercentage(percentage: Double): String = formatPercentage(percentage, "0.00") fun formatPercentage(percentage: Double, format: String?): String = -- cgit