diff options
10 files changed, 322 insertions, 6 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/CombatConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/CombatConfig.java index 4beede62b..7042b2fdb 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/combat/CombatConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/CombatConfig.java @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.config.features.combat; import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.features.combat.broodmother.BroodmotherConfig; import at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig; import at.hannibal2.skyhanni.config.features.combat.ghostcounter.GhostCounterConfig; import com.google.gson.annotations.Expose; @@ -61,6 +62,11 @@ public class CombatConfig { public FlareConfig flare = new FlareConfig(); @Expose + @ConfigOption(name = "Broodmother", desc = "") + @Accordion + public BroodmotherConfig broodmother = new BroodmotherConfig(); + + @Expose @ConfigOption(name = "Hide Damage Splash", desc = "Hide all damage splashes anywhere in SkyBlock.") @ConfigEditorBoolean @FeatureToggle diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherConfig.java new file mode 100644 index 000000000..8acd69c1f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherConfig.java @@ -0,0 +1,68 @@ +package at.hannibal2.skyhanni.config.features.combat.broodmother; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.combat.BroodmotherFeatures.StageEntry; +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.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class BroodmotherConfig { + + @Expose + @ConfigOption(name = "Countdown", desc = "Display a countdown until the Broodmother will spawn.\n" + + "§cCountdown will not show unless the time until spawn has been established, and may be off by a few seconds.") + @ConfigEditorBoolean + @FeatureToggle + public boolean countdown = true; + + @Expose + @ConfigOption(name = "Spawn Alert", desc = "Send a chat message, title and sound when the Broodmother spawns.") + @ConfigEditorBoolean + @FeatureToggle + public boolean alertOnSpawn = false; + + @Expose + @ConfigOption(name = "Alert Settings", desc = "") + @Accordion + public BroodmotherSpawnAlertConfig spawnAlert = new BroodmotherSpawnAlertConfig(); + + @Expose + @ConfigOption(name = "Imminent Warning", desc = "Warns you when the Broodmother is 1 minute away from spawning.") + @ConfigEditorBoolean + @FeatureToggle + public boolean imminentWarning = false; + + @Expose + @ConfigOption(name = "Chat Messages", desc = "Send a chat message when the Broodmother enters these stages.\n" + + "§cThe 'Alive!' and 'Imminent' stages are overridden by the \"Spawn Alert\" and \"Imminent Warning\" features.") + @ConfigEditorDraggableList + public List<StageEntry> stages = new ArrayList<>(Arrays.asList( + StageEntry.SLAIN, + StageEntry.ALIVE + )); + + @Expose + @ConfigOption(name = "Stage on Server Join", desc = "Send a chat message with the Broodmother's current stage upon joining the Spider's Den.") + @ConfigEditorBoolean + @FeatureToggle + public boolean stageOnJoin = false; + + @Expose + @ConfigOption(name = "Hide own kills", desc = "Disable the chat message for the §eSlain §rstage if at the Spider Mound.") + @ConfigEditorBoolean + @FeatureToggle + public boolean hideSlainWhenNearby = false; + + @Expose + @ConfigLink(owner = BroodmotherConfig.class, field = "countdown") + public Position countdownPosition = new Position(10, 10, false, true); + +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherSpawnAlertConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherSpawnAlertConfig.java new file mode 100644 index 000000000..d0c2ccfe9 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/broodmother/BroodmotherSpawnAlertConfig.java @@ -0,0 +1,41 @@ +package at.hannibal2.skyhanni.config.features.combat.broodmother;
+
+import at.hannibal2.skyhanni.features.combat.BroodmotherFeatures;
+import at.hannibal2.skyhanni.utils.OSUtils;
+import com.google.gson.annotations.Expose;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorButton;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorText;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
+
+public class BroodmotherSpawnAlertConfig {
+
+ @Expose
+ @ConfigOption(name = "Alert Sound", desc = "The sound that plays for the alert.")
+ @ConfigEditorText
+ public String alertSound = "note.pling";
+
+ @Expose
+ @ConfigOption(name = "Pitch", desc = "The pitch of the alert sound.")
+ @ConfigEditorSlider(minValue = 0.5f, maxValue = 2.0f, minStep = 0.1f)
+ public float pitch = 1.0f;
+
+ @ConfigOption(name = "Test Sound", desc = "Test current sound settings.")
+ @ConfigEditorButton(buttonText = "Test")
+ public Runnable testSound = BroodmotherFeatures::playTestSound;
+
+ @Expose
+ @ConfigOption(name = "Repeat Sound", desc = "How many times the sound should be repeated.")
+ @ConfigEditorSlider(minValue = 1, maxValue = 20, minStep = 1)
+ public int repeatSound = 20;
+
+ @ConfigOption(name = "Sounds", desc = "Click to open the list of available sounds.")
+ @ConfigEditorButton(buttonText = "OPEN")
+ public Runnable sounds = () -> OSUtils.openBrowser("https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2213619-1-8-all-playsound-sound-arguments");
+
+ @Expose
+ @ConfigOption(name = "Text", desc = "The text with color to be displayed as the title notification.")
+ @ConfigEditorText
+ public String text = "&4Broodmother has spawned!";
+
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/damageindicator/DamageIndicatorConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/damageindicator/DamageIndicatorConfig.java index 7010c7d35..ed37c396c 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/combat/damageindicator/DamageIndicatorConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/damageindicator/DamageIndicatorConfig.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.List; import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.ARACHNE; +import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.BROODMOTHER; import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.DIANA_MOBS; import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.GARDEN_PESTS; import static at.hannibal2.skyhanni.config.features.combat.damageindicator.DamageIndicatorConfig.BossCategory.INFERNO_DEMONLORD; @@ -96,6 +97,7 @@ public class DamageIndicatorConfig { DIANA_MOBS, SEA_CREATURES, ARACHNE, + BROODMOTHER, THE_RIFT_BOSSES, RIFTSTALKER_BLOODFIEND, REINDRAKE, @@ -129,6 +131,7 @@ public class DamageIndicatorConfig { RIFTSTALKER_BLOODFIEND("§bRiftstalker Bloodfiend", 23), REINDRAKE("§6Reindrake", 24), GARDEN_PESTS("§aGarden Pests", 25), + BROODMOTHER("§bBroodmother") ; private final String str; diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt index 523121b37..85c50528f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt @@ -195,7 +195,7 @@ enum class TabWidget( ), BROODMOTHER( // language=RegExp - "Broodmother: (?:§.)*(?<time>.*)", + "Broodmother: (?:§.)*(?<stage>.*)", ), EYES_PLACED( // language=RegExp diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/BroodmotherFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/BroodmotherFeatures.kt new file mode 100644 index 000000000..e087fdd19 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/BroodmotherFeatures.kt @@ -0,0 +1,183 @@ +package at.hannibal2.skyhanni.features.combat + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.data.model.TabWidget +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.events.WidgetUpdateEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.HypixelCommands +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.RenderUtils.renderString +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.SoundUtils +import at.hannibal2.skyhanni.utils.SoundUtils.playSound +import at.hannibal2.skyhanni.utils.StringUtils +import at.hannibal2.skyhanni.utils.TimeUtils.format +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.reflect.KMutableProperty0 +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.DurationUnit + +@SkyHanniModule +object BroodmotherFeatures { + + enum class StageEntry(private val str: String, val minutes: Int) { + SLAIN("§eSlain", 10), + DORMANT("§eDormant", 9), + SOON("§6Soon", 6), + AWAKENING("§6Awakening", 3), + IMMINENT("§4Imminent", 1), + ALIVE("§4Alive!", 0); + + override fun toString() = str + } + + private val config get() = SkyHanniMod.feature.combat.broodmother + private val spawnAlertConfig get() = config.spawnAlert + + private var lastStage: StageEntry? = null + private var currentStage: StageEntry? = null + private var broodmotherSpawnTime = SimpleTimeMark.farPast() + private var display = "" + + @SubscribeEvent + fun onTabListUpdate(event: WidgetUpdateEvent) { + if (!event.isWidget(TabWidget.BROODMOTHER)) return + val newStage = event.widget.matchMatcherFirstLine { group("stage") } ?: "" + if (newStage.isNotEmpty()) { + lastStage = currentStage + currentStage = StageEntry.valueOf(newStage.replace("!", "").uppercase()) + onStageUpdate() + } + } + + private fun onStageUpdate() { + ChatUtils.debug("New Broodmother stage: $currentStage") + + if (lastStage == null) { + if (onServerJoin()) return + } + + // ignore Hypixel bug where the stage may temporarily revert to Imminent after the Broodmother's death + if (currentStage == StageEntry.IMMINENT && lastStage == StageEntry.ALIVE) return + + if (currentStage == StageEntry.ALIVE) { + onBroodmotherSpawn() + return + } + + val timeUntilSpawn = currentStage?.minutes?.minutes + broodmotherSpawnTime = SimpleTimeMark.now() + timeUntilSpawn!! + + if (currentStage == StageEntry.IMMINENT && config.imminentWarning) { + playImminentWarning() + return + } + + if (config.stages.contains(currentStage) && lastStage != null) { + if (currentStage == StageEntry.SLAIN) { + onBroodmotherSlain() + } else { + val pluralize = StringUtils.pluralize(timeUntilSpawn.toInt(DurationUnit.MINUTES), "minute") + ChatUtils.chat( + "Broodmother: $lastStage §e-> $currentStage§e. §b${timeUntilSpawn.inWholeMinutes} $pluralize §euntil it spawns!" + ) + } + } + } + + private fun onServerJoin(): Boolean { + // don't send if user has config enabled for either of the alive messages + // this is so that two messages aren't immediately sent upon joining a server + if (config.stageOnJoin && !(currentStage == StageEntry.ALIVE && isAliveMessageEnabled())) { + val pluralize = StringUtils.pluralize(currentStage?.minutes ?: 0, "minute") + var message = "The Broodmother's current stage in this server is ${currentStage.toString().replace("!", "")}§e." + if (currentStage?.minutes != 0) { + message += " It will spawn within §b${currentStage?.minutes} $pluralize§e." + } + ChatUtils.chat(message) + return true + } else { + return false + } + } + + private fun onBroodmotherSpawn() { + broodmotherSpawnTime = SimpleTimeMark.farPast() + if (!isAliveMessageEnabled()) return + val feature: KMutableProperty0<*> + if (config.alertOnSpawn) { + feature = config::alertOnSpawn + val alertSound = SoundUtils.createSound(spawnAlertConfig.alertSound, spawnAlertConfig.pitch) + SoundUtils.repeatSound(100, spawnAlertConfig.repeatSound, alertSound) + LorenzUtils.sendTitle(spawnAlertConfig.text.replace("&", "§"), 3.seconds) + } else { + feature = config::stages + } + ChatUtils.clickToActionOrDisable( + "The Broodmother has spawned!", + feature, + actionName = "warp to the Top of the Nest", + action = { HypixelCommands.warp("nest") }, + ) + } + + private fun playImminentWarning() { + SoundUtils.repeatSound(100, 2, SoundUtils.createSound("note.pling", 0.5f)) + ChatUtils.chat("The Broodmother is §4Imminent§e! It will spawn in §b60 seconds§e!") + } + + private fun onBroodmotherSlain() { + broodmotherSpawnTime = SimpleTimeMark.now() + 10.minutes + if (!(config.hideSlainWhenNearby && SpidersDenAPI.isAtTopOfNest())) { + ChatUtils.chat("The Broodmother was killed!") + } + } + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + broodmotherSpawnTime = SimpleTimeMark.farPast() + lastStage = null + currentStage = null + display = "" + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { + if (!isCountdownEnabled()) return + if (display.isEmpty()) return + + config.countdownPosition.renderString(display, posLabel = "Broodmother Countdown") + } + + @SubscribeEvent + fun onSecondPassed(event: SecondPassedEvent) { + if (!isCountdownEnabled()) return + + if (broodmotherSpawnTime.isFarPast()) { + if (lastStage != null) { + display = "§4Broodmother spawned!" + } + } else { + val countdown = broodmotherSpawnTime.timeUntil().format() + display = "§4Broodmother spawning in §b$countdown" + } + } + + @JvmStatic + fun playTestSound() { + with(spawnAlertConfig) { + SoundUtils.createSound(alertSound, pitch).playSound() + } + } + + private fun inSpidersDen() = IslandType.SPIDER_DEN.isInIsland() + private fun isCountdownEnabled() = inSpidersDen() && config.countdown + private fun isAliveMessageEnabled() = config.alertOnSpawn || config.stages.contains(StageEntry.ALIVE) +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt new file mode 100644 index 000000000..7986c55e9 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt @@ -0,0 +1,12 @@ +package at.hannibal2.skyhanni.features.combat + +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard +import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.RegexUtils.matches + +@SkyHanniModule +object SpidersDenAPI { + private fun getSbLines(): List<String> = CustomScoreboard.activeLines + fun isAtTopOfNest(): Boolean = getSbLines().any { ScoreboardPattern.broodmotherPattern.matches(it) } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/BossType.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/BossType.kt index 3bc12fa4c..3d46d3edc 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/BossType.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/BossType.kt @@ -101,6 +101,7 @@ enum class BossType( DUMMY("Dummy", Type.DUMMY), ARACHNE_SMALL("§cSmall Arachne", Type.ARACHNE), ARACHNE_BIG("§4Big Arachne", Type.ARACHNE), + BROODMOTHER("§cBroodmother", Type.BROODMOTHER), // The Rift LEECH_SUPREME("§cLeech Supreme", Type.THE_RIFT_BOSSES), @@ -119,8 +120,6 @@ enum class BossType( GARDEN_PEST_SLUG("§cSlug", Type.GARDEN_PESTS), GARDEN_PEST_EARTHWORM("§cEarthworm", Type.GARDEN_PESTS), - // TODO arachne - // TODO Corleone // TODO bal diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/MobFinder.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/MobFinder.kt index e9b2f879b..975e3b4f8 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/MobFinder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/MobFinder.kt @@ -429,6 +429,11 @@ class MobFinder { entity.hasMaxHealth(2_400_000, true) -> return EntityResult(bossType = BossType.SLAYER_SPIDER_4) } } + if (entity.hasNameTagWith(1, "[§7Lv12§8] §4Broodmother")) { + if (entity.hasMaxHealth(6000)) { + return EntityResult(bossType = BossType.BROODMOTHER) + } + } checkArachne(entity as EntitySpider)?.let { return it } return null } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt index efe7c953d..9f3c009e5 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.features.gui.customscoreboard import at.hannibal2.skyhanni.data.HypixelData import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.features.combat.SpidersDenAPI.isAtTopOfNest import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.eventsConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardEvent.VOTING @@ -121,7 +122,7 @@ enum class ScoreboardEvent( ), BROODMOTHER( ::getBroodmotherLines, - ::getBroodmotherShowWhen, + ::isAtTopOfNest, "§4Broodmother§7: §eDormant", ), MINING_EVENTS( @@ -441,8 +442,6 @@ private fun getSoonEventShowWhen(): Boolean = private fun getBroodmotherLines(): List<String> = listOf(getSbLines().first { SbPattern.broodmotherPattern.matches(it) }) -private fun getBroodmotherShowWhen(): Boolean = getSbLines().any { SbPattern.broodmotherPattern.matches(it) } - private fun getMiningEventsLines() = buildList { // Wind if (getSbLines().any { SbPattern.windCompassPattern.matches(it) } |