summaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/damageindicator
diff options
context:
space:
mode:
authorLorenz <lo.scherf@gmail.com>2022-08-07 03:35:42 +0200
committerLorenz <lo.scherf@gmail.com>2022-08-07 03:35:42 +0200
commit336266ad88396d8df795f7a429174c5a010c1658 (patch)
tree8f74b66b4bfea3feb4603f0e631344a126e43d41 /src/main/java/at/hannibal2/skyhanni/damageindicator
parentbbe0216a3ace0781e06215a96428bb4b027e9730 (diff)
downloadskyhanni-336266ad88396d8df795f7a429174c5a010c1658.tar.gz
skyhanni-336266ad88396d8df795f7a429174c5a010c1658.tar.bz2
skyhanni-336266ad88396d8df795f7a429174c5a010c1658.zip
moved damage indicator classes outside of dungeon
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/damageindicator')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/damageindicator/BossDamageIndicator.kt349
-rw-r--r--src/main/java/at/hannibal2/skyhanni/damageindicator/BossFinder.kt455
-rw-r--r--src/main/java/at/hannibal2/skyhanni/damageindicator/BossType.kt21
-rw-r--r--src/main/java/at/hannibal2/skyhanni/damageindicator/EntityData.kt18
-rw-r--r--src/main/java/at/hannibal2/skyhanni/damageindicator/EntityResult.kt8
5 files changed, 851 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/damageindicator/BossDamageIndicator.kt b/src/main/java/at/hannibal2/skyhanni/damageindicator/BossDamageIndicator.kt
new file mode 100644
index 000000000..09032b6c3
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/damageindicator/BossDamageIndicator.kt
@@ -0,0 +1,349 @@
+package at.hannibal2.skyhanni.damageindicator
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.dungeon.DungeonData
+import at.hannibal2.skyhanni.events.DamageIndicatorFinalBossEvent
+import at.hannibal2.skyhanni.events.LorenzChatEvent
+import at.hannibal2.skyhanni.utils.*
+import at.hannibal2.skyhanni.utils.LorenzUtils.baseMaxHealth
+import net.minecraft.client.Minecraft
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.entity.EntityLivingBase
+import net.minecraft.entity.monster.EntityEnderman
+import net.minecraft.util.Vec3
+import net.minecraftforge.client.event.RenderWorldLastEvent
+import net.minecraftforge.event.entity.EntityJoinWorldEvent
+import net.minecraftforge.event.world.WorldEvent
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.math.max
+
+class BossDamageIndicator {
+
+ var data = mutableMapOf<UUID, EntityData>()
+ private var bossFinder: BossFinder? = null
+ private val decimalFormat = DecimalFormat("0.0")
+ private val maxHealth = mutableMapOf<UUID, Int>()
+
+ @SubscribeEvent
+ fun onWorldLoad(event: WorldEvent.Load) {
+ bossFinder = BossFinder()
+ data.clear()
+ }
+
+ @SubscribeEvent(receiveCanceled = true)
+ fun onChatMessage(event: LorenzChatEvent) {
+ bossFinder?.handleChat(event.message)
+ }
+
+ @SubscribeEvent
+ fun onWorldRender(event: RenderWorldLastEvent) {
+ if (!SkyHanniMod.feature.misc.bossDamageIndicator) return
+
+ GlStateManager.disableDepth()
+ GlStateManager.disableCull()
+
+ val player = Minecraft.getMinecraft().thePlayer
+
+ for (uuid in data.filter { System.currentTimeMillis() > it.value.timeLastTick + 100 }.map { it.key }) {
+ data.remove(uuid)
+ }
+
+ for (data in data.values) {
+ if (!data.ignoreBlocks) {
+ if (!player.canEntityBeSeen(data.entity)) continue
+ }
+ if (data.hidden) 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 onTickEvent(event: TickEvent.ClientTickEvent) {
+ if (!LorenzUtils.inSkyblock) return
+ for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) {
+ if (entity is EntityLivingBase) {
+ checkEntity(entity)
+ }
+ }
+ }
+
+ private fun checkEntity(entity: EntityLivingBase) {
+ try {
+ val entityData = grabData(entity) ?: return
+ if (LorenzUtils.inDungeons) {
+ checkFinalBoss(entityData.finalDungeonBoss, entity.entityId)
+ }
+
+ val biggestHealth = getMaxHealthFor(entity)
+
+ val health = entity.health.toInt()
+ val maxHealth: Int
+
+ if (biggestHealth == 0) {
+ val currentMaxHealth = entity.baseMaxHealth.toInt()
+ maxHealth = max(currentMaxHealth, health)
+ setMaxHealth(entity, maxHealth)
+ } else {
+ maxHealth = biggestHealth
+ }
+
+ var calcHealth = health
+ var calcMaxHealth = maxHealth
+ var extraPrefix = ""
+
+ if (DungeonData.isOneOf("F4")) {
+ calcHealth = when (health) {
+ 300_000 -> 4
+ 222_000 -> 3
+ 144_000 -> 2
+ 66_000 -> 1
+ else -> {
+ LorenzUtils.error("Unexpected health of thorn in F4! ($health)")
+ return
+ }
+ }
+ calcMaxHealth = 4
+ //TODO add m4 support
+// } else if (DungeonData.isOneOf("M4")) {
+// calcHealth = when (health) {
+// 300_000 -> 4
+// 222_000 -> 3
+// 144_000 -> 2
+// 66_000 -> 1
+// else -> {
+// LorenzUtils.error("Unexpected health of thorn in F4! ($health)")
+// return
+// }
+// }
+// calcMaxHealth = 4
+ }
+
+
+ if (entityData.bossType == BossType.END_ENDERMAN_SLAYER) {
+ //custom prefix and health for the four different ender slayers
+ when (maxHealth) {
+ 300_000 -> {
+ calcMaxHealth = 100_000
+ if (health > 200_000) {
+ calcHealth -= 200_000
+ extraPrefix = "1/3"
+ } else if (health > 100_000) {
+ calcHealth -= 100_000
+ extraPrefix = "2/3"
+ } else {
+ calcHealth = health
+ extraPrefix = "3/3"
+ }
+ }
+ 15_000_000 -> {
+ calcMaxHealth = 5_000_000
+ if (health > 10_000_000) {
+ extraPrefix = "1/3"
+ calcHealth -= 10_000_000
+ } else if (health > 5_000_000) {
+ calcHealth -= 5_000_000
+ extraPrefix = "2/3"
+ } else {
+ calcHealth = health
+ extraPrefix = "3/3"
+ }
+ }
+ 66_666_666 -> {
+ calcMaxHealth = 22_222_222
+ if (health > 44_444_444) {
+ calcHealth -= 44_444_444
+ extraPrefix = "1/3"
+ } else if (health > 22_222_222) {
+ calcHealth -= 22_222_222
+ extraPrefix = "2/3"
+ } else {
+ calcHealth = health
+ extraPrefix = "3/3"
+ }
+
+ }
+ 300_000_000 -> {
+ calcMaxHealth = 50_000_000
+ if (health > 250_000_000) {
+ calcHealth -= 250_000_000
+ extraPrefix = "1/6"
+ } else if (health > 200_000_000) {
+ calcHealth -= 200_000_000
+ extraPrefix = "2/6"
+ } else if (health > 150_000_000) {
+ calcHealth -= 150_000_000
+ extraPrefix = "3/6"
+ } else if (health > 100_000_000) {
+ calcHealth -= 100_000_000
+ extraPrefix = "4/6"
+ } else if (health > 50_000_000) {
+ calcHealth -= 50_000_000
+ extraPrefix = "5/6"
+ } else {
+ calcHealth = health
+ extraPrefix = "6/6"
+ }
+ }
+ else -> {
+ //TODO this is a workaround, find a sweet solution pls?
+ if (!entityData.hidden) {
+ LorenzUtils.warning("§c[SkyHanni] Unknown max enderman health: $maxHealth")
+ entityData.hidden = true
+ }
+
+ }
+ }
+
+ //Hides the damage indicator when in hit phase or in laser phase
+ if (entity is EntityEnderman) {
+ var hidden = false
+ if (entity.hasNameTagWith(0, 3, 0, " Hit")) {
+ hidden = true
+ }
+ if (entity.ridingEntity != null) {
+ hidden = true
+ }
+ entityData.hidden = hidden
+ }
+ }
+
+ //See through blocks when the barbarian duke stands on the platform and the player is below
+ if (entityData.bossType == BossType.NETHER_BARBARIAN_DUKE) {
+ val location = entity.getLorenzVec()
+ val y = location.y
+ var ignoreBlocks = false
+ val distance = Minecraft.getMinecraft().thePlayer.getLorenzVec().distance(location)
+ if (distance < 10) {
+ if (y == 117.0) {
+ ignoreBlocks = true
+ }
+ }
+ entityData.ignoreBlocks = ignoreBlocks
+ }
+
+ val percentage = calcHealth.toDouble() / calcMaxHealth.toDouble()
+ 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
+ }
+
+ if (data.containsKey(entity.uniqueID)) {
+ val lastHealth = data[entity.uniqueID]!!.lastHealth
+ val diff = lastHealth - health
+ if (diff != 0) {
+ val bossType = entityData.bossType
+ if (bossType == BossType.NETHER_ASHFANG) {
+ if (diff < 0) {
+ val oldHealth = lastHealth / 1_000_000
+ val newHealth = health / 1_000_000
+ LorenzUtils.chat("§e§lAshfang healing: ${oldHealth}M -> ${newHealth}M")
+ }
+ } else if (bossType == BossType.NETHER_BLADESOUL) {
+ if (diff < 0) {
+ val oldHealth = lastHealth / 1_000_000
+ val newHealth = health / 1_000_000
+ val oldFormat = NumberUtil.format(oldHealth)
+ val newFormat = NumberUtil.format(newHealth)
+ LorenzUtils.chat("§e§lBladesoul healing: §a+12.5m §e(${oldFormat}M -> ${newFormat}M)")
+ }
+ } else if (bossType == BossType.NETHER_BARBARIAN_DUKE) {
+ if (diff < 0) {
+ val oldHealth = lastHealth / 1_000_000
+ val newHealth = health / 1_000_000
+ val oldFormat = NumberUtil.format(oldHealth)
+ val newFormat = NumberUtil.format(newHealth)
+ LorenzUtils.chat("§e§lBarbarian Duke healing: §a+12.5m §e(${oldFormat}M -> ${newFormat}M)")
+ }
+ //TODO check for revive buffs
+// } else {
+// LorenzUtils.chat("$bossType diff: $diff")
+ }
+ }
+ }
+
+ entityData.lastHealth = health
+ entityData.text = extraPrefix + " " + NumberUtil.format(calcHealth)
+ entityData.color = color
+ entityData.timeLastTick = System.currentTimeMillis()
+ data[entity.uniqueID] = entityData
+
+ } catch (e: Throwable) {
+ e.printStackTrace()
+ }
+ }
+
+ private fun grabData(entity: EntityLivingBase): EntityData? {
+ if (data.contains(entity.uniqueID)) return data[entity.uniqueID]
+
+ val entityResult = bossFinder?.tryAdd(entity) ?: return null
+ return EntityData(
+ entity,
+ entityResult.ignoreBlocks,
+ entityResult.delayedStart,
+ entityResult.finalDungeonBoss,
+ entityResult.bossType
+ )
+ }
+
+ private fun checkFinalBoss(finalBoss: Boolean, id: Int) {
+ if (finalBoss) {
+ DamageIndicatorFinalBossEvent(id).postAndCatch()
+ }
+ }
+
+ private fun setMaxHealth(entity: EntityLivingBase, currentMaxHealth: Int) {
+ maxHealth[entity.uniqueID!!] = currentMaxHealth
+ }
+
+ private fun getMaxHealthFor(entity: EntityLivingBase): Int {
+ return maxHealth.getOrDefault(entity.uniqueID!!, 0)
+ }
+
+ @SubscribeEvent
+ fun onWorldRender(event: EntityJoinWorldEvent) {
+ bossFinder?.handleNewEntity(event.entity)
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/damageindicator/BossFinder.kt b/src/main/java/at/hannibal2/skyhanni/damageindicator/BossFinder.kt
new file mode 100644
index 000000000..4576afb73
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/damageindicator/BossFinder.kt
@@ -0,0 +1,455 @@
+package at.hannibal2.skyhanni.damageindicator
+
+import at.hannibal2.skyhanni.dungeon.DungeonData
+import at.hannibal2.skyhanni.test.LorenzTest
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.baseMaxHealth
+import at.hannibal2.skyhanni.utils.LorenzUtils.matchRegex
+import at.hannibal2.skyhanni.utils.LorenzVec
+import at.hannibal2.skyhanni.utils.getLorenzVec
+import net.minecraft.client.Minecraft
+import net.minecraft.client.entity.EntityOtherPlayerMP
+import net.minecraft.entity.Entity
+import net.minecraft.entity.EntityLiving
+import net.minecraft.entity.EntityLivingBase
+import net.minecraft.entity.boss.EntityDragon
+import net.minecraft.entity.boss.EntityWither
+import net.minecraft.entity.item.EntityArmorStand
+import net.minecraft.entity.monster.*
+import net.minecraft.util.AxisAlignedBB
+import java.util.*
+
+class BossFinder {
+
+ //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
+ private var floor5lividEntitySpawnTime = 0L
+
+ //F6
+ private var floor6Giants = false
+ private var floor6GiantsSpawnTime = 0L
+ private var floor6GiantsSeparateDelay = mutableMapOf<UUID, Long>()
+ private var floor6Sadan = false
+ private var floor6SadanSpawnTime = 0L
+
+ internal fun tryAdd(entity: EntityLivingBase): EntityResult? {
+ if (LorenzUtils.inDungeons) {
+ if (DungeonData.isOneOf("F1", "M1")) {
+ if (floor1bonzo1) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "Bonzo ") {
+ return EntityResult(floor1bonzo1SpawnTime)
+ }
+ }
+ }
+ if (floor1bonzo2) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "Bonzo ") {
+ return EntityResult(floor1bonzo2SpawnTime, finalDungeonBoss = 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) {
+ return EntityResult(floor2summons1SpawnTime)
+ } else {
+ floor2summonsDiedOnce.add(entity)
+ }
+ }
+ }
+ if (floor2secondPhase) {
+ return EntityResult(floor2secondPhaseSpawnTime)
+ }
+ }
+ }
+
+ 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) {
+ return EntityResult(floor2secondPhaseSpawnTime, finalDungeonBoss = 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)) {
+ return EntityResult(floor3GuardianShieldSpawnTime, true)
+ }
+ }
+ }
+
+ if (floor3Professor) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "The Professor") {
+ return EntityResult(
+ floor3ProfessorSpawnTime,
+ floor3ProfessorSpawnTime + 1_000 > System.currentTimeMillis()
+ )
+ }
+ }
+ }
+ if (floor3ProfessorGuardianPrepare) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "The Professor") {
+ return EntityResult(floor3ProfessorGuardianPrepareSpawnTime, true)
+ }
+ }
+ }
+
+ if (entity is EntityGuardian) {
+ if (floor3ProfessorGuardian) {
+ if (entity == floor3ProfessorGuardianEntity) {
+ return EntityResult(finalDungeonBoss = true)
+ }
+ }
+ }
+ }
+
+ if (DungeonData.isOneOf("F4", "M4")) {
+ if (entity is EntityGhast) {
+ val health = LorenzUtils.formatDouble(entity.health.toDouble())
+ //TODO add m4 support
+ LorenzTest.enabled = true
+ LorenzTest.text = "thorn has $health hp!"
+ return EntityResult(ignoreBlocks = true, finalDungeonBoss = true)
+ }
+
+ }
+
+ if (DungeonData.isOneOf("F5", "M5")) {
+ if (entity is EntityOtherPlayerMP) {
+ if (entity == floor5lividEntity) {
+ return EntityResult(floor5lividEntitySpawnTime, true, finalDungeonBoss = true)
+ }
+ }
+ }
+
+ if (DungeonData.isOneOf("F6", "M6")) {
+ if (entity is EntityGiantZombie && !entity.isInvisible) {
+ if (floor6Giants && entity.posY > 68) {
+ val extraDelay = checkExtraF6GiantsDelay(entity)
+ return EntityResult(
+ floor6GiantsSpawnTime + extraDelay,
+ floor6GiantsSpawnTime + extraDelay + 1_000 > System.currentTimeMillis()
+ )
+ }
+
+ if (floor6Sadan) {
+ return EntityResult(floor6SadanSpawnTime, finalDungeonBoss = true)
+ }
+ }
+ }
+ } else {
+
+ if (entity is EntityBlaze) {
+ if (entity.name != "Dinnerbone") {
+ if (entity.hasNameTagWith(0, 2, 0, "§e﴾ §8[§7Lv200§8] §l§8§lAshfang§r ")) {
+ if (entity.baseMaxHealth == 50_000_000.0) {
+ return EntityResult(bossType = BossType.NETHER_ASHFANG)
+ }
+ }
+ }
+ }
+ if (entity is EntitySkeleton) {
+ if (entity.hasNameTagWith(0, 5, 0, "§e﴾ §8[§7Lv200§8] §l§8§lBladesoul§r ")) {
+ return EntityResult(bossType = BossType.NETHER_BLADESOUL)
+ }
+ }
+ if (entity is EntityOtherPlayerMP) {
+ if (entity.name == "Mage Outlaw") {
+ return EntityResult(bossType = BossType.NETHER_MAGE_OUTLAW)
+ }
+ if (entity.name == "DukeBarb ") {
+ return EntityResult(bossType = BossType.NETHER_BARBARIAN_DUKE)
+ }
+ }
+
+ //TODO testing and make right and so
+ if (entity is EntityWither) {
+ if (entity.hasNameTagWith(0, 4, 0, "§8[§7Lv100§8] §c§5Vanquisher§r ")) {
+ return EntityResult(bossType = BossType.NETHER_VANQUISHER)
+ }
+ }
+
+ if (entity is EntityEnderman) {
+ if (entity.hasNameTagWith(0, 3, 0, "§c☠ §bVoidgloom Seraph ")) {
+ return EntityResult(bossType = BossType.END_ENDERMAN_SLAYER)
+ }
+ }
+
+ if (entity is EntityDragon) {
+ //TODO testing and make right and so
+ return EntityResult(bossType = BossType.END_ENDER_DRAGON)
+ }
+
+ if (entity is EntityIronGolem) {
+ //TODO testing
+ if (entity.hasNameTagWith(0, 3, 0, "§e﴾ §8[§7Lv100§8] §lEndstone Protector§r ")) {
+ return EntityResult(bossType = BossType.END_ENDSTONE_PROTECTOR, ignoreBlocks = true)
+ }
+ }
+
+ if (entity is EntityZombie) {
+ if (entity.hasNameTagWith(0, 2, 0, "§c☠ §fAtoned Horror ")) {
+ if (entity.baseMaxHealth == 10_000_000.0) {
+ return EntityResult(bossType = BossType.HUB_REVENANT_HORROR)
+ }
+ }
+ }
+ }
+
+ return null
+ }
+
+ private fun checkExtraF6GiantsDelay(entity: EntityGiantZombie): Long {
+ val uuid = entity.uniqueID
+
+ if (floor6GiantsSeparateDelay.contains(uuid)) {
+ return floor6GiantsSeparateDelay[uuid]!!
+ }
+
+ val middle = LorenzVec(-8, 0, 56)
+
+ val loc = entity.getLorenzVec()
+
+ var pos = 0
+
+ //first
+ if (loc.x > middle.x && loc.z > middle.z) {
+ pos = 2
+ }
+
+ //second
+ if (loc.x > middle.x && loc.z < middle.z) {
+ pos = 3
+ }
+
+ //third
+ if (loc.x < middle.x && loc.z < middle.z) {
+ pos = 0
+ }
+
+ //fourth
+ if (loc.x < middle.x && loc.z > middle.z) {
+ pos = 1
+ }
+
+ val extraDelay = 900L * pos
+ floor6GiantsSeparateDelay[uuid] = extraDelay
+
+ return extraDelay
+ }
+
+ fun handleChat(message: String) {
+ if (LorenzUtils.inDungeons) {
+ 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: This Orb you see, is Thorn, or what is left of him." -> {
+ floor5lividEntity = findLivid()
+ floor5lividEntitySpawnTime = System.currentTimeMillis() + 13_000
+ }
+
+ //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 (LorenzUtils.inDungeons) {
+ 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
+ }
+}
+
+fun EntityLiving.hasNameTagWith(x: Int, y: Int, z: Int, contains: String): Boolean {
+ val center = getLorenzVec().add(x, y, z)
+ val a = center.add(-1.6, -1.6, -1.6).toBlocPos()
+ val b = center.add(1.6, 1.6, 1.6).toBlocPos()
+ val alignedBB = AxisAlignedBB(a, b)
+ val clazz = EntityArmorStand::class.java
+ return worldObj.getEntitiesWithinAABB(clazz, alignedBB).any { it.name.contains(contains) }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/damageindicator/BossType.kt b/src/main/java/at/hannibal2/skyhanni/damageindicator/BossType.kt
new file mode 100644
index 000000000..889b0d674
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/damageindicator/BossType.kt
@@ -0,0 +1,21 @@
+package at.hannibal2.skyhanni.damageindicator
+
+enum class BossType {
+ DUNGEON,
+
+// CRIMSON_AILE_BLADESOUL,
+ NETHER_BLADESOUL,
+ NETHER_MAGMA_BOSS,
+ NETHER_ASHFANG,
+ NETHER_BARBARIAN_DUKE,
+ NETHER_MAGE_OUTLAW,
+
+ NETHER_VANQUISHER,
+
+ END_ENDSTONE_PROTECTOR,
+ END_ENDERMAN_SLAYER,
+ END_ENDER_DRAGON,
+
+ HUB_REVENANT_HORROR
+
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/damageindicator/EntityData.kt b/src/main/java/at/hannibal2/skyhanni/damageindicator/EntityData.kt
new file mode 100644
index 000000000..ffbe00a87
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/damageindicator/EntityData.kt
@@ -0,0 +1,18 @@
+package at.hannibal2.skyhanni.damageindicator
+
+import at.hannibal2.skyhanni.utils.LorenzColor
+import net.minecraft.entity.EntityLivingBase
+
+class EntityData(
+ val entity: EntityLivingBase,
+ var ignoreBlocks: Boolean,
+ val delayedStart: Long,
+ val finalDungeonBoss: Boolean,
+ val bossType: BossType = BossType.DUNGEON,
+
+ var lastHealth: Int = 0,
+ var text: String = "",
+ var color: LorenzColor = LorenzColor.DARK_GREEN,
+ var timeLastTick: Long = 0,
+ var hidden: Boolean = false
+) \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/damageindicator/EntityResult.kt b/src/main/java/at/hannibal2/skyhanni/damageindicator/EntityResult.kt
new file mode 100644
index 000000000..e2f8e9e69
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/damageindicator/EntityResult.kt
@@ -0,0 +1,8 @@
+package at.hannibal2.skyhanni.damageindicator
+
+class EntityResult(
+ val delayedStart: Long = -1L,
+ val ignoreBlocks: Boolean = false,
+ val finalDungeonBoss: Boolean = false,
+ val bossType: BossType = BossType.DUNGEON,
+) \ No newline at end of file