aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorILike2WatchMemes <ilike2watchmemes@gmail.com>2024-09-12 02:31:14 +0200
committerGitHub <noreply@github.com>2024-09-12 02:31:14 +0200
commitb2d1c22d4baebc6eaf9eef823b11fa9d1801ced1 (patch)
treec50c9326f59faf1ad13a0fe5719508dd66213b8f
parent5459fc8aa33915e8d4be0c538dbb19a5e80d29db (diff)
downloadskyhanni-b2d1c22d4baebc6eaf9eef823b11fa9d1801ced1.tar.gz
skyhanni-b2d1c22d4baebc6eaf9eef823b11fa9d1801ced1.tar.bz2
skyhanni-b2d1c22d4baebc6eaf9eef823b11fa9d1801ced1.zip
Feature: Zombie Shootout QOL (#2497)
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/event/EventConfig.java6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/CarnivalConfig.java13
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/ZombieShootoutConfig.java41
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalZombieShootout.kt164
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt21
5 files changed, 245 insertions, 0 deletions
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 57d3e0699..1c916bbe1 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
@@ -1,6 +1,7 @@
package at.hannibal2.skyhanni.config.features.event;
import at.hannibal2.skyhanni.config.features.event.bingo.BingoConfig;
+import at.hannibal2.skyhanni.config.features.event.carnival.CarnivalConfig;
import at.hannibal2.skyhanni.config.features.event.diana.DianaConfig;
import at.hannibal2.skyhanni.config.features.event.hoppity.HoppityEggsConfig;
import at.hannibal2.skyhanni.config.features.event.waypoints.LobbyWaypointsConfig;
@@ -43,6 +44,11 @@ public class EventConfig {
@Expose
public GreatSpookConfig spook = new GreatSpookConfig();
+ @ConfigOption(name = "Carnival", desc = "")
+ @Accordion
+ @Expose
+ public CarnivalConfig carnival = new CarnivalConfig();
+
// comment in if the event is needed again
// @ConfigOption(name = "300þ Anniversary Celebration", desc = "Features for the 300þ year of SkyBlock")
@Accordion
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/CarnivalConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/CarnivalConfig.java
new file mode 100644
index 000000000..b874f7558
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/CarnivalConfig.java
@@ -0,0 +1,13 @@
+package at.hannibal2.skyhanni.config.features.event.carnival;
+
+import com.google.gson.annotations.Expose;
+import io.github.notenoughupdates.moulconfig.annotations.Accordion;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
+
+public class CarnivalConfig {
+
+ @Expose
+ @ConfigOption(name = "Zombie Shootout", desc = "")
+ @Accordion
+ public ZombieShootoutConfig zombieShootout = new ZombieShootoutConfig();
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/ZombieShootoutConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/ZombieShootoutConfig.java
new file mode 100644
index 000000000..5709e7e58
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/carnival/ZombieShootoutConfig.java
@@ -0,0 +1,41 @@
+package at.hannibal2.skyhanni.config.features.event.carnival;
+
+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 ZombieShootoutConfig {
+
+ @Expose
+ @ConfigOption(name = "Enabled", desc = "QOL Features for Zombie Shootout.")
+ @FeatureToggle
+ @ConfigEditorBoolean
+ public boolean enabled = false;
+
+ @Expose
+ @ConfigOption(name = "Colored Hitboxes", desc = "Display colored hitboxes for zombies and lamps.")
+ @ConfigEditorBoolean
+ public boolean coloredHitboxes = true;
+
+ @Expose
+ @ConfigOption(name = "Colored Lines", desc = "Display a colored line to lamps.")
+ @ConfigEditorBoolean
+ public boolean coloredLines = true;
+
+ @Expose
+ @ConfigOption(name = "Highest Only", desc = "Only draw colored hitboxes/lines for the highest scoring zombies.")
+ @ConfigEditorBoolean
+ public boolean highestOnly = false;
+
+ @Expose
+ @ConfigOption(name = "Lamp Timer", desc = "Show time until current lamp disappears.")
+ @ConfigEditorBoolean
+ public boolean lampTimer = true;
+
+ @Expose
+ @ConfigLink(owner = ZombieShootoutConfig.class, field = "lampTimer")
+ public Position lampPosition = new Position(20, 20, false, true);
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalZombieShootout.kt b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalZombieShootout.kt
new file mode 100644
index 000000000..cae5cbda1
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalZombieShootout.kt
@@ -0,0 +1,164 @@
+package at.hannibal2.skyhanni.features.event.carnival
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.LorenzChatEvent
+import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent
+import at.hannibal2.skyhanni.events.ServerBlockChangeEvent
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.EntityUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzVec
+import at.hannibal2.skyhanni.utils.RegexUtils.matches
+import at.hannibal2.skyhanni.utils.RenderUtils
+import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine
+import at.hannibal2.skyhanni.utils.RenderUtils.drawHitbox
+import at.hannibal2.skyhanni.utils.RenderUtils.drawWaypointFilled
+import at.hannibal2.skyhanni.utils.RenderUtils.exactPlayerEyeLocation
+import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable
+import at.hannibal2.skyhanni.utils.SimpleTimeMark
+import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
+import net.minecraft.entity.monster.EntityZombie
+import net.minecraft.init.Blocks
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.awt.Color
+import kotlin.time.Duration.Companion.seconds
+
+@SkyHanniModule
+object CarnivalZombieShootout {
+
+ private val config get() = SkyHanniMod.feature.event.carnival.zombieShootout
+
+ private data class Lamp(var pos: LorenzVec, var time: SimpleTimeMark)
+ private data class Updates(var zombie: SimpleTimeMark, var content: SimpleTimeMark)
+
+ private var lastUpdate = Updates(SimpleTimeMark.farPast(), SimpleTimeMark.farPast())
+
+ private var content = Renderable.horizontalContainer(listOf())
+ private var drawZombies = mapOf<EntityZombie, ZombieType>()
+ private var lamp: Lamp? = null
+ private var started = false
+
+ private val patternGroup = RepoPattern.group("event.carnival")
+
+ /**
+ * REGEX-TEST: [NPC] Carnival Cowboy: Good luck, pal!
+ */
+ private val startPattern by patternGroup.pattern(
+ "shootout.start",
+ "\\[NPC] Carnival Cowboy: Good luck, pal!",
+ )
+
+ /**
+ * REGEX-TEST: Zombie Shootout
+ */
+ private val endPattern by patternGroup.pattern(
+ "shootout.end",
+ " {29}Zombie Shootout",
+ )
+
+ enum class ZombieType(val points: Int, val helmet: String, val color: Color) {
+ LEATHER(30, "Leather Cap", Color(165, 42, 42)), //Brown
+ IRON(50, "Iron Helmet", Color(192, 192, 192)), //Silver
+ GOLD(80, "Golden Helmet", Color(255, 215, 0)), //Gold
+ DIAMOND(120, "Diamond Helmet", Color(185, 242, 255)) //Diamond
+ }
+
+ @SubscribeEvent
+ fun onRenderWorld(event: LorenzRenderWorldEvent) {
+ if (!isEnabled() || !started || (!config.coloredHitboxes && !config.coloredLines)) return
+
+ lamp?.let {
+ if (config.coloredLines) event.draw3DLine(event.exactPlayerEyeLocation(), it.pos.add(0.0, 0.5, 0.0), Color.RED, 3, false)
+ if (config.coloredHitboxes) event.drawWaypointFilled(it.pos, Color.RED, minimumAlpha = 1.0f)
+ }
+
+ if (!config.coloredHitboxes) return
+
+ if (lastUpdate.zombie.passedSince() >= 0.25.seconds) {
+ val nearbyZombies = EntityUtils.getEntitiesNextToPlayer<EntityZombie>(50.0).mapNotNull { zombie ->
+ if (zombie.health <= 0) return@mapNotNull null
+ val armor = zombie.getCurrentArmor(3) ?: return@mapNotNull null
+ val type = toType(armor) ?: return@mapNotNull null
+ zombie to type
+ }.toMap()
+
+ drawZombies = nearbyZombies.filterValues { it == nearbyZombies.values.maxByOrNull { it.points } }
+ lastUpdate.zombie = SimpleTimeMark.now()
+ }
+
+ for ((zombie, type) in drawZombies) {
+ val entity = EntityUtils.getEntityByID(zombie.entityId) ?: continue
+
+ event.drawHitbox(
+ entity.entityBoundingBox.expand(0.1, 0.05, 0.0).offset(0.0, 0.05, 0.0),
+ lineWidth = 3,
+ type.color,
+ depth = false,
+ )
+ }
+ }
+
+ @SubscribeEvent
+ fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) {
+ if (!isEnabled() || !started || !config.lampTimer) return
+
+ val time = lamp?.time ?: return
+
+ val lamp = ItemStack(Blocks.redstone_lamp)
+ val timer = 6.seconds - (SimpleTimeMark.now() - time)
+ val prefix = when (timer) {
+ in 4.seconds..6.seconds -> "§a"
+ in 2.seconds..4.seconds -> "§e"
+ else -> "§c"
+ }
+
+ if (lastUpdate.content.passedSince() >= 0.1.seconds) {
+ content = Renderable.horizontalContainer(
+ listOf(
+ Renderable.itemStack(lamp),
+ Renderable.string("§6Disappears in $prefix${timer}"),
+ ),
+ spacing = 1,
+ verticalAlign = RenderUtils.VerticalAlignment.CENTER,
+ )
+ lastUpdate.content = SimpleTimeMark.now()
+ }
+
+ config.lampPosition.renderRenderable(content, posLabel = "Lantern Timer")
+ }
+
+ @SubscribeEvent
+ fun onBlockChange(event: ServerBlockChangeEvent) {
+ if (!isEnabled() || !started) return
+
+ val old = event.old
+ val new = event.new
+
+ lamp = when {
+ old == "redstone_lamp" && new == "lit_redstone_lamp" -> Lamp(event.location, SimpleTimeMark.now())
+ old == "lit_redstone_lamp" && new == "redstone_lamp" -> null
+ else -> lamp
+ }
+ }
+
+ @SubscribeEvent
+ fun onChat(event: LorenzChatEvent) {
+ if (!isEnabled()) return
+
+ val message = event.message.removeColor()
+
+ if (startPattern.matches(message)) {
+ started = true
+ } else if (endPattern.matches(message)) {
+ started = false
+ }
+ }
+
+ private fun toType(item: ItemStack) = ZombieType.entries.find { it.helmet == item.displayName }
+
+ private fun isEnabled() = config.enabled && LorenzUtils.skyBlockArea == "Carnival"
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
index 0d6417688..3442032e6 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
@@ -1611,6 +1611,27 @@ object RenderUtils {
GlStateManager.enableCull()
}
+ fun LorenzRenderWorldEvent.drawHitbox(
+ boundingBox: AxisAlignedBB,
+ lineWidth: Int,
+ color: Color,
+ depth: Boolean,
+ ) {
+ val cornersTop = boundingBox.getCorners(boundingBox.maxY)
+ val cornersBottom = boundingBox.getCorners(boundingBox.minY)
+
+ // Draw lines for the top and bottom faces
+ for (i in 0..3) {
+ this.draw3DLine(cornersTop[i], cornersTop[(i + 1) % 4], color, lineWidth, depth)
+ this.draw3DLine(cornersBottom[i], cornersBottom[(i + 1) % 4], color, lineWidth, depth)
+ }
+
+ // Draw lines connecting the top and bottom faces
+ for (i in 0..3) {
+ this.draw3DLine(cornersBottom[i], cornersTop[i], color, lineWidth, depth)
+ }
+ }
+
fun chromaColor(
timeTillRepeat: Duration,
offset: Float = 0f,