aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenz <ESs95s3P5z8Pheb>2022-07-09 04:18:07 +0200
committerLorenz <ESs95s3P5z8Pheb>2022-07-09 04:18:07 +0200
commita193bdca479ae7531da6f034c597335918b52699 (patch)
treebf8d56f262842d243a2628befc3360801edda8a5
parentf842a84e3aae31e5fe84b52f23550efca526f6aa (diff)
downloadskyhanni-a193bdca479ae7531da6f034c597335918b52699.tar.gz
skyhanni-a193bdca479ae7531da6f034c597335918b52699.tar.bz2
skyhanni-a193bdca479ae7531da6f034c597335918b52699.zip
added dungeon boss damage indicator
-rw-r--r--src/main/java/at/lorenz/mod/LorenzMod.java2
-rw-r--r--src/main/java/at/lorenz/mod/config/Features.java5
-rw-r--r--src/main/java/at/lorenz/mod/dungeon/DungeonData.kt14
-rw-r--r--src/main/java/at/lorenz/mod/dungeon/damageindicator/DungeonBossDamageIndicator.kt154
-rw-r--r--src/main/java/at/lorenz/mod/dungeon/damageindicator/DungeonBossFinder.kt338
-rw-r--r--src/main/java/at/lorenz/mod/dungeon/damageindicator/EntityData.kt6
-rw-r--r--src/main/java/at/lorenz/mod/misc/HypixelData.kt2
-rw-r--r--src/main/java/at/lorenz/mod/utils/LorenzUtils.kt5
-rw-r--r--src/main/java/at/lorenz/mod/utils/RenderUtils.kt43
9 files changed, 566 insertions, 3 deletions
diff --git a/src/main/java/at/lorenz/mod/LorenzMod.java b/src/main/java/at/lorenz/mod/LorenzMod.java
index 39da77c6a..5a7ddf5fd 100644
--- a/src/main/java/at/lorenz/mod/LorenzMod.java
+++ b/src/main/java/at/lorenz/mod/LorenzMod.java
@@ -9,6 +9,7 @@ import at.lorenz.mod.config.Features;
import at.lorenz.mod.dungeon.DungeonChatFilter;
import at.lorenz.mod.dungeon.DungeonData;
import at.lorenz.mod.dungeon.DungeonHighlightClickedBlocks;
+import at.lorenz.mod.dungeon.damageindicator.DungeonBossDamageIndicator;
import at.lorenz.mod.misc.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -59,6 +60,7 @@ public class LorenzMod {
MinecraftForge.EVENT_BUS.register(new ItemDisplayOverlayFeatures());
MinecraftForge.EVENT_BUS.register(new CurrentPetDisplay());
MinecraftForge.EVENT_BUS.register(new ExpBottleOnGroundHider());
+ MinecraftForge.EVENT_BUS.register(new DungeonBossDamageIndicator());
Commands.init();
diff --git a/src/main/java/at/lorenz/mod/config/Features.java b/src/main/java/at/lorenz/mod/config/Features.java
index 327aa2bcb..d4c1e6014 100644
--- a/src/main/java/at/lorenz/mod/config/Features.java
+++ b/src/main/java/at/lorenz/mod/config/Features.java
@@ -116,6 +116,11 @@ public class Features {
@ConfigOption(name = "Clicked Blocks", desc = "Highlight the following blocks when clicked in dungeon: Lever, Chest, Wither Essence")
@ConfigEditorBoolean
public boolean highlightClickedBlocks = false;
+
+ @Expose
+ @ConfigOption(name = "Boss Damage Indicator", desc = "Shows the missing health of a boss in the dungeon and the cooldown time until the boss becomes attackable.")
+ @ConfigEditorBoolean
+ public boolean bossDamageIndicator = false;
}
public static class Inventory {
diff --git a/src/main/java/at/lorenz/mod/dungeon/DungeonData.kt b/src/main/java/at/lorenz/mod/dungeon/DungeonData.kt
index d14183d99..870bcaa50 100644
--- a/src/main/java/at/lorenz/mod/dungeon/DungeonData.kt
+++ b/src/main/java/at/lorenz/mod/dungeon/DungeonData.kt
@@ -9,7 +9,19 @@ import net.minecraftforge.fml.common.gameevent.TickEvent
class DungeonData {
- var dungeonFloor: String? = null
+ companion object {
+ var dungeonFloor: String? = null
+
+ fun isOneOf(vararg floors: String): Boolean {
+ for (floor in floors) {
+ if (dungeonFloor == floor) {
+ return true
+ }
+ }
+
+ return false
+ }
+ }
@SubscribeEvent
fun onTick(event: TickEvent.ClientTickEvent) {
diff --git a/src/main/java/at/lorenz/mod/dungeon/damageindicator/DungeonBossDamageIndicator.kt b/src/main/java/at/lorenz/mod/dungeon/damageindicator/DungeonBossDamageIndicator.kt
new file mode 100644
index 000000000..47e0d7f52
--- /dev/null
+++ b/src/main/java/at/lorenz/mod/dungeon/damageindicator/DungeonBossDamageIndicator.kt
@@ -0,0 +1,154 @@
+package at.lorenz.mod.dungeon.damageindicator
+
+import at.lorenz.mod.LorenzMod
+import at.lorenz.mod.events.DungeonEnterEvent
+import at.lorenz.mod.events.LorenzChatEvent
+import at.lorenz.mod.utils.LorenzColor
+import at.lorenz.mod.utils.LorenzUtils
+import at.lorenz.mod.utils.LorenzUtils.baseMaxHealth
+import at.lorenz.mod.utils.NumberUtil
+import at.lorenz.mod.utils.RenderUtils
+import net.minecraft.client.Minecraft
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.entity.EntityLivingBase
+import net.minecraft.util.Vec3
+import net.minecraftforge.client.event.RenderLivingEvent
+import net.minecraftforge.client.event.RenderWorldLastEvent
+import net.minecraftforge.event.entity.EntityJoinWorldEvent
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.math.max
+
+class DungeonBossDamageIndicator {
+
+ var data = mutableMapOf<EntityLivingBase, EntityData>()
+ private var bossFinder: DungeonBossFinder? = null
+ private val decimalFormat = DecimalFormat("0.0")
+
+ @SubscribeEvent
+ fun onDungeonStart(event: DungeonEnterEvent) {
+ bossFinder = DungeonBossFinder()
+ }
+
+ @SubscribeEvent(receiveCanceled = true)
+ fun onChatMessage(event: LorenzChatEvent) {
+ if (!LorenzUtils.inDungeons) return
+ if (!LorenzMod.feature.dungeon.bossDamageIndicator) return
+
+ bossFinder?.handleChat(event.message)
+ }
+
+ @SubscribeEvent
+ fun onWorldRender(event: RenderWorldLastEvent) {
+ GlStateManager.disableDepth()
+ GlStateManager.disableCull()
+
+ val player = Minecraft.getMinecraft().thePlayer
+
+ for (data in data.values) {
+ if (System.currentTimeMillis() > data.time + 100) continue//TODO use removeIf
+ if (!data.ignoreBlocks) {
+ if (!player.canEntityBeSeen(data.entity)) continue
+ }
+
+ val entity = data.entity
+
+ var color = data.color
+ var text = data.text
+ val delayedStart = data.delayedStart
+ if (delayedStart != -1L) {
+ if (delayedStart > System.currentTimeMillis()) {
+ val delay = delayedStart - System.currentTimeMillis()
+ color = colorForTime(delay)
+ var d = delay * 1.0
+ d /= 1000
+ text = decimalFormat.format(d)
+ }
+ }
+
+ val partialTicks = event.partialTicks
+ RenderUtils.drawLabel(
+ Vec3(
+ RenderUtils.interpolate(entity.posX, entity.lastTickPosX, partialTicks),
+ RenderUtils.interpolate(entity.posY, entity.lastTickPosY, partialTicks) + 0.5f,
+ RenderUtils.interpolate(entity.posZ, entity.lastTickPosZ, partialTicks)
+ ),
+ text,
+ color.toColor(),
+ partialTicks,
+ true,
+ 6f
+ )
+ }
+ GlStateManager.enableDepth()
+ GlStateManager.enableCull()
+ }
+
+ private fun colorForTime(delayedStart: Long): LorenzColor = when {
+ delayedStart < 1_000 -> LorenzColor.DARK_PURPLE
+ delayedStart < 3_000 -> LorenzColor.LIGHT_PURPLE
+
+ else -> LorenzColor.WHITE
+ }
+
+ @SubscribeEvent
+ fun onRenderLivingPost(event: RenderLivingEvent.Post<*>) {
+ if (!LorenzUtils.inDungeons) return
+ if (!LorenzMod.feature.dungeon.bossDamageIndicator) return
+
+ try {
+ val entity = event.entity
+
+ var ignoreBlocks = false
+ var delayedStart = -1L
+ val show = bossFinder?.shouldShow(entity, { ignoreBlocks = it }, { delayedStart = it }) ?: false
+ if (!show) return
+
+ val currentMaxHealth = event.entity.baseMaxHealth
+
+ val debugMaxHealth = getMaxHealthFor(event.entity)
+ val biggestHealth = max(currentMaxHealth, debugMaxHealth)
+ if (biggestHealth > debugMaxHealth) {
+ setMaxHealth(event.entity, biggestHealth)
+ }
+
+ val percentage = event.entity.health / max(debugMaxHealth, currentMaxHealth)
+ val color = when {
+ percentage > 0.9 -> LorenzColor.DARK_GREEN
+ percentage > 0.75 -> LorenzColor.GREEN
+ percentage > 0.5 -> LorenzColor.YELLOW
+ percentage > 0.25 -> LorenzColor.GOLD
+ else -> LorenzColor.RED
+ }
+
+ data[entity] = EntityData(
+ entity,
+ NumberUtil.format(event.entity.health),
+ color,
+ System.currentTimeMillis(),
+ ignoreBlocks,
+ delayedStart
+ )
+
+ } catch (e: Throwable) {
+ e.printStackTrace()
+ }
+ }
+
+ //TODO test why this does not work
+ val maxHealth = mutableMapOf<UUID, Double>()
+
+ private fun setMaxHealth(entity: EntityLivingBase, currentMaxHealth: Double) {
+ maxHealth[entity.uniqueID!!] = currentMaxHealth
+ }
+
+ private fun getMaxHealthFor(entity: EntityLivingBase): Double {
+ return maxHealth.getOrDefault(entity.uniqueID!!, 0.0)
+ }
+
+ @SubscribeEvent
+ fun onWorldRender(event: EntityJoinWorldEvent) {
+ bossFinder?.handleNewEntity(event.entity)
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/lorenz/mod/dungeon/damageindicator/DungeonBossFinder.kt b/src/main/java/at/lorenz/mod/dungeon/damageindicator/DungeonBossFinder.kt
new file mode 100644
index 000000000..edc38edeb
--- /dev/null
+++ b/src/main/java/at/lorenz/mod/dungeon/damageindicator/DungeonBossFinder.kt
@@ -0,0 +1,338 @@
+package at.lorenz.mod.dungeon.damageindicator
+
+import at.lorenz.mod.dungeon.DungeonData
+import at.lorenz.mod.utils.LorenzUtils
+import at.lorenz.mod.utils.LorenzUtils.baseMaxHealth
+import at.lorenz.mod.utils.LorenzUtils.matchRegex
+import at.lorenz.mod.utils.getLorenzVec
+import net.minecraft.client.Minecraft
+import net.minecraft.client.entity.EntityOtherPlayerMP
+import net.minecraft.entity.Entity
+import net.minecraft.entity.EntityLivingBase
+import net.minecraft.entity.monster.EntityGiantZombie
+import net.minecraft.entity.monster.EntityGuardian
+
+class DungeonBossFinder {
+
+ //F1
+ private var floor1bonzo1 = false
+ private var floor1bonzo1SpawnTime = 0L
+ private var floor1bonzo2 = false
+ private var floor1bonzo2SpawnTime = 0L
+
+ //F2
+ private var floor2summons1 = false
+ private var floor2summons1SpawnTime = 0L
+ private var floor2summonsDiedOnce = mutableListOf<EntityOtherPlayerMP>()
+ private var floor2secondPhase = false
+ private var floor2secondPhaseSpawnTime = 0L
+
+ //F3
+ private var floor3GuardianShield = false
+ private var floor3GuardianShieldSpawnTime = 0L
+ private var guardians = mutableListOf<EntityGuardian>()
+ private var floor3Professor = false
+ private var floor3ProfessorSpawnTime = 0L
+ private var floor3ProfessorGuardianPrepare = false
+ private var floor3ProfessorGuardianPrepareSpawnTime = 0L
+ private var floor3ProfessorGuardian = false
+ private var floor3ProfessorGuardianEntity: EntityGuardian? = null
+
+ //F5
+ private var floor5lividEntity: EntityOtherPlayerMP? = null
+
+ //F6
+ private var floor6Giants = false
+ private var floor6GiantsSpawnTime = 0L //TODO different giants cooldown delayed from each other
+ private var floor6Sadan = false
+ private var floor6SadanSpawnTime = 0L
+
+ internal fun shouldShow(
+ entity: EntityLivingBase,
+ ignoreBlocks: (Boolean) -> Unit,
+ delayedStart: (Long) -> Unit
+ ): Boolean {
+ if (LorenzUtils.inDungeons) {
+ if (DungeonData.isOneOf("F1", "M1")) {
+ if (floor1bonzo1) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "Bonzo ") {
+ delayedStart(floor1bonzo1SpawnTime)
+ return true
+ }
+ }
+ }
+ if (floor1bonzo2) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "Bonzo ") {
+ delayedStart(floor1bonzo2SpawnTime)
+ return true
+ }
+ }
+ }
+ }
+
+ if (DungeonData.isOneOf("F2", "M2")) {
+ if (entity.name == "Summon ") {
+ if (entity is EntityOtherPlayerMP) {
+ if (floor2summons1) {
+ if (!floor2summonsDiedOnce.contains(entity)) {
+ if (entity.health.toInt() != 0) {
+ delayedStart(floor2summons1SpawnTime)
+ return true
+ } else {
+ floor2summonsDiedOnce.add(entity)
+ }
+ }
+ }
+ if (floor2secondPhase) {
+ delayedStart(floor2secondPhaseSpawnTime)
+ return true
+ }
+ }
+ }
+
+ if (floor2secondPhase) {
+ if (entity is EntityOtherPlayerMP) {
+ //TODO only show scarf after (all/at least x) summons are dead?
+ val result = entity.name == "Scarf "
+ if (result) {
+ delayedStart(floor2secondPhaseSpawnTime)
+ return true
+ }
+ }
+ }
+ }
+
+ if (DungeonData.isOneOf("F3", "M3")) {
+ if (entity is EntityGuardian) {
+ if (floor3GuardianShield) {
+ if (guardians.size == 4) {
+ var totalHealth = 0
+ for (guardian in guardians) {
+ totalHealth += guardian.health.toInt()
+ }
+ if (totalHealth == 0) {
+ floor3GuardianShield = false
+ guardians.clear()
+ }
+ } else {
+ findGuardians()
+ }
+ if (guardians.contains(entity)) {
+ ignoreBlocks(true)
+ delayedStart(floor3GuardianShieldSpawnTime)
+ return true
+ }
+ }
+ }
+
+ if (floor3Professor) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "The Professor") {
+ delayedStart(floor3ProfessorSpawnTime)
+ ignoreBlocks(floor3ProfessorSpawnTime + 1_000 > System.currentTimeMillis())
+ return true
+ }
+ }
+ }
+ if (floor3ProfessorGuardianPrepare) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "The Professor") {
+ delayedStart(floor3ProfessorGuardianPrepareSpawnTime)
+ ignoreBlocks(true)
+ return true
+ }
+ }
+ }
+
+ if (entity is EntityGuardian) {
+ if (floor3ProfessorGuardian) {
+ if (entity == floor3ProfessorGuardianEntity) {
+ return true
+ }
+ }
+ }
+ }
+
+ if (DungeonData.isOneOf("F5", "M5")) {
+ if (entity is EntityOtherPlayerMP) {
+ val floor5lividEntity1 = floor5lividEntity
+ if (entity == floor5lividEntity1) {
+ ignoreBlocks(entity.getLorenzVec().distance(5.5, 69.0, -2.5) < 5)
+ return true
+ }
+ }
+ }
+
+ if (DungeonData.isOneOf("F6", "M6")) {
+ if (entity is EntityGiantZombie && !entity.isInvisible) {
+ if (floor6Giants && entity.posY > 68) {
+ ignoreBlocks(floor6GiantsSpawnTime + 1_000 > System.currentTimeMillis())
+ delayedStart(floor6GiantsSpawnTime)
+ return true
+ }
+
+ if (floor6Sadan) {
+ delayedStart(floor6SadanSpawnTime)
+ return true
+ }
+ }
+ }
+ }
+
+ return false
+ }
+
+ fun handleChat(message: String) {
+ when (message) {
+ //F1
+ "§c[BOSS] Bonzo§r§f: Gratz for making it this far, but I’m basically unbeatable." -> {
+ floor1bonzo1 = true
+ floor1bonzo1SpawnTime = System.currentTimeMillis() + 11_250
+ }
+
+ "§c[BOSS] Bonzo§r§f: Oh noes, you got me.. what ever will I do?!" -> {
+ floor1bonzo1 = false
+ }
+
+ "§c[BOSS] Bonzo§r§f: Oh I'm dead!" -> {
+ floor1bonzo2 = true
+ floor1bonzo2SpawnTime = System.currentTimeMillis() + 4_200
+ }
+
+ "§c[BOSS] Bonzo§r§f: Alright, maybe I'm just weak after all.." -> {
+ floor1bonzo2 = false
+ }
+
+ //F2
+ "§c[BOSS] Scarf§r§f: ARISE, MY CREATIONS!" -> {
+ floor2summons1 = true
+ floor2summons1SpawnTime = System.currentTimeMillis() + 3_500
+ }
+
+ "§c[BOSS] Scarf§r§f: Those toys are not strong enough I see." -> {
+ floor2summons1 = false
+ }
+
+ "§c[BOSS] Scarf§r§f: Don't get too excited though." -> {
+ floor2secondPhase = true
+ floor2secondPhaseSpawnTime = System.currentTimeMillis() + 6_300
+ }
+
+ "§c[BOSS] Scarf§r§f: Whatever..." -> {
+ floor2secondPhase = false
+ }
+
+ //F3
+ "§c[BOSS] The Professor§r§f: I was burdened with terrible news recently..." -> {
+ floor3GuardianShield = true
+ floor3GuardianShieldSpawnTime = System.currentTimeMillis() + 16_400
+ }
+
+ "§c[BOSS] The Professor§r§f: Even if you took my barrier down, I can still fight." -> {
+ floor3GuardianShield = false
+ }
+
+ "§c[BOSS] The Professor§r§f: Oh? You found my Guardians one weakness?" -> {
+ floor3Professor = true
+ floor3ProfessorSpawnTime = System.currentTimeMillis() + 10_300
+ }
+
+ "§c[BOSS] The Professor§r§f: I see. You have forced me to use my ultimate technique." -> {
+ floor3Professor = false
+
+ floor3ProfessorGuardianPrepare = true
+ floor3ProfessorGuardianPrepareSpawnTime = System.currentTimeMillis() + 10_500
+ }
+
+ "§c[BOSS] The Professor§r§f: The process is irreversible, but I'll be stronger than a Wither now!" -> {
+ floor3ProfessorGuardian = true
+ }
+
+ "§c[BOSS] The Professor§r§f: What?! My Guardian power is unbeatable!" -> {
+ floor3ProfessorGuardian = false
+ }
+
+
+ //F5
+ "§c[BOSS] Livid§r§f: I respect you for making it to here, but I'll be your undoing." -> {
+ floor5lividEntity = findLivid()
+ }
+
+ //F6
+ "§c[BOSS] Sadan§r§f: ENOUGH!" -> {
+ floor6Giants = true
+ floor6GiantsSpawnTime = System.currentTimeMillis() + 7_400
+ }
+
+ "§c[BOSS] Sadan§r§f: You did it. I understand now, you have earned my respect." -> {
+ floor6Giants = false
+ floor6Sadan = true
+ floor6SadanSpawnTime = System.currentTimeMillis() + 32_500
+ }
+
+ "§c[BOSS] Sadan§r§f: NOOOOOOOOO!!! THIS IS IMPOSSIBLE!!" -> {
+ floor6Sadan = false
+ }
+ }
+
+ if (message.matchRegex("§c\\[BOSS] (.*) Livid§r§f: Impossible! How did you figure out which one I was\\?!")) {
+ floor5lividEntity = null
+ }
+ }
+
+ fun handleNewEntity(entity: Entity) {
+ if (floor3ProfessorGuardian) {
+ if (entity is EntityGuardian) {
+ if (floor3ProfessorGuardianEntity == null) {
+ floor3ProfessorGuardianEntity = entity
+ floor3ProfessorGuardianPrepare = false
+ }
+ }
+ }
+ }
+
+ private fun findGuardians() {
+ guardians.clear()
+
+ for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) {
+ if (entity is EntityGuardian) {
+
+ val maxHealth = entity.baseMaxHealth.toInt()
+
+ //F3
+ if (maxHealth == 1_000_000 || maxHealth == 1_200_000) {
+ guardians.add(entity)
+ }
+
+ //F3 Derpy
+ if (maxHealth == 2_000_000 || maxHealth == 2_400_000) {
+ guardians.add(entity)
+ }
+
+ //M3
+ if (maxHealth == 240_000_000 || maxHealth == 280_000_000) {
+ guardians.add(entity)
+ }
+
+ //M3 Derpy
+ if (maxHealth == 120_000_000 || maxHealth == 140_000_000) {
+ guardians.add(entity)
+ }
+ }
+ }
+ }
+
+ private fun findLivid(): EntityOtherPlayerMP? {
+ for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "Livid ") {
+ return entity
+ }
+ }
+ }
+
+ return null
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/lorenz/mod/dungeon/damageindicator/EntityData.kt b/src/main/java/at/lorenz/mod/dungeon/damageindicator/EntityData.kt
new file mode 100644
index 000000000..4d60626fc
--- /dev/null
+++ b/src/main/java/at/lorenz/mod/dungeon/damageindicator/EntityData.kt
@@ -0,0 +1,6 @@
+package at.lorenz.mod.dungeon.damageindicator
+
+import at.lorenz.mod.utils.LorenzColor
+import net.minecraft.entity.EntityLivingBase
+
+class EntityData(val entity: EntityLivingBase, val text: String, val color: LorenzColor, val time: Long, val ignoreBlocks: Boolean, val delayedStart: Long) \ No newline at end of file
diff --git a/src/main/java/at/lorenz/mod/misc/HypixelData.kt b/src/main/java/at/lorenz/mod/misc/HypixelData.kt
index 9d83e2679..e7c5a02f6 100644
--- a/src/main/java/at/lorenz/mod/misc/HypixelData.kt
+++ b/src/main/java/at/lorenz/mod/misc/HypixelData.kt
@@ -1,8 +1,6 @@
package at.lorenz.mod.misc
-import at.lorenz.mod.events.DungeonEnterEvent
import at.lorenz.mod.events.PacketEvent
-import at.lorenz.mod.utils.LorenzUtils
import net.minecraft.client.Minecraft
import net.minecraft.network.play.server.S38PacketPlayerListItem
import net.minecraft.network.play.server.S3DPacketDisplayScoreboard
diff --git a/src/main/java/at/lorenz/mod/utils/LorenzUtils.kt b/src/main/java/at/lorenz/mod/utils/LorenzUtils.kt
index 2295fa513..b36fbb94e 100644
--- a/src/main/java/at/lorenz/mod/utils/LorenzUtils.kt
+++ b/src/main/java/at/lorenz/mod/utils/LorenzUtils.kt
@@ -2,6 +2,8 @@ package at.lorenz.mod.utils
import at.lorenz.mod.misc.HypixelData
import net.minecraft.client.Minecraft
+import net.minecraft.entity.EntityLivingBase
+import net.minecraft.entity.SharedMonsterAttributes
import net.minecraft.util.ChatComponentText
import org.intellij.lang.annotations.Language
import java.text.SimpleDateFormat
@@ -109,4 +111,7 @@ object LorenzUtils {
}
fun String.between(start: String, end: String): String = this.split(start, end)[1]
+
+ val EntityLivingBase.baseMaxHealth: Double
+ get() = this.getEntityAttribute(SharedMonsterAttributes.maxHealth).baseValue
} \ No newline at end of file
diff --git a/src/main/java/at/lorenz/mod/utils/RenderUtils.kt b/src/main/java/at/lorenz/mod/utils/RenderUtils.kt
index 17532c613..7acd5b42b 100644
--- a/src/main/java/at/lorenz/mod/utils/RenderUtils.kt
+++ b/src/main/java/at/lorenz/mod/utils/RenderUtils.kt
@@ -9,6 +9,7 @@ import net.minecraft.inventory.Slot
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.MathHelper
import net.minecraft.util.ResourceLocation
+import net.minecraft.util.Vec3
import net.minecraftforge.client.event.RenderWorldLastEvent
import org.lwjgl.opengl.GL11
import java.awt.Color
@@ -309,4 +310,46 @@ object RenderUtils {
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f)
GlStateManager.popMatrix()
}
+
+ /**
+ * @author Mojang
+ */
+ fun drawLabel(
+ pos: Vec3,
+ text: String,
+ color: Color,
+ partialTicks: Float,
+ shadow: Boolean = false,
+ scale: Float = 1f
+ ) {
+ var mc = Minecraft.getMinecraft()
+ val player = mc.thePlayer
+ val x =
+ pos.xCoord - player.lastTickPosX + (pos.xCoord - player.posX - (pos.xCoord - player.lastTickPosX)) * partialTicks
+ val y =
+ pos.yCoord - player.lastTickPosY + (pos.yCoord - player.posY - (pos.yCoord - player.lastTickPosY)) * partialTicks
+ val z =
+ pos.zCoord - player.lastTickPosZ + (pos.zCoord - player.posZ - (pos.zCoord - player.lastTickPosZ)) * partialTicks
+ val renderManager = mc.renderManager
+ val f1 = 0.0266666688
+ val width = mc.fontRendererObj.getStringWidth(text) / 2
+ GlStateManager.pushMatrix()
+ GlStateManager.translate(x, y, z)
+ GL11.glNormal3f(0f, 1f, 0f)
+ GlStateManager.rotate(-renderManager.playerViewY, 0f, 1f, 0f)
+ GlStateManager.rotate(renderManager.playerViewX, 1f, 0f, 0f)
+ GlStateManager.scale(-f1, -f1, -f1)
+ GlStateManager.scale(scale, scale, scale)
+ GlStateManager.enableBlend()
+ GlStateManager.disableLighting()
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0)
+ GlStateManager.enableTexture2D()
+ mc.fontRendererObj.drawString(text, (-width).toFloat(), 0f, color.rgb, shadow)
+ GlStateManager.disableBlend()
+ GlStateManager.popMatrix()
+ }
+
+ fun interpolate(currentValue: Double, lastValue: Double, multiplier: Float): Double {
+ return lastValue + (currentValue - lastValue) * multiplier
+ }
} \ No newline at end of file