aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/items
diff options
context:
space:
mode:
authorLorenz <ESs95s3P5z8Pheb>2022-07-14 12:06:07 +0200
committerLorenz <ESs95s3P5z8Pheb>2022-07-14 12:06:07 +0200
commita5c540d977a3510812cac7fac340fe17e7d10983 (patch)
treedbbe5b208e6871378a10868d1206d1d78beeb950 /src/main/java/at/hannibal2/skyhanni/items
parentd6c99ed30a2b1cb228b2fdc3d3178cf1f369dc53 (diff)
downloadskyhanni-a5c540d977a3510812cac7fac340fe17e7d10983.tar.gz
skyhanni-a5c540d977a3510812cac7fac340fe17e7d10983.tar.bz2
skyhanni-a5c540d977a3510812cac7fac340fe17e7d10983.zip
renamed mod to SkyHanni
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/items')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/items/HideNotClickableItems.kt440
-rw-r--r--src/main/java/at/hannibal2/skyhanni/items/ItemDisplayOverlayFeatures.kt107
-rw-r--r--src/main/java/at/hannibal2/skyhanni/items/abilitycooldown/ItemAbilityCooldown.kt197
-rw-r--r--src/main/java/at/hannibal2/skyhanni/items/abilitycooldown/WitherImpactDetection.kt65
4 files changed, 809 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/items/HideNotClickableItems.kt b/src/main/java/at/hannibal2/skyhanni/items/HideNotClickableItems.kt
new file mode 100644
index 000000000..dd533b3d2
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/items/HideNotClickableItems.kt
@@ -0,0 +1,440 @@
+package at.hannibal2.skyhanni.items
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.bazaar.BazaarApi
+import at.hannibal2.skyhanni.events.GuiContainerEvent
+import at.hannibal2.skyhanni.utils.ItemUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.cleanName
+import at.hannibal2.skyhanni.utils.ItemUtils.getLore
+import at.hannibal2.skyhanni.utils.LorenzColor
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.removeColorCodes
+import at.hannibal2.skyhanni.utils.RenderUtils.highlight
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.inventory.GuiChest
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.inventory.ContainerChest
+import net.minecraft.item.ItemStack
+import net.minecraftforge.event.entity.player.ItemTooltipEvent
+import net.minecraftforge.fml.common.eventhandler.EventPriority
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import org.lwjgl.opengl.GL11
+
+class HideNotClickableItems {
+
+ private var hideReason = ""
+
+ private var lastClickTime = 0L
+ private var bypassUntil = 0L
+
+ @SubscribeEvent
+ fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) {
+ if (!LorenzUtils.inSkyblock) return
+ if (isDisabled()) return
+ if (event.gui !is GuiChest) return
+ val guiChest = event.gui
+ val chest = guiChest.inventorySlots as ContainerChest
+ val chestName = chest.lowerChestInventory.displayName.unformattedText.trim()
+
+ val lightingState = GL11.glIsEnabled(GL11.GL_LIGHTING)
+ GlStateManager.disableLighting()
+ GlStateManager.color(1f, 1f, 1f, 1f)
+
+ for (slot in chest.inventorySlots) {
+ if (slot == null) continue
+
+ if (slot.slotNumber == slot.slotIndex) continue
+ if (slot.stack == null) continue
+
+ if (hide(chestName, slot.stack)) {
+ slot highlight LorenzColor.GRAY
+ }
+ }
+
+ if (lightingState) GlStateManager.enableLighting()
+ }
+
+ @SubscribeEvent
+ fun onDrawSlot(event: GuiContainerEvent.DrawSlotEvent.Pre) {
+ if (isDisabled()) return
+ if (event.gui !is GuiChest) return
+ val guiChest = event.gui
+ val chest = guiChest.inventorySlots as ContainerChest
+ val chestName = chest.lowerChestInventory.displayName.unformattedText.trim()
+
+ val slot = event.slot
+ if (slot.slotNumber == slot.slotIndex) return
+ if (slot.stack == null) return
+
+ val stack = slot.stack
+
+ if (hide(chestName, stack)) {
+ event.isCanceled = true
+ }
+ }
+
+ @SubscribeEvent(priority = EventPriority.LOWEST)
+ fun onTooltip(event: ItemTooltipEvent) {
+ if (isDisabled()) return
+ if (event.toolTip == null) return
+ val guiChest = Minecraft.getMinecraft().currentScreen
+ if (guiChest !is GuiChest) return
+ val chest = guiChest.inventorySlots as ContainerChest
+ val chestName = chest.lowerChestInventory.displayName.unformattedText.trim()
+
+ val stack = event.itemStack
+ if (ItemUtils.getItemsInOpenChest().contains(stack)) return
+
+ if (hide(chestName, stack)) {
+ val first = event.toolTip[0]
+ event.toolTip.clear()
+ event.toolTip.add("§7" + first.removeColorCodes())
+ event.toolTip.add("")
+ if (hideReason == "") {
+ event.toolTip.add("§4No hide reason!")
+ LorenzUtils.warning("Not hide reason for not clickable item!")
+ } else {
+ event.toolTip.add("§c$hideReason")
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) {
+ if (isDisabled()) return
+ if (event.gui !is GuiChest) return
+ val guiChest = event.gui
+ val chest = guiChest.inventorySlots as ContainerChest
+ val chestName = chest.lowerChestInventory.displayName.unformattedText.trim()
+
+ val slot = event.slot ?: return
+
+ if (slot.slotNumber == slot.slotIndex) return
+ if (slot.stack == null) return
+
+ val stack = slot.stack
+
+ if (hide(chestName, stack)) {
+ event.isCanceled = true
+
+ if (System.currentTimeMillis() > lastClickTime + 5_000) {
+ lastClickTime = System.currentTimeMillis()
+ }
+ return
+ }
+ }
+
+ private fun isDisabled(): Boolean {
+ if (bypassUntil > System.currentTimeMillis()) return true
+
+ return !SkyHanniMod.feature.items.hideNotClickableItems
+ }
+
+ private fun hide(chestName: String, stack: ItemStack): Boolean {
+ hideReason = ""
+ return when {
+ hideNpcSell(chestName, stack) -> true
+ hideChestBackpack(chestName, stack) -> true
+ hideSalvage(chestName, stack) -> true
+ hideTrade(chestName, stack) -> true
+ hideBazaarOrAH(chestName, stack) -> true
+ hideAccessoryBag(chestName, stack) -> true
+ hideSackOfSacks(chestName, stack) -> true
+ hideFishingBag(chestName, stack) -> true
+ hidePotionBag(chestName, stack) -> true
+
+ else -> false
+ }
+ }
+
+ private fun hidePotionBag(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Potion Bag")) return false
+
+ val name = stack.cleanName()
+ if (isSkyBlockMenuItem(name)) {
+ hideReason = "The SkyBlock Menu cannot be put into the potion bag!"
+ return true
+ }
+
+ if (stack.cleanName().endsWith(" Potion")) return false
+
+ hideReason = "This item is not a potion!"
+ return true
+ }
+
+ private fun hideFishingBag(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Fishing Bag")) return false
+
+ val name = stack.cleanName()
+ if (isSkyBlockMenuItem(name)) {
+ hideReason = "The SkyBlock Menu cannot be put into the fishing bag!"
+ return true
+ }
+
+ if (stack.cleanName().endsWith(" Bait")) return false
+
+ hideReason = "This item is not a fishing bait!"
+ return true
+ }
+
+ private fun hideSackOfSacks(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Sack of Sacks")) return false
+
+ val name = stack.cleanName()
+ if (ItemUtils.isSack(name)) return false
+ if (isSkyBlockMenuItem(name)) return false
+
+ hideReason = "This item is not a sack!"
+ return true
+ }
+
+ private fun hideAccessoryBag(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Accessory Bag")) return false
+
+ if (stack.getLore().any { it.contains("ACCESSORY") }) return false
+ if (isSkyBlockMenuItem(stack.cleanName())) return false
+
+ hideReason = "This item is not an accessory!"
+ return true
+ }
+
+ private fun hideTrade(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("You ")) return false
+
+ if (ItemUtils.isCoOpSoulBound(stack)) {
+ hideReason = "Coop-Soulbound items cannot be traded!"
+ return true
+ }
+
+ val name = stack.cleanName()
+
+ if (ItemUtils.isSack(name)) {
+ hideReason = "Sacks cannot be traded!"
+ return true
+ }
+
+ if (isSkyBlockMenuItem(name)) {
+ hideReason = "The SkyBlock Menu cannot be traded!"
+ return true
+ }
+
+ val result = when {
+ name.contains("Personal Deletor") -> true
+ name.contains("Day Crystal") -> true
+ name.contains("Night Crystal") -> true
+ name.contains("Cat Talisman") -> true
+ name.contains("Lynx Talisman") -> true
+ name.contains("Cheetah Talisman") -> true
+ else -> false
+ }
+
+ if (result) hideReason = "This item cannot be traded!"
+ return result
+ }
+
+ private fun hideNpcSell(chestName: String, stack: ItemStack): Boolean {
+ if (chestName != "Trades" && chestName != "Ophelia") return false
+
+ var name = stack.cleanName()
+ val size = stack.stackSize
+ val amountText = " x$size"
+ if (name.endsWith(amountText)) {
+ name = name.substring(0, name.length - amountText.length)
+ }
+
+ if (isSkyBlockMenuItem(name)) {
+ hideReason = "The SkyBlock Menu cannot be sold at the NPC!"
+ return true
+ }
+
+ if (!ItemUtils.isRecombobulated(stack)) {
+ when (name) {
+ "Health Potion VIII Splash Potion" -> return false
+ "Stone Button" -> return false
+ "Revive Stone" -> return false
+ "Premium Flesh" -> return false
+ "Defuse Kit" -> return false
+ "White Wool" -> return false
+ "Enchanted Wool" -> return false
+ "Training Weights" -> return false
+ "Journal Entry" -> return false
+ "Twilight Arrow Poison" -> return false
+ "Lever" -> return false
+
+ "Fairy's Galoshes" -> return false
+ }
+ if (name.endsWith("Gem Rune I")) return false
+
+ if (name.startsWith("Music Disc")) return false
+ }
+
+ hideReason = "This item should not be sold at the NPC!"
+ return true
+ }
+
+ private fun hideChestBackpack(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.contains("Ender Chest") && !chestName.contains("Backpack")) return false
+
+ val name = stack.cleanName()
+
+ if (isSkyBlockMenuItem(name)) {
+ hideReason = "The SkyBlock Menu cannot be put into the storage!"
+ return true
+ }
+ if (ItemUtils.isSack(name)) {
+ hideReason = "Sacks cannot be put into the storage!"
+ return true
+ }
+
+ val result = when {
+ name.endsWith(" New Year Cake Bag") -> true
+ name == "Nether Wart Pouch" -> true
+ name == "Basket of Seeds" -> true
+ name == "Builder's Wand" -> true
+
+ else -> false
+ }
+
+ if (result) hideReason = "Bags cannot be put into the storage!"
+ return result
+ }
+
+ private fun hideSalvage(chestName: String, stack: ItemStack): Boolean {
+ if (chestName != "Salvage Item") return false
+
+ if (ItemUtils.isRecombobulated(stack)) {
+ hideReason = "This item should not be salvaged! (Recombobulated)"
+ return true
+ }
+ for (line in stack.getLore()) {
+ if (line.contains("LEGENDARY DUNGEON")) {
+ hideReason = "This item should not be salvaged! (Legendary)"
+ return true
+ }
+ }
+
+ val name = stack.cleanName()
+
+ val armorSets = listOf(
+ "Zombie Knight",
+ "Heavy",
+ "Zombie Soldier",
+ "Skeleton Grunt",
+ "Skeleton Soldier",
+ "Zombie Commander",
+ "Skeleton Master",
+ "Sniper",
+ "Skeletor",
+ "Rotten",
+ )
+
+ val items = mutableListOf<String>()
+ for (armor in armorSets) {
+ items.add("$armor Helmet")
+ items.add("$armor Chestplate")
+ items.add("$armor Leggings")
+ items.add("$armor Boots")
+ }
+
+ items.add("Zombie Soldier Cutlass")
+ items.add("Silent Death")
+ items.add("Zombie Knight Sword")
+ items.add("Conjuring")
+ items.add("Dreadlord Sword")
+ items.add("Soulstealer Bow")
+ items.add("Machine Gun Bow")
+ items.add("Earth Shard")
+ items.add("Zombie Commander Whip")
+ items.add("Sniper Bow")
+
+ for (item in items) {
+ if (name.endsWith(" $item")) {
+ return false
+ }
+ }
+
+ if (isSkyBlockMenuItem(name)) {
+ hideReason = "The SkyBlock Menu cannot be salvaged!"
+ return true
+ }
+
+ hideReason = "This item cannot be salvaged!"
+ return true
+ }
+
+ private fun hideBazaarOrAH(chestName: String, stack: ItemStack): Boolean {
+ val bazaarInventory = BazaarApi.isBazaarInventory(chestName)
+
+ val auctionHouseInventory =
+ chestName == "Co-op Auction House" || chestName == "Auction House" || chestName == "Create BIN Auction" || chestName == "Create Auction"
+ if (!bazaarInventory && !auctionHouseInventory) return false
+
+
+ val displayName = stack.displayName
+
+ if (isSkyBlockMenuItem(displayName.removeColorCodes())) {
+ if (bazaarInventory) hideReason = "The SkyBlock Menu is not a Bazaar Product!"
+ if (auctionHouseInventory) hideReason = "The SkyBlock Menu cannot be auctioned!"
+ return true
+ }
+
+ if (bazaarInventory != BazaarApi.isBazaarItem(displayName)) {
+ if (bazaarInventory) hideReason = "This item is not a Bazaar Product!"
+ if (auctionHouseInventory) hideReason = "Bazaar Products cannot be auctioned!"
+
+ return true
+ }
+
+ if (isNotAuctionable(stack)) return true
+
+ return false
+ }
+
+ private fun isNotAuctionable(stack: ItemStack): Boolean {
+ if (ItemUtils.isCoOpSoulBound(stack)) {
+ hideReason = "Coop-Soulbound items cannot be auctioned!"
+ return true
+ }
+
+ val name = stack.cleanName()
+
+ if (ItemUtils.isSack(name)) {
+ hideReason = "Sacks cannot be auctioned!"
+ return true
+ }
+
+ val result = when {
+ name.contains("Personal Deletor") -> true
+ name.contains("Day Crystal") -> true
+ name.contains("Night Crystal") -> true
+
+ name.contains("Cat Talisman") -> true
+ name.contains("Lynx Talisman") -> true
+ name.contains("Cheetah Talisman") -> true
+
+ name.contains("Hoe of Great Tilling") -> true
+ name.contains("Hoe of Greater Tilling") -> true
+ name.contains("InfiniDirt") -> true
+ name.contains("Prismapump") -> true
+ name.contains("Mathematical Hoe Blueprint") -> true
+ name.contains("Basket of Seeds") -> true
+ name.contains("Nether Wart Pouch") -> true
+
+ name.contains("Carrot Hoe") -> true
+ name.contains("Sugar Cane Hoe") -> true
+ name.contains("Nether Warts Hoe") -> true
+ name.contains("Potato Hoe") -> true
+ name.contains("Melon Dicer") -> true
+ name.contains("Pumpkin Dicer") -> true
+ name.contains("Coco Chopper") -> true
+ name.contains("Wheat Hoe") -> true
+
+ else -> false
+ }
+
+ if (result) hideReason = "This item cannot be auctioned!"
+ return result
+ }
+
+ private fun isSkyBlockMenuItem(name: String): Boolean = name == "SkyBlock Menu (Right Click)"
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/items/ItemDisplayOverlayFeatures.kt b/src/main/java/at/hannibal2/skyhanni/items/ItemDisplayOverlayFeatures.kt
new file mode 100644
index 000000000..6f2073969
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/items/ItemDisplayOverlayFeatures.kt
@@ -0,0 +1,107 @@
+package at.hannibal2.skyhanni.items
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.GuiRenderItemEvent
+import at.hannibal2.skyhanni.utils.ItemUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.cleanName
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.between
+import at.hannibal2.skyhanni.utils.LorenzUtils.matchRegex
+import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimal
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+class ItemDisplayOverlayFeatures {
+
+ @SubscribeEvent
+ fun onRenderItemOverlayPost(event: GuiRenderItemEvent.RenderOverlayEvent.Post) {
+ val item = event.stack ?: return
+
+ if (!LorenzUtils.inSkyblock || item.stackSize != 1) return
+
+ val stackTip = getStackTip(item)
+
+ if (stackTip.isNotEmpty()) {
+ GlStateManager.disableLighting()
+ GlStateManager.disableDepth()
+ GlStateManager.disableBlend()
+ event.fr.drawStringWithShadow(
+ stackTip,
+ (event.x + 17 - event.fr.getStringWidth(stackTip)).toFloat(),
+ (event.y + 9).toFloat(),
+ 16777215
+ )
+ GlStateManager.enableLighting()
+ GlStateManager.enableDepth()
+ }
+
+ }
+
+ private fun getStackTip(item: ItemStack): String {
+ val name = item.cleanName()
+
+ if (SkyHanniMod.feature.items.displayMasterStarNumber) {
+ when (name) {
+ "First Master Star" -> return "1"
+ "Second Master Star" -> return "2"
+ "Third Master Star" -> return "3"
+ "Fourth Master Star" -> return "4"
+ "Fifth Master Star" -> return "5"
+ }
+ }
+
+ if (SkyHanniMod.feature.items.displayMasterSkullNumber) {
+ if (name.matchRegex("(.*)Master Skull - Tier .")) {
+ return name.substring(name.length - 1)
+ }
+ }
+
+ if (SkyHanniMod.feature.items.displayDungeonHeadFloor) {
+ if (name.contains("Golden ") || name.contains("Diamond ")) {
+ when {
+ name.contains("Bonzo") -> return "1"
+ name.contains("Scarf") -> return "2"
+ name.contains("Professor") -> return "3"
+ name.contains("Thorn") -> return "4"
+ name.contains("Livid") -> return "5"
+ name.contains("Sadan") -> return "6"
+ name.contains("Necron") -> return "7"
+ }
+ }
+ }
+
+ if (SkyHanniMod.feature.items.displayNewYearCakeNumber) {
+ if (name.startsWith("New Year Cake (")) {
+ return "§b" + name.between("(Year ", ")")
+ }
+ }
+
+ if (SkyHanniMod.feature.items.displayPetLevel) {
+ if (ItemUtils.isPet(name)) {
+ val level = name.between("Lvl ", "] ").toInt()
+ if (level != ItemUtils.maxPetLevel(name)) {
+ return "$level"
+ }
+ }
+ }
+
+ if (SkyHanniMod.feature.items.displaySackName) {
+ if (ItemUtils.isSack(name)) {
+ val split = name.split(" ")
+ val sackName = split[split.size - 2]
+ return (if (name.contains("Enchanted")) "§5" else "") + sackName.substring(0, 2)
+ }
+ }
+
+ if (SkyHanniMod.feature.items.displayMinionTier) {
+ if (name.contains(" Minion ")) {
+ val array = name.split(" ")
+ val last = array[array.size - 1]
+ return last.romanToDecimal().toString()
+ }
+ }
+
+ return ""
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/items/abilitycooldown/ItemAbilityCooldown.kt b/src/main/java/at/hannibal2/skyhanni/items/abilitycooldown/ItemAbilityCooldown.kt
new file mode 100644
index 000000000..708b81693
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/items/abilitycooldown/ItemAbilityCooldown.kt
@@ -0,0 +1,197 @@
+package at.hannibal2.skyhanni.items.abilitycooldown
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.GuiRenderItemEvent
+import at.hannibal2.skyhanni.events.LorenzActionBarEvent
+import at.hannibal2.skyhanni.utils.ItemUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.cleanName
+import at.hannibal2.skyhanni.utils.LorenzColor
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.between
+import net.minecraft.client.Minecraft
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.item.ItemStack
+import net.minecraftforge.common.MinecraftForge
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+
+class ItemAbilityCooldown {
+
+ var lastAbility = ""
+ var tick = 0
+ val items = mutableMapOf<ItemStack, ItemText>()
+ val witherImpactDetection = WitherImpactDetection(this)
+
+ init {
+ MinecraftForge.EVENT_BUS.register(witherImpactDetection)
+ }
+
+ fun clickWitherImpact() {
+ Ability.WITHER_IMPACT.click()
+ }
+
+ @SubscribeEvent
+ fun onActionBar(event: LorenzActionBarEvent) {
+ if (!isEnabled()) return
+
+ val message: String = event.message
+ if (message.contains(" (§6")) {
+ if (message.contains("§b) ")) {
+ val name: String = message.between(" (§6", "§b) ")
+ if (name == lastAbility) return
+ lastAbility = name
+ for (ability in Ability.values()) {
+ if (ability.abilityName == name) {
+ click(ability)
+ return
+ }
+ }
+ return
+ }
+ }
+ lastAbility = ""
+ }
+
+ private fun isEnabled(): Boolean {
+ return LorenzUtils.inSkyblock && SkyHanniMod.feature.items.itemAbilityCooldown
+ }
+
+ private fun click(ability: Ability) {
+// if (ability.isActive()) return
+ if (!ability.actionBarDetection) return
+ ability.click()
+ }
+
+ @SubscribeEvent
+ fun onTick(event: TickEvent.ClientTickEvent) {
+ if (!isEnabled()) return
+
+ tick++
+ if (tick % 2 == 0) {
+ checkHotbar()
+ }
+ }
+
+ private fun checkHotbar() {
+ items.clear()
+ for ((stack, slot) in ItemUtils.getItemsInInventoryWithSlots(true)) {
+// val inHotbar = slot in 36..43
+
+ val itemName: String = stack.cleanName()
+ val ability = hasAbility(itemName)
+ if (ability != null) {
+
+ if (ability.isOnCooldown()) {
+ val duration: Long = ability.lastClick + ability.getCooldown() - System.currentTimeMillis()
+ val color = if (duration < 600) LorenzColor.RED else LorenzColor.YELLOW
+ items[stack] = ItemText(color, ability.getDurationText(), true)
+ } else {
+ items[stack] = ItemText(LorenzColor.GREEN, "R", false)
+ }
+ }
+ }
+
+ }
+
+ @SubscribeEvent
+ fun onRenderItemOverlayPost(event: GuiRenderItemEvent.RenderOverlayEvent.Post) {
+ if (!isEnabled()) return
+
+ val item = event.stack ?: return
+ if (item.stackSize != 1) return
+
+ var stackTip = ""
+
+ val guiOpen = Minecraft.getMinecraft().currentScreen != null
+ val itemText = items.filter { it.key == item }
+ .firstNotNullOfOrNull { it.value } ?: return
+ if (guiOpen && !itemText.onCooldown) return
+
+ stackTip = itemText.color.getChatColor() + itemText.text
+
+ if (stackTip.isNotEmpty()) {
+ GlStateManager.disableLighting()
+ GlStateManager.disableDepth()
+ GlStateManager.disableBlend()
+ event.fr.drawStringWithShadow(
+ stackTip,
+ (event.x + 17 - event.fr.getStringWidth(stackTip)).toFloat(),
+ (event.y + 9).toFloat(),
+ 16777215
+ )
+ GlStateManager.enableLighting()
+ GlStateManager.enableDepth()
+ }
+ }
+
+ private fun hasAbility(itemName: String): Ability? {
+ for (ability in Ability.values()) {
+ for (name in ability.itemNames) {
+ if (itemName.contains(name)) {
+ return ability
+ }
+ }
+ }
+ return null
+ }
+
+ enum class Ability(
+ val abilityName: String,
+ val cooldownInSeconds: Long,
+ vararg val itemNames: String,
+ var lastClick: Long = 0L,
+ val actionBarDetection: Boolean = true
+ ) {
+ ATOMSPLIT("Soulcry", 4, "Atomsplit Katana", "Vorpal Katana", "Voidedge Katana"),
+ WITHER_IMPACT("Wither Impact", 5, "Hyperion", "Scylla", "Valkyrie", "Astrea", actionBarDetection = false),
+
+ HEAL_1("Small Heal", 7, "Wand of Healing"),
+ HEAL_2("Medium Heal", 7, "Wand of Mending"),
+ HEAL_3("Big Heal", 7, "Wand of Restoration"),
+ HEAL_4("Huge Heal", 7, "Wand of Atonement"),
+
+ ICE_SPRAY("Ice Spray", 5, "Ice Spray Wand"),
+ GYRO("Gravity Storm", 30, "Gyrokinetic Wand"),
+ GIANTS_SWORD("Giant's Slam", 30, "Giant's Sword"),
+
+ STAR_FALL("Starfall", 2, "Starlight Wand"),
+ VODOO_DOLL("Acupuncture", 5, "Voodoo Doll"),
+ INK_WAND("Ink Bomb", 30, "Ink Wand"),
+ GOLEM_SWORD("Iron Punch", 3, "Golem Sword"),
+ EMBER_ROD("Fire Blast", 30, "Ember Rod"),
+ ENDER_BOW("Ender Warp", 30, "Ender Bow"),
+
+ LIVID_DAGGER("Throw", 5, "Livid Dagger"),
+ WEIRD_TUBA("Howl", 20, "Weird Tuba"),
+
+ ENDSTONE_SWORD("Extreme Focus", 5, "End Stone Sword"),
+ PIGMAN_SWORD("Burning Souls", 5, "Pigman Sword"),
+
+ SOULWARD("Soulward", 20, "Soul Esoward");
+
+ fun click() {
+ lastClick = System.currentTimeMillis()
+ }
+
+ fun isOnCooldown(): Boolean = lastClick + getCooldown() > System.currentTimeMillis()
+
+ fun getCooldown(): Long = cooldownInSeconds * 1000
+
+ fun getDurationText(): String {
+ var duration: Long = lastClick + getCooldown() - System.currentTimeMillis()
+ return if (duration < 1600) {
+ duration /= 100
+ var d = duration.toDouble()
+ d /= 10.0
+ LorenzUtils.formatDouble(d)
+ } else {
+ duration /= 1000
+ duration++
+ LorenzUtils.formatInteger(duration.toInt())
+ }
+ }
+
+ }
+
+ class ItemText(val color: LorenzColor, val text: String, val onCooldown: Boolean)
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/items/abilitycooldown/WitherImpactDetection.kt b/src/main/java/at/hannibal2/skyhanni/items/abilitycooldown/WitherImpactDetection.kt
new file mode 100644
index 000000000..52caa59d0
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/items/abilitycooldown/WitherImpactDetection.kt
@@ -0,0 +1,65 @@
+package at.hannibal2.skyhanni.items.abilitycooldown
+
+import at.hannibal2.skyhanni.events.PacketEvent
+import at.hannibal2.skyhanni.utils.ItemUtil.asStringSet
+import at.hannibal2.skyhanni.utils.ItemUtil.getExtraAttributes
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import net.minecraft.client.Minecraft
+import net.minecraft.init.Items
+import net.minecraft.network.play.client.C08PacketPlayerBlockPlacement
+import net.minecraft.network.play.server.S1CPacketEntityMetadata
+import net.minecraft.network.play.server.S2APacketParticles
+import net.minecraft.util.EnumParticleTypes
+import net.minecraftforge.common.util.Constants
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+
+/**
+ * Taken from Skytils under AGPL 3.0
+ * Modified
+ * https://github.com/Skytils/SkytilsMod/blob/1.x/LICENSE.md
+ * @author Skytils
+ */
+class WitherImpactDetection(private val itemAbilityCooldown: ItemAbilityCooldown) {
+
+ val S2APacketParticles.type: EnumParticleTypes
+ get() = this.particleType
+ var lastShieldUse = -1L
+ var lastShieldClick = 0L
+
+ @SubscribeEvent
+ fun onReceivePacket(event: PacketEvent.ReceiveEvent) {
+ val mc = Minecraft.getMinecraft()
+ if (!LorenzUtils.inSkyblock || mc.theWorld == null) return
+
+ event.packet.apply {
+
+ if (this is S1CPacketEntityMetadata && lastShieldClick != -1L && entityId == mc.thePlayer?.entityId && System.currentTimeMillis() - lastShieldClick <= 500 && func_149376_c()?.any { it.dataValueId == 17 } == true) {
+ lastShieldUse = System.currentTimeMillis()
+ lastShieldClick = -1
+ itemAbilityCooldown.clickWitherImpact()
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onSendPacket(event: PacketEvent.SendEvent) {
+ val mc = Minecraft.getMinecraft()
+ if (!LorenzUtils.inSkyblock || lastShieldUse != -1L || mc.thePlayer?.heldItem == null) return
+ if (event.packet is C08PacketPlayerBlockPlacement && mc.thePlayer.heldItem.item == Items.iron_sword && getExtraAttributes(
+ mc.thePlayer.heldItem
+ )?.getTagList("ability_scroll", Constants.NBT.TAG_STRING)?.asStringSet()
+ ?.contains("WITHER_SHIELD_SCROLL") == true
+ ) {
+ lastShieldClick = System.currentTimeMillis()
+ }
+ }
+
+ @SubscribeEvent
+ fun onTick(event: TickEvent.ClientTickEvent) {
+ if (lastShieldUse != -1L) {
+ val diff = ((lastShieldUse + 5000 - System.currentTimeMillis()) / 1000f)
+ if (diff < 0) lastShieldUse = -1
+ }
+ }
+} \ No newline at end of file