From 6b4f3a330869360b55a9f55fc0f9dc554e195feb Mon Sep 17 00:00:00 2001 From: martimavocado <39881008+martimavocado@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:14:57 +0100 Subject: Fix: Great Spook mob cooldown and timer (#2804) Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../skyhanni/config/features/dev/DebugConfig.java | 5 + .../skyhanni/data/jsonobjects/repo/EventsJson.kt | 9 + .../skyhanni/features/event/spook/TheGreatSpook.kt | 188 +++++++++++++++++---- .../java/at/hannibal2/skyhanni/utils/ChatUtils.kt | 16 +- 4 files changed, 178 insertions(+), 40 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/EventsJson.kt diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DebugConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DebugConfig.java index 56a17dfb9..9f92436cf 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DebugConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DebugConfig.java @@ -162,6 +162,11 @@ public class DebugConfig { @ConfigEditorBoolean public boolean alwaysHoppitys = false; + @Expose + @ConfigOption(name = "Always Great Spook", desc = "Assumes the Great Spook is always active.") + @ConfigEditorBoolean + public Property forceGreatSpook = Property.of(false); + // Does not have a config element! @Expose public Position trackSoundPosition = new Position(0, 0); diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/EventsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/EventsJson.kt new file mode 100644 index 000000000..cab8ae7fe --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/EventsJson.kt @@ -0,0 +1,9 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo + +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +data class EventsJson( + @Expose @SerializedName("great_spook") val greatSpook: Map, +) diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/spook/TheGreatSpook.kt b/src/main/java/at/hannibal2/skyhanni/features/event/spook/TheGreatSpook.kt index 4e88237e0..9125f25a2 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/spook/TheGreatSpook.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/spook/TheGreatSpook.kt @@ -1,84 +1,167 @@ package at.hannibal2.skyhanni.features.event.spook import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.jsonobjects.repo.EventsJson import at.hannibal2.skyhanni.data.model.SkyblockStat +import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.events.SecondPassedEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.ConditionalUtils.afterChange import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.HypixelCommands import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NEUCalculator import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable import at.hannibal2.skyhanni.utils.RenderUtils.renderString +import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.SoundUtils import at.hannibal2.skyhanni.utils.StringUtils -import at.hannibal2.skyhanni.utils.TabListData +import at.hannibal2.skyhanni.utils.TimeUnit +import at.hannibal2.skyhanni.utils.TimeUtils.format +import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds @SkyHanniModule object TheGreatSpook { - - // §r§cPrimal Fears§r§7: §r§6§lREADY!! private val config get() = SkyHanniMod.feature.event.spook - private var displayTimer = "" - private var displayTimeLeft = "" - private var notificationSeconds = 0 + + private var isGreatSpookActive = false + private var greatSpookTimeRange: ClosedRange? = null + private var greatSpookEndTime = SimpleTimeMark.farPast() + + private var displayMobCooldown: Renderable? = null + private var displayGreatSpookEnd: Renderable? = null + + private var timeUntilNextMob = SimpleTimeMark.farPast() + + private val patternGroup = RepoPattern.group("event.greatspook") + + /** + * REGEX-TEST: §d§lQUICK MATHS! §r§7Solve: §r§e(10*2)+12*5 + */ + private val mathFearMessagePattern by patternGroup.pattern( + "chat.math", + "§d§lQUICK MATHS! §r§7Solve: §r§e(?.*)", + ) + + /** + * REGEX-TEST: §4[FEAR] Public Speaking Demon§r§f: Speak PlasticEating! + */ + private val speakingFearMessagePattern by patternGroup.pattern( + "chat.speaking", + "§4\\[FEAR] Public Speaking Demon§r§f: (Speak|Say something interesting) (?.*)!", + ) + + /** + * REGEX-TEST: §5§lFEAR. §r§eA §r§dPrimal Fear §r§ehas been summoned! + */ + private val primalFearSpawnPattern by patternGroup.pattern( + "mob.spawn", + "§5§lFEAR\\. §r§eA §r§dPrimal Fear §r§ehas been summoned!", + ) @SubscribeEvent fun onSecondPassed(event: SecondPassedEvent) { if (!LorenzUtils.inSkyBlock) return + if (!isGreatSpookActive) return + + val fear = SkyblockStat.FEAR.lastKnownValue ?: 0.0 + val mobCooldown = timeUntilNextMob.minus((3 * fear).seconds) + val mobCooldownString = if (mobCooldown.isInFuture()) { + "§5Next fear in: §b${ + mobCooldown.timeUntil().format( + biggestUnit = TimeUnit.MINUTE, + showMilliSeconds = false, + showSmallerUnits = false, + ) + }" + } else { + "§5§lPrimal Fear Ready!" + } + displayMobCooldown = Renderable.string(mobCooldownString) - if (config.primalFearTimer || config.primalFearNotification) displayTimer = checkTabList(" §r§cPrimal Fears§r§7: ") - if (config.greatSpookTimeLeft) displayTimeLeft = checkTabList(" §r§dEnds In§r§7: ") - if (config.primalFearNotification) { - if (displayTimer.endsWith("READY!!")) { - if (notificationSeconds > 0) { - SoundUtils.playBeepSound() - notificationSeconds-- + if (config.primalFearNotification && mobCooldown.isInFuture()) { + SoundUtils.playPlingSound() + } + + val greatSpookEnd = greatSpookTimeRange?.endInclusive ?: return + val timeLeftString = if (greatSpookEnd.isInFuture()) { + "§5Great Spook time left: §b${ + greatSpookEnd.timeUntil().format( + biggestUnit = TimeUnit.DAY, + maxUnits = 2, + ) + }" + } else { + "§5§lThe Great Spook has ended!" + } + displayGreatSpookEnd = Renderable.string(timeLeftString) + } + + @SubscribeEvent + fun onConfigLoad(event: ConfigLoadEvent) { + val config = SkyHanniMod.feature.dev.debug.forceGreatSpook + config.afterChange { + if (config.get()) { + isGreatSpookActive = true + greatSpookEndTime = SimpleTimeMark.farFuture() + } else { + val timeRange = greatSpookTimeRange + if (timeRange == null) { + isGreatSpookActive = false + greatSpookEndTime = SimpleTimeMark.farPast() + return@afterChange } - } else if (displayTimer.isNotEmpty()) { - notificationSeconds = 5 + isGreatSpookActive = SimpleTimeMark.now() in timeRange + greatSpookEndTime = timeRange.endInclusive } } } - private fun checkTabList(matchString: String): String { - return (TabListData.getTabList().find { it.contains(matchString) }.orEmpty()).trim() + @SubscribeEvent + fun onWorldSwitch(event: IslandChangeEvent) { + val currentTime = SimpleTimeMark.now() + val timeRange = greatSpookTimeRange ?: run { + isGreatSpookActive = false + return + } + + isGreatSpookActive = currentTime in timeRange } @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { if (!LorenzUtils.inSkyBlock) return + if (!isGreatSpookActive) return - if (config.primalFearTimer) config.positionTimer.renderString(displayTimer, posLabel = "Primal Fear Timer") + if (config.primalFearTimer) { + displayMobCooldown.let { + config.positionTimer.renderRenderable(it, posLabel = "Primal Fear Timer") + } + } if (config.fearStatDisplay) { SkyblockStat.FEAR.displayValue?.let { config.positionFear.renderString(it, posLabel = "Fear Stat Display") } } - if (config.greatSpookTimeLeft) config.positionTimeLeft.renderString(displayTimeLeft, posLabel = "Time Left Display") + if (config.greatSpookTimeLeft) { + displayGreatSpookEnd.let { + config.positionTimeLeft.renderRenderable(it, posLabel = "Great Spook Time Left") + } + } } - /** - * REGEX-TEST: §d§lQUICK MATHS! §r§7Solve: §r§e(10*2)+12*5 - */ - private val mathFearMessagePattern by RepoPattern.pattern( - "chat.math", - "§d§lQUICK MATHS! §r§7Solve: §r§e(?.*)", - ) - - /** - * REGEX-TEST: §4[FEAR] Public Speaking Demon§r§f: Speak PlasticEating! - */ - private val speakingFearMessagePattern by RepoPattern.pattern( - "chat.speaking", - "§4\\[FEAR] Public Speaking Demon§r§f: (Speak|Say something interesting) (?.*)!", - ) - private fun mathSolver(query: String?) { val answer = query?.let { NEUCalculator.calculateOrNull(it)?.toInt() } ?: run { ChatUtils.userError("Failed to solve $query!") @@ -108,6 +191,18 @@ object TheGreatSpook { @SubscribeEvent fun onChat(event: LorenzChatEvent) { if (!LorenzUtils.inSkyBlock) return + if (!isGreatSpookActive) return + + if (primalFearSpawnPattern.matches(event.message)) { + timeUntilNextMob = SimpleTimeMark.now().plus(6.minutes) + if (SkyblockStat.FEAR.lastKnownValue == null && (config.primalFearNotification || config.primalFearTimer)) { + ChatUtils.userError( + "Fear stat not found! Please enable the Stats widget and enable the Fear stat for the best results.", + replaceSameMessage = true, + ) + } + return + } if (config.primalFearSolver.math) { mathFearMessagePattern.matchMatcher(event.message) { @@ -125,4 +220,27 @@ object TheGreatSpook { } } } + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + val data = event.getConstant("Events").greatSpook + + val startTime = data["start_time"] ?: SimpleTimeMark.farPast() + val endTime = data["end_time"] ?: SimpleTimeMark.farPast() + + greatSpookTimeRange = startTime..endTime + greatSpookEndTime = if (SkyHanniMod.feature.dev.debug.forceGreatSpook.get()) SimpleTimeMark.farFuture() else endTime + } + + @SubscribeEvent + fun onDebug(event: DebugDataCollectEvent) { + event.title("Great Spook") + + event.addIrrelevant { + add("isActive: $isGreatSpookActive") + add("activeTimeRange: $greatSpookTimeRange") + add("eventEndTime: $greatSpookEndTime") + add("timeUntilNextMob: $timeUntilNextMob") + } + } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt index 1547e39b5..d48c8d8a7 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt @@ -44,8 +44,11 @@ object ChatUtils { * * @see DEBUG_PREFIX */ - fun debug(message: String) { - if (LorenzUtils.debug && internalChat(DEBUG_PREFIX + message)) { + fun debug( + message: String, + replaceSameMessage: Boolean = false, + ) { + if (LorenzUtils.debug && internalChat(DEBUG_PREFIX + message, replaceSameMessage)) { LorenzUtils.consoleLog("[Debug] $message") } } @@ -58,8 +61,11 @@ object ChatUtils { * * @see USER_ERROR_PREFIX */ - fun userError(message: String) { - internalChat(USER_ERROR_PREFIX + message) + fun userError( + message: String, + replaceSameMessage: Boolean = false, + ) { + internalChat(USER_ERROR_PREFIX + message, replaceSameMessage) } /** @@ -87,7 +93,7 @@ object ChatUtils { private fun internalChat( message: String, - replaceSameMessage: Boolean = false, + replaceSameMessage: Boolean, ): Boolean { val text = ChatComponentText(message) -- cgit