feat: support separate boss health bars per dimension

Add dimension-aware tracking for boss mobs and update the boss health
GUI system to maintain independent state for each dimension (Overworld,
Nether, End). This prevents conflicts when multiple bosses exist across
different dimensions simultaneously.

- Add `getDimension()` to `BossMob` base class and implement in
  `EnderDragon` and `WitherBoss`
- Replace static boss GUI state with dimension-indexed storage
- Introduce `getIndexFromDimension()` helper for dimension mapping
- Update rendering logic to use per-dimension state
- Isolate darkening effects and health display per dimension

Ported from LCERenewed commit 5ec8a0e41ba8146aba450258d8620cd3cb0299e0 by 3UR
This commit is contained in:
George V. 2026-04-08 03:27:30 +03:00
parent aaae8b01a9
commit ff96cd3687
7 changed files with 44 additions and 20 deletions

View file

@ -1,16 +1,25 @@
#include "stdafx.h"
#include "BossMobGuiInfo.h"
#include "../Minecraft.World/BossMob.h"
#include "../Minecraft.World/LevelData.h"
float BossMobGuiInfo::healthProgress = 0.0f;
int BossMobGuiInfo::displayTicks = 0;
wstring BossMobGuiInfo::name = L"";
bool BossMobGuiInfo::darkenWorld = false;
float BossMobGuiInfo::healthProgress[3] = { 0.0f, 0.0f, 0.0f };
int BossMobGuiInfo::displayTicks[3] = { 0, 0, 0 };
wstring BossMobGuiInfo::name[3];
bool BossMobGuiInfo::darkenWorld[3] = { false, false, false };
void BossMobGuiInfo::setBossHealth(shared_ptr<BossMob> boss, bool darkenWorld)
{
healthProgress = (float) boss->getHealth() / (float) boss->getMaxHealth();
displayTicks = SharedConstants::TICKS_PER_SECOND * 5;
name = boss->getAName();
BossMobGuiInfo::darkenWorld = darkenWorld;
int idx = getIndexFromDimension(boss->getDimension());
healthProgress[idx] = (float) boss->getHealth() / (float) boss->getMaxHealth();
displayTicks[idx] = SharedConstants::TICKS_PER_SECOND * 5;
name[idx] = boss->getAName();
BossMobGuiInfo::darkenWorld[idx] = darkenWorld;
}
int BossMobGuiInfo::getIndexFromDimension(int dimension)
{
if (dimension == LevelData::DIMENSION_NETHER) return 1;
if (dimension == LevelData::DIMENSION_END) return 2;
return 0;
}

View file

@ -5,10 +5,12 @@ class BossMob;
class BossMobGuiInfo
{
public:
static float healthProgress;
static int displayTicks;
static wstring name;
static bool darkenWorld;
static float healthProgress[3];
static int displayTicks[3];
static wstring name[3];
static bool darkenWorld[3];
static void setBossHealth(shared_ptr<BossMob> boss, bool darkenWorld);
static int getIndexFromDimension(int dimension);
};

View file

@ -124,8 +124,9 @@ void UIScene_HUD::tick()
return;
}
int idx = BossMobGuiInfo::getIndexFromDimension(pMinecraft->localplayers[m_iPad]->dimension);
// Is boss present?
bool noBoss = BossMobGuiInfo::name.empty() || BossMobGuiInfo::displayTicks <= 0;
bool noBoss = BossMobGuiInfo::name[idx].empty() || BossMobGuiInfo::displayTicks[idx] <= 0;
if (noBoss)
{
if (m_showDragonHealth)
@ -143,14 +144,14 @@ void UIScene_HUD::tick()
}
else
{
BossMobGuiInfo::displayTicks--;
BossMobGuiInfo::displayTicks[idx]--;
m_ticksWithNoBoss = 0;
SetDragonHealth(BossMobGuiInfo::healthProgress);
SetDragonHealth(BossMobGuiInfo::healthProgress[idx]);
if (!m_showDragonHealth)
{
SetDragonLabel(BossMobGuiInfo::name);
SetDragonLabel(BossMobGuiInfo::name[idx]);
ShowDragonHealth(true);
}
}
@ -248,7 +249,15 @@ void UIScene_HUD::handleReload()
m_labelDisplayName.setVisible(m_lastShowDisplayName);
SetDragonLabel(BossMobGuiInfo::name);
Minecraft* pMinecraft = Minecraft::GetInstance();
int idx = 0;
if(pMinecraft->localplayers[m_iPad] != nullptr)
{
idx = BossMobGuiInfo::getIndexFromDimension(pMinecraft->localplayers[m_iPad]->dimension);
}
SetDragonLabel(BossMobGuiInfo::name[idx]);
SetSelectedLabel(L"");
for(unsigned int i = 0; i < CHAT_LINES_COUNT; ++i)
@ -258,7 +267,7 @@ void UIScene_HUD::handleReload()
m_labelJukebox.init(L"");
int iGuiScale;
Minecraft *pMinecraft = Minecraft::GetInstance();
if(pMinecraft->localplayers[m_iPad] == nullptr || pMinecraft->localplayers[m_iPad]->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN)
{
iGuiScale=app.GetGameSettings(m_iPad,eGameSetting_UISize);

View file

@ -228,14 +228,15 @@ void GameRenderer::tick(bool first) // 4J - add bFirst
PIXEndNamedEvent();
darkenWorldAmountO = darkenWorldAmount;
if (BossMobGuiInfo::darkenWorld)
int idx = BossMobGuiInfo::getIndexFromDimension((int)mc->level->dimension);
if (BossMobGuiInfo::darkenWorld[idx])
{
darkenWorldAmount += 1.0f / (static_cast<float>(SharedConstants::TICKS_PER_SECOND) * 1);
if (darkenWorldAmount > 1)
{
darkenWorldAmount = 1;
}
BossMobGuiInfo::darkenWorld = false;
BossMobGuiInfo::darkenWorld[idx] = false;
}
else if (darkenWorldAmount > 0)
{

View file

@ -6,4 +6,5 @@ public:
virtual float getMaxHealth() = 0;
virtual float getHealth() = 0;
virtual wstring getAName() = 0;
virtual int getDimension() = 0;
};

View file

@ -186,4 +186,5 @@ public:
virtual wstring getAName() { return app.GetString(IDS_ENDERDRAGON); };
virtual float getHealth() { return LivingEntity::getHealth(); };
virtual float getMaxHealth() { return LivingEntity::getMaxHealth(); };
virtual int getDimension() { return Entity::dimension; }
};

View file

@ -106,4 +106,5 @@ public:
virtual float getMaxHealth() { return Monster::getMaxHealth(); };
virtual float getHealth() { return Monster::getHealth(); };
virtual wstring getAName() { return app.GetString(IDS_WITHER); };
virtual int getDimension() { return Entity::dimension; }
};