Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broodmother temp #1

Merged
merged 9 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -60,6 +61,11 @@ public class CombatConfig {
@Accordion
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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);

}
Original file line number Diff line number Diff line change
@@ -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!";

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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;
Expand Down Expand Up @@ -96,6 +97,7 @@ public String toString() {
DIANA_MOBS,
SEA_CREATURES,
ARACHNE,
BROODMOTHER,
THE_RIFT_BOSSES,
RIFTSTALKER_BLOODFIEND,
REINDRAKE,
Expand Down Expand Up @@ -129,6 +131,7 @@ public enum BossCategory implements HasLegacyId {
RIFTSTALKER_BLOODFIEND("§bRiftstalker Bloodfiend", 23),
REINDRAKE("§6Reindrake", 24),
GARDEN_PESTS("§aGarden Pests", 25),
BROODMOTHER("§bBroodmother")
;

private final String str;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ enum class TabWidget(
),
BROODMOTHER(
// language=RegExp
"Broodmother: (?:§.)*(?<time>.*)",
"Broodmother: (?:§.)*(?<stage>.*)",
),
EYES_PLACED(
// language=RegExp
Expand Down
Original file line number Diff line number Diff line change
@@ -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.LocationUtils.isAtTopOfNest
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)) {
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")
ChatUtils.chat("The Broodmother's current stage in this server is ${currentStage.toString().replace("!", "")}.")
if (currentStage?.minutes != 0) {
ChatUtils.chat("It will spawn in §bup to ${currentStage?.minutes} $pluralize§e.")
}
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 && 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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Loading