feat: implement hardcore hearts with game mode lock
Display hardcore heart textures when a world is in hardcore mode, matching Java Edition behavior. Hearts switch between normal/hardcore across all states (poison, wither, flash) and all HUD resolutions. C++ changes: - IUIScene_HUD: check isHardcore() and call SetHardcoreMode() each tick - UIScene_HUD: send hardcore boolean to Flash via Iggy, invalidate SetHealth dirty check on state change to force heart redraw - CreateWorldMenu/LoadMenu: lock game mode to Survival when hardcore - MinecraftServer: gate server.properties hardcore override behind MINECRAFT_SERVER_BUILD so offline worlds preserve their saved flag SWF changes (via new Java tools): - AddHardcoreBitmaps: adds 10 hardcore heart bitmaps to graphics SWFs - AddHardcoreHearts: adds 10 new frames (15-24) to health sprite - PatchHudABC: patches HUD ActionScript bytecode with SetHardcore method and frame offset logic (+14 normal/poison, +6 wither) Also updates README changelog styling with consistent ### headings.
This commit is contained in:
Binary file not shown.
@@ -5,6 +5,8 @@
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.item.h"
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.entity.ai.attributes.h"
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.entity.monster.h"
|
||||
#include "..\..\MultiPlayerLevel.h"
|
||||
#include "..\..\..\Minecraft.World\LevelData.h"
|
||||
#include "IUIScene_HUD.h"
|
||||
|
||||
#include "UI.h"
|
||||
@@ -20,6 +22,7 @@ IUIScene_HUD::IUIScene_HUD()
|
||||
m_lastMaxHealth = 20;
|
||||
m_lastHealthBlink = false;
|
||||
m_lastHealthPoison = false;
|
||||
m_lastHealthHardcore = false;
|
||||
m_iCurrentFood = -1;
|
||||
m_lastFoodPoison = false;
|
||||
m_lastAir = 10;
|
||||
@@ -94,9 +97,10 @@ void IUIScene_HUD::updateFrameTick()
|
||||
ShowHealth(false);
|
||||
ShowFood(false);
|
||||
ShowAir(false);
|
||||
ShowArmour(false);
|
||||
ShowArmour(false);
|
||||
ShowExpBar(false);
|
||||
SetHealthAbsorb(0);
|
||||
SetHealthAbsorb(0);
|
||||
SetHardcoreMode(false);
|
||||
}
|
||||
|
||||
if(pMinecraft->localplayers[iPad]->isRidingJumpable())
|
||||
@@ -206,6 +210,12 @@ void IUIScene_HUD::renderPlayerHealth()
|
||||
// Update armour
|
||||
int armor = pMinecraft->localplayers[iPad]->getArmorValue();
|
||||
|
||||
// Check hardcore mode
|
||||
bool bHardcore = pMinecraft->level != nullptr
|
||||
&& pMinecraft->level->getLevelData() != nullptr
|
||||
&& pMinecraft->level->getLevelData()->isHardcore();
|
||||
SetHardcoreMode(bHardcore);
|
||||
|
||||
SetHealth(currentHealth, oldHealth, blink, bHasPoison || bHasWither, bHasWither);
|
||||
SetHealthAbsorb(totalAbsorption);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ protected:
|
||||
int m_iCurrentHealth;
|
||||
int m_lastMaxHealth;
|
||||
bool m_lastHealthBlink, m_lastHealthPoison, m_lastHealthWither;
|
||||
bool m_lastHealthHardcore;
|
||||
int m_iCurrentFood;
|
||||
bool m_lastFoodPoison;
|
||||
int m_lastAir, m_currentExtraAir;
|
||||
@@ -46,6 +47,7 @@ protected:
|
||||
virtual void SetActiveSlot(int slot) = 0;
|
||||
|
||||
virtual void SetHealth(int iHealth, int iLastHealth, bool bBlink, bool bPoison, bool bWither) = 0;
|
||||
virtual void SetHardcoreMode(bool bHardcore) = 0;
|
||||
virtual void SetFood(int iFood, int iLastFood, bool bPoison) = 0;
|
||||
virtual void SetAir(int iAir, int extra) = 0;
|
||||
virtual void SetArmour(int iArmour) = 0;
|
||||
|
||||
@@ -461,6 +461,8 @@ void UIScene_CreateWorldMenu::handlePress(F64 controlId, F64 childId)
|
||||
}
|
||||
break;
|
||||
case eControl_GameModeToggle:
|
||||
if (s_bHardcore)
|
||||
break; // Hardcore mode locks game mode to Survival
|
||||
switch(m_iGameModeId)
|
||||
{
|
||||
case 0: // Creative
|
||||
@@ -473,7 +475,7 @@ void UIScene_CreateWorldMenu::handlePress(F64 controlId, F64 childId)
|
||||
m_iGameModeId = GameType::ADVENTURE->getId();
|
||||
m_bGameModeCreative = false;
|
||||
break;
|
||||
case 2: // Survival
|
||||
case 2: // Survival
|
||||
m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_SURVIVAL));
|
||||
m_iGameModeId = GameType::SURVIVAL->getId();
|
||||
m_bGameModeCreative = false;
|
||||
@@ -665,6 +667,14 @@ void UIScene_CreateWorldMenu::handleSliderMove(F64 sliderId, F64 currentValue)
|
||||
else
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[value]));
|
||||
m_sliderDifficulty.setLabel(TempString);
|
||||
|
||||
// Hardcore locks game mode to Survival
|
||||
if (s_bHardcore && m_iGameModeId != GameType::SURVIVAL->getId())
|
||||
{
|
||||
m_iGameModeId = GameType::SURVIVAL->getId();
|
||||
m_bGameModeCreative = false;
|
||||
m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_SURVIVAL));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,6 +655,23 @@ void UIScene_HUD::SetHorseJumpBarProgress(float progress)
|
||||
}
|
||||
}
|
||||
|
||||
void UIScene_HUD::SetHardcoreMode(bool bHardcore)
|
||||
{
|
||||
IggyDataValue result;
|
||||
IggyDataValue value[1];
|
||||
value[0].type = IGGY_DATATYPE_boolean;
|
||||
value[0].boolval = bHardcore;
|
||||
IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSetHardcore , 1 , value );
|
||||
|
||||
// When hardcore state changes, invalidate SetHealth's dirty check
|
||||
// so hearts are redrawn with the correct frame set on the next tick
|
||||
if(bHardcore != m_lastHealthHardcore)
|
||||
{
|
||||
m_lastHealthHardcore = bHardcore;
|
||||
m_lastMaxHealth = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void UIScene_HUD::SetHealthAbsorb(int healthAbsorb)
|
||||
{
|
||||
if(m_iCurrentHealthAbsorb != healthAbsorb)
|
||||
|
||||
@@ -25,6 +25,7 @@ protected:
|
||||
IggyName m_funcRepositionHud, m_funcSetDisplayName, m_funcSetTooltipsEnabled;
|
||||
IggyName m_funcSetRidingHorse, m_funcSetHorseHealth, m_funcSetHorseJumpBarProgress;
|
||||
IggyName m_funcSetHealthAbsorb;
|
||||
IggyName m_funcSetHardcore;
|
||||
UI_BEGIN_MAP_ELEMENTS_AND_NAMES(UIScene)
|
||||
UI_MAP_ELEMENT(m_labelChatText[0],"Label1")
|
||||
UI_MAP_ELEMENT(m_labelChatText[1],"Label2")
|
||||
@@ -89,6 +90,7 @@ protected:
|
||||
UI_MAP_NAME(m_funcSetHorseJumpBarProgress, L"SetHorseJumpBarProgress")
|
||||
|
||||
UI_MAP_NAME(m_funcSetHealthAbsorb, L"SetHealthAbsorb")
|
||||
UI_MAP_NAME(m_funcSetHardcore, L"SetHardcore")
|
||||
UI_END_MAP_ELEMENTS_AND_NAMES()
|
||||
|
||||
public:
|
||||
@@ -159,6 +161,8 @@ private:
|
||||
|
||||
void SetHealthAbsorb(int healthAbsorb);
|
||||
|
||||
void SetHardcoreMode(bool bHardcore);
|
||||
|
||||
public:
|
||||
void SetSelectedLabel(const wstring &label);
|
||||
void ShowDisplayName(bool show);
|
||||
|
||||
@@ -579,6 +579,11 @@ void UIScene_LoadMenu::tick()
|
||||
WCHAR TempString[256];
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ), L"Hardcore");
|
||||
m_sliderDifficulty.init(TempString, eControl_Difficulty, 0, 4, 4);
|
||||
|
||||
// Hardcore locks game mode to Survival
|
||||
m_iGameModeId = GameType::SURVIVAL->getId();
|
||||
m_bGameModeCreative = false;
|
||||
m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_SURVIVAL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,6 +738,8 @@ void UIScene_LoadMenu::handlePress(F64 controlId, F64 childId)
|
||||
switch(static_cast<int>(controlId))
|
||||
{
|
||||
case eControl_GameMode:
|
||||
if (m_bHardcore)
|
||||
break; // Hardcore mode locks game mode to Survival
|
||||
switch(m_iGameModeId)
|
||||
{
|
||||
case 0: // Survival
|
||||
|
||||
@@ -1008,8 +1008,11 @@ bool MinecraftServer::loadLevel(LevelStorageSource *storageSource, const wstring
|
||||
#endif
|
||||
levels[i]->getLevelData()->setGameType(gameType);
|
||||
|
||||
// Apply hardcore flag from host option to level data so loaded worlds respect server.properties
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
// Dedicated server: server.properties hardcore flag is authoritative
|
||||
levels[i]->getLevelData()->setHardcore(isHardcore());
|
||||
#endif
|
||||
// Offline/client-hosted: keep the world's saved hardcore flag from NBT
|
||||
|
||||
if(app.getLevelGenerationOptions() != nullptr)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user