diff options
author | CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> | 2024-04-19 11:43:33 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-19 03:43:33 +0200 |
commit | fdee390d8e0b4af67f2dfca38316884ccc04e3e0 (patch) | |
tree | 4cf7749a3404d427b2bfe1d5c1fb41492c973b27 /src/main/java/at | |
parent | cef5bc4c9914235476d9b1a07c8ef83e8d159827 (diff) | |
download | skyhanni-fdee390d8e0b4af67f2dfca38316884ccc04e3e0.tar.gz skyhanni-fdee390d8e0b4af67f2dfca38316884ccc04e3e0.tar.bz2 skyhanni-fdee390d8e0b4af67f2dfca38316884ccc04e3e0.zip |
Feature: Stuff for chocolate factory and hoppity event (#1434)
Co-authored-by: Thunderblade73 <85900443+Thunderblade73@users.noreply.github.com>
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src/main/java/at')
16 files changed, 1184 insertions, 1 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index d1ce70441..374f414b4 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -123,6 +123,13 @@ import at.hannibal2.skyhanni.features.dungeon.DungeonTeammateOutlines import at.hannibal2.skyhanni.features.dungeon.HighlightDungeonDeathmite import at.hannibal2.skyhanni.features.dungeon.TerracottaPhase import at.hannibal2.skyhanni.features.event.UniqueGiftingOpportunitiesFeatures +import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryAPI +import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryBarnManager +import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryInventory +import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryStats +import at.hannibal2.skyhanni.features.event.chocolatefactory.HoppityEggLocator +import at.hannibal2.skyhanni.features.event.chocolatefactory.HoppityEggsManager +import at.hannibal2.skyhanni.features.event.chocolatefactory.HoppityEggsShared import at.hannibal2.skyhanni.features.event.diana.AllBurrowsList import at.hannibal2.skyhanni.features.event.diana.BurrowWarpHelper import at.hannibal2.skyhanni.features.event.diana.DianaProfitTracker @@ -550,6 +557,7 @@ class SkyHanniMod { loadModule(PestAPI) loadModule(MiningAPI) loadModule(FossilExcavatorAPI) + loadModule(ChocolateFactoryAPI) // features loadModule(BazaarOrderHelper()) @@ -605,6 +613,12 @@ class SkyHanniMod { loadModule(SkyblockXPInChat()) loadModule(AreaMiniBossFeatures()) loadModule(MobHighlight()) + loadModule(ChocolateFactoryBarnManager) + loadModule(ChocolateFactoryInventory) + loadModule(HoppityEggsManager) + loadModule(HoppityEggLocator) + loadModule(HoppityEggsShared) + loadModule(ChocolateFactoryStats) loadModule(SpawnTimers()) loadModule(MarkedPlayerManager()) loadModule(SlayerMiniBossFeatures()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/ChocolateFactoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/ChocolateFactoryConfig.java new file mode 100644 index 000000000..ad129e0e3 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/ChocolateFactoryConfig.java @@ -0,0 +1,90 @@ +package at.hannibal2.skyhanni.config.features.event; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.event.chocolatefactory.ChocolateFactoryStats.ChocolateFactoryStat; +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.ConfigEditorDraggableList; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ChocolateFactoryConfig { + + @Expose + @ConfigOption(name = "Hoppity Eggs", desc = "") + @Accordion + public HoppityEggsConfig hoppityEggs = new HoppityEggsConfig(); + + @Expose + @ConfigOption(name = "Chocolate Factory Features", desc = "Global toggle for all chocolate factory features.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = true; + + @Expose + @ConfigOption(name = "Chocolate Factory Stats", desc = "Show general info about your chocolate factory.") + @ConfigEditorBoolean + @FeatureToggle + public boolean statsDisplay = true; + + @Expose + @ConfigOption( + name = "Stats List", + desc = "Drag text to change what displays in the chocolate factory stats list and what order the text appears in." + ) + @ConfigEditorDraggableList + public List<ChocolateFactoryStat> statsDisplayList = new ArrayList<>(Arrays.asList( + ChocolateFactoryStat.HEADER, + ChocolateFactoryStat.CURRENT, + ChocolateFactoryStat.THIS_PRESTIGE, + ChocolateFactoryStat.ALL_TIME, + ChocolateFactoryStat.EMPTY, + ChocolateFactoryStat.PER_SECOND, + ChocolateFactoryStat.PER_MINUTE, + ChocolateFactoryStat.PER_HOUR, + ChocolateFactoryStat.PER_DAY, + ChocolateFactoryStat.EMPTY_2, + ChocolateFactoryStat.MULTIPLIER, + ChocolateFactoryStat.BARN, + ChocolateFactoryStat.LEADERBOARD_POS + )); + + @Expose + @ConfigOption(name = "Show Stack Sizes", desc = "Shows additional info as many items in the chocolate menu as the stack size.") + @ConfigEditorBoolean + public boolean showStackSizes = true; + + @Expose + @ConfigOption(name = "Highlight Upgrades", desc = "Highlight any upgrades that you can afford.") + @ConfigEditorBoolean + public boolean highlightUpgrades = true; + + @Expose + @ConfigOption(name = "Use Middle Click", desc = "Click on slots with middle click to speed up interactions.") + @ConfigEditorBoolean + public boolean useMiddleClick = true; + + @Expose + @ConfigOption(name = "Rabbit Warning", desc = "Warn when the rabbit that needs to be clicked appears.") + @ConfigEditorBoolean + public boolean rabbitWarning = true; + + @Expose + @ConfigOption( + name = "Rabbit Crush Threshold", + desc = "How close should you be to your barn capacity should you be before being warned about needing to upgrade it." + ) + @ConfigEditorSlider(minValue = 3, maxValue = 20, minStep = 1) + public int barnCapacityThreshold = 6; + + @Expose + @ConfigLink(owner = ChocolateFactoryConfig.class, field = "statsDisplay") + public Position position = new Position(183, 160, false, true); +} 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 149c8c6a4..b68664d79 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 @@ -23,6 +23,10 @@ public class EventConfig { @Expose public WinterConfig winter = new WinterConfig(); + @Expose + @Category(name = "Hoppity", desc = "Features for the Hoppity event and the chocolate factory.") + public ChocolateFactoryConfig chocolateFactory = new ChocolateFactoryConfig(); + @ConfigOption(name = "City Project", desc = "") @Accordion @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/HoppityEggsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/HoppityEggsConfig.java new file mode 100644 index 000000000..f935cb699 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/HoppityEggsConfig.java @@ -0,0 +1,39 @@ +package at.hannibal2.skyhanni.config.features.event; + +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 HoppityEggsConfig { + + @Expose + @ConfigOption(name = "Hoppity Waypoints", desc = "Toggle guess waypoints for Hoppity's Hunt.") + @ConfigEditorBoolean + @FeatureToggle + public boolean waypoints = true; + + @Expose + @ConfigOption(name = "Show All Waypoints", desc = "Show all possible egg waypoints for the current lobby. §e" + + "Only works when you don't have an Egglocator in your inventory.") + @ConfigEditorBoolean + public boolean showAllWaypoints = false; + + @Expose + @ConfigOption(name = "Show Claimed Eggs", desc = "Displays which eggs have been found in the last SkyBlock day.") + @ConfigEditorBoolean + @FeatureToggle + public boolean showClaimedEggs = false; + + @Expose + @ConfigOption(name = "Shared Hoppity Waypoints", desc = "Enable being able to share and receive egg waypoints in your lobby.") + @ConfigEditorBoolean + @FeatureToggle + public boolean sharedWaypoints = true; + + @Expose + @ConfigLink(owner = HoppityEggsConfig.class, field = "showClaimedEggs") + public Position position = new Position(33, 72, false, true); +} 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 3f62f3a1b..b802b2281 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -49,6 +49,17 @@ public class ProfileSpecificStorage { public String currentPet = ""; @Expose + public ChocolateFactoryStorage chocolateFactory = new ChocolateFactoryStorage(); + + public static class ChocolateFactoryStorage { + @Expose + public int currentRabbits = 0; + + @Expose + public int maxRabbits = -1; + } + + @Expose public MaxwellPowerStorage maxwell = new MaxwellPowerStorage(); public static class MaxwellPowerStorage { diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt new file mode 100644 index 000000000..1aed17041 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt @@ -0,0 +1,19 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo + +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.utils.LorenzVec +import com.google.gson.annotations.Expose + +data class HoppityEggLocationsJson( + @Expose val eggLocations: Map<IslandType, List<LorenzVec>>, + @Expose val rabbitSlots: Map<Int, Int>, + @Expose val otherUpgradeSlots: Set<Int>, + @Expose val noPickblockSlots: Set<Int>, + @Expose val barnIndex: Int, + @Expose val infoIndex: Int, + @Expose val productionInfoIndex: Int, + @Expose val prestigeIndex: Int, + @Expose val milestoneIndex: Int, + @Expose val leaderboardIndex: Int, + @Expose val maxRabbits: Int, +) diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryAPI.kt new file mode 100644 index 000000000..9f77ea0cf --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryAPI.kt @@ -0,0 +1,256 @@ +package at.hannibal2.skyhanni.features.event.chocolatefactory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.features.event.ChocolateFactoryConfig +import at.hannibal2.skyhanni.config.storage.ProfileSpecificStorage.ChocolateFactoryStorage +import at.hannibal2.skyhanni.data.ProfileStorageData +import at.hannibal2.skyhanni.data.jsonobjects.repo.DisabledFeaturesJson +import at.hannibal2.skyhanni.data.jsonobjects.repo.HoppityEggLocationsJson +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.InventoryUpdatedEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter +import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble +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.SkyblockSeason +import at.hannibal2.skyhanni.utils.SoundUtils +import at.hannibal2.skyhanni.utils.StringUtils.matchFirst +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.UtilsPatterns +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object ChocolateFactoryAPI { + + val config: ChocolateFactoryConfig get() = SkyHanniMod.feature.event.chocolateFactory + val profileStorage: ChocolateFactoryStorage? get() = ProfileStorageData.profileSpecific?.chocolateFactory + + val patternGroup = RepoPattern.group("misc.chocolatefactory") + private val chocolateAmountPattern by patternGroup.pattern( + "chocolate.amount", + "(?<amount>[\\d,]+) Chocolate" + ) + private val chocolatePerSecondPattern by patternGroup.pattern( + "chocolate.persecond", + "§6(?<amount>[\\d.,]+) §8per second" + ) + private val chocolateAllTimePattern by patternGroup.pattern( + "chocolate.alltime", + "§7All-time Chocolate: §6(?<amount>[\\d,]+)" + ) + private val chocolateThisPrestigePattern by patternGroup.pattern( + "chocolate.thisprestige", + "§7Chocolate this Prestige: §6(?<amount>[\\d,]+)" + ) + private val chocolateMultiplierPattern by patternGroup.pattern( + "chocolate.multiplier", + "§7Total Multiplier: §6(?<amount>[\\d.]+)x" + ) + private val barnAmountPattern by patternGroup.pattern( + "barn.amount", + "§7Your Barn: §.(?<rabbits>\\d+)§7/§.(?<max>\\d+) Rabbits" + ) + private val prestigeLevelPattern by patternGroup.pattern( + "prestige.level", + "'§6Chocolate Factory (?<prestige>[IVX]+)" + ) + private val clickMeRabbitPattern by patternGroup.pattern( + "rabbit.clickme", + "§e§lCLICK ME!" + ) + private val leaderboardPlacePattern by patternGroup.pattern( + "leaderboard.place", + "§7You are §8#§b(?<position>[\\d,]+)" + ) + + var rabbitSlots = mapOf<Int, Int>() + var otherUpgradeSlots = setOf<Int>() + var noPickblockSlots = setOf<Int>() + var barnIndex = 34 + private var infoIndex = 13 + private var productionInfoIndex = 45 + private var prestigeIndex = 28 + var milestoneIndex = 53 + private var leaderboardIndex = 51 + var maxRabbits = 395 + + var inChocolateFactory = false + + var currentPrestige = 0 + var chocolateCurrent = 0L + var chocolateAllTime = 0L + var chocolatePerSecond = 0.0 + var chocolateThisPrestige = 0L + var chocolateMultiplier = 1.0 + var leaderboardPosition: Int? = null + + val upgradeableSlots: MutableSet<Int> = mutableSetOf() + var bestUpgrade: Int? = null + var bestRabbitUpgrade: String? = null + var clickRabbitSlot: Int? = null + + @SubscribeEvent + fun onInventoryOpen(event: InventoryFullyOpenedEvent) { + if (!isEnabled()) return + if (event.inventoryName != "Chocolate Factory") return + inChocolateFactory = true + + DelayedRun.runNextTick { + updateInventoryItems(event.inventoryItems) + } + } + + @SubscribeEvent + fun onInventoryUpdated(event: InventoryUpdatedEvent) { + if (!inChocolateFactory) return + + updateInventoryItems(event.inventoryItems) + } + + private fun updateInventoryItems(inventory: Map<Int, ItemStack>) { + val profileStorage = profileStorage ?: return + + val infoItem = InventoryUtils.getItemAtSlotIndex(infoIndex) ?: return + val prestigeItem = InventoryUtils.getItemAtSlotIndex(prestigeIndex) ?: return + val productionInfoItem = InventoryUtils.getItemAtSlotIndex(productionInfoIndex) ?: return + val leaderboardItem = InventoryUtils.getItemAtSlotIndex(leaderboardIndex) ?: return + + processInfoItems(infoItem, prestigeItem, productionInfoItem, leaderboardItem) + + bestUpgrade = null + upgradeableSlots.clear() + var bestAffordableUpgradeRatio = Double.MAX_VALUE + var bestPossibleUpgradeRatio = Double.MAX_VALUE + clickRabbitSlot = null + + for ((slotIndex, item) in inventory) { + if (config.rabbitWarning && clickMeRabbitPattern.matches(item.name)) { + SoundUtils.playBeepSound() + clickRabbitSlot = slotIndex + } + + val lore = item.getLore() + val upgradeCost = lore.getUpgradeCost() ?: continue + + if (slotIndex == barnIndex) { + lore.matchFirst(barnAmountPattern) { + profileStorage.currentRabbits = group("rabbits").formatInt() + profileStorage.maxRabbits = group("max").formatInt() + + ChocolateFactoryBarnManager.trySendBarnFullMessage() + } + } + + val canAfford = upgradeCost <= chocolateCurrent + if (canAfford) upgradeableSlots.add(slotIndex) + + if (slotIndex in rabbitSlots) { + val chocolateIncrease = rabbitSlots[slotIndex] ?: 0 + val upgradeRatio = upgradeCost.toDouble() / chocolateIncrease + + if (canAfford && upgradeRatio < bestAffordableUpgradeRatio) { + bestUpgrade = slotIndex + bestAffordableUpgradeRatio = upgradeRatio + } + if (upgradeRatio < bestPossibleUpgradeRatio) { + bestPossibleUpgradeRatio = upgradeRatio + bestRabbitUpgrade = item.name + } + } + } + } + + private fun processInfoItems( + chocolateItem: ItemStack, + prestigeItem: ItemStack, + productionItem: ItemStack, + leaderboardItem: ItemStack, + ) { + chocolateAmountPattern.matchMatcher(chocolateItem.name.removeColor()) { + chocolateCurrent = group("amount").formatLong() + } + for (line in chocolateItem.getLore()) { + chocolatePerSecondPattern.matchMatcher(line) { + chocolatePerSecond = group("amount").formatDouble() + } + chocolateAllTimePattern.matchMatcher(line) { + chocolateAllTime = group("amount").formatLong() + } + } + prestigeLevelPattern.matchMatcher(prestigeItem.name) { + currentPrestige = group("prestige").romanToDecimal() + } + prestigeItem.getLore().matchFirst(chocolateThisPrestigePattern) { + chocolateThisPrestige = group("amount").formatLong() + } + productionItem.getLore().matchFirst(chocolateMultiplierPattern) { + chocolateMultiplier = group("amount").formatDouble() + } + leaderboardItem.getLore().matchFirst(leaderboardPlacePattern) { + leaderboardPosition = group("position").formatInt() + } + if (!config.statsDisplay) return + ChocolateFactoryStats.updateDisplay() + } + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + clearData() + } + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + clearData() + } + + private fun clearData() { + inChocolateFactory = false + } + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + val data = event.getConstant<HoppityEggLocationsJson>("HoppityEggLocations") + + HoppityEggLocator.eggLocations = data.eggLocations + + rabbitSlots = data.rabbitSlots + otherUpgradeSlots = data.otherUpgradeSlots + noPickblockSlots = data.noPickblockSlots + barnIndex = data.barnIndex + infoIndex = data.infoIndex + productionInfoIndex = data.productionInfoIndex + prestigeIndex = data.prestigeIndex + milestoneIndex = data.milestoneIndex + leaderboardIndex = data.leaderboardIndex + maxRabbits = data.maxRabbits + + val disabledFeatures = event.getConstant<DisabledFeaturesJson>("DisabledFeatures") + HOPPITY_EVENT_DISABLED = disabledFeatures.features["HOPPITY_EVENT_DISABLED"] ?: false + } + + private var HOPPITY_EVENT_DISABLED = false + + private fun List<String>.getUpgradeCost(): Long? { + val nextLine = this.nextAfter({ UtilsPatterns.costLinePattern.matches(it) }) ?: return null + return chocolateAmountPattern.matchMatcher(nextLine.removeColor()) { + group("amount").formatLong() + } + } + + fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled + + fun isHoppityEvent() = SkyblockSeason.getCurrentSeason() == SkyblockSeason.SPRING && + (LorenzUtils.isOnAlphaServer || !HOPPITY_EVENT_DISABLED) +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryBarnManager.kt b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryBarnManager.kt new file mode 100644 index 000000000..353e0dfe3 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryBarnManager.kt @@ -0,0 +1,77 @@ +package at.hannibal2.skyhanni.features.event.chocolatefactory + +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.SoundUtils +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.seconds + +object ChocolateFactoryBarnManager { + + private val config get() = ChocolateFactoryAPI.config + private val profileStorage get() = ChocolateFactoryAPI.profileStorage + + private val newRabbitPattern by ChocolateFactoryAPI.patternGroup.pattern( + "rabbit.new", + "§d§lNEW RABBIT! §6\\+\\d Chocolate §7and §6\\+0.\\d+x Chocolate §7per second!" + ) + private val rabbitDuplicatePattern by ChocolateFactoryAPI.patternGroup.pattern( + "rabbit.duplicate", + "§7§lDUPLICATE RABBIT! §6\\+[\\d,]+ Chocolate" + ) + + var barnFull = false + private var lastBarnFullWarning = SimpleTimeMark.farPast() + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!LorenzUtils.inSkyBlock) return + + newRabbitPattern.matchMatcher(event.message) { + val profileStorage = profileStorage ?: return + profileStorage.currentRabbits += 1 + trySendBarnFullMessage() + HoppityEggsManager.shareWaypointPrompt() + } + + rabbitDuplicatePattern.matchMatcher(event.message) { + HoppityEggsManager.shareWaypointPrompt() + } + } + + fun trySendBarnFullMessage() { + if (!ChocolateFactoryAPI.isEnabled()) return + val profileStorage = profileStorage ?: return + + val remainingSpace = profileStorage.maxRabbits - profileStorage.currentRabbits + barnFull = + remainingSpace <= config.barnCapacityThreshold && profileStorage.maxRabbits < ChocolateFactoryAPI.maxRabbits + if (!barnFull) return + + if (lastBarnFullWarning.passedSince() < 30.seconds) return + + if (profileStorage.maxRabbits == -1) { + ChatUtils.clickableChat( + "Open your chocolate factory to see your barn's capacity status!", + "cf" + ) + return + } + + ChatUtils.clickableChat( + "§cYour barn is almost full! " + + "§7(${barnStatus()}). §cUpgrade it so they don't get crushed", + "cf" + ) + SoundUtils.playBeepSound() + lastBarnFullWarning = SimpleTimeMark.now() + } + + fun barnStatus(): String { + val profileStorage = profileStorage ?: return "Unknown" + return "${profileStorage.currentRabbits}/${profileStorage.maxRabbits} Rabbits" + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryInventory.kt b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryInventory.kt new file mode 100644 index 000000000..bad268f96 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryInventory.kt @@ -0,0 +1,115 @@ +package at.hannibal2.skyhanni.features.event.chocolatefactory + +import at.hannibal2.skyhanni.events.GuiContainerEvent +import at.hannibal2.skyhanni.events.GuiRenderItemEvent +import at.hannibal2.skyhanni.events.RenderInventoryItemTipEvent +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimal +import at.hannibal2.skyhanni.utils.RenderUtils.drawSlotText +import at.hannibal2.skyhanni.utils.RenderUtils.highlight +import at.hannibal2.skyhanni.utils.StringUtils.matchFirst +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object ChocolateFactoryInventory { + + private val config get() = ChocolateFactoryAPI.config + + private val rabbitAmountPattern by ChocolateFactoryAPI.patternGroup.pattern( + "rabbit.amount", + "Rabbit \\S+ - \\[(?<amount>\\d+)].*" + ) + private val upgradeTierPattern by ChocolateFactoryAPI.patternGroup.pattern( + "upgradetier", + ".*\\s(?<tier>[IVXLC]+)" + ) + private val unclaimedRewardsPattern by ChocolateFactoryAPI.patternGroup.pattern( + "unclaimedrewards", + "§7§aYou have \\d+ unclaimed rewards?!" + ) + + @SubscribeEvent + fun onRenderItemOverlayPost(event: GuiRenderItemEvent.RenderOverlayEvent.GuiRenderItemPost) { + if (!ChocolateFactoryAPI.inChocolateFactory) return + if (!config.highlightUpgrades) return + + val item = event.stack ?: return + val itemName = item.name + if (itemName != ChocolateFactoryAPI.bestRabbitUpgrade) return + + event.drawSlotText(event.x + 18, event.y, "§6✦", .8f) + } + + @SubscribeEvent + fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) { + if (!ChocolateFactoryAPI.inChocolateFactory) return + if (!config.highlightUpgrades) return + + for (slot in InventoryUtils.getItemsInOpenChest()) { + if (slot.slotIndex in ChocolateFactoryAPI.upgradeableSlots) { + if (slot.slotIndex == ChocolateFactoryAPI.bestUpgrade) { + slot highlight LorenzColor.GREEN.addOpacity(200) + } else { + slot highlight LorenzColor.GREEN.addOpacity(75) + } + } + if (slot.slotIndex == ChocolateFactoryAPI.barnIndex && ChocolateFactoryBarnManager.barnFull) { + slot highlight LorenzColor.RED + } + if (slot.slotIndex == ChocolateFactoryAPI.clickRabbitSlot) { + slot highlight LorenzColor.RED + } + } + } + + @SubscribeEvent + fun onRenderItemTip(event: RenderInventoryItemTipEvent) { + if (!ChocolateFactoryAPI.inChocolateFactory) return + if (!config.showStackSizes) return + + val item = event.stack + val itemName = item.name.removeColor() + val slotNumber = event.slot.slotNumber + + if (slotNumber in ChocolateFactoryAPI.rabbitSlots) { + rabbitAmountPattern.matchMatcher(itemName) { + val rabbitTip = when (val rabbitAmount = group("amount").formatInt()) { + in (0..9) -> "$rabbitAmount" + in (10..74) -> "§a$rabbitAmount" + in (75..124) -> "§9$rabbitAmount" + in (125..174) -> "§5$rabbitAmount" + in (175..199) -> "§6$rabbitAmount" + 200 -> "§d$rabbitAmount" + else -> "§c$rabbitAmount" + } + + event.stackTip = rabbitTip + } + } + if (slotNumber in ChocolateFactoryAPI.otherUpgradeSlots) { + upgradeTierPattern.matchMatcher(itemName) { + event.stackTip = group("tier").romanToDecimal().toString() + } + } + if (slotNumber == ChocolateFactoryAPI.milestoneIndex) { + item.getLore().matchFirst(unclaimedRewardsPattern) { + event.stackTip = "§c!!!" + } + } + } + + @SubscribeEvent + fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { + if (!ChocolateFactoryAPI.inChocolateFactory) return + val slot = event.slot ?: return + if (!config.useMiddleClick) return + if (slot.slotNumber in ChocolateFactoryAPI.noPickblockSlots) return + + event.makePickblock() + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryStats.kt b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryStats.kt new file mode 100644 index 000000000..e1df1672d --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/ChocolateFactoryStats.kt @@ -0,0 +1,79 @@ +package at.hannibal2.skyhanni.features.event.chocolatefactory + +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object ChocolateFactoryStats { + + private val config get() = ChocolateFactoryAPI.config + + private var displayList = listOf<String>() + + @SubscribeEvent + fun onBackgroundDraw(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) { + if (!ChocolateFactoryAPI.inChocolateFactory) return + if (!config.statsDisplay) return + + config.position.renderStrings(displayList, posLabel = "Chocolate Factory Stats") + } + + fun updateDisplay() { + val perSecond = ChocolateFactoryAPI.chocolatePerSecond + val perMinute = perSecond * 60 + val perHour = perMinute * 60 + val perDay = perHour * 24 + val position = ChocolateFactoryAPI.leaderboardPosition?.addSeparators() ?: "???" + + displayList = formatList(buildList { + add("§6§lChocolate Factory Stats") + + add("§eCurrent Chocolate: §6${ChocolateFactoryAPI.chocolateCurrent.addSeparators()}") + add("§eThis Prestige: §6${ChocolateFactoryAPI.chocolateThisPrestige.addSeparators()}") + add("§eAll-time: §6${ChocolateFactoryAPI.chocolateAllTime.addSeparators()}") + + add("§ePer Second: §6${perSecond.addSeparators()}") + add("§ePer Minute: §6${perMinute.addSeparators()}") + add("§ePer Hour: §6${perHour.addSeparators()}") + add("§ePer Day: §6${perDay.addSeparators()}") + + add("§eChocolate Multiplier: §6${ChocolateFactoryAPI.chocolateMultiplier}") + add("§eBarn: §6${ChocolateFactoryBarnManager.barnStatus()}") + + add("§ePosition: §7#§b$position") + + add("") + add("") + add("") + }) + } + + private fun formatList(list: List<String>): List<String> { + return config.statsDisplayList + .filter { ChocolateFactoryAPI.currentPrestige != 1 || it != ChocolateFactoryStat.THIS_PRESTIGE } + .map { list[it.ordinal] } + } + + enum class ChocolateFactoryStat(private val display: String) { + HEADER("§6§lChocolate Factory Stats"), + CURRENT("§eCurrent Chocolate: §65,272,230"), + THIS_PRESTIGE("§eThis Prestige: §6483,023,853"), + ALL_TIME("§eAll-time: §6641,119,115"), + PER_SECOND("§ePer Second: §63,780.72"), + PER_MINUTE("§ePer Minute: §6226,843.2"), + PER_HOUR("§ePer Hour: §613,610,592"), + PER_DAY("§ePer Day: §6326,654,208"), + MULTIPLIER("§eChocolate Multiplier: §61.77"), + BARN("§eBarn: §6171/190 Rabbits"), + LEADERBOARD_POS("§ePosition: §7#§b103"), + EMPTY(""), + EMPTY_2(""), + EMPTY_3(""), + ; + + override fun toString(): String { + return display + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggLocator.kt b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggLocator.kt new file mode 100644 index 000000000..eee3abc34 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggLocator.kt @@ -0,0 +1,240 @@ +package at.hannibal2.skyhanni.features.event.chocolatefactory + +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.events.ReceiveParticleEvent +import at.hannibal2.skyhanni.test.GriffinUtils.drawWaypointFilled +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine +import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import net.minecraft.item.ItemStack +import net.minecraft.util.EnumParticleTypes +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.seconds + +object HoppityEggLocator { + + private val config get() = ChocolateFactoryAPI.config.hoppityEggs + + private val locatorItem = "EGGLOCATOR".asInternalName() + + private var lastParticlePosition: LorenzVec? = null + private val validParticleLocations = mutableListOf<LorenzVec>() + + private var drawLocations = false + private var firstPos = LorenzVec() + private var secondPos = LorenzVec() + private var possibleEggLocations = listOf<LorenzVec>() + + private var ticksSinceLastParticleFound = -1 + private var lastGuessMade = SimpleTimeMark.farPast() + private var eggLocationWeights = listOf<Double>() + + var sharedEggLocation: LorenzVec? = null + var currentEggType: HoppityEggType? = null + + var eggLocations: Map<IslandType, List<LorenzVec>> = mapOf() + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + resetData() + } + + private fun resetData() { + validParticleLocations.clear() + ticksSinceLastParticleFound = -1 + possibleEggLocations = emptyList() + firstPos = LorenzVec() + secondPos = LorenzVec() + drawLocations = false + sharedEggLocation = null + currentEggType = null + } + + @SubscribeEvent + fun onRenderWorld(event: LorenzRenderWorldEvent) { + if (!isEnabled()) return + + event.draw3DLine(firstPos, secondPos, LorenzColor.RED.toColor(), 2, false) + + if (drawLocations) { + for ((index, eggLocation) in possibleEggLocations.withIndex()) { + val eggLabel = "§aGuess #${index + 1}" + event.drawWaypointFilled( + eggLocation, + LorenzColor.GREEN.toColor(), + seeThroughBlocks = true, + ) + event.drawDynamicText(eggLocation.add(y = 1), eggLabel, 1.5) + } + return + } + + val sharedEggLocation = sharedEggLocation + if (sharedEggLocation != null && config.sharedWaypoints) { + event.drawWaypointFilled( + sharedEggLocation, + LorenzColor.GREEN.toColor(), + seeThroughBlocks = true, + ) + event.drawDynamicText(sharedEggLocation.add(y = 1), "§aShared Egg", 1.5) + return + } + + if (!config.showAllWaypoints) return + if (hasLocatorInInventory()) return + if (!HoppityEggType.eggsRemaining()) return + + val islandEggsLocations = getCurrentIslandEggLocations() ?: return + for (eggLocation in islandEggsLocations) { + event.drawWaypointFilled( + eggLocation, + LorenzColor.GREEN.toColor(), + seeThroughBlocks = true, + ) + event.drawDynamicText(eggLocation.add(y = 1), "§aEgg", 1.5) + } + } + + fun eggFound() { + resetData() + } + + @SubscribeEvent + fun onReceiveParticle(event: ReceiveParticleEvent) { + if (!isEnabled()) return + if (!hasLocatorInInventory()) return + if (!event.isVillagerParticle() && !event.isEnchantmentParticle()) return + + val lastParticlePosition = lastParticlePosition ?: run { + lastParticlePosition = event.location + return + } + if (lastParticlePosition == event.location) { + validParticleLocations.add(event.location) + ticksSinceLastParticleFound = 0 + } + HoppityEggLocator.lastParticlePosition = null + } + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + if (!isEnabled()) return + if (validParticleLocations.isEmpty()) return + ticksSinceLastParticleFound++ + + if (ticksSinceLastParticleFound < 6) return + + calculateEggPosition() + + ticksSinceLastParticleFound = 0 + validParticleLocations.clear() + } + + private fun calculateEggPosition() { + if (lastGuessMade.passedSince() < 1.seconds) return + lastGuessMade = SimpleTimeMark.now() + possibleEggLocations = emptyList() + + val islandEggsLocations = getCurrentIslandEggLocations() ?: return + val listSize = validParticleLocations.size + + if (listSize < 5) return + + val secondPoint = validParticleLocations.removeLast() + firstPos = validParticleLocations.removeLast() + + val xDiff = secondPoint.x - firstPos.x + val yDiff = secondPoint.y - firstPos.y + val zDiff = secondPoint.z - firstPos.z + + secondPos = LorenzVec( + secondPoint.x + xDiff * 1000, + secondPoint.y + yDiff * 1000, + secondPoint.z + zDiff * 1000 + ) + + val sortedEggs = islandEggsLocations.map { + it to it.getEggLocationWeight(firstPos, secondPos) + }.sortedBy { it.second } + + eggLocationWeights = sortedEggs.map { + it.second.round(3) + }.take(5) + + val filteredEggs = sortedEggs.filter { + it.second < 1 + }.map { it.first } + + val maxLineDistance = filteredEggs.sortedByDescending { + it.nearestPointOnLine(firstPos, secondPos).distance(firstPos) + } + + if (maxLineDistance.isEmpty()) { + LorenzUtils.sendTitle("§cNo eggs found, try getting closer", 2.seconds) + return + } + secondPos = maxLineDistance.first().nearestPointOnLine(firstPos, secondPos) + + possibleEggLocations = filteredEggs + + drawLocations = true + } + + fun getCurrentIslandEggLocations(): List<LorenzVec>? = + eggLocations[LorenzUtils.skyBlockIsland] + + fun isValidEggLocation(location: LorenzVec): Boolean = + getCurrentIslandEggLocations()?.any { it.distance(location) < 5.0 } ?: false + + private fun ReceiveParticleEvent.isVillagerParticle() = + type == EnumParticleTypes.VILLAGER_HAPPY && speed == 0.0f && count == 1 + + private fun ReceiveParticleEvent.isEnchantmentParticle() = + type == EnumParticleTypes.ENCHANTMENT_TABLE && speed == -2.0f && count == 10 + + private fun isEnabled() = LorenzUtils.inSkyBlock && config.waypoints + && ChocolateFactoryAPI.isHoppityEvent() + + private val ItemStack.isLocatorItem get() = getInternalName() == locatorItem + fun hasLocatorInInventory() = InventoryUtils.getItemsInOwnInventory().any { it.isLocatorItem } + + private fun LorenzVec.getEggLocationWeight(firstPoint: LorenzVec, secondPoint: LorenzVec): Double { + val distToLine = this.distanceToLine(firstPoint, secondPoint) + val distToStart = this.distance(firstPoint) + val distMultiplier = distToStart * 2 / 100 + 5 + val disMultiplierSquared = distMultiplier * distMultiplier + return distToLine / disMultiplierSquared + } + + @SubscribeEvent + fun onDebugDataCollect(event: DebugDataCollectEvent) { + event.title("Hoppity Eggs Locations") + + if (!isEnabled()) { + event.addIrrelevant("not in skyblock or waypoints are disabled") + return + } + + event.addData { + add("First Pos: $firstPos") + add("Second Pos: $secondPos") + add("Possible Egg Locations: ${possibleEggLocations.size}") + add("Egg Location Weights: $eggLocationWeights") + add("Last Time Checked: ${lastGuessMade.passedSince().inWholeSeconds}s ago") + add("Draw Locations: $drawLocations") + add("Shared Egg Location: ${sharedEggLocation ?: "None"}") + add("Current Egg Type: ${currentEggType ?: "None"}") + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggType.kt b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggType.kt new file mode 100644 index 000000000..c0c88d5f6 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggType.kt @@ -0,0 +1,53 @@ +package at.hannibal2.skyhanni.features.event.chocolatefactory + +import io.github.moulberry.notenoughupdates.util.SkyBlockTime + +enum class HoppityEggType( + val mealName: String, + val resetsAt: Int, + private val mealColour: String, + var lastResetDay: Int = -1, + private var claimed: Boolean = false +) { + BREAKFAST("Breakfast", 7, "§a"), + LUNCH("Lunch", 14, "§9"), + DINNER("Dinner", 21, "§6"), + ; + + fun markClaimed() { + claimed = true + } + + fun markSpawned() { + claimed = false + } + + fun isClaimed() = claimed + val formattedName by lazy { "$mealColour$mealName" } + + companion object { + fun allFound() = entries.forEach { it.markClaimed() } + + fun getMealByName(mealName: String) = entries.find { it.mealName == mealName } + + fun checkClaimed() { + val currentSbTime = SkyBlockTime.now() + val currentSbDay = currentSbTime.day + val currentSbHour = currentSbTime.hour + + for (eggType in entries) { + if (currentSbHour < eggType.resetsAt || eggType.lastResetDay == currentSbDay) continue + eggType.markSpawned() + eggType.lastResetDay = currentSbDay + if (HoppityEggLocator.currentEggType == eggType) { + HoppityEggLocator.currentEggType = null + HoppityEggLocator.sharedEggLocation = null + } + } + } + + fun eggsRemaining(): Boolean { + return entries.any { !it.claimed } + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggsManager.kt b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggsManager.kt new file mode 100644 index 000000000..43ab8c488 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggsManager.kt @@ -0,0 +1,123 @@ +package at.hannibal2.skyhanni.features.event.chocolatefactory + +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.features.fame.ReminderUtils +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.LocationUtils +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.RecalculatingValue +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Matcher +import kotlin.time.Duration.Companion.seconds + +object HoppityEggsManager { + + private val config get() = ChocolateFactoryAPI.config.hoppityEggs + + private val eggFoundPattern by ChocolateFactoryAPI.patternGroup.pattern( + "egg.found", + "§d§lHOPPITY'S HUNT §r§dYou found a §r§.Chocolate (?<meal>\\w+) Egg.*" + ) + private val noEggsLeftPattern by ChocolateFactoryAPI.patternGroup.pattern( + "egg.noneleft", + "§cThere are no hidden Chocolate Rabbit Eggs nearby! Try again later!" + ) + private val eggSpawnedPattern by ChocolateFactoryAPI.patternGroup.pattern( + "egg.spawned", + "§d§lHOPPITY'S HUNT §r§dA §r§.Chocolate (?<meal>\\w+) Egg §r§dhas appeared!" + ) + private val eggAlreadyCollectedPattern by ChocolateFactoryAPI.patternGroup.pattern( + "egg.alreadycollected", + "§cYou have already collected this Chocolate (?<meal>\\w+) Egg§r§c! Try again when it respawns!" + ) + + private var lastMeal: HoppityEggType? = null + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + lastMeal = null + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!LorenzUtils.inSkyBlock) return + + eggFoundPattern.matchMatcher(event.message) { + HoppityEggLocator.eggFound() + val meal = getEggType(event) + meal.markClaimed() + lastMeal = meal + } + + noEggsLeftPattern.matchMatcher(event.message) { + HoppityEggType.allFound() + return + } + + eggAlreadyCollectedPattern.matchMatcher(event.message) { + getEggType(event).markClaimed() + } + + eggSpawnedPattern.matchMatcher(event.message) { + getEggType(event).markSpawned() + } + } + + internal fun Matcher.getEggType(event: LorenzChatEvent): HoppityEggType = + HoppityEggType.getMealByName(group("meal")) ?: run { + ErrorManager.skyHanniError( + "Unknown meal: ${group("meal")}", + "message" to event.message + ) + } + + fun shareWaypointPrompt() { + if (!config.sharedWaypoints) return + val meal = lastMeal ?: return + lastMeal = null + + val currentLocation = LocationUtils.playerLocation() + DelayedRun.runNextTick { + ChatUtils.clickableChat( + "Click here to share the location of this chocolate egg with the server!", + onClick = { HoppityEggsShared.shareNearbyEggLocation(currentLocation, meal) }, + expireAt = 30.seconds.fromNow() + ) + } + } + + private val hasLocatorInInventory = RecalculatingValue(1.seconds) { + HoppityEggLocator.hasLocatorInInventory() + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { + if (!LorenzUtils.inSkyBlock) return + if (!config.showClaimedEggs) return + if (ReminderUtils.isBusy()) return + if (!ChocolateFactoryAPI.isHoppityEvent()) return + if (!hasLocatorInInventory.getValue()) return + + val displayList = HoppityEggType.entries + .filter { !it.isClaimed() } + .map { "§7 - ${it.formattedName}" } + .toMutableList() + displayList.add(0, "§bUnfound Eggs:") + if (displayList.size == 1) return + + config.position.renderStrings(displayList, posLabel = "Hoppity Eggs") + } + + @SubscribeEvent + fun onSecondPassed(event: SecondPassedEvent) { + HoppityEggType.checkClaimed() + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggsShared.kt b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggsShared.kt new file mode 100644 index 000000000..3dac4b856 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/chocolatefactory/HoppityEggsShared.kt @@ -0,0 +1,57 @@ +package at.hannibal2.skyhanni.features.event.chocolatefactory + +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.event.chocolatefactory.HoppityEggsManager.getEggType +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object HoppityEggsShared { + + private val config get() = ChocolateFactoryAPI.config.hoppityEggs + + /** + * REGEX-TEST: CalMWolfs: [SkyHanni] Breakfast Chocolate Egg located at x: 142, y: 71, z: -453 + */ + private val sharedEggPattern by ChocolateFactoryAPI.patternGroup.pattern( + "egg.shared", + ".*\\[SkyHanni] (?<meal>\\w+) Chocolate Egg located at x: (?<x>-?\\d+), y: (?<y>-?\\d+), z: (?<z>-?\\d+)" + ) + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + + sharedEggPattern.matchMatcher(event.message.removeColor()) { + val (x, y, z) = listOf(group("x"), group("y"), group("z")).map { it.formatInt() } + val eggLocation = LorenzVec(x, y, z) + + val meal = getEggType(event) + + if (meal.isClaimed()) return + if (!HoppityEggLocator.isValidEggLocation(eggLocation)) return + + HoppityEggLocator.sharedEggLocation = eggLocation + HoppityEggLocator.currentEggType = meal + } + } + + fun shareNearbyEggLocation(playerLocation: LorenzVec, meal: HoppityEggType) { + if (!isEnabled()) return + val islandEggsLocations = HoppityEggLocator.getCurrentIslandEggLocations() ?: return + val closestEgg = islandEggsLocations.minByOrNull { it.distance(playerLocation) } ?: return + + val x = closestEgg.x.toInt() + val y = closestEgg.y.toInt() + val z = closestEgg.z.toInt() + + val message = "[SkyHanni] ${meal.mealName} Chocolate Egg located at x: $x, y: $y, z: $z" + ChatUtils.sendCommandToServer("ac $message") + } + + fun isEnabled() = LorenzUtils.inSkyBlock && config.waypoints && config.sharedWaypoints +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt index 9bc8ff5ae..69ca8fc59 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt @@ -36,7 +36,9 @@ object InventoryUtils { fun ContainerChest.getInventoryName() = this.lowerChestInventory.displayName.unformattedText.trim() - fun getItemsInOwnInventory() = Minecraft.getMinecraft().thePlayer.inventory.mainInventory.filterNotNull() + fun getItemsInOwnInventory() = + Minecraft.getMinecraft().thePlayer?.inventory?.mainInventory?.filterNotNull() ?: emptyList() + fun getItemsInOwnInventoryWithNull() = Minecraft.getMinecraft().thePlayer.inventory.mainInventory fun countItemsInLowerInventory(predicate: (ItemStack) -> Boolean) = diff --git a/src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt b/src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt index 18d450040..797207d0b 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt @@ -55,6 +55,10 @@ object UtilsPatterns { "item.amount.behind", "(?<name>(?:§.)*(?:[^§] ?)+)(?:§8x(?<amount>[\\d,]+))?" ) + val costLinePattern by patternGroup.pattern( + "item.cost.line", + "§7Cost" + ) val timeAmountPattern by patternGroup.pattern( "time.amount", |