diff --git a/src/main/java/de/bixilon/minosoft/data/player/LocalPlayerEntity.kt b/src/main/java/de/bixilon/minosoft/data/player/LocalPlayerEntity.kt index 1a1b33be3..1e4fdda80 100644 --- a/src/main/java/de/bixilon/minosoft/data/player/LocalPlayerEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/player/LocalPlayerEntity.kt @@ -563,6 +563,9 @@ class LocalPlayerEntity( fovMultiplier.value = 1.0 + MMath.clamp(walkingSpeed * 1.9, -2.0, 2.0) } + override val health: Double + get() = healthCondition.hp.toDouble() + companion object { private val CLIMBABLE_TAG = "minecraft:climbable".toResourceLocation() private val SOUL_SPEED_BLOCKS = "minecraft:soul_speed_blocks".toResourceLocation() diff --git a/src/main/java/de/bixilon/minosoft/data/registries/effects/DefaultStatusEffects.kt b/src/main/java/de/bixilon/minosoft/data/registries/effects/DefaultStatusEffects.kt index cce01cb70..b130af7d9 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/effects/DefaultStatusEffects.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/effects/DefaultStatusEffects.kt @@ -25,4 +25,6 @@ object DefaultStatusEffects { val DOLPHINS_GRACE = "minecraft:dolphins_grace".toResourceLocation() val NIGHT_VISION = "minecraft:night_vision".toResourceLocation() val CONDUIT_POWER = "minecraft:conduit_power".toResourceLocation() + val WITHER = "minecraft:wither".toResourceLocation() + val POISON = "minecraft:poison".toResourceLocation() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index fb8d629c6..6058e2545 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -168,7 +168,7 @@ class RenderWindow( textureManager.staticTextures.createTexture(RenderConstants.DEBUG_TEXTURE_RESOURCE_LOCATION) WHITE_TEXTURE = TextureLikeTexture( texture = textureManager.staticTextures.createTexture(ResourceLocation("minosoft:textures/white.png")), - uvStart = Vec2(0, 0), + uvStart = Vec2(0.0f, 0.0f), uvEnd = Vec2(0.001f, 0.001f), size = Vec2i(16, 16) ) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/ImageElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/ImageElement.kt index 6cce33524..cbbebcbcf 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/ImageElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/primitive/ImageElement.kt @@ -71,6 +71,8 @@ open class ImageElement( } private var matrix: Mat4 = hudRenderer.matrix + private var lastOffset: Vec2i = Vec2i(-1, -1) + init { this.size = size @@ -82,13 +84,14 @@ open class ImageElement( override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int { val matrix = hudRenderer.matrix - if (matrix == this.matrix && cacheUpToDate) { + if (offset == lastOffset && matrix == this.matrix && cacheUpToDate) { consumer.addCache(cache) return 1 } val cache = GUIMeshCache(matrix, GUIMesh.GUIMeshStruct.FLOATS_PER_VERTEX * 6) cache.addQuad(offset, offset + size, z, texture, uvStart, uvEnd, tint) + this.lastOffset = offset this.matrix = matrix this.cache = cache this.cacheUpToDate = true diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/HUDRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/HUDRenderer.kt index edf91b6ef..0f87e43e5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/HUDRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/HUDRenderer.kt @@ -23,6 +23,7 @@ import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.HUDAtlasManager import de.bixilon.minosoft.gui.rendering.gui.hud.elements.* +import de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar.HotbarHUDElement import de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab.TabListHUDElement import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh import de.bixilon.minosoft.gui.rendering.modding.events.ResizeWindowEvent @@ -80,6 +81,7 @@ class HUDRenderer( } registerElement(TabListHUDElement) registerElement(BreakProgressHUDElement) + registerElement(HotbarHUDElement) } override fun init() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasElement.kt index 28c4967db..2df598f4c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasElement.kt @@ -21,7 +21,7 @@ class HUDAtlasElement( override val texture: AbstractTexture, val start: Vec2i, val end: Vec2i, - val slots: Map>, // ToDo: Use an array? + val slots: Map, // ToDo: Use an array? ) : TextureLike { override val size: Vec2i = end - start override lateinit var uvStart: Vec2 diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasManager.kt index 0e48f6c40..5414432f5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasManager.kt @@ -51,12 +51,12 @@ class HUDAtlasManager(private val hudRenderer: HUDRenderer) { val texture = hudRenderer.renderWindow.textureManager.staticTextures.createTexture(versionData["texture"].toResourceLocation()) val start = versionData["start"].toVec2i() val end = versionData["end"].toVec2i() - val slots: MutableMap> = mutableMapOf() + val slots: MutableMap = mutableMapOf() versionData["slots"]?.mapCast()?.let { for ((slotId, slotData) in it) { val slot = slotData.mapCast()!! - slots[slotId.toInt()] = Vec2Binding( + slots[slotId.toInt()] = Vec2iBinding( start = slot["start"].toVec2i(), end = slot["end"].toVec2i(), ) @@ -87,6 +87,10 @@ class HUDAtlasManager(private val hudRenderer: HUDRenderer) { return elements[resourceLocation] } + operator fun get(resourceLocation: String): HUDAtlasElement? { + return elements[resourceLocation.toResourceLocation()] + } + companion object { private val ATLAS_DATA = "minosoft:mapping/atlas.json".toResourceLocation() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/Vec2Binding.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/Vec2iBinding.kt similarity index 87% rename from src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/Vec2Binding.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/Vec2iBinding.kt index 5bd8fcbc5..df143f31d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/Vec2Binding.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/Vec2iBinding.kt @@ -13,9 +13,11 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.atlas -import glm_.vec2.Vec2t +import glm_.vec2.Vec2i -data class Vec2Binding( - val start: Vec2t, - val end: Vec2t, -) +data class Vec2iBinding( + val start: Vec2i, + val end: Vec2i, +) { + val size = end - start +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarBaseElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarBaseElement.kt new file mode 100644 index 000000000..9c303ffb2 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarBaseElement.kt @@ -0,0 +1,52 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar + +import de.bixilon.minosoft.gui.rendering.gui.elements.Element +import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement +import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer +import de.bixilon.minosoft.util.KUtil.toResourceLocation +import glm_.vec2.Vec2i + +class HotbarBaseElement(hudRenderer: HUDRenderer) : Element(hudRenderer) { + private val baseAtlasElement = hudRenderer.atlasManager[BASE]!! + private val base = ImageElement(hudRenderer, baseAtlasElement) + private val frame = ImageElement(hudRenderer, hudRenderer.atlasManager[FRAME]!!, size = Vec2i(FRAME_SIZE)) + + override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int { + base.render(offset + HORIZONTAL_MARGIN, z, consumer) + + baseAtlasElement.slots[hudRenderer.connection.player.selectedHotbarSlot]?.let { + frame.render(offset + it.start - HORIZONTAL_MARGIN + FRAME_OFFSET, z + 1, consumer) + } + + return 2 // bar + frame ToDo: Item rendering + } + + override fun silentApply() { + size = HOTBAR_BASE_SIZE + Vec2i(HORIZONTAL_MARGIN * 2, 1) // offset left and right; offset for the frame is just on top, not on the bottom + } + + + companion object { + private val BASE = "minecraft:hotbar_base".toResourceLocation() + private val FRAME = "minecraft:hotbar_frame".toResourceLocation() + + private val HOTBAR_BASE_SIZE = Vec2i(182, 22) + private const val FRAME_SIZE = 24 + private const val HORIZONTAL_MARGIN = 1 + private const val FRAME_OFFSET = -2 // FRAME_SIZE - HOTBAR_BASE_SIZE.y + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarElement.kt new file mode 100644 index 000000000..c6b895986 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarElement.kt @@ -0,0 +1,48 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar + +import de.bixilon.minosoft.gui.rendering.gui.elements.Element +import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer +import glm_.vec2.Vec2i +import java.lang.Integer.max + +class HotbarElement(hudRenderer: HUDRenderer) : Element(hudRenderer) { + private val base = HotbarBaseElement(hudRenderer) + private val health = HotbarHealthElement(hudRenderer) + + + init { + silentApply() + } + + override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int { + silentApply() + val initialOffset = Vec2i(offset) + var maxZ = 0 + maxZ = max(maxZ, health.render(offset, z, consumer)) + offset.y += health.size.y + maxZ = max(maxZ, base.render(offset, z, consumer)) + + return maxZ + } + + override fun silentApply() { + base.silentApply() + health.silentApply() + + size = base.size + Vec2i(0, health.size.y) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarHUDElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarHUDElement.kt new file mode 100644 index 000000000..e3bd78cdc --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarHUDElement.kt @@ -0,0 +1,48 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar + +import de.bixilon.minosoft.data.registries.ResourceLocation +import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder +import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDElement +import de.bixilon.minosoft.util.KUtil.toResourceLocation +import glm_.vec2.Vec2i + +class HotbarHUDElement(hudRenderer: HUDRenderer) : HUDElement(hudRenderer) { + private val connection = renderWindow.connection + override lateinit var layout: HotbarElement + + + override val layoutOffset: Vec2i + get() = Vec2i((hudRenderer.scaledSize.x - layout.size.x) / 2, hudRenderer.scaledSize.y - layout.size.y) + + + override fun init() { + } + + override fun postInit() { + layout = HotbarElement(hudRenderer) + layout.prefMaxSize = Vec2i(-1, -1) + } + + + companion object : HUDBuilder { + override val RESOURCE_LOCATION: ResourceLocation = "minosoft:hotbar".toResourceLocation() + + override fun build(hudRenderer: HUDRenderer): HotbarHUDElement { + return HotbarHUDElement(hudRenderer) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarHealthElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarHealthElement.kt new file mode 100644 index 000000000..db8b6870d --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarHealthElement.kt @@ -0,0 +1,249 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.gui.hud.elements.hotbar + +import de.bixilon.minosoft.data.registries.effects.DefaultStatusEffects +import de.bixilon.minosoft.data.registries.effects.attributes.DefaultStatusEffectAttributeNames +import de.bixilon.minosoft.gui.rendering.gui.elements.Element +import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement +import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.HUDAtlasElement +import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer +import de.bixilon.minosoft.util.KUtil.decide +import de.bixilon.minosoft.util.KUtil.unsafeCast +import de.bixilon.minosoft.util.MMath.ceil +import glm_.vec2.Vec2i + +class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer) { + private val witherStatusEffect = hudRenderer.connection.registries.statusEffectRegistry[DefaultStatusEffects.WITHER] + private val poisonStatusEffect = hudRenderer.connection.registries.statusEffectRegistry[DefaultStatusEffects.POISON] + private val atlasManager = hudRenderer.atlasManager + + /** + * [normal|hardcore][normal|poison|wither][normal|damage][full|half] + */ + private val hearts = arrayOf( + arrayOf( + arrayOf( + arrayOf( + atlasManager["minecraft:normal_heart"], + atlasManager["minecraft:half_normal_heart"], + ), + arrayOf( + atlasManager["minecraft:normal_damage_heart"], + atlasManager["minecraft:half_normal_damage_heart"], + ), + ), + arrayOf( + arrayOf( + atlasManager["minecraft:poison_heart"], + atlasManager["minecraft:half_poison_heart"], + ), + arrayOf( + atlasManager["minecraft:poison_damage_heart"], + atlasManager["minecraft:half_poison_damage_heart"], + ), + ), + arrayOf( + arrayOf( + atlasManager["minecraft:wither_heart"], + atlasManager["minecraft:half_wither_heart"], + ), + arrayOf( + atlasManager["minecraft:wither_damage_heart"], + atlasManager["minecraft:half_wither_damage_heart"], + ), + ), + ), + arrayOf( + arrayOf( + arrayOf( + atlasManager["minecraft:hardcore_normal_heart"], + atlasManager["minecraft:hardcore_half_normal_heart"], + ), + arrayOf( + atlasManager["minecraft:hardcore_normal_damage_heart"], + atlasManager["minecraft:hardcore_half_normal_damage_heart"], + ), + ), + arrayOf( + arrayOf( + atlasManager["minecraft:hardcore_poison_heart"], + atlasManager["minecraft:hardcore_half_poison_heart"], + ), + arrayOf( + atlasManager["minecraft:hardcore_poison_damage_heart"], + atlasManager["minecraft:hardcore_half_poison_damage_heart"], + ), + ), + arrayOf( + arrayOf( + atlasManager["minecraft:hardcore_wither_heart"], + atlasManager["minecraft:hardcore_half_wither_heart"], + ), + arrayOf( + atlasManager["minecraft:hardcore_wither_damage_heart"], + atlasManager["minecraft:hardcore_half_wither_damage_heart"], + ), + ), + ), + ) + + /** + * [normal|hardcore][full|half] + */ + private val absorptionHearts = arrayOf( + arrayOf( + atlasManager["minecraft:absorption_heart"], + atlasManager["minecraft:half_absorption_heart"], + ), + arrayOf( + atlasManager["minecraft:hardcore_absorption_heart"], + atlasManager["minecraft:hardcore_half_absorption_heart"], + ), + ) + + /** + * [normal|hardcore][full|half] + */ + private val frozenHearts = arrayOf( + arrayOf( + atlasManager["minecraft:frozen_heart"], + atlasManager["minecraft:half_frozen_heart"], + ), + arrayOf( + atlasManager["minecraft:hardcore_frozen_heart"], + atlasManager["minecraft:hardcore_half_frozen_heart"], + ), + ) + private val whiteHeartContainer = atlasManager["minecraft:white_heart_container"] + private val blackHeartContainer = atlasManager["minecraft:black_heart_container"] + + private var hardcode = false + private var poison = false + private var wither = false + private var frozen = false + + private var health = 0.0f + private var absorptionsAmount = 0.0f + private var totalHealth = 0.0f + + private var maxHealth = 0.0f + private var totalMaxHealth = 0.0f + + private var totalMaxHearts = 0 + private var rows = 0 + + override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int { + blackHeartContainer ?: return 0 + whiteHeartContainer ?: return 0 + + // ToDo: Damage animation, regeneration, caching + for (heart in 0 until totalMaxHearts) { + val row = heart / HEARTS_PER_ROW + val column = heart % HEARTS_PER_ROW + + val image = ImageElement(hudRenderer, blackHeartContainer) + + image.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z, consumer) + } + + val hardcoreIndex = hardcode.decide(1, 0) + + var healthLeft = totalHealth + var heart = 0 + + while (healthLeft > 0.5f) { + val row = heart / HEARTS_PER_ROW + val column = heart % HEARTS_PER_ROW + + + var selectArray: Array<*>? = null + + var normalHeart = false + + if (healthLeft <= absorptionsAmount) { + selectArray = absorptionHearts[hardcoreIndex] + } else { + selectArray = hearts[hardcoreIndex] + + // heart type + selectArray = selectArray[when { + poison -> 1 + wither -> 2 + else -> { + normalHeart = true + 0 + } + }] + + // ToDo: damage heart + selectArray = selectArray[0] + } + + if (frozen && normalHeart) { + selectArray = frozenHearts[hardcoreIndex] + } + + + val halfHeart = healthLeft < 1.5f + val image = when { + halfHeart -> selectArray.unsafeCast>()[1]?.let { ImageElement(hudRenderer, it) } + else -> selectArray.unsafeCast>()[0]?.let { ImageElement(hudRenderer, it) } + } + + image?.render(offset + Vec2i(column, (rows - 1) - row) * HEART_SIZE, z + 1, consumer) + + heart++ + healthLeft -= halfHeart.decide(1.0f, 2.0f) + } + + return 2 + } + + override fun silentApply() { + blackHeartContainer ?: return + whiteHeartContainer ?: return + + val player = hudRenderer.connection.player + + hardcode = hudRenderer.connection.world.hardcore + poison = poisonStatusEffect?.let { player.activeStatusEffects[it] != null } ?: false + wither = witherStatusEffect?.let { player.activeStatusEffects[it] != null } ?: false + frozen = player.ticksFrozen > 0 + + health = player.healthCondition.hp + absorptionsAmount = player.playerAbsorptionHearts // ToDo: This is (probably) calculated as effect instance + totalHealth = health + absorptionsAmount + + maxHealth = player.getAttributeValue(DefaultStatusEffectAttributeNames.GENERIC_MAX_HEALTH).toFloat() + totalMaxHealth = maxHealth + absorptionsAmount + + totalMaxHearts = (totalMaxHealth / 2).ceil + + rows = totalMaxHearts / HEARTS_PER_ROW + if (totalMaxHearts % HP_PER_ROW != 0) { + rows++ + } + + size = Vec2i(HEARTS_PER_ROW, rows) * HEART_SIZE + } + + + companion object { + private const val HP_PER_ROW = 20 + private const val HEARTS_PER_ROW = HP_PER_ROW / 2 + private val HEART_SIZE = Vec2i(8, 9) + } +}