Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Pesthunter Shop Profit Display #3020

Open
wants to merge 10 commits into
base: beta
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package at.hannibal2.skyhanni.config.features.garden.pests;

import at.hannibal2.skyhanni.config.FeatureToggle;
import at.hannibal2.skyhanni.config.core.config.Position;
import com.google.gson.annotations.Expose;
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
import io.github.notenoughupdates.moulconfig.annotations.ConfigLink;
import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;

public class PesthunterShopConfig {

@Expose
@ConfigOption(
name = "Enable",
desc = "Enable the Pesthunter Profit display."
)
@ConfigEditorBoolean
@FeatureToggle
public boolean pesthunterProfitEnabled = false;

@Expose
@ConfigLink(owner = PesthunterShopConfig.class, field = "pesthunterProfitEnabled")
public Position pesthunterProfitPos = new Position(206, 158, false, true);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ public class PestsConfig {
@Accordion
@Expose
public StereoHarmonyConfig stereoHarmony = new StereoHarmonyConfig();

@ConfigOption(name = "Pesthunter Profit Display", desc = "")
@Accordion
@Expose
public PesthunterShopConfig pesthunterShop = new PesthunterShopConfig();
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import at.hannibal2.skyhanni.features.garden.farming.GardenCropSpeed
import at.hannibal2.skyhanni.features.garden.fortuneguide.FFGuideGUI
import at.hannibal2.skyhanni.features.garden.fortuneguide.FarmingItems
import at.hannibal2.skyhanni.features.garden.inventory.SkyMartCopperPrice
import at.hannibal2.skyhanni.features.garden.pests.PesthunterProfit
import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI
import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI
import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateShopPrice
Expand Down Expand Up @@ -198,7 +199,8 @@ object GardenAPI {
ChocolateShopPrice.inInventory ||
ChocolateFactoryAPI.inChocolateFactory ||
ChocolateFactoryAPI.chocolateFactoryPaused ||
HoppityCollectionStats.inInventory
HoppityCollectionStats.inInventory ||
PesthunterProfit.inInventory

fun resetCropSpeed() {
storage?.cropsPerSecond?.clear()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package at.hannibal2.skyhanni.features.garden.pests

import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.InventoryCloseEvent
import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent
import at.hannibal2.skyhanni.features.garden.GardenAPI
import at.hannibal2.skyhanni.features.inventory.patternGroup
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.test.command.ErrorManager
import at.hannibal2.skyhanni.utils.DisplayTableEntry
import at.hannibal2.skyhanni.utils.InventoryUtils
import at.hannibal2.skyhanni.utils.ItemPriceUtils.getPrice
import at.hannibal2.skyhanni.utils.ItemUtils
import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
import at.hannibal2.skyhanni.utils.ItemUtils.itemName
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.NEUInternalName
import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat
import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher
import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables
import at.hannibal2.skyhanni.utils.renderables.Renderable
import net.minecraft.item.ItemStack
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent

@SkyHanniModule
object PesthunterProfit {

data class PesthunterTrade(val internalName: NEUInternalName, val coinsPerPest: Double)
var bestPesthunterTrade = mutableListOf<PesthunterTrade>()

private val config get() = GardenAPI.config.pests.pesthunterShop
private var display = emptyList<Renderable>()

var inInventory = false

/**
* REGEX-TEST: §2100 Pests
*/
private val pestCostPattern by patternGroup.pattern(
"garden.pests.inventory.cost",
"§2(?<pests>\\d+) Pests"
)

@SubscribeEvent
fun onInventoryClose(event: InventoryCloseEvent) {
inInventory = false
}

@SubscribeEvent
fun onInventoryOpen(event: InventoryFullyOpenedEvent) {
if (!config.pesthunterProfitEnabled) return
if (event.inventoryName != "Pesthunter's Wares") return

inInventory = true

val table = mutableListOf<DisplayTableEntry>()
for ((slot, item) in event.inventoryItems) {
try {
readItem(slot, item, table)
} catch (e: Throwable) {
ErrorManager.logErrorWithData(
e, "Error in PesthunterProfit while reading item '${item.itemName}'",
"item" to item,
Not-a-cowfr marked this conversation as resolved.
Show resolved Hide resolved
"name" to item.itemName,
"inventory name" to InventoryUtils.openInventoryName(),
)
}
}

val newList = mutableListOf<Renderable>()
newList.add(Renderable.string("§ePesthunter Shop Profit"))
newList.add(LorenzUtils.fillTable(table, padding = 5, itemScale = 0.7))
display = newList
}

private fun readItem(slot: Int, item: ItemStack, table: MutableList<DisplayTableEntry>) {
val itemName = item.displayName
if (itemName == " " || itemName == "§cClose") return
if (itemName == "§aSell Item" || itemName == "§6Pesthunter's Wares") return

val totalCost = getFullCost(getRequiredItems(item))
if (totalCost < 0) return

val (name, amount) = ItemUtils.readItemAmount(itemName) ?: return

var internalName = NEUInternalName.fromItemNameOrNull(name.replace("[Lvl 100]", "[Lvl {LVL}]"))
if (internalName == null) {
internalName = item.getInternalName()
}

val itemPrice = internalName.getPrice() * amount
if (itemPrice < 0) return

val profit = itemPrice - totalCost
val pestsCost = getPestsCost(item)
val profitPerPest = if (pestsCost > 0) profit / pestsCost else 0.0
val color = if (profitPerPest > 0) "§6" else "§c"

val hover = listOf(
itemName.replace("[Lvl {LVL}]", "[Lvl 1]"),
"",
"§7Item price: §6${itemPrice.shortFormat()} ",
"§7Material cost: §6${totalCost.shortFormat()} ",
"§7Final profit: §6${profit.shortFormat()} ",
"§7Profit per pest: §6${profitPerPest.shortFormat()} ",
)

table.add(
DisplayTableEntry(
itemName.replace("[Lvl {LVL}]", "[Lvl 1]"), // show level 1 hedgehog instead of level 100
"$color${profitPerPest.shortFormat()}",
profitPerPest,
internalName,
hover,
highlightsOnHoverSlots = listOf(slot),
),
)

if (bestPesthunterTrade.isEmpty() || profitPerPest > (
bestPesthunterTrade.maxByOrNull {
it.coinsPerPest
}?.coinsPerPest ?: 0.0
)
) {
bestPesthunterTrade.clear()
bestPesthunterTrade.add(PesthunterTrade(internalName, profitPerPest))
}
}

private fun getRequiredItems(item: ItemStack): MutableList<String> {
val items = mutableListOf<String>()
var next = false

for (line in item.getLore()) {
when {
line == "§7Cost" -> {
next = true
}
next -> {
if (line.isBlank()) {
next = false
} else {
pestCostPattern.matchMatcher(line.replace(",", "")) { break }
Not-a-cowfr marked this conversation as resolved.
Show resolved Hide resolved
items.add(line.replace("§8 ", " §8"))
}
}
}
}

return items
}

private fun getFullCost(requiredItems: List<String>): Double {
var otherItemsPrice = 0.0
for (itemName in requiredItems) {
val pair = ItemUtils.readItemAmount(itemName)
if (pair == null) {
ErrorManager.logErrorStateWithData(
"Error in Pesthunter Profit", "Could not read item amount",
"itemName" to itemName,
)
continue
}

val (name, amount) = pair
otherItemsPrice += NEUInternalName.fromItemName(name).getPrice() * amount
}
return otherItemsPrice
}

private fun getPestsCost(item: ItemStack): Int {
val lore = item.getLore()
for (line in lore) {
val pestCost = line.replace(",", "")
pestCostPattern.matchMatcher(pestCost) {
return group("pests")?.toInt() ?: 0
}
}
return 0
Not-a-cowfr marked this conversation as resolved.
Show resolved Hide resolved
}

@SubscribeEvent
fun onBackgroundDraw(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
if (inInventory) {
config.pesthunterProfitPos.renderRenderables(
display,
extraSpace = 5,
posLabel = "Pesthunter Profit",
)
}
}

@SubscribeEvent
fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) {
event.move(3, "garden.pesthunterProfitEnabled", "garden.pests.pesthunterProfitEnabled")
event.move(3, "garden.pesthunterProfitPos", "garden.pests.pesthunterProfitPos")
}
Not-a-cowfr marked this conversation as resolved.
Show resolved Hide resolved
}
Loading