aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuna <luna@alexia.lol>2024-05-03 14:07:46 +0200
committerGitHub <noreply@github.com>2024-05-03 14:07:46 +0200
commit37a9fd7df3695fcc0fb4dd5427a91b73bdadefbb (patch)
treed98eea116bde6df39468be209de81dd5953b1767 /src
parent23a5bc7eaf0e6ddc189b54d88d49d86c87174440 (diff)
downloadskyhanni-37a9fd7df3695fcc0fb4dd5427a91b73bdadefbb.tar.gz
skyhanni-37a9fd7df3695fcc0fb4dd5427a91b73bdadefbb.tar.bz2
skyhanni-37a9fd7df3695fcc0fb4dd5427a91b73bdadefbb.zip
Feature: Add overflow crop milestones (#997)
Co-authored-by: HiZe <superhize@hotmail.com> Co-authored-by: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt9
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesConfig.java5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/garden/cropmilestones/CropMilestonesOverflowConfig.java38
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestones.kt99
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/GardenCropMilestonesCommunityFix.kt16
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/CropType.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/FarmingMilestoneCommand.kt50
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/GardenLevelDisplay.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt15
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt65
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryTooltipOverflow.kt93
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt18
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/skillprogress/SkillTooltip.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt1
18 files changed, 359 insertions, 67 deletions
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
@@ -292,6 +293,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",
{ SkillAPI.onCommand(it) },
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
@@ -37,6 +37,11 @@ public class CropMilestonesConfig {
public boolean progress = true;
@Expose
+ @ConfigOption(name = "Overflow", desc = "")
+ @Accordion
+ public CropMilestonesOverflowConfig overflow = new CropMilestonesOverflowConfig();
+
+ @Expose
@ConfigOption(
name = "Warn When Close",
desc = "Warn with title and sound when the next crop milestone upgrade happens in 5 seconds. " +
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
@@ -362,6 +362,9 @@ public class ProfileSpecificStorage {
public Map<String, LorenzVec> npcVisitorLocations = new HashMap<>();
@Expose
+ public Map<CropType, Integer> customGoalMilestone = new HashMap<>();
+
+ @Expose
public PestProfitTracker.Data pestProfitTracker = new PestProfitTracker.Data();
@Expose
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(?<name>.*)"
)
+ 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<CropType, List<Int>> = emptyMap()
val cropCounter: MutableMap<CropType, Long>? 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<String>): List<String> {
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<CropType, Long>()
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<List<Any>>()
private val cultivatingData = mutableMapOf<CropType, Long>()
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<Int, List<Any>>()
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<Any>()
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<Int, List<Any>>()
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<List<Any>>()
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<Double>()
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<String>,
+ currentTier: Int,
+ ): Pair<String, String> {
+ 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<Long, Long> {
+ 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<String>): 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 =