summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Blocks/BlockEnchantmentTable.h37
-rw-r--r--src/Blocks/BlockHandler.cpp2
-rw-r--r--src/ClientHandle.cpp36
-rw-r--r--src/Enchantments.h5
-rw-r--r--src/FastRandom.cpp10
-rw-r--r--src/FastRandom.h3
-rw-r--r--src/Item.cpp106
-rw-r--r--src/Item.h3
-rw-r--r--src/Protocol/Protocol125.cpp18
-rw-r--r--src/Protocol/Protocol125.h1
-rw-r--r--src/Protocol/Protocol17x.cpp16
-rw-r--r--src/Protocol/Protocol17x.h1
-rw-r--r--src/UI/SlotArea.cpp96
-rw-r--r--src/UI/SlotArea.h28
-rw-r--r--src/UI/Window.cpp15
-rw-r--r--src/UI/Window.h12
16 files changed, 388 insertions, 1 deletions
diff --git a/src/Blocks/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h
new file mode 100644
index 000000000..e8a87179b
--- /dev/null
+++ b/src/Blocks/BlockEnchantmentTable.h
@@ -0,0 +1,37 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "../UI/Window.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cBlockEnchantmentTableHandler :
+ public cBlockHandler
+{
+public:
+ cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+
+ virtual void OnUse(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
+ {
+ cWindow * Window = new cEnchantingWindow(a_BlockX, a_BlockY, a_BlockZ);
+ a_Player->OpenWindow(Window);
+ }
+
+
+ virtual bool IsUseable(void) override
+ {
+ return true;
+ }
+};
+
+
+
+
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 4a29ff628..a764c6f44 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -25,6 +25,7 @@
#include "BlockDirt.h"
#include "BlockDoor.h"
#include "BlockDropSpenser.h"
+#include "BlockEnchantmentTable.h"
#include "BlockEnderchest.h"
#include "BlockEntity.h"
#include "BlockFarmland.h"
@@ -119,6 +120,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_DOUBLE_WOODEN_SLAB: return new cBlockDoubleSlabHandler (a_BlockType);
case E_BLOCK_DROPPER: return new cBlockDropSpenserHandler (a_BlockType);
case E_BLOCK_EMERALD_ORE: return new cBlockOreHandler (a_BlockType);
+ case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(a_BlockType);
case E_BLOCK_ENDER_CHEST: return new cBlockEnderchestHandler (a_BlockType);
case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler ( );
case E_BLOCK_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType);
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 5876e55c7..73a275ab1 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -2685,4 +2685,40 @@ void cClientHandle::SocketClosed(void)
+void cClientHandle::HandleEnchantItem(Byte & WindowID, Byte & Enchantment)
+{
+ //Get Item
+ cItem EnchantItem = m_Player->GetDraggingItem();
+
+ cEnchantmentsArray enchantments;
+ cItem::GetApplicableEnchantmentsForType(EnchantItem.m_ItemType, enchantments);
+
+ m_Player->SendMessage(Printf("ItemType: %d", EnchantItem.m_ItemType));
+
+
+ m_Player->SendMessage(enchantments[1].ToString());
+
+ //shuffle enchantments (i don't know if this is good)
+ std::random_shuffle(enchantments.begin(), enchantments.end());
+
+ m_Player->SendMessage(enchantments[1].ToString());
+
+
+
+
+
+
+ //Enchant Item
+ EnchantItem.m_Enchantments.AddFromString(enchantments[1].ToString());
+
+ //Set Enchanted Item to Window Slot
+ m_Player->GetWindow()->SetSlot(*m_Player, 0, EnchantItem);
+
+ LOGWARN("Item enchanted!");
+}
+
+
+
+
+
diff --git a/src/Enchantments.h b/src/Enchantments.h
index f77b535d8..2af772928 100644
--- a/src/Enchantments.h
+++ b/src/Enchantments.h
@@ -28,6 +28,9 @@ mapping each enchantment's id onto its level. ID may be either a number or the e
Level value of 0 means no such enchantment, and it will not be stored in the m_Enchantments.
Serialization will never put zero-level enchantments into the stringspec and will always use numeric IDs.
*/
+
+typedef std::vector<cEnchantments> cEnchantmentsArray;
+
// tolua_begin
class cEnchantments
{
@@ -61,7 +64,7 @@ public:
enchLuckOfTheSea = 61,
enchLure = 62,
} ;
-
+
/// Creates an empty enchantments container
cEnchantments(void);
diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp
index e6634bb0d..c45261947 100644
--- a/src/FastRandom.cpp
+++ b/src/FastRandom.cpp
@@ -172,3 +172,13 @@ float cFastRandom::NextFloat(float a_Range, int a_Salt)
+
+int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End)
+{
+ cFastRandom Random;
+ return Random.NextInt(a_End - a_Begin + 1) + a_Begin;
+}
+
+
+
+
diff --git a/src/FastRandom.h b/src/FastRandom.h
index bf70822cf..1c20fa39f 100644
--- a/src/FastRandom.h
+++ b/src/FastRandom.h
@@ -43,6 +43,9 @@ public:
/// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness
float NextFloat(float a_Range, int a_Salt);
+
+ /// Returns a random int in the range [a_Begin .. a_End]
+ int GenerateRandomInteger(int a_Begin, int a_End);
protected:
int m_Seed;
diff --git a/src/Item.cpp b/src/Item.cpp
index 856b68be6..093147b54 100644
--- a/src/Item.cpp
+++ b/src/Item.cpp
@@ -209,6 +209,112 @@ bool cItem::IsEnchantable(short item)
+void cItem::GetApplicableEnchantmentsForType(short a_ItemType, cEnchantmentsArray & a_Enchantments)
+{
+ LOGWARN("Get Enchantments");
+
+ if (ItemCategory::IsSword(a_ItemType))
+ {
+ a_Enchantments.push_back(cEnchantments("Sharpness=4"));
+ a_Enchantments.push_back(cEnchantments("Smite=5"));
+ a_Enchantments.push_back(cEnchantments("BaneOfArthropods=5"));
+ a_Enchantments.push_back(cEnchantments("Knockback=2"));
+ a_Enchantments.push_back(cEnchantments("FireAspect=2"));
+ a_Enchantments.push_back(cEnchantments("Looting=3"));
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ }
+
+ else if (ItemCategory::IsPickaxe(a_ItemType))
+ {
+ a_Enchantments.push_back(cEnchantments("Efficiency=4"));
+ a_Enchantments.push_back(cEnchantments("SilkTouch=1"));
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ a_Enchantments.push_back(cEnchantments("Fortune=3"));
+ }
+
+ else if (ItemCategory::IsAxe(a_ItemType))
+ {
+ a_Enchantments.push_back(cEnchantments("Efficiency=4"));
+ a_Enchantments.push_back(cEnchantments("SilkTouch=1"));
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ a_Enchantments.push_back(cEnchantments("Fortune=3"));
+ }
+
+ else if (ItemCategory::IsShovel(a_ItemType))
+ {
+ a_Enchantments.push_back(cEnchantments("Efficiency=4"));
+ a_Enchantments.push_back(cEnchantments("SilkTouch=1"));
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ a_Enchantments.push_back(cEnchantments("Fortune=3"));
+ }
+
+ else if (ItemCategory::IsHoe(a_ItemType))
+ {
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ }
+
+ else if (ItemCategory::IsArmor(a_ItemType))
+ {
+ a_Enchantments.push_back(cEnchantments("Protection=4"));
+ a_Enchantments.push_back(cEnchantments("FireProtection=4"));
+ a_Enchantments.push_back(cEnchantments("BlastProtection=4"));
+ a_Enchantments.push_back(cEnchantments("ProjectileProtection=4"));
+ a_Enchantments.push_back(cEnchantments("Thorns=3"));
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+
+ if (ItemCategory::IsHelmet(a_ItemType))
+ {
+ a_Enchantments.push_back(cEnchantments("Respiration=3"));
+ a_Enchantments.push_back(cEnchantments("AquaAffinity=1"));
+ }
+
+ else if (ItemCategory::IsBoots(a_ItemType))
+ {
+ a_Enchantments.push_back(cEnchantments("FeatherFalling=4"));
+ }
+ }
+
+ //Bow
+ else if (a_ItemType == 261)
+ {
+ a_Enchantments.push_back(cEnchantments("Power=4"));
+ a_Enchantments.push_back(cEnchantments("Punch=2"));
+ a_Enchantments.push_back(cEnchantments("Flame=1"));
+ a_Enchantments.push_back(cEnchantments("Infinity=1"));
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ }
+
+ //Fishing Rod
+ else if (a_ItemType == 346)
+ {
+ a_Enchantments.push_back(cEnchantments("LuckOfTheSea=3"));
+ a_Enchantments.push_back(cEnchantments("Lure=3"));
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ }
+
+ //Shears
+ else if (a_ItemType == 359)
+ {
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ }
+
+ //Flint and Steel
+ else if (a_ItemType == 259)
+ {
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ }
+
+ //Carrot on a Stick
+ else if (a_ItemType == 398)
+ {
+ a_Enchantments.push_back(cEnchantments("Unbreaking=3"));
+ }
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cItems:
diff --git a/src/Item.h b/src/Item.h
index 910ecb382..620c77b29 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -175,6 +175,9 @@ public:
/** Returns true if the specified item type is enchantable (as per 1.2.5 protocol requirements) */
static bool IsEnchantable(short a_ItemType); // tolua_export
+ /** Fills a_Enchantments with the list of enchantments applicable to the specified item type */
+ static void cItem::GetApplicableEnchantmentsForType(short a_ItemType, cEnchantmentsArray & a_Enchantments);
+
// tolua_begin
short m_ItemType;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index bf946ef19..867cf3ef3 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -96,6 +96,7 @@ enum
PACKET_INVENTORY_WHOLE = 0x68,
PACKET_WINDOW_PROPERTY = 0x69,
PACKET_CREATIVE_INVENTORY_ACTION = 0x6B,
+ PACKET_ENCHANT_ITEM = 0x6C,
PACKET_UPDATE_SIGN = 0x82,
PACKET_ITEM_DATA = 0x83,
PACKET_PLAYER_LIST_ITEM = 0xC9,
@@ -1236,6 +1237,7 @@ int cProtocol125::ParsePacket(unsigned char a_PacketType)
case PACKET_SLOT_SELECTED: return ParseSlotSelected();
case PACKET_UPDATE_SIGN: return ParseUpdateSign();
case PACKET_USE_ENTITY: return ParseUseEntity();
+ case PACKET_ENCHANT_ITEM: return ParseEnchantItem();
case PACKET_WINDOW_CLICK: return ParseWindowClick();
case PACKET_WINDOW_CLOSE: return ParseWindowClose();
}
@@ -1597,6 +1599,22 @@ int cProtocol125::ParseUseEntity(void)
+int cProtocol125::ParseEnchantItem(void)
+{
+ HANDLE_PACKET_READ(ReadByte, byte, WindowID);
+ HANDLE_PACKET_READ(ReadByte, byte, Enchantment);
+
+ LOGWARN("Older Protocol: Enchantment Packet received!");
+
+ m_Client->HandleEnchantItem(WindowID, Enchantment);
+
+ return PARSE_OK;
+}
+
+
+
+
+
int cProtocol125::ParseWindowClick(void)
{
HANDLE_PACKET_READ(ReadChar, char, WindowID);
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index 08d3ebbe9..753458ebc 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -155,6 +155,7 @@ protected:
virtual int ParseSlotSelected (void);
virtual int ParseUpdateSign (void);
virtual int ParseUseEntity (void);
+ virtual int ParseEnchantItem (void);
virtual int ParseWindowClick (void);
virtual int ParseWindowClose (void);
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index a4319df37..785dbf935 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -1431,6 +1431,7 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return true;
case 0x0f: // Confirm transaction - not used in MCS
case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
+ case 0x11: HandlePacketEnchantItem (a_ByteBuffer); return true;
case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true;
case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return true;
case 0x14: HandlePacketTabComplete (a_ByteBuffer); return true;
@@ -1912,6 +1913,21 @@ void cProtocol172::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer)
+void cProtocol172::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer)
+{
+ HANDLE_READ(a_ByteBuffer, ReadByte, Byte, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Enchantment);
+
+ LOGWARN("Protocol 1.7: Enchantment Packet received!");
+
+ m_Client->HandleEnchantItem(WindowID, Enchantment);
+
+}
+
+
+
+
+
void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID);
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 91186b270..a1ad1f049 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -279,6 +279,7 @@ protected:
void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer);
void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer);
void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer);
+ void HandlePacketEnchantItem (cByteBuffer & a_ByteBuffer);
void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer);
void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer);
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index 88977e005..9463bc593 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -13,6 +13,8 @@
#include "Window.h"
#include "../CraftingRecipes.h"
#include "../Root.h"
+#include "../FastRandom.h"
+#include "../BlockArea.h"
@@ -593,6 +595,100 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSlotAreaEnchanting:
+
+cSlotAreaEnchanting::cSlotAreaEnchanting(int a_NumSlots, cWindow & a_ParentWindow) :
+cSlotAreaTemporary(a_NumSlots, a_ParentWindow)
+{
+}
+
+
+
+
+
+void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
+{
+ LOGWARN("Clicked");
+ // Check if Slot is in the Enchantment Table
+ if (a_SlotNum == 0)
+ {
+ if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick))
+ {
+ ShiftClickedResult(a_Player);
+ }
+ else
+ {
+ ClickedResult(a_Player);
+ }
+ return;
+ }
+ super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
+}
+
+
+
+
+
+void cSlotAreaEnchanting::OnPlayerRemoved(cPlayer & a_Player)
+{
+ // Toss the item in the enchanting slot
+ TossItems(a_Player, 0, 0);
+ // Player not found - that is acceptable
+}
+
+
+
+
+
+void cSlotAreaEnchanting::ClickedResult(cPlayer & a_Player)
+{
+ LOGWARN("Click!");
+
+ if (a_Player.GetDraggingItem().IsEmpty())
+ {
+ LOGWARN("EMPTY");
+ m_ParentWindow.SetProperty(0, 0);
+ m_ParentWindow.SetProperty(1, 0);
+ m_ParentWindow.SetProperty(2, 0);
+ }
+ else if (a_Player.GetDraggingItem().IsEnchantable)
+ {
+ int bookshelves = 15; // TODO: Check Bookshelves
+
+ cFastRandom Random;
+ int base = (Random.GenerateRandomInteger(1, 8) + floor(bookshelves / 2) + Random.GenerateRandomInteger(0, bookshelves));
+ int topSlot = std::max(base / 3, 1);
+ int middleSlot = (base * 2) / 3 + 1;
+ int bottomSlot = std::max(base, bookshelves * 2);
+
+ LOGWARN("Enchantable");
+ m_ParentWindow.SetProperty(0, topSlot);
+ m_ParentWindow.SetProperty(1, middleSlot);
+ m_ParentWindow.SetProperty(2, bottomSlot);
+ }
+ else
+ {
+ LOGWARN("Not Enchantable");
+ m_ParentWindow.SetProperty(0, 0);
+ m_ParentWindow.SetProperty(1, 0);
+ m_ParentWindow.SetProperty(2, 0);
+ }
+}
+
+
+
+
+
+void cSlotAreaEnchanting::ShiftClickedResult(cPlayer & a_Player)
+{
+ LOGWARN("Shift Click!");
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaEnderChest:
cSlotAreaEnderChest::cSlotAreaEnderChest(cEnderChestEntity * a_EnderChest, cWindow & a_ParentWindow) :
diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h
index 25b367cff..82360ffbe 100644
--- a/src/UI/SlotArea.h
+++ b/src/UI/SlotArea.h
@@ -252,6 +252,34 @@ protected:
+class cSlotAreaEnchanting :
+ public cSlotAreaTemporary
+{
+ typedef cSlotAreaTemporary super;
+
+public:
+ /// a_GridSize is allowed to be only 2 or 3
+ cSlotAreaEnchanting(int a_NumSlots, cWindow & a_ParentWindow);
+
+ // cSlotAreaTemporary overrides:
+ virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
+ virtual void OnPlayerRemoved(cPlayer & a_Player) override;
+
+ // Distributing items into this area is completely disabled
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override {}
+
+protected:
+ /// Handles a click in the result slot. Crafts using the current recipe, if possible
+ void ClickedResult(cPlayer & a_Player);
+
+ /// Handles a shift-click in the result slot. Crafts using the current recipe until it changes or no more space for result.
+ void ShiftClickedResult(cPlayer & a_Player);
+};
+
+
+
+
+
class cSlotAreaChest :
public cSlotArea
{
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index aae7b99a3..5d89534dd 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -805,6 +805,21 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cEnchantingWindow:
+
+cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+cWindow(wtEnchantment, "Enchant")
+{
+ m_SlotAreas.push_back(new cSlotAreaEnchanting(1, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChestWindow:
cChestWindow::cChestWindow(cChestEntity * a_Chest) :
diff --git a/src/UI/Window.h b/src/UI/Window.h
index 030182888..cdaec5aaa 100644
--- a/src/UI/Window.h
+++ b/src/UI/Window.h
@@ -231,6 +231,18 @@ public:
+class cEnchantingWindow :
+ public cWindow
+{
+ typedef cWindow super;
+public:
+ cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+};
+
+
+
+
+
class cFurnaceWindow :
public cWindow
{