From cbaf89d4a78e8e004ff712733987b1a54e39784f Mon Sep 17 00:00:00 2001 From: YuRaNnNzZZ Date: Sun, 12 Mar 2023 20:16:18 +0300 Subject: [PATCH] android health bar + 1px wider energy bar --- .../ru/dbotthepony/mc/otm/ClientConfig.kt | 4 + .../dbotthepony/mc/otm/client/MatteryGUI.kt | 110 +++++++++++++++++- .../textures/gui/player_bars.png | Bin 348 -> 282 bytes .../textures/gui/player_bars_health.png | Bin 0 -> 292 bytes 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/assets/overdrive_that_matters/textures/gui/player_bars_health.png diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ClientConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ClientConfig.kt index 5f1638064..ebfcfc052 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/ClientConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ClientConfig.kt @@ -22,6 +22,10 @@ object ClientConfig { .comment("Allow to scroll Exopack inventory in non OTM inventories when hovering just over inventory slots, not only scrollbar") .define("exopackFreeScroll", true) + var ANDROID_HEALTH_HUD: Boolean by specBuilder + .comment("Replace hearts with health bar on HUD when you are an android") + .define("ANDROID_HEALTH_HUD", true) + init { spec = specBuilder.build() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/MatteryGUI.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/MatteryGUI.kt index bdca96c1e..ff845b2b8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/MatteryGUI.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/MatteryGUI.kt @@ -17,6 +17,7 @@ import net.minecraftforge.client.event.RenderLevelStageEvent import net.minecraftforge.client.event.ScreenEvent import net.minecraftforge.client.gui.overlay.ForgeGui import net.minecraftforge.client.gui.overlay.GuiOverlayManager +import ru.dbotthepony.mc.otm.ClientConfig import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.capability.MatteryCapability @@ -30,13 +31,23 @@ import java.util.* import kotlin.math.ceil object MatteryGUI { - private val BARS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "player_bars"), 80f, 36f) + private val BARS = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "player_bars"), 81f, 36f) val CHARGE = BARS.subElement(height = 9f) val CHARGE_BG = BARS.subElement(y = 9f, height = 9f) val CHARGE_HUNGER = BARS.subElement(y = 18f, height = 9f) val CHARGE_HUNGER_BG = BARS.subElement(y = 27f, height = 9f) + private val BARS_HP = AtlasSkinElement(ResourceLocation(OverdriveThatMatters.MOD_ID, "player_bars_health"), 81f, 54f) + + val HEALTH = BARS_HP.subElement(height = 9f) + val HEALTH_BG = BARS_HP.subElement(y = 9f, height = 9f) + + val HEALTH_POISON = BARS_HP.subElement(y = 18f, height = 9f) + val HEALTH_WITHER = BARS_HP.subElement(y = 27f, height = 9f) + val HEALTH_ABSORB = BARS_HP.subElement(y = 36f, height = 9f) + val HEALTH_FROZEN = BARS_HP.subElement(y = 45f, height = 9f) + private var originalBedButtonX = -1 private var originalBedButtonY = -1 @@ -99,6 +110,10 @@ object MatteryGUI { GuiOverlayManager.findOverlay(ResourceLocation("minecraft", "air_level")) } + private val PLAYER_HEALTH_ELEMENT by lazy { + GuiOverlayManager.findOverlay(ResourceLocation("minecraft", "player_health")) + } + var iteration = 0 var showIterationUntil = 0L var showIterationUntilFade = 0L @@ -177,7 +192,7 @@ object MatteryGUI { showIteration(event) } - fun onLayerRenderEvent(event: RenderGuiOverlayEvent.Pre) { + private fun renderFoodAndAir(event: RenderGuiOverlayEvent.Pre) { if (event.overlay != FOOD_LEVEL_ELEMENT && event.overlay != AIR_LEVEL_ELEMENT) { return } @@ -208,6 +223,8 @@ object MatteryGUI { return } + if (!gui.shouldDrawSurvivalElements()) return + var level: Float if (mattery.androidEnergy.maxBatteryLevel.isZero) { @@ -228,14 +245,14 @@ object MatteryGUI { val top: Int = height - gui.rightHeight gui.rightHeight += 10 - val leftPadding = ceil(level * 79f - 0.5f) + val leftPadding = ceil(level * 80f - 0.5f) if (ply.hasEffect(MobEffects.HUNGER)) { CHARGE_HUNGER_BG.render(event.poseStack, left.toFloat(), top.toFloat()) - CHARGE_HUNGER.renderPartial(event.poseStack, left.toFloat() - leftPadding + 79f, top.toFloat(), width = leftPadding) + CHARGE_HUNGER.renderPartial(event.poseStack, left.toFloat() - leftPadding + 80f, top.toFloat(), width = leftPadding) } else { CHARGE_BG.render(event.poseStack, left.toFloat(), top.toFloat()) - CHARGE.renderPartial(event.poseStack, left.toFloat() - leftPadding + 79f, top.toFloat(), width = leftPadding) + CHARGE.renderPartial(event.poseStack, left.toFloat() - leftPadding + 80f, top.toFloat(), width = leftPadding) } val formattedPower = mattery.androidEnergy.batteryLevel.formatPower() @@ -249,4 +266,87 @@ object MatteryGUI { event.poseStack.popPose() } } + + private fun getSpriteForPlayer(player: Player): SubSkinElement { + if (player.hasEffect(MobEffects.POISON)) { + return HEALTH_POISON + } else if (player.hasEffect(MobEffects.WITHER)) { + return HEALTH_WITHER + } else if (player.isFullyFrozen()) { + return HEALTH_FROZEN + } + + return HEALTH + } + + private fun getHealthColorForPlayer(player: Player): Int { + if (player.hasEffect(MobEffects.POISON)) { + return RGBAColor.DARK_GREEN.toInt() + } else if (player.hasEffect(MobEffects.WITHER)) { + return RGBAColor.WHITE.toInt() + } else if (player.isFullyFrozen()) { + return RGBAColor.AQUA.toInt() + } + + return RGBAColor.RED.toInt() + } // можно вынести в конфиг, но для этого нужен селектор цвета + + private fun renderPlayerHealth(event: RenderGuiOverlayEvent.Pre) { + if (!ClientConfig.ANDROID_HEALTH_HUD) return + + val ply: LocalPlayer = minecraft.player ?: return + + var mattery = ply.matteryPlayer + + if (!ply.isAlive && mattery == null) { + mattery = lastState + } + + val gui = minecraft.gui as? ForgeGui ?: return + + if (mattery != null && mattery.isAndroid) { + event.isCanceled = true + lastState = mattery + + if (!gui.shouldDrawSurvivalElements()) return + + val level: Float = (ply.health / ply.maxHealth).coerceIn(0.0f, 1.0f) + val levelAbsorb: Float = (ply.absorptionAmount / ply.maxHealth).coerceIn(0.0f, 1.0f) + + gui.setupOverlayRenderState(true, false) + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) + + val width = event.window.guiScaledWidth + val height = event.window.guiScaledHeight + val left = width / 2 - 10 - 81 + val top: Int = height - gui.leftHeight + gui.leftHeight += 10 + + HEALTH_BG.render(event.poseStack, left.toFloat(), top.toFloat()) + getSpriteForPlayer(ply).renderPartial(event.poseStack, left.toFloat(), top.toFloat(), width = ceil(level * 80f - 0.5f)) + if (levelAbsorb > 0) { + HEALTH_ABSORB.renderPartial(event.poseStack, left.toFloat(), top.toFloat(), width = ceil(levelAbsorb * 80f - 0.5f)) + } + + var formattedHealth = "%d/%d".format(ply.health.toInt(), ply.maxHealth.toInt()) + if (ply.absorptionAmount > 0) + formattedHealth = "%d+%d/%d".format(ply.health.toInt(), ply.absorptionAmount.toInt(), ply.maxHealth.toInt()) + + event.poseStack.pushPose() + event.poseStack.scale(0.5f, 0.5f, 0.5f) + + minecraft.font.drawAligned(event.poseStack, formattedHealth, TextAlign.CENTER_RIGHT, (left - 1f) * 2f, (top + 5.5f) * 2f, RGBAColor.BLACK.toInt()) + minecraft.font.drawAligned(event.poseStack, formattedHealth, TextAlign.CENTER_RIGHT, (left - 2f) * 2f, (top + 4.5f) * 2f, getHealthColorForPlayer(ply)) + + event.poseStack.popPose() + } + } + + fun onLayerRenderEvent(event: RenderGuiOverlayEvent.Pre) { + if (event.overlay == FOOD_LEVEL_ELEMENT || event.overlay == AIR_LEVEL_ELEMENT) { + renderFoodAndAir(event) + } else if (event.overlay == PLAYER_HEALTH_ELEMENT) { + renderPlayerHealth(event) + } + } } diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/player_bars.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/player_bars.png index 4c867588e72db77b743a676a3ee8de66f049f0b6..8e35511c97fe8e852d6a18f44dd708b4bd564489 100644 GIT binary patch delta 217 zcmcb^G>d71BnLAC1H)5}e&30T3Z@bPJ|V9EA9()10Tg7=(9qcUIA-BZSs_PmAos)S z!`eWKqa?^L_&)?N+-u$&Inhp{zTDHrF(kwJ?KMZP1_K_KixFFQ{_nkehEYhO zZrkdk*LcfW85kPu4gfiSAM|Hf0Ob(CLUzJWMw@fn6_@A9@*V_Nn{1`bpw1tT>lFT?-mvY@-#Fwrc_8|1an-ua^?R0`w9vQ+S=Mz)|+2h#L)2c zJ>$MlKsEA}Li>Oee@T#E@P8D*aOKX7g+M9J0*}aI1_r(ZAk3I`t&*0S6vt$6s?M|N9@)erj)cD?`!mOcoDE|Al;Km4XE)&Xcm;I&ZFPnyX8dqKL^k4UNFP#?HE(=y4*H$qnLu_VO#~UR*jWexz8gEm2 QfEF@%y85}Sb4q9e07nXK-v9sr literal 0 HcmV?d00001