Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package at.hannibal2.skyhanni.config.features.minion

import at.hannibal2.skyhanni.config.FeatureToggle
import at.hannibal2.skyhanni.config.core.config.Position
import at.hannibal2.skyhanni.config.features.misc.tracker.individual.IndividualItemTrackerConfig
import com.google.gson.annotations.Expose
import io.github.notenoughupdates.moulconfig.annotations.Accordion
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean
import io.github.notenoughupdates.moulconfig.annotations.ConfigLink
import io.github.notenoughupdates.moulconfig.annotations.ConfigOption

class InfernoMinionProfitTrackerConfig {
@Expose
@ConfigOption(name = "Enabled", desc = "Track items collected from Inferno Minions.")
@ConfigEditorBoolean
@FeatureToggle
var enabled: Boolean = true

@Expose
@ConfigLink(owner = InfernoMinionProfitTrackerConfig::class, field = "enabled")
val position: Position = Position(250, 250)

@Expose
@ConfigOption(
name = "Show After Collection",
desc = "Show the tracker for a few seconds after collecting from an Inferno Minion.",
)
@ConfigEditorBoolean
var showAfterCollection: Boolean = true

@Expose
@ConfigOption(name = "Tracker Settings", desc = "")
@Accordion
val perTrackerConfig: IndividualItemTrackerConfig = IndividualItemTrackerConfig()
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,9 @@ class MinionsConfig {
@ConfigEditorBoolean
@FeatureToggle
var infernoFuelBlocker: Boolean = false

@Expose
@ConfigOption(name = "Inferno Minion Profit Tracker", desc = "")
@Accordion
val infernoMinionProfitTracker: InfernoMinionProfitTrackerConfig = InfernoMinionProfitTrackerConfig()
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import at.hannibal2.skyhanni.features.garden.tracker.PestProfitTracker
import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward
import at.hannibal2.skyhanni.features.gifting.GiftProfitTracker
import at.hannibal2.skyhanni.features.hunting.HuntingProfitTracker
import at.hannibal2.skyhanni.features.minion.InfernoMinionProfitTracker
import at.hannibal2.skyhanni.features.inventory.EquipmentApi
import at.hannibal2.skyhanni.features.inventory.chocolatefactory.stray.CFStrayTracker
import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker
Expand Down Expand Up @@ -830,6 +831,9 @@ class ProfileSpecificStorage(
}
}

@Expose
var infernoMinionProfitTracker: InfernoMinionProfitTracker.Data = InfernoMinionProfitTracker.Data()

// - misc
@Expose
var trapperData: TrapperData = TrapperData()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,18 @@ object InfernoMinionFeatures {
* REGEX-TEST: Inferno Minion II
* REGEX-TEST: Inferno Minion IX
*/
private val infernoMinionTitlePattern by RepoPattern.pattern(
val infernoMinionTitlePattern by RepoPattern.pattern(
"minion.infernominiontitle",
"Inferno Minion .*",
)
private var fuelItemIds = listOf<NeuInternalName>()
var fuelItemIds = setOf<NeuInternalName>()
private set
private var inInventory = false

@HandleEvent
fun onRepoReload(event: RepositoryReloadEvent) {
val data = event.getConstant<InfernoMinionFuelsJson>("InfernoMinionFuels")
fuelItemIds = data.minionFuels
fuelItemIds = data.minionFuels.toSet()
}

@HandleEvent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package at.hannibal2.skyhanni.features.minion

import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.api.event.HandleEvent
import at.hannibal2.skyhanni.config.commands.CommandCategory
import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent
import at.hannibal2.skyhanni.events.InventoryUpdatedEvent
import at.hannibal2.skyhanni.events.MinionCloseEvent
import at.hannibal2.skyhanni.events.MinionOpenEvent
import at.hannibal2.skyhanni.events.SackChangeEvent
import at.hannibal2.skyhanni.events.entity.ItemAddInInventoryEvent
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.InventoryDetector
import at.hannibal2.skyhanni.utils.ItemPriceUtils.getPrice
import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull
import at.hannibal2.skyhanni.utils.NeuInternalName
import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat
import at.hannibal2.skyhanni.utils.RegexUtils.matches
import at.hannibal2.skyhanni.utils.RenderDisplayHelper
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.SkyBlockUtils
import at.hannibal2.skyhanni.utils.collection.RenderableCollectionUtils.addSearchString
import at.hannibal2.skyhanni.utils.renderables.Renderable
import at.hannibal2.skyhanni.utils.renderables.Searchable
import at.hannibal2.skyhanni.utils.renderables.toSearchable
import at.hannibal2.skyhanni.utils.tracker.ItemTrackerData
import at.hannibal2.skyhanni.utils.tracker.SessionUptime
import at.hannibal2.skyhanni.utils.tracker.SkyHanniItemTracker
import com.google.gson.annotations.Expose
import net.minecraft.world.item.ItemStack
import kotlin.time.Duration.Companion.seconds

@SkyHanniModule
object InfernoMinionProfitTracker {

private val config get() = SkyHanniMod.feature.misc.minions.infernoMinionProfitTracker

private val infernoMinionInventory = InventoryDetector { name ->
InfernoMinionFeatures.infernoMinionTitlePattern.matches(name)
}

private var isInfernoMinion = false
private var lastFuelItem: NeuInternalName? = null
private var lastCollectionTime = SimpleTimeMark.farPast()
private var itemsCollected = false

private val tracker = SkyHanniItemTracker(
"Inferno Minion Profit Tracker",
{ Data() },
{ it.infernoMinionProfitTracker },
trackerConfig = { config.perTrackerConfig },
) { drawDisplay(it) }

data class Data(
@Expose var totalFuelCost: Double = 0.0,
) : ItemTrackerData<SessionUptime.Normal>(SessionUptime.Normal::class) {

override fun getDescription(timesGained: Long): List<String> {
val totalItems = items.values.sumOf { it.timesGained }
val percentage = if (totalItems > 0) timesGained.toDouble() / totalItems else 0.0
val dropRate = "%.1f%%".format(percentage * 100)
return listOf(
"§7Dropped §e${timesGained.addSeparators()} §7times.",
"§7Drop chance: §c$dropRate",
)
}

override fun getCoinName(item: TrackedItem) = ""

override fun getCoinDescription(item: TrackedItem) = listOf<String>()
}

init {
RenderDisplayHelper(
inventory = infernoMinionInventory,
outsideInventory = true,
condition = { config.enabled && SkyBlockUtils.inSkyBlock && (infernoMinionInventory.isInside() || isRecentCollection()) },
onRender = { tracker.renderDisplay(config.position) },
)
}

private fun drawDisplay(data: Data): List<Searchable> = buildList {
addSearchString("§e§lInferno Minion Profit Tracker")

var profit = tracker.drawItems(data, { true }, this)
profit = addFuelCost(data, profit)

val totalCollections = data.items.values.sumOf { it.timesGained }
add(
Renderable.hoverTips(
"§7Total collections: §e${totalCollections.addSeparators()}",
listOf("§7You've collected from Inferno Minions §e${totalCollections.addSeparators()} §7times."),
).toSearchable(),
)

val duration = data.getTotalUptime()
addAll(tracker.addTotalProfit(profit, totalCollections, "collection", duration, "Collections"))

tracker.addPriceFromButton(this)
}

private fun MutableList<Searchable>.addFuelCost(data: Data, profit: Double): Double {
val fuelCost = data.totalFuelCost
if (fuelCost <= 0) return profit
add(
Renderable.hoverTips(
"§7Fuel cost: §c-${fuelCost.shortFormat()}",
listOf(
"§7Total spent on fuel items.",
"§7This is subtracted from your profit.",
),
).toSearchable("Fuel Cost"),
)
return profit - fuelCost
}

@HandleEvent
fun onMinionOpen(event: MinionOpenEvent) {
val firstOpen = !isInfernoMinion
isInfernoMinion = InfernoMinionFeatures.infernoMinionTitlePattern.matches(event.inventoryName)
if (!isInfernoMinion) return
if (firstOpen) {
lastFuelItem = getFuelFromInventory(event.inventoryItems)
}
}

@HandleEvent
fun onInventoryUpdated(event: InventoryUpdatedEvent) {
if (!isInfernoMinion) return
if (!config.enabled) return
val newFuel = getFuelFromInventory(event.inventoryItems)
if (newFuel != null && newFuel != lastFuelItem) {
tracker.modify { it.totalFuelCost += newFuel.getPrice() }
}
lastFuelItem = newFuel
}

@HandleEvent(onlyOnSkyblock = true)
fun onItemAddInInventory(event: ItemAddInInventoryEvent) {
if (!isInfernoMinion) return
if (!config.enabled) return
tracker.addItem(event.internalName, event.amount, command = false)
itemsCollected = true
}

@HandleEvent(onlyOnSkyblock = true)
fun onSackChange(event: SackChangeEvent) {
if (!config.enabled) return
if (lastCollectionTime.passedSince() > 5.seconds) return
for (sackChange in event.sackChanges) {
if (sackChange.delta > 0) {
tracker.addItem(sackChange.internalName, sackChange.delta, command = false)
}
}
}

@HandleEvent
fun onMinionClose(event: MinionCloseEvent) {
if (!isInfernoMinion) return
if (!config.enabled) return
lastCollectionTime = SimpleTimeMark.now()
lastFuelItem = null
isInfernoMinion = false
itemsCollected = false
}

private fun getFuelFromInventory(inventoryItems: Map<Int, ItemStack>): NeuInternalName? {
val fuelStack = inventoryItems[19] ?: return null
val name = fuelStack.getInternalNameOrNull() ?: return null
return if (name in InfernoMinionFeatures.fuelItemIds) name else null
}

private fun isRecentCollection() = config.showAfterCollection && lastCollectionTime.passedSince() < 10.seconds

@HandleEvent
fun onCommandRegistration(event: CommandRegistrationEvent) {
event.registerBrigadier("shresetinfernominiontracker") {
description = "Resets the Inferno Minion Profit Tracker"
category = CommandCategory.USERS_RESET
simpleCallback { tracker.resetCommand() }
}
}
}
Loading