diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java index 41d5771ab475..c0e9fab59a5d 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java @@ -3,6 +3,7 @@ import at.hannibal2.skyhanni.config.features.event.bingo.BingoConfig; import at.hannibal2.skyhanni.config.features.event.carnival.CarnivalConfig; import at.hannibal2.skyhanni.config.features.event.diana.DianaConfig; +import at.hannibal2.skyhanni.config.features.event.gifting.GiftingConfig; import at.hannibal2.skyhanni.config.features.event.hoppity.HoppityEggsConfig; import at.hannibal2.skyhanni.config.features.event.waypoints.LobbyWaypointsConfig; import at.hannibal2.skyhanni.config.features.event.winter.WinterConfig; @@ -25,6 +26,10 @@ public class EventConfig { @Expose public WinterConfig winter = new WinterConfig(); + @Category(name = "Gifting", desc = "Giving and receiving gifts") + @Expose + public GiftingConfig gifting = new GiftingConfig(); + @Expose @Category(name = "Hoppity Eggs", desc = "Features for the Hoppity event that happens every SkyBlock spring.") public HoppityEggsConfig hoppityEggs = new HoppityEggsConfig(); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/gifting/GiftTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/gifting/GiftTrackerConfig.java new file mode 100644 index 000000000000..88a146c9bc6d --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/gifting/GiftTrackerConfig.java @@ -0,0 +1,34 @@ +package at.hannibal2.skyhanni.config.features.event.gifting; + +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.ConfigEditorInfoText; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class GiftTrackerConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Enable the gift profit tracker.") + @ConfigEditorBoolean + public boolean enabled = false; + + @Expose + @ConfigOption( + name = "§cNote", + desc = "§cDue to the complexities of gifts leaving and re-entering the inventory or stash, gift usage is not auto-tracked. " + + "§cUse §e/shaddusedgifts §cto manually add gifts used." + ) + @ConfigEditorInfoText + public String note = ""; + + @Expose + @ConfigOption(name = "Holding Gift", desc = "Only show the tracker while holding a gift.") + @ConfigEditorBoolean + public boolean holdingGift = false; + + @Expose + @ConfigLink(owner = GiftTrackerConfig.class, field = "enabled") + public Position position = new Position(-274, 0, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/gifting/GiftingConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/gifting/GiftingConfig.java new file mode 100644 index 000000000000..10a28f297281 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/gifting/GiftingConfig.java @@ -0,0 +1,25 @@ +package at.hannibal2.skyhanni.config.features.event.gifting; + +import at.hannibal2.skyhanni.config.features.event.winter.GiftingOpportunitiesConfig; +import at.hannibal2.skyhanni.config.features.event.winter.UniqueGiftConfig; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class GiftingConfig { + + @Expose + @ConfigOption(name = "Gift Profit Tracker", desc = "") + @Accordion + public GiftTrackerConfig giftProfitTracker = new GiftTrackerConfig(); + + @Expose + @ConfigOption(name = "Unique Gifting Opportunities", desc = "Highlight players who you haven't given gifts to yet.") + @Accordion + public GiftingOpportunitiesConfig giftingOpportunities = new GiftingOpportunitiesConfig(); + + @Accordion + @Expose + @ConfigOption(name = "Unique Gift Counter", desc = "Keep track of how many unique players you have given gifts to.") + public UniqueGiftConfig uniqueGiftCounter = new UniqueGiftConfig(); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java index 550ceaeee0ec..60f13d07139b 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java @@ -15,16 +15,6 @@ public class WinterConfig { @Accordion public FrozenTreasureConfig frozenTreasureTracker = new FrozenTreasureConfig(); - @Accordion - @Expose - @ConfigOption(name = "Unique Gifting Opportunities", desc = "Highlight players who you haven't given gifts to yet.") - public GiftingOpportunitiesConfig giftingOpportunities = new GiftingOpportunitiesConfig(); - - @Accordion - @Expose - @ConfigOption(name = "Unique Gift Counter", desc = "Keep track of how many unique players you have given gifts to.") - public UniqueGiftConfig uniqueGiftCounter = new UniqueGiftConfig(); - @Accordion @Expose @ConfigOption(name = "Refined Bottle of Jyrre Timer", desc = "") 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 44e4fd6dfd65..98e8703e5e03 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -31,6 +31,7 @@ import at.hannibal2.skyhanni.features.garden.pests.PestProfitTracker; import at.hannibal2.skyhanni.features.garden.pests.VinylType; import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward; +import at.hannibal2.skyhanni.features.gifting.GiftProfitTracker; import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker; import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker; import at.hannibal2.skyhanni.features.inventory.wardrobe.WardrobeAPI; @@ -885,4 +886,7 @@ public int hashCode() { ); } } + + @Expose + public GiftProfitTracker.Data giftProfitTracker = new GiftProfitTracker.Data(); } diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt index 6f596c20fa26..9555f662288e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt @@ -10,6 +10,7 @@ import at.hannibal2.skyhanni.features.chat.PowderMiningChatFilter.genericMiningR import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.features.garden.pests.PestAPI +import at.hannibal2.skyhanni.features.gifting.GiftProfitTracker import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.RegexUtils.groupOrEmpty @@ -311,37 +312,19 @@ object ChatFilter { ) // Winter Gift - private val winterGiftPatterns = listOf( - // winter gifts useless - "§f§lCOMMON! §r§3.* XP §r§egift with §r.*§r§e!".toPattern(), - "(§f§lCOMMON|§9§lRARE)! §r.* XP Boost .* Potion §r.*§r§e!".toPattern(), - "(§f§lCOMMON|§9§lRARE)! §r§6.* coins §r§egift with §r.*§r§e!".toPattern(), - - // enchanted book - "§9§lRARE! §r§9Scavenger IV §r§egift with §r.*§r§e!".toPattern(), - "§9§lRARE! §r§9Looting IV §r§egift with §r.*§r§e!".toPattern(), - "§9§lRARE! §r§9Luck VI §r§egift with §r.*§r§e!".toPattern(), - - // minion skin - "§e§lSWEET! §r§f(Grinch|Santa|Gingerbread Man) Minion Skin §r§egift with §r.*§r§e!".toPattern(), - - // rune - "§9§lRARE! §r§f◆ Ice Rune §r§egift with §r.*§r§e!".toPattern(), - - // furniture - "§e§lSWEET! §r§fTall Holiday Tree §r§egift with §r.*§r§e!".toPattern(), - "§e§lSWEET! §r§fNutcracker §r§egift with §r.*§r§e!".toPattern(), - "§e§lSWEET! §r§fPresent Stack §r§egift with §r.*§r§e!".toPattern(), - - "§e§lSWEET! §r§9(Winter|Battle) Disc §r§egift with §r.*§r§e!".toPattern(), - - // winter gifts a bit useful - "§e§lSWEET! §r§9Winter Sack §r§egift with §r.*§r§e!".toPattern(), - "§e§lSWEET! §r§5Snow Suit .* §r§egift with §r.*§r§e!".toPattern(), - - // winter gifts not your gifts - "§cThis gift is for §r.*§r§c, sorry!".toPattern(), - ) + private val winterGiftPatterns = buildList { + GiftProfitTracker.run { + listOf( + xpGainedPattern, + coinsGainedPattern, + northStarsPattern, + boostPotionPattern, + enchantmentBookPattern, + genericRewardPattern + ).forEach { add(it) } + } + addAll(GiftProfitTracker.spamPatterns) + } private val fireSalePattern by RepoPattern.pattern( "chat.firesale", diff --git a/src/main/java/at/hannibal2/skyhanni/features/gifting/GiftProfitTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/gifting/GiftProfitTracker.kt new file mode 100644 index 000000000000..8639d5b4c34d --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gifting/GiftProfitTracker.kt @@ -0,0 +1,397 @@ +package at.hannibal2.skyhanni.features.gifting + +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.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.gifting.UniqueGiftingOpportunitiesFeatures.isHoldingGift +import at.hannibal2.skyhanni.features.skillprogress.SkillType +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut +import at.hannibal2.skyhanni.utils.CollectionUtils.addSearchString +import at.hannibal2.skyhanni.utils.CollectionUtils.sumAllValues +import at.hannibal2.skyhanni.utils.ItemPriceUtils.getPrice +import at.hannibal2.skyhanni.utils.ItemUtils +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.NumberUtil.formatLong +import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimal +import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +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.repopatterns.RepoPattern +import at.hannibal2.skyhanni.utils.tracker.ItemTrackerData +import at.hannibal2.skyhanni.utils.tracker.SkyHanniItemTracker +import com.google.gson.annotations.Expose +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object GiftProfitTracker { + val config get() = SkyHanniMod.feature.event.gifting.giftProfitTracker + val patternGroup = RepoPattern.group("misc.gifting") + + // + /** + * REGEX-TEST: §f§lCOMMON! + * REGEX-TEST: §9§lRARE! + * REGEX-TEST: §e§lSWEET! + * REGEX-TEST: §c§lSANTA TIER! + * REGEX-TEST: §c§lPARTY TIER! + */ + private val giftRewardRarityPattern by patternGroup.pattern( + "reward.rarity", + "§.§l(?COMMON|RARE|SWEET|SANTA|PARTY)(?: TIER)?!.*" + ) + + /** + * REGEX-TEST: §f§lCOMMON! §r§3+500 Enchanting XP §r§egift with §r§b[MVP§r§d+§r§b] paysley§r§f§r§e! + * REGEX-TEST: §f§lCOMMON! §r§3+500 Combat XP §r§egift with §r§b[MVP§r§f+§r§b] m640§r§f§r§e! + * REGEX-TEST: §f§lCOMMON! §r§3+500 Enchanting XP §r§egift with §r§7CreationV3§r§7§r§e! + */ + val xpGainedPattern by patternGroup.pattern( + "reward.skillxp", + "§.§l.*! §r§.\\+(?[\\d,]+) (?[\\w ]+) XP §r§egift with §r.*" + ) + + /** + * REGEX-TEST: §9§lRARE! §r§6+5,000 coins §r§egift with §r§b[MVP§r§d+§r§b] kizzazz§r§f§r§e! + * REGEX-TEST: §f§lCOMMON! §r§6+5,000 coins §r§egift with §r§a[VIP] Deato_Wez§r§f§r§e! + * REGEX-TEST: §9§lRARE! §r§6+20,000 coins §r§egift with §r§a[VIP§r§6+§r§a] Grazma§r§f§r§e! + * REGEX-TEST: §e§lSWEET! §r§6+100,000 coins §r§egift with §r§a[VIP] Destrudot§r§f§r§e! + */ + val coinsGainedPattern by patternGroup.pattern( + "reward.coins", + "§.§l.*! §r§.\\+(?[\\d,]+) coins §r§egift with §r.*" + ) + + /** + * REGEX-TEST: §5§lEXTRA! §d+5 North Stars + * REGEX-TEST: §5§lEXTRA! §d+4 North Stars + * REGEX-TEST: §5§lEXTRA! §d+1 North Star + */ + val northStarsPattern by patternGroup.pattern( + "reward.northstars", + "§5§lEXTRA! §d\\+(?[\\d,]+) North Stars?" + ) + + /** + * REGEX-TEST: §9§lRARE! §r§aForaging XP Boost III Potion §r§egift with §r§b[MVP§r§f+§r§b] m640§r§f§r§e! + * REGEX-TEST: §9§lRARE! §r§aFarming XP Boost III Potion §r§egift with §r§7gay_player§r§7§r§e! + * REGEX-TEST: §9§lRARE! §r§aEnchanting XP Boost III Potion §r§egift with §r§7cfitz24§r§7§r§e! + */ + val boostPotionPattern by patternGroup.pattern( + "reward.boostpotion", + "§.§l.*! §r§.(?[\\w ]+) XP Boost (?[IVXLCDM]+) Potion §r§egift with §r.*" + ) + + /** + * REGEX-TEST: §9§lRARE! §r§9Scavenger IV §r§egift with ... + * REGEX-TEST: §9§lRARE! §r§9Looting IV §r§egift with ... + * REGEX-TEST: §9§lRARE! §r§9Luck VI §r§egift with ... + */ + val enchantmentBookPattern by patternGroup.pattern( + "reward.enchantmentbook", + "§9§lRARE! §r§9(?.+) (?[IVXLCDM]+) §r§egift with .*" + ) + + /** + * REGEX-TEST: §e§lSWEET! §r§5Snow Suit Helmet §r§egift with §r§b[MVP§r§4+§r§b] FearNotMyName§r§f§r§e! + * REGEX-TEST: §9§lRARE! §r§f◆ Ice Rune §r§egift with §r§b[MVP§r§2+§r§b] TravisScotties§r§f§r§e! + * REGEX-TEST: §e§lSWEET! §r§5Snow Suit Chestplate §r§egift with §r§7Sanstin21§r§7§r§e! + * REGEX-TEST: §c§lSANTA TIER! §r§6Cryopowder Shard §r§egift with §r§7MicrosoftDotInc§r§7§r§e! + */ + val genericRewardPattern by patternGroup.pattern( + "reward.generic", + "§.§l.*! §r§.(?.+) §r§egift with §r.*" + ) + + // Patterns to remove from chat - kept here to centralize more specific patterns away from ChatUtils + val spamPatterns = listOf( + "§cThis player is playing a profile mode which doesn't allow gifting!", + "§cAn error occurred!", + "§cCan't place gifts this close to spawn!", + "§cYou cannot place a gift so close to an NPC!", + "§eClick a player to gift them! §r§cThis isn't a player!", + ".*§r§cdisconnected, gift refunded!", + "§cThis gift is for .*, sorry!" + ).map { it.toPattern() } + // + + private val tracker = SkyHanniItemTracker("Gift Tracker", { Data() }, { it.giftProfitTracker }) { + drawDisplay(it) + } + + class Data : ItemTrackerData() { + override fun resetItems() { + giftsUsed.clear() + rarityRewardTypesGained.clear() + northStarsGained = 0 + skillXpGained.clear() + } + + override fun getDescription(timesGained: Long): List { + val totalRewards = rarityRewardTypesGained.sumAllValues().toLong().takeIf { it > 0 } ?: 1 + val percentage = timesGained.toDouble() / totalRewards + val dropRate = LorenzUtils.formatPercentage(percentage.coerceAtMost(1.0)) + return listOf( + "§7Dropped §e${timesGained.addSeparators()} §7times.", + "§7Your drop rate: §c$dropRate.", + ) + } + + override fun getCoinName(item: TrackedItem) = "§6Gift Coins" + + override fun getCoinDescription(item: TrackedItem): List { + val giftCoinsFormat = item.totalAmount.shortFormat() + return listOf( + "§7Coins occasionally drop from gifts.", + "§7You got §6$giftCoinsFormat coins §7that way.", + ) + } + + @Expose + var giftsUsed: MutableMap = mutableMapOf() + + @Expose + var rarityRewardTypesGained: MutableMap = mutableMapOf() + + @Expose + var northStarsGained: Long = 0 + + @Expose + var skillXpGained: MutableMap = mutableMapOf() + } + + enum class GiftType( + val displayName: String, + ) { + WHITE("§fWhite Gift"), + GREEN("§aGreen Gift"), + RED("§9§cRed Gift"), + PARTY("§aParty Gift"), + ; + + fun toInternalName() = "${name}_GIFT".toInternalName() + + companion object { + fun byUserInput(name: String) = entries.firstOrNull { it.name.equals(name, true) } + } + } + + enum class GiftRewardRarityType( + val displayName: String, + ) { + COMMON("§f§lCOMMON"), + RARE("§9§lRARE"), + SWEET("§e§lSWEET"), + SANTA("§c§lSANTA TIER"), + PARTY("§c§lPARTY TIER"), + ; + + override fun toString() = displayName + + companion object { + fun getByNameOrNull(name: String) = entries.firstOrNull { + it.name.uppercase() == name.uppercase() + } + } + } + + private val boostPotionCache = mutableMapOf, NEUInternalName>() + private fun getBoostPotion(skill: SkillType, tier: Int) = boostPotionCache.getOrPut(skill to tier) { + "POTION_${skill.name.uppercase()}_XP_BOOST;$tier".toInternalName() + } + + private const val ADD_GIFT_USAGE = "§eUsage:\n§6/shaddusedgifts §e<§6giftType§7: white,red,green§e> <§6amount§e>\n" + + "§eExample: §6/shaddusedgifts white 10\n§eIf no amount is specified, 1 is assumed." + + private fun tryAddUsedGift(args: Array): String { + if (args.isEmpty()) return ADD_GIFT_USAGE + val giftName = args[0] + val gift = GiftType.byUserInput(giftName) ?: return ADD_GIFT_USAGE + val amountArg = args.getOrNull(1) ?: "1" + val amount = amountArg.toLongOrNull() ?: return "§cInvalid amount (§4${args[1]}§c) specified.\n$ADD_GIFT_USAGE" + tracker.modify { + it.giftsUsed.addOrPut(gift, amount) + } + val pluralization = if (amount == 1L) "" else "s" + return "§aAdded §2${amount.addSeparators()}§8x §7${gift.displayName}$pluralization §ato used gifts." + } + + @HandleEvent + fun onCommandRegistration(event: CommandRegistrationEvent) { + event.register("shaddusedgifts") { + description = "Add used gifts to the gift profit tracker." + category = CommandCategory.USERS_ACTIVE + callback { + ChatUtils.chat(tryAddUsedGift(it)) + } + } + event.register("shresetgifttracker") { + description = "Reset the gift profit tracker." + category = CommandCategory.USERS_RESET + callback { tracker.resetCommand() } + } + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent) { + if (!isEnabled()) return + tracker.renderDisplay(config.position) + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!LorenzUtils.inSkyBlock) return + + northStarsPattern.matchMatcher(event.message) { + val amount = group("amount").formatInt() + tracker.modify { + it.northStarsGained += amount + } + return // Don't continue to other patterns + } + + giftRewardRarityPattern.matchMatcher(event.message) { + val rewardRarity = GiftRewardRarityType.getByNameOrNull(group("rarity")) ?: return + tracker.modify { + it.rarityRewardTypesGained.addOrPut(rewardRarity, 1) + } + } ?: return // All gift messages should start with a rarity, if not, ignore the message + + xpGainedPattern.matchMatcher(event.message) { + val skill = SkillType.getByNameOrNull(group("skill")) ?: return + val amount = group("amount").formatLong() + tracker.modify { + it.skillXpGained.addOrPut(skill, amount) + } + return // Don't continue to other patterns + } + + coinsGainedPattern.matchMatcher(event.message) { + val amount = group("amount").formatInt() + tracker.addCoins(amount, false) + return // Don't continue to other patterns + } + + boostPotionPattern.matchMatcher(event.message) { + val skill = SkillType.getByNameOrNull(group("skill")) ?: return + val tier = group("tier").romanToDecimal() + val item = getBoostPotion(skill, tier) + tracker.addItem(item, 1, false) + return // Don't continue to other patterns + } + + enchantmentBookPattern.matchMatcher(event.message) { + val enchantment = group("enchantment") + val tier = group("tier").romanToDecimal() + val item = "${enchantment.uppercase()};$tier".toInternalName() + tracker.addItem(item, 1, false) + return // Don't continue to other patterns + } + + genericRewardPattern.matchMatcher(event.message) { + val (itemName, amount) = when (group("item")) { + "◆ Ice Rune" -> "ICE_RUNE;1" to 1 + else -> ItemUtils.readItemAmount(group("item")) ?: return + } + NEUInternalName.fromItemNameOrNull(itemName)?.let { item -> + tracker.addItem(item, amount, false) + } + } + } + + private fun drawDisplay(data: Data): List = buildList { + addSearchString("§e§lGift Profit Tracker") + var profit = tracker.drawItems(data, { true }, this) + + val giftsUsed = data.giftsUsed + val applicableGifts = giftsUsed.filter { it.value > 0 } + var totalGiftCost = 0.0 + val giftCostStrings = buildList { + applicableGifts.forEach { (gift, count) -> + val item = gift.toInternalName() + val price = item.getPrice() + val totalPrice = price * count + if (totalPrice > 0) { + profit -= totalPrice + totalGiftCost += totalPrice + add("§7${count}x ${gift.displayName}§7: §c-${totalPrice.shortFormat()}") + } + } + } + + // Add loss due to used gifts + giftsUsed.sumAllValues().takeIf { it > 0 }?.let { + val specificGiftFormat = if (applicableGifts.count() == 1) applicableGifts.keys.first().displayName else "§eGifts" + val giftFormat = "§7${it.addSeparators()}x $specificGiftFormat§7: §c-${totalGiftCost.shortFormat()}" + add( + if (applicableGifts.count() == 1) Renderable.string(giftFormat).toSearchable() + else Renderable.hoverTips( + giftFormat, + giftCostStrings, + ).toSearchable(), + ) + } + + // North star gains + data.northStarsGained.takeIf { it > 0 }?.let { + val northStarsFormat = it.shortFormat() + add( + Renderable.hoverTips( + "§d$northStarsFormat §5North Stars§7", + listOf("§7You gained §d${it.addSeparators()} §5North Stars."), + ).toSearchable(), + ) + } + + // Skill XP gains + data.skillXpGained.sumAllValues().takeIf { it > 0 }?.let { sumXpGained -> + val applicableSkills = data.skillXpGained.filter { it.value > 0 } + val skillHoverTips = buildList { + applicableSkills.forEach { (skill, xp) -> + add("§7${xp.addSeparators()} §3${skill.displayName} XP") + } + }.toMutableList() + if (applicableSkills.size > 1) { + skillHoverTips.add("§7You gained §e${sumXpGained.addSeparators()} §7total skill XP.") + } + add( + Renderable.hoverTips( + "§7${sumXpGained.shortFormat()} §3Skill XP", + skillHoverTips, + ).toSearchable(), + ) + } + + // Breakdown of rewards by rarity + val totalRewards = data.rarityRewardTypesGained.sumAllValues().toLong() + val applicableRarities = data.rarityRewardTypesGained.filter { it.value > 0 } + val rewardHoverTips = buildList { + applicableRarities.forEach { (rarity, count) -> + add("§7${count.addSeparators()}x ${rarity.displayName}§7") + } + } + totalRewards.takeIf { it > 0 }?.let { + add( + Renderable.hoverTips( + "§eTotal Rewards§7: ${it.shortFormat()}", + rewardHoverTips, + ).toSearchable(), + ) + } + + add(tracker.addTotalProfit(profit, totalRewards, "gift")) + tracker.addPriceFromButton(this) + } + + private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled && (!config.holdingGift || isHoldingGift()) +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/winter/UniqueGiftCounter.kt b/src/main/java/at/hannibal2/skyhanni/features/gifting/UniqueGiftCounter.kt similarity index 94% rename from src/main/java/at/hannibal2/skyhanni/features/event/winter/UniqueGiftCounter.kt rename to src/main/java/at/hannibal2/skyhanni/features/gifting/UniqueGiftCounter.kt index 9889864f77b8..d6b4d771d413 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/winter/UniqueGiftCounter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gifting/UniqueGiftCounter.kt @@ -1,4 +1,4 @@ -package at.hannibal2.skyhanni.features.event.winter +package at.hannibal2.skyhanni.features.gifting import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.event.HandleEvent @@ -20,7 +20,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object UniqueGiftCounter { - private val config get() = SkyHanniMod.feature.event.winter.uniqueGiftCounter + private val config get() = SkyHanniMod.feature.event.gifting.uniqueGiftCounter private val storage get() = ProfileStorageData.playerSpecific?.winter private val giftedAmountPattern by RepoPattern.pattern( diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/UniqueGiftingOpportunitiesFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/gifting/UniqueGiftingOpportunitiesFeatures.kt similarity index 95% rename from src/main/java/at/hannibal2/skyhanni/features/event/UniqueGiftingOpportunitiesFeatures.kt rename to src/main/java/at/hannibal2/skyhanni/features/gifting/UniqueGiftingOpportunitiesFeatures.kt index 91b09201e91f..92db2aa15ac0 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/UniqueGiftingOpportunitiesFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gifting/UniqueGiftingOpportunitiesFeatures.kt @@ -1,4 +1,4 @@ -package at.hannibal2.skyhanni.features.event +package at.hannibal2.skyhanni.features.gifting import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.event.HandleEvent @@ -9,7 +9,6 @@ import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.entity.EntityCustomNameUpdateEvent import at.hannibal2.skyhanni.events.entity.EntityEnterWorldEvent -import at.hannibal2.skyhanni.features.event.winter.UniqueGiftCounter import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ColorUtils.addAlpha @@ -57,13 +56,15 @@ object UniqueGiftingOpportunitiesFeatures { private var holdingGift = false + fun isHoldingGift() = holdingGift + private fun hasGiftedPlayer(player: EntityPlayer) = playerList?.contains(player.name) == true private fun addGiftedPlayer(playerName: String) { playerList?.add(playerName) } - private val config get() = SkyHanniMod.feature.event.winter.giftingOpportunities + private val config get() = SkyHanniMod.feature.event.gifting.giftingOpportunities private fun isEnabled() = holdingGift