aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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/Storage.java12
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/MiscConfig.java71
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/powdertracker/PowderChestReward.kt64
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/powdertracker/PowderTracker.kt350
5 files changed, 499 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index 7628a2bfb..5fbbb8e1a 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -58,6 +58,7 @@ import at.hannibal2.skyhanni.features.misc.ghostcounter.GhostCounter
import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValue
import at.hannibal2.skyhanni.features.misc.items.EstimatedWardrobePrice
import at.hannibal2.skyhanni.features.misc.massconfiguration.DefaultConfigFeatures
+import at.hannibal2.skyhanni.features.misc.powdertracker.PowderTracker
import at.hannibal2.skyhanni.features.misc.tabcomplete.PlayerTabComplete
import at.hannibal2.skyhanni.features.misc.tabcomplete.WarpTabComplete
import at.hannibal2.skyhanni.features.misc.teleportpad.TeleportPadCompactName
@@ -389,6 +390,7 @@ class SkyHanniMod {
loadModule(GardenPlotBorders())
loadModule(CosmeticFollowingLine())
loadModule(SuperpairsClicksAlert())
+ loadModule(PowderTracker())
init()
diff --git a/src/main/java/at/hannibal2/skyhanni/config/Storage.java b/src/main/java/at/hannibal2/skyhanni/config/Storage.java
index 2b9755926..9ec45a70c 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/Storage.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/Storage.java
@@ -10,6 +10,7 @@ import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward;
import at.hannibal2.skyhanni.features.misc.EnderNode;
import at.hannibal2.skyhanni.features.misc.FrozenTreasure;
import at.hannibal2.skyhanni.features.misc.ghostcounter.GhostData;
+import at.hannibal2.skyhanni.features.misc.powdertracker.PowderChestReward;
import at.hannibal2.skyhanni.features.rift.area.westvillage.KloonTerminal;
import at.hannibal2.skyhanni.utils.LorenzVec;
import at.hannibal2.skyhanni.utils.NEUInternalName;
@@ -273,6 +274,17 @@ public class Storage {
}
@Expose
+ public Map<Integer, PowderTracker> powderTracker = new HashMap<>();
+
+ public static class PowderTracker {
+ @Expose
+ public int totalChestPicked = 0;
+
+ @Expose
+ public Map<PowderChestReward, Long> rewards = new HashMap<>();
+ }
+
+ @Expose
public FrozenTreasureTracker frozenTreasureTracker = new FrozenTreasureTracker();
public static class FrozenTreasureTracker {
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/MiscConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/MiscConfig.java
index 6a8bc4576..84a5977a8 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/MiscConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/MiscConfig.java
@@ -808,6 +808,77 @@ public class MiscConfig {
}
@Expose
+ @ConfigOption(name = "Powder Tracker", desc = "")
+ @Accordion
+ public PowderTrackerConfig powderTrackerConfig = new PowderTrackerConfig();
+
+ public static class PowderTrackerConfig {
+
+ @Expose
+ @ConfigOption(name = "Enabled", desc = "Enable the Powder Tracker overlay.")
+ @ConfigEditorBoolean
+ public boolean enabled = false;
+
+ @Expose
+ @ConfigOption(name = "Only when Grinding", desc = "Only show the overlay when powder grinding.")
+ @ConfigEditorBoolean
+ public boolean onlyWhenPowderGrinding = false;
+
+ @Expose
+ @ConfigOption(name = "Great Explorer", desc = "Enable this if your Great Explorer perk is maxed.")
+ @ConfigEditorBoolean
+ public boolean greatExplorerMaxed = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Text Format",
+ desc = "Drag text to change the appearance of the overlay."
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "§b§lPowder Tracker",
+ "§d852 Total chests Picked §7(950/h)",
+ "§bx2 Powder: §aActive!",
+ "§b250,420 §aMithril Powder §7(350,000/h)",
+ "§b250,420 §dGemstone Powder §7(350,000/h)",
+ "",
+ "§50§7-§90§7-§a0§f-0 §cRuby Gemstone",
+ "§50§7-§90§7-§a0§f-0 §bSapphire Gemstone",
+ "§50§7-§90§7-§a0§f-0 §6Amber Gemstone",
+ "§50§7-§90§7-§a0§f-0 §5Amethyst Gemstone",
+ "§50§7-§90§7-§a0§f-0 §aJade Gemstone",
+ "§50§7-§90§7-§a0§f-0 §eTopaz Gemstone",
+
+ "§b14 §9FTX 3070",
+ "§b14 §9Electron Transmitter",
+ "§b14 §9Robotron Reflector",
+ "§b14 §9Superlite Motor",
+ "§b14 §9Control Switch",
+ "§b14 §9Synthetic Heart",
+ "§b14 §9Total Robot Parts",
+
+ "§90§7-§a0§7-§c0§f-§e0§f-§30 §fGoblin Egg",
+
+ "§b12 §aWishing Compass",
+
+ "§b320 §aSludge Juice",
+ "§b2 §9Ascension Rope",
+ "§b6 §5Treasurite",
+ "§b4 §6Jungle Heart",
+ "§b1 §5Pickonimbus 2000",
+ "§b14 §aYoggie",
+ "§b9 §fPrehistoric Egg",
+ "§b25 §aOil Barrel"
+ }
+ )
+ public Property<List<Integer>> textFormat = Property.of(new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)));
+
+ @Expose
+ public Position position = new Position(-274, 0, false, true);
+
+ }
+
+ @Expose
@ConfigOption(name = "Cosmetic", desc = "")
@Accordion
public CosmeticConfig cosmeticConfig = new CosmeticConfig();
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/powdertracker/PowderChestReward.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/powdertracker/PowderChestReward.kt
new file mode 100644
index 000000000..8a6fce7d5
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/powdertracker/PowderChestReward.kt
@@ -0,0 +1,64 @@
+package at.hannibal2.skyhanni.features.misc.powdertracker
+
+import java.util.regex.Pattern
+
+enum class PowderChestReward(val displayName: String, val pattern: Pattern) {
+
+
+ MITHRIL_POWDER("§aMithril Powder", "§aYou received §r§b[+](?<amount>.*) §r§aMithril Powder.".toPattern()),
+ GEMSTONE_POWDER("§dGemstone Powder", "§aYou received §r§b[+](?<amount>.*) §r§aGemstone Powder.".toPattern()),
+
+ ROUGH_RUBY_GEMSTONE("§fRough Ruby Gemstone", "§aYou received §r§f(?<amount>.*) §r§f❤ §r§fRough Ruby Gemstone§r§a.".toPattern()),
+ FLAWED_RUBY_GEMSTONE("§aFlawed Sapphire Gemstone", "§aYou received §r§f(?<amount>.*) §r§a❤ §r§aFlawed RubyGemstone§r§a.".toPattern()),
+ FINE_RUBY_GEMSTONE("§9Fine Ruby Gemstone", "§aYou received §r§f(?<amount>.*) §r§9❤ §r§9Fine Ruby Gemstone§r§a.".toPattern()),
+ FLAWLESS_RUBY_GEMSTONE("§5Flawless Ruby Gemstone", "§aYou received §r§f(?<amount>.*) §r§9❤ §r§5Flawless Ruby Gemstone§r§a.".toPattern()),
+
+ ROUGH_SAPPHIRE_GEMSTONE("§fRough Sapphire Gemstone", "§aYou received §r§f(?<amount>.*) §r§f✎ §r§fRough Sapphire Gemstone§r§a.".toPattern()),
+ FLAWED_SAPPHIRE_GEMSTONE("§aFlawed Sapphire Gemstone", "§aYou received §r§f(?<amount>.*) §r§a✎ §r§aFlawed Sapphire Gemstone§r§a.".toPattern()),
+ FINE_SAPPHIRE_GEMSTONE("§9Fine Sapphire Gemstone", "§aYou received §r§f(?<amount>.*) §r§9✎ §r§9Fine Sapphire Gemstone§r§a.".toPattern()),
+ FLAWLESS_SAPPHIRE_GEMSTONE("§5Flawless Sapphire Gemstone", "§aYou received §r§f(?<amount>.*) §r§9✎ §r§5Flawless Sapphire Gemstone§r§a.".toPattern()),
+
+ ROUGH_AMBER_GEMSTONE("§fRough Amber Gemstone", "§aYou received §r§f(?<amount>.*) §r§f⸕ §r§fRough Amber Gemstone§r§a.".toPattern()),
+ FLAWED_AMBER_GEMSTONE("§aFlawed Amber Gemstone", "§aYou received §r§f(?<amount>.*) §r§a⸕ §r§aFlawed Amber Gemstone§r§a.".toPattern()),
+ FINE_AMBER_GEMSTONE("§9Fine Amber Gemstone", "§aYou received §r§f(?<amount>.*) §r§9⸕ §r§9Fine Amber Gemstone§r§a.".toPattern()),
+ FLAWLESS_AMBER_GEMSTONE("§5Flawless Amber Gemstone", "§aYou received §r§f(?<amount>.*) §r§9⸕ §r§5Flawless Amber Gemstone§r§a.".toPattern()),
+
+ ROUGH_AMETHYST_GEMSTONE("§fRough Amethyst Gemstone", "§aYou received §r§f(?<amount>.*) §r§f❈ §r§fRough Amethyst Gemstone§r§a.".toPattern()),
+ FLAWED_AMETHYST_GEMSTONE("§aFlawed Amethyst Gemstone", "§aYou received §r§f(?<amount>.*) §r§a❈ §r§aFlawed Amethyst Gemstone§r§a.".toPattern()),
+ FINE_AMETHYST_GEMSTONE("§9Fine Amethyst Gemstone", "§aYou received §r§f(?<amount>.*) §r§9❈ §r§9Fine Amethyst Gemstone§r§a.".toPattern()),
+ FLAWLESS_AMETHYST_GEMSTONE("§5Flawless Amethyst Gemstone", "§aYou received §r§f(?<amount>.*) §r§9❈ §r§5Flawless Amethyst Gemstone§r§a.".toPattern()),
+
+ ROUGH_JADE_GEMSTONE("§fRough Jade Gemstone", "§aYou received §r§f(?<amount>.*) §r§f☘ §r§fRough Jade Gemstone§r§a.".toPattern()),
+ FLAWED_JADE_GEMSTONE("§aFlawed Jade Gemstone", "§aYou received §r§f(?<amount>.*) §r§a☘ §r§aFlawed Jade Gemstone§r§a.".toPattern()),
+ FINE_JADE_GEMSTONE("§9Fine Jade Gemstone", "§aYou received §r§f(?<amount>.*) §r§9☘ §r§9Fine Jade Gemstone§r§a.".toPattern()),
+ FLAWLESS_JADE_GEMSTONE("§5Flawless Jade Gemstone", "§aYou received §r§f(?<amount>.*) §r§9☘ §r§5Flawless Jade Gemstone§r§a.".toPattern()),
+
+ ROUGH_TOPAZ_GEMSTONE("§fRough Topaz Gemstone", "§aYou received §r§f(?<amount>.*) §r§f✧ §r§fRough Topaz Gemstone§r§a.".toPattern()),
+ FLAWED_TOPAZ_GEMSTONE("§aFlawed Topaz Gemstone", "§aYou received §r§f(?<amount>.*) §r§a✧ §r§aFlawed Topaz Gemstone§r§a.".toPattern()),
+ FINE_TOPAZ_GEMSTONE("§9Fine Topaz Gemstone", "§aYou received §r§f(?<amount>.*) §r§9✧ §r§9Fine Topaz Gemstone§r§a.".toPattern()),
+ FLAWLESS_TOPAZ_GEMSTONE("§5Flawless Topaz Gemstone", "§aYou received §r§f(?<amount>.*) §r§9✧ §r§5Flawless Topaz Gemstone§r§a.".toPattern()),
+
+ FTX_3070("§9FTX 3070", "§aYou received §r§f(?<amount>.*) §r§9FTX 3070§r§a.".toPattern()),
+ ELECTRON_TRANSIMTTER("§9Electron Transmitter", "§aYou received §r§f(?<amount>.*) §r§9Electron Transmitter§r§a.".toPattern()),
+ ROBOTRON_REFLECTOR("§9Robotron Reflector", "§aYou received §r§f(?<amount>.*) §r§9Robotron Reflector§r§a.".toPattern()),
+ SUPERLITE_MOTOR("§9Superlite Motor", "§aYou received §r§f(?<amount>.*) §r§9Superlite Motor§r§a.".toPattern()),
+ CONTROL_SWITCH("§9Control Switch", "§aYou received §r§f(?<amount>.*) §r§9Control Switch§r§a.".toPattern()),
+ SYNTHETIC_HEART("§9Synthetic Heart", "§aYou received §r§f(?<amount>.*) §r§9Synthetic Heart§r§a.".toPattern()),
+
+ GOBLIN_EGG("§9Goblin Egg", "§aYou received §r§f(?<amount>.*) §r§9Goblin Egg§r§a.".toPattern()),
+ GREEN_GOBLIN_EGG("§aGreen Goblin Egg", "§aYou received §r§f(?<amount>.*) §r§a§r§aGreen Goblin Egg§r§a.".toPattern()),
+ RED_GOBLIN_EGG("§cRed Goblin Egg", "§aYou received §r§f(?<amount>.*) §r§9§r§cRed Goblin Egg§r§a.".toPattern()),
+ YELLOW_GOBLIN_EGG("§eYellow Goblin Egg", "§aYou received §r§f(?<amount>.*) §r§9§r§eYellow Goblin Egg§r§a.".toPattern()),
+ BLUE_GOBLIN_EGG("§3Blue Goblin Egg", "§aYou received §r§f(?<amount>.*) §r§9§r§3Blue Goblin Egg§r§a.".toPattern()),
+
+ WISHING_COMPASS("§aWishing Compass", "§aYou received §r§f(?<amount>.*) §r§aWishing Compass§r§a.".toPattern()),
+
+ SLUDGE_JUICE("§aSludge Juice", "§aYou received §r§f(?<amount>.*) §r§aSludge Juice§r§a.".toPattern()),
+ ASCENSION_ROPE("§9Ascension Rope", "§aYou received §r§f(?<amount>.*) §r§9Ascension Rope§r§a.".toPattern()),
+ TREASURITE("§5Treasurite", "§aYou received §r§f(?<amount>.*) §r§5Treasurite§r§a.".toPattern()),
+ JUNGLE_HEART("§6Jungle Heart", "§aYou received §r§f(?<amount>.*) §r§6Jungle Heart§r§a.".toPattern()),
+ PICKONIMBUS_2000("§5Pickonimbus 2000", "§aYou received §r§f(?<amount>.*) §r§5Pickonimbus 2000§r§a.".toPattern()),
+ YOGGIE("§aYoggie", "§aYou received §r§f(?<amount>.*) §r§aYoggie§r§a.".toPattern()),
+ PREHISTORIC_EGG("§fPrehistoric Egg", "§aYou received §r§f(?<amount>.*) §r§fPrehistoric Egg§r§a.".toPattern()),
+ OIL_BARREL("§aOil Barrel", "§aYou received §r§f(?<amount>.*) §r§aOil Barrel§r§a.".toPattern()),
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/powdertracker/PowderTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/powdertracker/PowderTracker.kt
new file mode 100644
index 000000000..3dfb082ad
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/powdertracker/PowderTracker.kt
@@ -0,0 +1,350 @@
+package at.hannibal2.skyhanni.features.misc.powdertracker
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.config.Storage
+import at.hannibal2.skyhanni.data.IslandType
+import at.hannibal2.skyhanni.data.ProfileStorageData
+import at.hannibal2.skyhanni.events.*
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList
+import at.hannibal2.skyhanni.utils.LorenzUtils.addSelector
+import at.hannibal2.skyhanni.utils.LorenzUtils.afterChange
+import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
+import at.hannibal2.skyhanni.utils.NumberUtil.formatNumber
+import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems
+import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.inventory.GuiInventory
+import net.minecraft.entity.boss.BossStatus
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import kotlin.concurrent.fixedRateTimer
+
+class PowderTracker {
+
+ private val config get() = SkyHanniMod.feature.misc.powderTrackerConfig
+ private var display = emptyList<List<Any>>()
+ private val picked = "§6You have successfully picked the lock on this chest!".toPattern()
+ private val uncovered = "§aYou uncovered a treasure chest!".toPattern()
+ private val powderEvent = ".*§r§b§l2X POWDER STARTED!.*".toPattern()
+ private val powderEnded = ".*§r§b§l2X POWDER ENDED!.*".toPattern()
+ private val powderBossBar = "§e§lPASSIVE EVENT §b§l2X POWDER §e§lRUNNING FOR §a§l(?<time>.*)§r".toPattern()
+ private var lastChestPicked = 0L
+ private var isGrinding = false
+ private val gemstoneInfo = ResourceInfo(0L, 0L, 0, 0.0, mutableListOf())
+ private val mithrilInfo = ResourceInfo(0L, 0L, 0, 0.0, mutableListOf())
+ private val chestInfo = ResourceInfo(0L, 0L, 0, 0.0, mutableListOf())
+ private var doublePowder = false
+ private var powderTimer = ""
+ private var currentDisplayMode = DisplayMode.TOTAL
+ private var inventoryOpen = false
+ private var currentSessionData = mutableMapOf<Int, Storage.ProfileSpecific.PowderTracker>()
+ private val gemstones = listOf(
+ "Ruby" to "§c",
+ "Sapphire" to "§b",
+ "Amber" to "§6",
+ "Amethyst" to "§5",
+ "Jade" to "§a",
+ "Topaz" to "§e"
+ )
+
+ init {
+ fixedRateTimer(name = "skyhanni-powder-tracker", period = 1000) {
+ if (!isEnabled()) return@fixedRateTimer
+ calculateResourceHour(gemstoneInfo)
+ calculateResourceHour(mithrilInfo)
+ calculateResourceHour(chestInfo)
+ }
+ }
+
+ @SubscribeEvent
+ fun onRenderOverlay(event: GuiRenderEvent) {
+ if (!isEnabled()) return
+
+ val currentlyOpen = Minecraft.getMinecraft().currentScreen is GuiInventory
+ if (inventoryOpen != currentlyOpen) {
+ inventoryOpen = currentlyOpen
+ saveAndUpdate()
+ }
+
+ if (config.onlyWhenPowderGrinding && !isGrinding) return
+
+ config.position.renderStringsAndItems(
+ display,
+ posLabel = "Powder Chest Tracker"
+ )
+ }
+
+ @SubscribeEvent
+ fun onChat(event: LorenzChatEvent) {
+ if (!isEnabled()) return
+ val msg = event.message
+ val both = currentLog() ?: return
+
+ if (config.greatExplorerMaxed) {
+ uncovered.matchMatcher(msg) {
+ both.modify {
+ it.totalChestPicked += 1
+ }
+ isGrinding = true
+ lastChestPicked = System.currentTimeMillis()
+ }
+ }
+
+ picked.matchMatcher(msg) {
+ both.modify {
+ it.totalChestPicked += 1
+ }
+ isGrinding = true
+ lastChestPicked = System.currentTimeMillis()
+ }
+
+ powderEvent.matchMatcher(msg) { doublePowder = true }
+ powderEnded.matchMatcher(msg) { doublePowder = false }
+
+ for (reward in PowderChestReward.entries) {
+ reward.pattern.matchMatcher(msg) {
+ both.modify {
+ val count = it.rewards[reward] ?: 0
+ var amount = group("amount").formatNumber()
+ if ((reward == PowderChestReward.MITHRIL_POWDER || reward == PowderChestReward.GEMSTONE_POWDER) && doublePowder)
+ amount *= 2
+ it.rewards[reward] = count + amount
+ }
+ }
+ }
+ saveAndUpdate()
+ }
+
+ @SubscribeEvent
+ fun onTick(event: LorenzTickEvent) {
+ if (!isEnabled()) return
+ if (event.repeatSeconds(1)) {
+ doublePowder = powderBossBar.matcher(BossStatus.bossName).find()
+ powderBossBar.matchMatcher(BossStatus.bossName) {
+ powderTimer = group("time")
+ doublePowder = powderTimer != "00:00"
+
+ saveAndUpdate()
+ }
+ }
+ if (System.currentTimeMillis() - lastChestPicked > 60_000) {
+ isGrinding = false
+ }
+ }
+
+ @SubscribeEvent
+ fun onConfigLoad(event: ConfigLoadEvent) {
+ config.textFormat.afterChange { saveAndUpdate() }
+ }
+
+ @SubscribeEvent
+ fun onWorldChange(event: LorenzWorldChangeEvent) {
+ if (!isEnabled()) return
+ gemstoneInfo.perHour = 0.0
+ gemstoneInfo.stoppedChecks = 0
+ gemstoneInfo.perMin.clear()
+ mithrilInfo.perHour = 0.0
+ mithrilInfo.stoppedChecks = 0
+ mithrilInfo.perMin.clear()
+ chestInfo.perHour = 0.0
+ chestInfo.stoppedChecks = 0
+ chestInfo.perMin.clear()
+ doublePowder = false
+ saveAndUpdate()
+ }
+
+ private fun saveAndUpdate() {
+ calculateGemstone()
+ calculateMithril()
+ calculateChest()
+ display = formatDisplay(drawDisplay())
+ }
+
+ private fun formatDisplay(map: List<List<Any>>) = buildList {
+ if (map.isEmpty()) return@buildList
+ for (index in config.textFormat.get()) {
+ add(map[index])
+ }
+ }
+
+ private fun drawDisplay() = buildList<List<Any>> {
+ addAsSingletonList("§b§lPowder Tracker")
+ if (inventoryOpen) {
+ addSelector<DisplayMode>(
+ "§7Display Mode: ",
+ getName = { type -> type.displayName },
+ isCurrent = { it == currentDisplayMode },
+ onChange = {
+ currentDisplayMode = it
+ saveAndUpdate()
+ }
+ )
+ }
+ val both = currentLog() ?: return@buildList
+ val display = both.get(currentDisplayMode)
+ val rewards = display.rewards
+
+ val chestPerHour = if (chestInfo.perHour < 0) 0 else chestInfo.perHour.toInt().addSeparators()
+ addAsSingletonList("§d${display.totalChestPicked.addSeparators()} Total Chests Picked §7($chestPerHour/h)")
+ addAsSingletonList("§bDouble Powder: ${if (doublePowder) "§aActive! §7($powderTimer)" else "§cInactive!"}")
+
+ val mithril = PowderChestReward.entries[0]
+ val mithrilCount = rewards.getOrDefault(mithril, 0).addSeparators()
+ val mithrilPerHour = if (mithrilInfo.perHour < 0) 0 else mithrilInfo.perHour.toInt().addSeparators()
+ addAsSingletonList("§b$mithrilCount ${mithril.displayName} §7($mithrilPerHour/h)")
+
+ val gemstone = PowderChestReward.entries[1]
+ val gemstoneCount = rewards.getOrDefault(gemstone, 0).addSeparators()
+ val gemstonePerHour = if (gemstoneInfo.perHour < 0) 0 else gemstoneInfo.perHour.toInt().addSeparators()
+ addAsSingletonList("§b$gemstoneCount ${gemstone.displayName} §7($gemstonePerHour/h)")
+
+ addAsSingletonList("")
+
+ for ((gem, color) in gemstones) {
+ var totalGemstone = 0L
+
+ for (quality in arrayOf("ROUGH", "FLAWED", "FINE", "FLAWLESS")) {
+ val gemstoneType = PowderChestReward.valueOf("${quality}_${gem.uppercase()}_GEMSTONE")
+ val count = rewards.getOrDefault(gemstoneType, 0)
+ val multiplier = when (quality) {
+ "FLAWED" -> 80
+ "FINE" -> 6400
+ "FLAWLESS" -> 512000
+ else -> 1
+ }
+ totalGemstone += count * multiplier
+ }
+
+ val (flawless, fine, flawed, rough) = convert(totalGemstone)
+ addAsSingletonList("§5${flawless}§7-§9${fine}§7-§a${flawed}§f-${rough} $color$gem Gemstone")
+ }
+
+ var totalParts = 0L
+ for (reward in PowderChestReward.entries.subList(26, 32)) { // robots part
+ val count = rewards.getOrDefault(reward, 0)
+ totalParts += count
+ addAsSingletonList("§b${count.addSeparators()} ${reward.displayName}")
+ }
+ addAsSingletonList("§b${totalParts.addSeparators()} §9Total Robot Parts")
+
+ val goblinEgg = rewards.getOrDefault(PowderChestReward.GOBLIN_EGG, 0)
+ val greenEgg = rewards.getOrDefault(PowderChestReward.GREEN_GOBLIN_EGG, 0)
+ val redEgg = rewards.getOrDefault(PowderChestReward.RED_GOBLIN_EGG, 0)
+ val yellowEgg = rewards.getOrDefault(PowderChestReward.YELLOW_GOBLIN_EGG, 0)
+ val blueEgg = rewards.getOrDefault(PowderChestReward.BLUE_GOBLIN_EGG, 0)
+ addAsSingletonList("§9$goblinEgg§7-§a$greenEgg§7-§c$redEgg§f-§e$yellowEgg§f-§3$blueEgg §fGoblin Egg")
+
+ for (reward in PowderChestReward.entries.subList(37, 46)) {
+ val count = rewards.getOrDefault(reward, 0).addSeparators()
+ addAsSingletonList("§b$count ${reward.displayName}")
+ }
+ }
+
+ private fun calculateResourceHour(resourceInfo: ResourceInfo) {
+ val difference = resourceInfo.estimated - resourceInfo.lastEstimated
+ resourceInfo.lastEstimated = resourceInfo.estimated
+
+ if (difference == resourceInfo.estimated) {
+ return
+ }
+
+ resourceInfo.perHour = resourceInfo.perMin.average() * 3600
+ resourceInfo.perMin.add(difference)
+
+ if (difference == 0L) {
+ resourceInfo.stoppedChecks += 1
+
+ if (resourceInfo.stoppedChecks == 60) {
+ resourceInfo.stoppedChecks = 0
+ resourceInfo.perMin.clear()
+ resourceInfo.perHour = 0.0
+ }
+ return
+ }
+ resourceInfo.stoppedChecks = 0
+ }
+
+ private fun calculateGemstone() {
+ val both = currentLog() ?: return
+ val display = both.get(currentDisplayMode)
+ val rewards = display.rewards
+ gemstoneInfo.estimated = 0
+ gemstoneInfo.estimated += rewards.getOrDefault(PowderChestReward.GEMSTONE_POWDER, 0)
+ }
+
+ private fun calculateMithril() {
+ val both = currentLog() ?: return
+ val display = both.get(currentDisplayMode)
+ val rewards = display.rewards
+ mithrilInfo.estimated = 0
+ mithrilInfo.estimated += rewards.getOrDefault(PowderChestReward.MITHRIL_POWDER, 0)
+ }
+
+ private fun calculateChest() {
+ val both = currentLog() ?: return
+ val display = both.get(currentDisplayMode)
+ chestInfo.estimated = 0
+ chestInfo.estimated += display.totalChestPicked
+ }
+
+ private fun convert(roughCount: Long): Gem {
+ val flawlessRatio = 512000
+ val fineRatio = 6400
+ val flawedRatio = 80
+
+ val flawlessCount = roughCount / flawlessRatio
+ val remainingAfterFlawless = roughCount % flawlessRatio
+
+ val fineCount = remainingAfterFlawless / fineRatio
+ val remainingAfterFine = remainingAfterFlawless % fineRatio
+
+ val flawedCount = remainingAfterFine / flawedRatio
+ val remainingRoughCount = remainingAfterFine % flawedRatio
+
+ return Gem(flawlessCount, fineCount, flawedCount, remainingRoughCount)
+ }
+
+ data class Gem(val flawless: Long, val fine: Long, val flawed: Long, val rough: Long)
+ private data class ResourceInfo(
+ var estimated: Long,
+ var lastEstimated: Long,
+ var stoppedChecks: Int,
+ var perHour: Double,
+ val perMin: MutableList<Long>
+ )
+
+ enum class DisplayMode(val displayName: String) {
+ TOTAL("Total"),
+ CURRENT("This Session"),
+ ;
+ }
+
+
+ private fun currentLog(): AbstractPowderTracker? {
+ val profileSpecific = ProfileStorageData.profileSpecific ?: return null
+
+ return AbstractPowderTracker(
+ profileSpecific.powderTracker.getOrPut(0) { Storage.ProfileSpecific.PowderTracker() },
+ currentSessionData.getOrPut(0) { Storage.ProfileSpecific.PowderTracker() }
+ )
+ }
+
+ class AbstractPowderTracker(
+ private val total: Storage.ProfileSpecific.PowderTracker,
+ private val currentSession: Storage.ProfileSpecific.PowderTracker,
+ ) {
+
+ fun modify(modifyFunction: (Storage.ProfileSpecific.PowderTracker) -> Unit) {
+ modifyFunction(total)
+ modifyFunction(currentSession)
+ }
+
+ fun get(displayMode: DisplayMode) = when (displayMode) {
+ DisplayMode.TOTAL -> total
+ DisplayMode.CURRENT -> currentSession
+ }
+ }
+
+ private fun isEnabled() =
+ LorenzUtils.inSkyBlock && LorenzUtils.skyBlockIsland == IslandType.CRYSTAL_HOLLOWS && config.enabled
+} \ No newline at end of file