aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorObsidian <108832807+Obsidianninja11@users.noreply.github.com>2024-04-10 00:51:20 -0800
committerGitHub <noreply@github.com>2024-04-10 10:51:20 +0200
commitf541212f286940b7260df85ab419a02228daf1ea (patch)
treeaba4f1dac12cd0b1993800dc05cecda4d42277a5
parent8e4a4a156b659fcbb26dfec8ff619777771d0c59 (diff)
downloadskyhanni-f541212f286940b7260df85ab419a02228daf1ea.tar.gz
skyhanni-f541212f286940b7260df85ab419a02228daf1ea.tar.bz2
skyhanni-f541212f286940b7260df85ab419a02228daf1ea.zip
Improvement: Better Visitor Reward Warning (#1417)
* Price per copper based visitor blocking + improvements * Fixed merge conflicts + minor bug * Fixed merge conflicts + Fixed Accept offer title not rendering in tooltip * Messed something up during merge conflicts. fixed now * fixing merge conflicts * Code cleanup + more features + fixes * Code cleanup + improvements * optimized imports * Cache tooltip * Use GuiContainerEvent.SlotClickEvent * Lots of code cleanup + merge conflicts + fixes * fix * fix merge conflicts --------- Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java52
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt17
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorAPI.kt36
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt22
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorRewardWarning.kt116
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt2
7 files changed, 227 insertions, 20 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index a2a99eb20..02db25131 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -226,6 +226,7 @@ import at.hannibal2.skyhanni.features.garden.visitor.HighlightVisitorsOutsideOfG
import at.hannibal2.skyhanni.features.garden.visitor.NPCVisitorFix
import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI
import at.hannibal2.skyhanni.features.garden.visitor.VisitorListener
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorRewardWarning
import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard
import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern
import at.hannibal2.skyhanni.features.inventory.AuctionsHighlighter
@@ -469,6 +470,7 @@ class SkyHanniMod {
loadModule(GardenCropMilestonesCommunityFix)
loadModule(GardenCropUpgrades())
loadModule(VisitorListener())
+ loadModule(VisitorRewardWarning())
loadModule(OwnInventoryData())
loadModule(ToolTipData())
loadModule(HighlightVisitorsOutsideOfGarden())
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java
index 230085347..2ea448148 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/visitor/RewardWarningConfig.java
@@ -6,6 +6,7 @@ import com.google.gson.annotations.Expose;
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList;
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorKeybind;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider;
import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
import org.lwjgl.input.Keyboard;
@@ -28,15 +29,15 @@ public class RewardWarningConfig {
public boolean showOverName = true;
@Expose
- @ConfigOption(name = "Prevent Refusing", desc = "Prevent the refusal of a visitor with reward.")
+ @ConfigOption(name = "Block Refusing Reward", desc = "Prevent the refusal of a visitor with reward.")
@ConfigEditorBoolean
@FeatureToggle
public boolean preventRefusing = true;
@Expose
- @ConfigOption(name = "Bypass Key", desc = "Hold that key to bypass the Prevent Refusing feature.")
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE)
- public int bypassKey = Keyboard.KEY_NONE;
+ @ConfigOption(name = "Bypass Key", desc = "Hold this key to bypass the Prevent Refusing feature.")
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_LCONTROL)
+ public int bypassKey = Keyboard.KEY_LCONTROL;
@Expose
@@ -55,4 +56,47 @@ public class RewardWarningConfig {
VisitorReward.REPLENISH
));
+ @Expose
+ @ConfigOption(
+ name = "Coins Per Copper",
+ desc = "The price to use for the below options.\n" +
+ "Requires one of the below options to be on."
+ )
+ @ConfigEditorSlider(minValue = 1, maxValue = 50_000, minStep = 250)
+ public int coinsPerCopperPrice = 6_000;
+
+ @Expose
+ @ConfigOption(name = "Block Refusing Copper", desc = "Prevent refusing a visitor with a coins per copper lower than the set value.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean preventRefusingCopper = false;
+
+ @Expose
+ @ConfigOption(name = "Block Accepting Copper", desc = "Prevent accepting a visitor with a coins per copper higher than the set value.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean preventAcceptingCopper = false;
+
+ @Expose
+ @ConfigOption(name = "Block Refusing New Visitors", desc = "Prevents refusing a visitor you've never completed an offer with.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean preventRefusingNew = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Opacity",
+ desc = "How strong should the offer buttons be grayed out when blocked?"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 255,
+ minStep = 5
+ )
+ public int opacity = 180;
+
+ @Expose
+ @ConfigOption(name = "Outline", desc = "Adds a red/green line around the best offer button.")
+ @ConfigEditorBoolean
+ public boolean optionOutline = true;
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt
index 47785eba9..479569961 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt
@@ -21,6 +21,7 @@ import at.hannibal2.skyhanni.events.garden.visitor.VisitorRenderEvent
import at.hannibal2.skyhanni.features.garden.CropType.Companion.getByNameOrNull
import at.hannibal2.skyhanni.features.garden.GardenAPI
import at.hannibal2.skyhanni.features.garden.farming.GardenCropSpeed.getSpeed
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.blockReason
import at.hannibal2.skyhanni.features.inventory.bazaar.BazaarApi
import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper
import at.hannibal2.skyhanni.test.command.ErrorManager
@@ -128,7 +129,9 @@ object GardenVisitorFeatures {
visitor.shoppingList[internalName] = amount
}
- readToolTip(visitor, offerItem)
+ visitor.lastLore = listOf()
+ visitor.blockedLore = listOf()
+ visitor.blockReason = visitor.blockReason()
val alreadyReady = offerItem.getLore().any { it == "§eClick to give!" }
if (alreadyReady) {
@@ -297,16 +300,14 @@ object GardenVisitorFeatures {
fun onTooltip(visitor: VisitorAPI.Visitor, itemStack: ItemStack, toolTip: MutableList<String>) {
if (itemStack.name != "§aAccept Offer") return
- toolTip.clear()
-
if (visitor.lastLore.isEmpty()) {
- readToolTip(visitor, itemStack)
+ readToolTip(visitor, itemStack, toolTip)
}
-
+ toolTip.clear()
toolTip.addAll(visitor.lastLore)
}
- private fun readToolTip(visitor: VisitorAPI.Visitor, itemStack: ItemStack?) {
+ private fun readToolTip(visitor: VisitorAPI.Visitor, itemStack: ItemStack?, toolTip: MutableList<String>) {
val stack = itemStack ?: error("Accept offer item not found for visitor ${visitor.visitorName}")
var totalPrice = 0.0
var farmingTimeRequired = 0.seconds
@@ -351,7 +352,7 @@ object GardenVisitorFeatures {
}
readingShoppingList = true
- val finalList = stack.getLore().toMutableList()
+ val finalList = toolTip.map { it.removePrefix("§5§o")}.toMutableList()
var offset = 0
for ((i, formattedLine) in finalList.toMutableList().withIndex()) {
val index = i + offset
@@ -366,6 +367,7 @@ object GardenVisitorFeatures {
copperPattern.matchMatcher(formattedLine) {
val copper = group("amount").formatInt()
val pricePerCopper = NumberUtil.format((totalPrice / copper).toInt())
+ visitor.pricePerCopper = (totalPrice / copper).toInt()
val timePerCopper = (farmingTimeRequired / copper).format()
var copperLine = formattedLine
if (config.inventory.copperPrice) copperLine += " §7(§6$pricePerCopper §7per)"
@@ -378,7 +380,6 @@ object GardenVisitorFeatures {
if (formattedLine.contains("Rewards")) {
readingShoppingList = false
}
-
val (itemName, amount) = ItemUtils.readItemAmount(formattedLine) ?: continue
val internalName = NEUInternalName.fromItemNameOrNull(itemName)?.replace("◆_", "") ?: continue
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorAPI.kt
index dab1d40e7..295e3c08e 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorAPI.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorAPI.kt
@@ -22,9 +22,14 @@ object VisitorAPI {
private var visitors = mapOf<String, Visitor>()
var inInventory = false
+ var lastClickedNpc = 0
val config get() = GardenAPI.config.visitors
private val logger = LorenzLogger("garden/visitors/api")
+ const val INFO_SLOT = 13
+ const val ACCEPT_SLOT = 29
+ const val REFUSE_SLOT = 33
+
val patternGroup = RepoPattern.group("garden.visitor.api")
val visitorCountPattern by patternGroup.pattern(
"visitor.count",
@@ -124,10 +129,13 @@ object VisitorAPI {
val shoppingList: MutableMap<NEUInternalName, Int> = mutableMapOf(),
var offer: VisitorOffer? = null,
) {
-
+ var offersAccepted: Int? = null
+ var pricePerCopper: Int? = null
var lore: List<String> = emptyList()
var allRewards = listOf<NEUInternalName>()
var lastLore = listOf<String>()
+ var blockedLore = listOf<String>()
+ var blockReason: VisitorBlockReason? = null
fun getEntity() = EntityUtils.getEntityByID(entityId)
fun getNameTagEntity() = EntityUtils.getEntityByID(nameTagEntityId)
@@ -184,4 +192,30 @@ object VisitorAPI {
}
return visitorsInTab
}
+
+ fun Visitor.blockReason(): VisitorBlockReason? {
+
+ val visitorHasReward = config.rewardWarning.preventRefusing && this.hasReward() != null
+ if (visitorHasReward) {
+ return VisitorBlockReason.RARE_REWARD
+ }
+ else if (config.rewardWarning.preventRefusingNew && this.offersAccepted == 0) {
+ return VisitorBlockReason.NEVER_ACCEPTED
+ }
+ val pricePerCopper = this.pricePerCopper ?: return VisitorBlockReason.EXPENSIVE_COPPER
+ return if (config.rewardWarning.preventRefusingCopper && pricePerCopper <= config.rewardWarning.coinsPerCopperPrice) {
+ VisitorBlockReason.CHEAP_COPPER
+ }
+ else if (config.rewardWarning.preventAcceptingCopper && pricePerCopper > config.rewardWarning.coinsPerCopperPrice) {
+ VisitorBlockReason.EXPENSIVE_COPPER
+ }
+ else null
+ }
+
+ enum class VisitorBlockReason(val description: String, val blockRefusing: Boolean) {
+ NEVER_ACCEPTED("§cNever accepted", true),
+ RARE_REWARD("§aRare visitor reward found", true),
+ CHEAP_COPPER("§aCheap copper", true),
+ EXPENSIVE_COPPER("§cExpensive copper", false)
+ }
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt
index a1a3c859d..22d7f4784 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt
@@ -13,7 +13,9 @@ import at.hannibal2.skyhanni.events.TabListUpdateEvent
import at.hannibal2.skyhanni.events.garden.visitor.VisitorOpenEvent
import at.hannibal2.skyhanni.events.garden.visitor.VisitorRenderEvent
import at.hannibal2.skyhanni.features.garden.GardenAPI
-import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.VisitorStatus
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.ACCEPT_SLOT
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.INFO_SLOT
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.lastClickedNpc
import at.hannibal2.skyhanni.mixins.transformers.gui.AccessorGuiContainer
import at.hannibal2.skyhanni.utils.ChatUtils
import at.hannibal2.skyhanni.utils.DelayedRun
@@ -24,8 +26,10 @@ import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer
import at.hannibal2.skyhanni.utils.LorenzLogger
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.RenderUtils.exactLocation
+import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
import at.hannibal2.skyhanni.utils.StringUtils.matches
import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.entity.item.EntityArmorStand
@@ -37,12 +41,16 @@ import org.lwjgl.input.Keyboard
import kotlin.time.Duration.Companion.seconds
class VisitorListener {
+ private val offersAcceptedPattern by RepoPattern.pattern(
+ "garden.visitor.offersaccepted",
+ "§7Offers Accepted: §a(?<offersAccepted>\\d+)"
+ )
private val config get() = VisitorAPI.config
- private var lastClickedNpc = 0
private val logger = LorenzLogger("garden/visitors/listener")
+
companion object {
private val VISITOR_INFO_ITEM_SLOT = 13
private val VISITOR_ACCEPT_ITEM_SLOT = 29
@@ -75,6 +83,7 @@ class VisitorListener {
if (!hasVisitorInfo) return
val visitorsInTab = VisitorAPI.visitorsInTabList(event.tabList)
+
if (LorenzUtils.lastWorldSwitch.passedSince() > 2.seconds) {
VisitorAPI.getVisitors().forEach {
val name = it.visitorName
@@ -94,11 +103,11 @@ class VisitorListener {
@SubscribeEvent
fun onInventoryOpen(event: InventoryFullyOpenedEvent) {
if (!GardenAPI.inGarden()) return
- val npcItem = event.inventoryItems[VISITOR_INFO_ITEM_SLOT] ?: return
+ val npcItem = event.inventoryItems[INFO_SLOT] ?: return
val lore = npcItem.getLore()
if (!VisitorAPI.isVisitorInfo(lore)) return
- val offerItem = event.inventoryItems[VISITOR_ACCEPT_ITEM_SLOT] ?: return
+ val offerItem = event.inventoryItems[ACCEPT_SLOT] ?: return
if (offerItem.name != "§aAccept Offer") return
VisitorAPI.inInventory = true
@@ -112,6 +121,7 @@ class VisitorListener {
val visitor = VisitorAPI.getOrCreateVisitor(name) ?: return
+ visitor.offersAccepted = offersAcceptedPattern.matchMatcher(lore[3]) { group("offersAccepted").toInt() }
visitor.entityId = lastClickedNpc
visitor.offer = visitorOffer
VisitorOpenEvent(visitor).postAndCatch()
@@ -161,7 +171,7 @@ class VisitorListener {
}
}
- VisitorAPI.changeStatus(visitor, VisitorStatus.REFUSED, "refused")
+ VisitorAPI.changeStatus(visitor, VisitorAPI.VisitorStatus.REFUSED, "refused")
// fallback if tab list is disabled
DelayedRun.runDelayed(10.seconds) {
VisitorAPI.removeVisitor(visitor.visitorName)
@@ -171,7 +181,7 @@ class VisitorListener {
if (event.slotId == VISITOR_ACCEPT_ITEM_SLOT && event.slot?.stack?.getLore()
?.any { it == "§eClick to give!" } == true
) {
- VisitorAPI.changeStatus(visitor, VisitorStatus.ACCEPTED, "accepted")
+ VisitorAPI.changeStatus(visitor, VisitorAPI.VisitorStatus.ACCEPTED, "accepted")
return
}
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorRewardWarning.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorRewardWarning.kt
new file mode 100644
index 000000000..641794ce7
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorRewardWarning.kt
@@ -0,0 +1,116 @@
+package at.hannibal2.skyhanni.features.garden.visitor
+
+import at.hannibal2.skyhanni.data.ItemRenderBackground.Companion.background
+import at.hannibal2.skyhanni.data.ItemRenderBackground.Companion.borderLine
+import at.hannibal2.skyhanni.events.GuiContainerEvent
+import at.hannibal2.skyhanni.features.garden.GardenAPI
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.ACCEPT_SLOT
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.REFUSE_SLOT
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.VisitorBlockReason
+import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.lastClickedNpc
+import at.hannibal2.skyhanni.utils.ItemUtils.name
+import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld
+import at.hannibal2.skyhanni.utils.LorenzColor
+import at.hannibal2.skyhanni.utils.NumberUtil
+import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import net.minecraft.item.ItemStack
+import net.minecraftforge.event.entity.player.ItemTooltipEvent
+import net.minecraftforge.fml.common.eventhandler.EventPriority
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import org.lwjgl.input.Keyboard
+
+
+class VisitorRewardWarning {
+ private val config get() = VisitorAPI.config.rewardWarning
+
+ @SubscribeEvent
+ fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) {
+ if (!VisitorAPI.inInventory) return
+ if (!config.preventRefusing && !config.preventRefusingCopper && !config.preventAcceptingCopper) return
+
+ val visitor = VisitorAPI.getVisitor(lastClickedNpc) ?: return
+ val refuseOfferStack = event.gui.inventorySlots.getSlot(REFUSE_SLOT).stack
+ val acceptOfferStack = event.gui.inventorySlots.getSlot(ACCEPT_SLOT).stack
+ val blockReason = visitor.blockReason ?: return
+
+ if (blockReason.blockRefusing) {
+ renderColor(refuseOfferStack, acceptOfferStack, LorenzColor.GREEN)
+ } else {
+ renderColor(acceptOfferStack, refuseOfferStack, LorenzColor.RED)
+ }
+ }
+
+ private fun renderColor(backgroundStack: ItemStack?, outlineStack: ItemStack?, outlineColor: LorenzColor) {
+ if (!config.bypassKey.isKeyHeld()) backgroundStack?.background = LorenzColor.DARK_GRAY.addOpacity(config.opacity).rgb
+ if (config.optionOutline) outlineStack?.borderLine = outlineColor.addOpacity(200).rgb
+ }
+
+ @SubscribeEvent(priority = EventPriority.HIGH)
+ fun onStackClick(event: GuiContainerEvent.SlotClickEvent) {
+ if (!VisitorAPI.inInventory) return
+ val slot = event.slot ?: return
+
+ val visitor = VisitorAPI.getVisitor(lastClickedNpc) ?: return
+ val blockReason = visitor.blockReason
+
+ val isRefuseSlot = slot.stack.name == "§cRefuse Offer"
+ val isAcceptSlot = slot.stack.name == "§aAccept Offer"
+
+ if (blockReason != null && !config.bypassKey.isKeyHeld() &&
+ ((blockReason.blockRefusing && isRefuseSlot) || !blockReason.blockRefusing && isAcceptSlot)) {
+ event.isCanceled = true
+ return
+ }
+
+ if (isRefuseSlot) {
+ VisitorAPI.changeStatus(visitor, VisitorAPI.VisitorStatus.REFUSED, "refused")
+ return
+ }
+ if (isAcceptSlot) {
+ if (slot.stack?.name != "§eClick to give!") return
+ VisitorAPI.changeStatus(visitor, VisitorAPI.VisitorStatus.ACCEPTED, "accepted")
+ return
+ }
+ }
+
+ @SubscribeEvent(priority = EventPriority.HIGH)
+ fun onTooltip(event: ItemTooltipEvent) {
+ if (!GardenAPI.onBarnPlot) return
+ if (!VisitorAPI.inInventory) return
+ val visitor = VisitorAPI.getVisitor(lastClickedNpc) ?: return
+ if (config.bypassKey.isKeyHeld()) return
+
+ val isRefuseSlot = event.itemStack.name == "§cRefuse Offer"
+ val isAcceptSlot = event.itemStack.name == "§aAccept Offer"
+
+ val blockReason = visitor.blockReason?: return
+ if (blockReason.blockRefusing && !isRefuseSlot) return
+ if (!blockReason.blockRefusing && !isAcceptSlot) return
+
+ if (visitor.blockedLore.isEmpty()) {
+ val copiedTooltip = event.toolTip.toList()
+ val blockedToolTip = mutableListOf<String>()
+
+ for (line in copiedTooltip) {
+ if (line.contains("§aAccept Offer§r")) {
+ blockedToolTip.add(line.replace("§aAccept Offer§r", "§7Accept Offer§8"))
+ } else if (line.contains("§cRefuse Offer§r")) {
+ blockedToolTip.add(line.replace("§cRefuse Offer§r", "§7Refuse Offer§8"))
+ } else if (!line.contains("minecraft:") && !line.contains("NBT:")) {
+ blockedToolTip.add("§8" + line.removeColor())
+ }
+ }
+ blockedToolTip.add("")
+ val pricePerCopper = visitor.pricePerCopper?.let { NumberUtil.format(it) }
+ blockedToolTip.add(
+ if (blockReason == VisitorBlockReason.CHEAP_COPPER || blockReason == VisitorBlockReason.EXPENSIVE_COPPER)
+ "${blockReason.description} §7(§6$pricePerCopper §7per)" else blockReason.description
+ )
+ blockedToolTip.add(" §7(Bypass by holding ${Keyboard.getKeyName(config.bypassKey)})")
+
+ visitor.blockedLore = blockedToolTip
+ }
+ event.toolTip.clear()
+ event.toolTip.addAll(visitor.blockedLore)
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt b/src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt
index b6781bde0..97a4ab51c 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt
@@ -49,7 +49,7 @@ object UtilsPatterns {
)
val readAmountBeforePattern by patternGroup.pattern(
"item.amount.front",
- "(?: *§8(\\+§\\w)?(?<amount>[\\d.km,]+)(x )?)?(?<name>.*)"
+ "(?: +§8(?:\\+§.)?(?<amount>[\\d.,]+[km]?)x? )?(?<name>.*)"
)
val readAmountAfterPattern by patternGroup.pattern(
"item.amount.behind",