diff --git a/Minecraft.Assets/Common/res/1_2_2/gui/beacon.png b/Minecraft.Assets/Common/res/1_2_2/gui/beacon.png new file mode 100644 index 000000000..f51a2ef51 Binary files /dev/null and b/Minecraft.Assets/Common/res/1_2_2/gui/beacon.png differ diff --git a/Minecraft.Assets/Common/res/lang/en_US.lang b/Minecraft.Assets/Common/res/lang/en_US.lang index 0b005e48c..890a2f576 100644 --- a/Minecraft.Assets/Common/res/lang/en_US.lang +++ b/Minecraft.Assets/Common/res/lang/en_US.lang @@ -436,6 +436,9 @@ tile.oreEmerald.name=Emerald Ore tile.blockEmerald.name=Block of Emerald tile.tripWire.name=Tripwire tile.tripWireSource.name=Tripwire Hook +tile.beacon.name=Beacon +tile.beacon.primary=Primary Power +tile.beacon.secondary=Secondary Power item.shovelIron.name=Iron Shovel item.pickaxeIron.name=Iron Pickaxe diff --git a/Minecraft.Client/Player/LocalPlayer.cpp b/Minecraft.Client/Player/LocalPlayer.cpp index 79003a286..442bb1f97 100644 --- a/Minecraft.Client/Player/LocalPlayer.cpp +++ b/Minecraft.Client/Player/LocalPlayer.cpp @@ -1,5 +1,6 @@ #include "../Platform/stdafx.h" #include "LocalPlayer.h" +#include "UI/Screens/BeaconScreen.h" #include "UI/Screens/BrewingStandScreen.h" #include "UI/Screens/EnchantmentScreen.h" #include "UI/Screens/HopperScreen.h" @@ -696,9 +697,13 @@ bool LocalPlayer::openBrewingStand( } bool LocalPlayer::openBeacon(std::shared_ptr beacon) { - // minecraft->setScreen(new BeaconScreen(inventory, beacon)); +#ifdef ENABLE_JAVA_GUIS + minecraft->setScreen(new BeaconScreen(inventory, beacon)); + bool success = true; +#else bool success = app.LoadBeaconMenu(GetXboxPad(), inventory, beacon); if (success) ui.PlayUISFX(eSFX_Press); +#endif return success; } diff --git a/Minecraft.Client/Textures/Textures.cpp b/Minecraft.Client/Textures/Textures.cpp index bbd96f14a..907f51927 100644 --- a/Minecraft.Client/Textures/Textures.cpp +++ b/Minecraft.Client/Textures/Textures.cpp @@ -180,6 +180,7 @@ const wchar_t* Textures::preLoaded[TN_COUNT] = { L"gui/horse", L"gui/anvil", L"gui/trap", + L"gui/beacon", L"gui/hopper", L"gui/enchant", L"gui/villager", diff --git a/Minecraft.Client/Textures/Textures.h b/Minecraft.Client/Textures/Textures.h index 3edec4b5d..fd59fc66b 100644 --- a/Minecraft.Client/Textures/Textures.h +++ b/Minecraft.Client/Textures/Textures.h @@ -162,6 +162,7 @@ typedef enum _TEXTURE_NAME { TN_GUI_HORSE, TN_GUI_ANVIL, TN_GUI_TRAP, + TN_GUI_BEACON, TN_GUI_HOPPER, TN_GUI_ENCHANT, TN_GUI_VILLAGER, diff --git a/Minecraft.Client/UI/AbstractBeaconButton.cpp b/Minecraft.Client/UI/AbstractBeaconButton.cpp new file mode 100644 index 000000000..b2d874ddc --- /dev/null +++ b/Minecraft.Client/UI/AbstractBeaconButton.cpp @@ -0,0 +1,46 @@ +#include "../../Platform/stdafx.h" +#include "AbstractBeaconButton.h" +#include "../Textures/Textures.h" +#include "../../../Minecraft.Client/Minecraft.h" +#include + +// 4jcraft: referenced from MCP 8.11 (JE 1.6.4) +#ifdef ENABLE_JAVA_GUIS +extern ResourceLocation GUI_BEACON_LOCATION; +#endif + +AbstractBeaconButton::AbstractBeaconButton(int id, int x, int y) + : Button(id, x, y, 22, 22, L"") { + hovered = false; + selected = false; + iconRes = nullptr; + iconU = iconV = 0; +} + +void AbstractBeaconButton::renderBg(Minecraft* minecraft, int xm, int ym) { +#ifdef ENABLE_JAVA_GUIS + if (!visible) return; + + hovered = (xm >= x && ym >= y && xm < x + w && ym < y + h); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + minecraft->textures->bindTexture(&GUI_BEACON_LOCATION); + + int texU = 0; + if (!active) { + texU += w * 2; + } else if (selected) { + texU += w * 1; + } else if (hovered) { + texU += w * 3; + } + int texV = 219; + + blit(x, y, texU, texV, w, h); + + if (iconRes != nullptr && iconRes != &GUI_BEACON_LOCATION) { + minecraft->textures->bindTexture(iconRes); + } + blit(x + 2, y + 2, iconU, iconV, 18, 18); +#endif +} \ No newline at end of file diff --git a/Minecraft.Client/UI/AbstractBeaconButton.h b/Minecraft.Client/UI/AbstractBeaconButton.h new file mode 100644 index 000000000..3254f4912 --- /dev/null +++ b/Minecraft.Client/UI/AbstractBeaconButton.h @@ -0,0 +1,24 @@ +#pragma once +#include "Button.h" + +class ResourceLocation; + +class AbstractBeaconButton : public Button { +protected: + bool hovered; + bool selected; + ResourceLocation* iconRes; + int iconU, iconV; + +public: + AbstractBeaconButton(int id, int x, int y); + + void setSelected(bool sel) { selected = sel; } + bool isSelected() const { return selected; } + bool isHovered() const { return hovered; } + + virtual void renderTooltip(int xm, int ym) = 0; + +protected: + virtual void renderBg(Minecraft* minecraft, int xm, int ym) override; +}; \ No newline at end of file diff --git a/Minecraft.Client/UI/BeaconCancelButton.cpp b/Minecraft.Client/UI/BeaconCancelButton.cpp new file mode 100644 index 000000000..081029e4c --- /dev/null +++ b/Minecraft.Client/UI/BeaconCancelButton.cpp @@ -0,0 +1,25 @@ +#include "../../Platform/stdafx.h" +#include "BeaconCancelButton.h" +#include "Screens/BeaconScreen.h" +#include "../../../Minecraft.World/Headers/net.minecraft.locale.h" + +// 4jcraft: referenced from MCP 8.11 (JE 1.6.4) +#ifdef ENABLE_JAVA_GUIS +extern ResourceLocation GUI_BEACON_LOCATION; +#endif + +BeaconCancelButton::BeaconCancelButton(BeaconScreen* screen, int id, int x, + int y) + : AbstractBeaconButton(id, x, y) { + this->screen = screen; +#ifdef ENABLE_JAVA_GUIS + this->iconRes = &GUI_BEACON_LOCATION; +#endif + this->iconU = 112; + this->iconV = 220; +} + +void BeaconCancelButton::renderTooltip(int xm, int ym) { + screen->renderTooltip(Language::getInstance()->getElement(L"gui.cancel"), + xm, ym); +} \ No newline at end of file diff --git a/Minecraft.Client/UI/BeaconCancelButton.h b/Minecraft.Client/UI/BeaconCancelButton.h new file mode 100644 index 000000000..f9d62456e --- /dev/null +++ b/Minecraft.Client/UI/BeaconCancelButton.h @@ -0,0 +1,13 @@ +#pragma once +#include "AbstractBeaconButton.h" + +class BeaconScreen; + +class BeaconCancelButton : public AbstractBeaconButton { +public: + BeaconCancelButton(BeaconScreen* screen, int id, int x, int y); + void renderTooltip(int xm, int ym) override; + +private: + BeaconScreen* screen; +}; \ No newline at end of file diff --git a/Minecraft.Client/UI/BeaconConfirmButton.cpp b/Minecraft.Client/UI/BeaconConfirmButton.cpp new file mode 100644 index 000000000..00871f6e1 --- /dev/null +++ b/Minecraft.Client/UI/BeaconConfirmButton.cpp @@ -0,0 +1,25 @@ +#include "../../Platform/stdafx.h" +#include "BeaconConfirmButton.h" +#include "Screens/BeaconScreen.h" +#include "../../../Minecraft.World/Headers/net.minecraft.locale.h" + +// 4jcraft: referenced from MCP 8.11 (JE 1.6.4) +#ifdef ENABLE_JAVA_GUIS +extern ResourceLocation GUI_BEACON_LOCATION; +#endif + +BeaconConfirmButton::BeaconConfirmButton(BeaconScreen* screen, int id, int x, + int y) + : AbstractBeaconButton(id, x, y) { + this->screen = screen; +#ifdef ENABLE_JAVA_GUIS + this->iconRes = &GUI_BEACON_LOCATION; +#endif + this->iconU = 90; + this->iconV = 220; +} + +void BeaconConfirmButton::renderTooltip(int xm, int ym) { + screen->renderTooltip(Language::getInstance()->getElement(L"gui.done"), xm, + ym); +} \ No newline at end of file diff --git a/Minecraft.Client/UI/BeaconConfirmButton.h b/Minecraft.Client/UI/BeaconConfirmButton.h new file mode 100644 index 000000000..ab1d28177 --- /dev/null +++ b/Minecraft.Client/UI/BeaconConfirmButton.h @@ -0,0 +1,13 @@ +#pragma once +#include "AbstractBeaconButton.h" + +class BeaconScreen; + +class BeaconConfirmButton : public AbstractBeaconButton { +public: + BeaconConfirmButton(BeaconScreen* screen, int id, int x, int y); + void renderTooltip(int xm, int ym) override; + +private: + BeaconScreen* screen; +}; \ No newline at end of file diff --git a/Minecraft.Client/UI/BeaconPowerButton.cpp b/Minecraft.Client/UI/BeaconPowerButton.cpp new file mode 100644 index 000000000..958badfe7 --- /dev/null +++ b/Minecraft.Client/UI/BeaconPowerButton.cpp @@ -0,0 +1,39 @@ +#include "../../Platform/stdafx.h" +#include "BeaconPowerButton.h" +#include "Screens/BeaconScreen.h" +#include "../../../Minecraft.World/Entities/MobEffect.h" +#include "../../../Minecraft.World/Headers/net.minecraft.locale.h" +#include "../Textures/Textures.h" +#include "Textures/ResourceLocation.h" + +// 4jcraft: referenced from MCP 8.11 (JE 1.6.4) +#ifdef ENABLE_JAVA_GUIS +ResourceLocation GUI_INVENTORY_LOCATION = ResourceLocation(TN_GUI_INVENTORY); +#endif + +BeaconPowerButton::BeaconPowerButton(BeaconScreen* screen, int id, int x, int y, + int effectId, int tier) + : AbstractBeaconButton(id, x, y) { + this->screen = screen; + this->effectId = effectId; + this->tier = tier; + +#ifdef ENABLE_JAVA_GUIS + this->iconRes = &GUI_INVENTORY_LOCATION; +#endif + + int statusIconIndex = MobEffect::javaId(effectId); + this->iconU = (statusIconIndex % 8) * 18; + this->iconV = 198 + (statusIconIndex / 8) * 18; +} + +void BeaconPowerButton::renderTooltip(int xm, int ym) { + MobEffect* effect = MobEffect::effects[effectId]; + if (!effect) return; + + std::wstring name = app.GetString(effect->getDescriptionId()); + if (tier >= 3 && effect->id != MobEffect::regeneration->id) { + name += L" II"; + } + screen->renderTooltip(name, xm, ym); +} \ No newline at end of file diff --git a/Minecraft.Client/UI/BeaconPowerButton.h b/Minecraft.Client/UI/BeaconPowerButton.h new file mode 100644 index 000000000..fc6e40266 --- /dev/null +++ b/Minecraft.Client/UI/BeaconPowerButton.h @@ -0,0 +1,18 @@ +#pragma once +#include "AbstractBeaconButton.h" +#include "../../../Minecraft.World/Headers/net.minecraft.world.effect.h" + +class BeaconScreen; + +class BeaconPowerButton : public AbstractBeaconButton { +public: + BeaconPowerButton(BeaconScreen* screen, int id, int x, int y, int effectId, + int tier); + void renderTooltip(int xm, int ym) override; + bool isSelected() const { return selected; } + +private: + BeaconScreen* screen; + int effectId; + int tier; +}; \ No newline at end of file diff --git a/Minecraft.Client/UI/Screens/BeaconScreen.cpp b/Minecraft.Client/UI/Screens/BeaconScreen.cpp new file mode 100644 index 000000000..d44378d83 --- /dev/null +++ b/Minecraft.Client/UI/Screens/BeaconScreen.cpp @@ -0,0 +1,229 @@ +#include "../../Platform/stdafx.h" +#include "BeaconScreen.h" +#include "../BeaconConfirmButton.h" +#include "../BeaconCancelButton.h" +#include "../BeaconPowerButton.h" +#include +#include +#include "../../Player/MultiPlayerLocalPlayer.h" +#include "../../Rendering/Lighting.h" +#include "../../Textures/Textures.h" +#include "../../../Minecraft.World/Headers/net.minecraft.locale.h" +#include "../../../Minecraft.World/Containers/Slot.h" +#include "../../../Minecraft.World/Headers/net.minecraft.world.item.h" +#include "../../../Minecraft.Client/Minecraft.h" +#include "../../../Minecraft.Client/Network/ClientConnection.h" +#include "../../../Minecraft.World/IO/Streams/ByteArrayOutputStream.h" +#include "../../../Minecraft.World/IO/Streams/DataOutputStream.h" + +// 4jcraft: referenced from MCP 8.11 (JE 1.6.4) and the existing +// container classes (and iggy too) +#ifdef ENABLE_JAVA_GUIS +ResourceLocation GUI_BEACON_LOCATION = ResourceLocation(TN_GUI_BEACON); +#endif + +BeaconScreen::BeaconScreen(std::shared_ptr inventory, + std::shared_ptr beacon) + : AbstractContainerScreen(new BeaconMenu(inventory, beacon)) { + this->inventory = inventory; + this->beacon = beacon; + this->beaconMenu = static_cast(menu); + this->imageWidth = 230; + this->imageHeight = 219; + this->buttonsNotDrawn = true; + this->beaconConfirmButton = nullptr; +} + +BeaconScreen::~BeaconScreen() = default; + +void BeaconScreen::init() { + AbstractContainerScreen::init(); + + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + + beaconConfirmButton = new BeaconConfirmButton(this, -1, xo + 164, yo + 107); + buttons.push_back(beaconConfirmButton); + buttons.push_back(new BeaconCancelButton(this, -2, xo + 190, yo + 107)); + + buttonsNotDrawn = true; + beaconConfirmButton->active = false; +} + +void BeaconScreen::tick() { + if (buttonsNotDrawn && beacon->getLevels() >= 0) { + buttonsNotDrawn = false; + + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + + for (int tier = 0; tier <= 2; ++tier) { + int effectCount = BeaconTileEntity::BEACON_EFFECTS_EFFECTS; + int actualCount = 0; + for (int e = 0; e < effectCount; ++e) { + if (BeaconTileEntity::BEACON_EFFECTS[tier][e] != nullptr) { + actualCount++; + } else { + break; + } + } + + int totalWidth = actualCount * 22 + (actualCount - 1) * 2; + int startX = xo + 53 + (actualCount * 24 - totalWidth) / 2; + + for (int e = 0; e < actualCount; ++e) { + MobEffect* effect = BeaconTileEntity::BEACON_EFFECTS[tier][e]; + if (effect == nullptr) break; + + int buttonId = (tier << 8) | effect->id; + BeaconPowerButton* button = new BeaconPowerButton( + this, buttonId, startX + e * 24, yo + 22 + tier * 25, + effect->id, tier); + buttons.push_back(button); + + if (tier >= beacon->getLevels()) { + button->active = false; + } else if (effect->id == beacon->getPrimaryPower()) { + button->setSelected(true); + } + } + } + + int tier = 3; + int effectCount = BeaconTileEntity::BEACON_EFFECTS_EFFECTS; + int actualCount = 0; + for (int e = 0; e < effectCount; ++e) { + if (BeaconTileEntity::BEACON_EFFECTS[tier][e] != nullptr) { + actualCount++; + } else { + break; + } + } + + int totalWidth = (actualCount + 1) * 22 + actualCount * 2; + int startX = xo + 143 + ((actualCount + 1) * 24 - totalWidth) / 2; + + for (int e = 0; e < actualCount; ++e) { + MobEffect* effect = BeaconTileEntity::BEACON_EFFECTS[tier][e]; + if (effect == nullptr) break; + + int buttonId = (tier << 8) | effect->id; + BeaconPowerButton* button = new BeaconPowerButton( + this, buttonId, startX + e * 24, yo + 47, effect->id, tier); + buttons.push_back(button); + + if (tier >= beacon->getLevels()) { + button->active = false; + } else if (effect->id == beacon->getSecondaryPower()) { + button->setSelected(true); + } + } + + if (beacon->getPrimaryPower() > 0) { + int buttonId = (tier << 8) | beacon->getPrimaryPower(); + BeaconPowerButton* button = + new BeaconPowerButton(this, buttonId, startX + actualCount * 24, + yo + 47, beacon->getPrimaryPower(), tier); + buttons.push_back(button); + + if (tier >= beacon->getLevels()) { + button->active = false; + } else if (beacon->getPrimaryPower() == + beacon->getSecondaryPower()) { + button->setSelected(true); + } + } + } + + beaconConfirmButton->active = + (beacon->getItem(0) != nullptr && beacon->getPrimaryPower() > 0); +} + +void BeaconScreen::removed() { AbstractContainerScreen::removed(); } + +void BeaconScreen::renderLabels() { + std::wstring primaryLabel = + Language::getInstance()->getElement(L"tile.beacon.primary"); + font->drawShadow(primaryLabel, 25, 10, 0xE1E1E1); + + std::wstring secondaryLabel = + Language::getInstance()->getElement(L"tile.beacon.secondary"); + font->drawShadow(secondaryLabel, 125, 10, 0xE1E1E1); +} + +void BeaconScreen::renderBg(float a) { +#ifdef ENABLE_JAVA_GUIS + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + minecraft->textures->bindTexture(&GUI_BEACON_LOCATION); + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + blit(xo, yo, 0, 0, imageWidth, imageHeight); + + // Render payment item icons + itemRenderer->renderGuiItem( + font, minecraft->textures, + std::shared_ptr(new ItemInstance(Item::emerald_Id, 1, 0)), + xo + 42, yo + 109); + itemRenderer->renderGuiItem( + font, minecraft->textures, + std::shared_ptr(new ItemInstance(Item::diamond_Id, 1, 0)), + xo + 42 + 22, yo + 109); + itemRenderer->renderGuiItem(font, minecraft->textures, + std::shared_ptr( + new ItemInstance(Item::goldIngot_Id, 1, 0)), + xo + 42 + 44, yo + 109); + itemRenderer->renderGuiItem(font, minecraft->textures, + std::shared_ptr( + new ItemInstance(Item::ironIngot_Id, 1, 0)), + xo + 42 + 66, yo + 109); +#endif +} + +void BeaconScreen::render(int xm, int ym, float a) { + AbstractContainerScreen::render(xm, ym, a); + for (Button* button : buttons) { + AbstractBeaconButton* beaconButton = + dynamic_cast(button); + if (beaconButton && beaconButton->isHovered()) { + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + beaconButton->renderTooltip(xm, ym); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + break; + } + } +} + +void BeaconScreen::buttonClicked(Button* button) { + if (button->id == -2) { + minecraft->player->closeContainer(); + } else if (button->id == -1) { + // 4jcraft: copied from IUIScene_BeaconMenu + ByteArrayOutputStream baos; + DataOutputStream dos(&baos); + dos.writeInt(beacon->getPrimaryPower()); + dos.writeInt(beacon->getSecondaryPower()); + + minecraft->player->connection->send( + std::shared_ptr(new CustomPayloadPacket( + CustomPayloadPacket::SET_BEACON_PACKET, baos.toByteArray()))); + minecraft->player->closeContainer(); + } else if (dynamic_cast(button)) { + int effectId = button->id & 255; + int tier = button->id >> 8; + + if (tier < 3) { + beacon->setPrimaryPower(effectId); + } else { + beacon->setSecondaryPower(effectId); + } + + for (Button* btn : buttons) { + delete btn; + } + buttons.clear(); + init(); + tick(); + } +} \ No newline at end of file diff --git a/Minecraft.Client/UI/Screens/BeaconScreen.h b/Minecraft.Client/UI/Screens/BeaconScreen.h new file mode 100644 index 000000000..03a9db927 --- /dev/null +++ b/Minecraft.Client/UI/Screens/BeaconScreen.h @@ -0,0 +1,32 @@ +#pragma once + +#include "AbstractContainerScreen.h" +#include "../../../Minecraft.World/Containers/BeaconMenu.h" +#include "../../../Minecraft.World/Headers/net.minecraft.world.level.tile.entity.h" + +class BeaconConfirmButton; +class BeaconCancelButton; + +class BeaconScreen : public AbstractContainerScreen { +public: + BeaconScreen(std::shared_ptr inventory, + std::shared_ptr beacon); + virtual ~BeaconScreen(); + + void init() override; + void removed() override; + void tick() override; + void renderLabels() override; + void renderBg(float a) override; + void render(int xm, int ym, float a) override; + void buttonClicked(Button* button) override; + + std::shared_ptr getBeacon() { return beacon; } + +private: + std::shared_ptr inventory; + std::shared_ptr beacon; + BeaconMenu* beaconMenu; + BeaconConfirmButton* beaconConfirmButton; + bool buttonsNotDrawn; +}; \ No newline at end of file diff --git a/Minecraft.Client/UI/Screens/TitleScreen.cpp b/Minecraft.Client/UI/Screens/TitleScreen.cpp index 50b527600..650d49af8 100644 --- a/Minecraft.Client/UI/Screens/TitleScreen.cpp +++ b/Minecraft.Client/UI/Screens/TitleScreen.cpp @@ -5,6 +5,7 @@ #include "JoinMultiplayerScreen.h" #include "../../Rendering/Tesselator.h" #include "../../Textures/Textures.h" +#include "../../GameState/Options.h" #include "../../../Minecraft.World/Util/StringHelpers.h" #include "../../../Minecraft.World/IO/Streams/InputOutputStream.h" #include "../../../Minecraft.World/Headers/net.minecraft.locale.h" diff --git a/Minecraft.World/Entities/MobEffect.cpp b/Minecraft.World/Entities/MobEffect.cpp index a0822934f..828b5a4e3 100644 --- a/Minecraft.World/Entities/MobEffect.cpp +++ b/Minecraft.World/Entities/MobEffect.cpp @@ -443,4 +443,53 @@ void MobEffect::addAttributeModifiers(std::shared_ptr entity, double MobEffect::getAttributeModifierValue(int amplifier, AttributeModifier* original) { return original->getAmount() * (amplifier + 1); +} + +// 4jcraft: helper for inventoryscreen and beaconscreen +int MobEffect::javaId(int id) { + // mapped to java based on the inventory texture (see gui/inventory.png) + switch (id) { + case 1: + return 0; + case 2: + return 1; + case 3: + return 2; + case 4: + return 3; + case 5: + return 4; + case 18: + return 5; + case 19: + return 6; + case 10: + return 7; + case 14: + return 8; + case 17: + return 9; + case 8: + return 10; + case 9: + return 11; + case 16: + return 12; + case 15: + return 13; + case 11: + return 14; + case 12: + return 15; + case 13: + return 16; + case 20: + return 17; + case 21: + return 18; + case 22: + return 18; + default: + return 0; + } } \ No newline at end of file diff --git a/Minecraft.World/Entities/MobEffect.h b/Minecraft.World/Entities/MobEffect.h index 8e7ccce17..5576a2b4b 100644 --- a/Minecraft.World/Entities/MobEffect.h +++ b/Minecraft.World/Entities/MobEffect.h @@ -134,4 +134,6 @@ public: int amplifier); virtual double getAttributeModifierValue(int amplifier, AttributeModifier* original); + static int javaId( + int id); // 4jcraft: helper for inventoryscreen and beaconscreen }; \ No newline at end of file