summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattes D <github@xoft.cz>2014-05-06 21:46:50 +0200
committerMattes D <github@xoft.cz>2014-05-06 21:46:50 +0200
commit66c5c81e02dd9350542e1dd65b8e33c2f45a011b (patch)
treee719f55d50354e881c8ace1ca83516596519abaf
parentMerge pull request #927 from mc-server/fixes (diff)
parentRename CanRepairWithItem to CanRepairWithRawMaterial and rename Size() to Count() (diff)
downloadcuberite-66c5c81e02dd9350542e1dd65b8e33c2f45a011b.tar
cuberite-66c5c81e02dd9350542e1dd65b8e33c2f45a011b.tar.gz
cuberite-66c5c81e02dd9350542e1dd65b8e33c2f45a011b.tar.bz2
cuberite-66c5c81e02dd9350542e1dd65b8e33c2f45a011b.tar.lz
cuberite-66c5c81e02dd9350542e1dd65b8e33c2f45a011b.tar.xz
cuberite-66c5c81e02dd9350542e1dd65b8e33c2f45a011b.tar.zst
cuberite-66c5c81e02dd9350542e1dd65b8e33c2f45a011b.zip
-rw-r--r--src/Blocks/BlockAnvil.h7
-rw-r--r--src/ClientHandle.cpp27
-rw-r--r--src/ClientHandle.h3
-rw-r--r--src/Enchantments.cpp9
-rw-r--r--src/Enchantments.h3
-rw-r--r--src/Items/ItemArmor.h43
-rw-r--r--src/Items/ItemHandler.cpp19
-rw-r--r--src/Items/ItemHandler.h6
-rw-r--r--src/Items/ItemPickaxe.h13
-rw-r--r--src/Items/ItemShovel.h14
-rw-r--r--src/Items/ItemSword.h13
-rw-r--r--src/Simulator/SandSimulator.cpp4
-rw-r--r--src/UI/SlotArea.cpp401
-rw-r--r--src/UI/SlotArea.h38
-rw-r--r--src/UI/Window.cpp45
-rw-r--r--src/UI/Window.h29
16 files changed, 671 insertions, 3 deletions
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h
index 93a796ef7..35a356678 100644
--- a/src/Blocks/BlockAnvil.h
+++ b/src/Blocks/BlockAnvil.h
@@ -23,6 +23,13 @@ public:
{
a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2));
}
+
+
+ virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
+ {
+ cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ);
+ a_Player->OpenWindow(Window);
+ }
virtual bool GetPlacementBlockTypeMeta(
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index d414c3178..94f031ed6 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -633,6 +633,10 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
// Client <-> Server branding exchange
SendPluginMessage("MC|Brand", "MCServer");
}
+ else if (a_Channel == "MC|ItemName")
+ {
+ HandleAnvilItemName(a_Message.c_str(), a_Message.size());
+ }
else if (a_Channel == "REGISTER")
{
if (HasPluginChannel(a_Channel))
@@ -774,6 +778,29 @@ void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Leng
+void cClientHandle::HandleAnvilItemName(const char * a_Data, size_t a_Length)
+{
+ if (a_Length < 1)
+ {
+ return;
+ }
+
+ if ((m_Player->GetWindow() == NULL) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil))
+ {
+ return;
+ }
+
+ AString Name(a_Data, a_Length);
+ if (Name.length() <= 30)
+ {
+ ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(Name, m_Player);
+ }
+}
+
+
+
+
+
void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status)
{
LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i",
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 9fd17ac00..4dc6ab074 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -385,6 +385,9 @@ private:
/** Handles the "MC|AdvCdm" plugin message */
void HandleCommandBlockMessage(const char * a_Data, size_t a_Length);
+
+ /** Handles the "MC|ItemName" plugin message */
+ void HandleAnvilItemName(const char * a_Data, size_t a_Length);
// cSocketThreads::cCallback overrides:
virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
diff --git a/src/Enchantments.cpp b/src/Enchantments.cpp
index 64f89815b..264878c22 100644
--- a/src/Enchantments.cpp
+++ b/src/Enchantments.cpp
@@ -83,6 +83,15 @@ void cEnchantments::AddFromString(const AString & a_StringSpec)
+size_t cEnchantments::Count(void)
+{
+ return m_Enchantments.size();
+}
+
+
+
+
+
AString cEnchantments::ToString(void) const
{
// Serialize all the enchantments into a string
diff --git a/src/Enchantments.h b/src/Enchantments.h
index ec42257c8..85a316414 100644
--- a/src/Enchantments.h
+++ b/src/Enchantments.h
@@ -84,6 +84,9 @@ public:
/** Adds enchantments in the stringspec; if a specified enchantment already exists, overwrites it */
void AddFromString(const AString & a_StringSpec);
+ /** Get the count of enchantments */
+ size_t Count(void);
+
/** Serializes all the enchantments into a string */
AString ToString(void) const;
diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h
index 08cddb1ad..2436df5bd 100644
--- a/src/Items/ItemArmor.h
+++ b/src/Items/ItemArmor.h
@@ -60,6 +60,49 @@ public:
return true;
}
+ virtual bool CanRepairWithRawMaterial(short a_ItemType) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_CHAIN_BOOTS:
+ case E_ITEM_CHAIN_CHESTPLATE:
+ case E_ITEM_CHAIN_HELMET:
+ case E_ITEM_CHAIN_LEGGINGS:
+ {
+ return (a_ItemType == E_ITEM_IRON);
+ }
+ case E_ITEM_DIAMOND_BOOTS:
+ case E_ITEM_DIAMOND_CHESTPLATE:
+ case E_ITEM_DIAMOND_HELMET:
+ case E_ITEM_DIAMOND_LEGGINGS:
+ {
+ return (a_ItemType == E_ITEM_DIAMOND);
+ }
+ case E_ITEM_IRON_BOOTS:
+ case E_ITEM_IRON_CHESTPLATE:
+ case E_ITEM_IRON_HELMET:
+ case E_ITEM_IRON_LEGGINGS:
+ {
+ return (a_ItemType == E_ITEM_IRON);
+ }
+ case E_ITEM_GOLD_BOOTS:
+ case E_ITEM_GOLD_CHESTPLATE:
+ case E_ITEM_GOLD_HELMET:
+ case E_ITEM_GOLD_LEGGINGS:
+ {
+ return (a_ItemType == E_ITEM_GOLD);
+ }
+ case E_ITEM_LEATHER_BOOTS:
+ case E_ITEM_LEATHER_CAP:
+ case E_ITEM_LEATHER_PANTS:
+ case E_ITEM_LEATHER_TUNIC:
+ {
+ return (a_ItemType == E_ITEM_LEATHER);
+ }
+ }
+ return false;
+ }
+
} ;
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index ce9593a70..5cc5b66a0 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -511,6 +511,25 @@ bool cItemHandler::IsPlaceable(void)
+
+bool cItemHandler::CanRepairWithRawMaterial(short a_ItemType)
+{
+ return false;
+}
+
+
+
+
+
+int cItemHandler::GetRepairCost(void)
+{
+ return 0;
+}
+
+
+
+
+
bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
{
UNUSED(a_BlockType);
diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h
index 4993eac85..ca090eb29 100644
--- a/src/Items/ItemHandler.h
+++ b/src/Items/ItemHandler.h
@@ -85,6 +85,12 @@ public:
/** Blocks simply get placed */
virtual bool IsPlaceable(void);
+ /** Can the anvil repair this item, when a_Item is the second input? */
+ virtual bool CanRepairWithRawMaterial(short a_ItemType);
+
+ /** Get the repair cost from the item, or 0 if the item hasn't repair cost. */
+ virtual int GetRepairCost(void);
+
/** Called before a block is placed into a world.
The handler should return true to allow placement, false to refuse.
Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block.
diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h
index 2a8e40daa..ff2c2069b 100644
--- a/src/Items/ItemPickaxe.h
+++ b/src/Items/ItemPickaxe.h
@@ -85,6 +85,19 @@ public:
}
return false;
}
+
+ virtual bool CanRepairWithRawMaterial(short a_ItemType) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_WOODEN_PICKAXE: return (a_ItemType == E_BLOCK_PLANKS);
+ case E_ITEM_STONE_PICKAXE: return (a_ItemType == E_BLOCK_COBBLESTONE);
+ case E_ITEM_IRON_PICKAXE: return (a_ItemType == E_ITEM_IRON);
+ case E_ITEM_GOLD_PICKAXE: return (a_ItemType == E_ITEM_GOLD);
+ case E_ITEM_DIAMOND_PICKAXE: return (a_ItemType == E_ITEM_DIAMOND);
+ }
+ return false;
+ }
} ;
diff --git a/src/Items/ItemShovel.h b/src/Items/ItemShovel.h
index 873d5ae25..333ba46e8 100644
--- a/src/Items/ItemShovel.h
+++ b/src/Items/ItemShovel.h
@@ -41,4 +41,18 @@ public:
{
return (a_BlockType == E_BLOCK_SNOW);
}
+
+ virtual bool CanRepairWithRawMaterial(short a_ItemType) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_WOODEN_SHOVEL: return (a_ItemType == E_BLOCK_PLANKS);
+ case E_ITEM_STONE_SHOVEL: return (a_ItemType == E_BLOCK_COBBLESTONE);
+ case E_ITEM_IRON_SHOVEL: return (a_ItemType == E_ITEM_IRON);
+ case E_ITEM_GOLD_SHOVEL: return (a_ItemType == E_ITEM_GOLD);
+ case E_ITEM_DIAMOND_SHOVEL: return (a_ItemType == E_ITEM_DIAMOND);
+ }
+ return false;
+ }
+
};
diff --git a/src/Items/ItemSword.h b/src/Items/ItemSword.h
index a7c1d2432..44feb2d83 100644
--- a/src/Items/ItemSword.h
+++ b/src/Items/ItemSword.h
@@ -23,6 +23,19 @@ public:
{
return (a_BlockType == E_BLOCK_COBWEB);
}
+
+ virtual bool CanRepairWithRawMaterial(short a_ItemType) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_WOODEN_SWORD: return (a_ItemType == E_BLOCK_PLANKS);
+ case E_ITEM_STONE_SWORD: return (a_ItemType == E_BLOCK_COBBLESTONE);
+ case E_ITEM_IRON_SWORD: return (a_ItemType == E_ITEM_IRON);
+ case E_ITEM_GOLD_SWORD: return (a_ItemType == E_ITEM_GOLD);
+ case E_ITEM_DIAMOND_SWORD: return (a_ItemType == E_ITEM_DIAMOND);
+ }
+ return false;
+ }
} ;
diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp
index f305ba61a..c4f57c86a 100644
--- a/src/Simulator/SandSimulator.cpp
+++ b/src/Simulator/SandSimulator.cpp
@@ -254,6 +254,10 @@ void cSandSimulator::FinishFalling(
{
// Rematerialize the material here:
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FallingBlockType, a_FallingBlockMeta);
+ if (a_FallingBlockType == E_BLOCK_ANVIL)
+ {
+ a_World->BroadcastSoundParticleEffect(1022, a_BlockX, a_BlockY, a_BlockZ, 0);
+ }
return;
}
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index 87b4032e0..fcf5f6f6b 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -244,7 +244,7 @@ void cSlotArea::OnPlayerRemoved(cPlayer & a_Player)
-void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots)
+void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
{
for (int i = 0; i < m_NumSlots; i++)
{
@@ -264,7 +264,7 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_
{
NumFit = a_ItemStack.m_ItemCount;
}
- if (a_Apply)
+ if (a_ShouldApply)
{
cItem NewSlot(a_ItemStack);
NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
@@ -596,6 +596,403 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSlotAreaAnvil:
+
+cSlotAreaAnvil::cSlotAreaAnvil(cAnvilWindow & a_ParentWindow) :
+ cSlotAreaTemporary(3, a_ParentWindow),
+ m_MaximumCost(0)
+{
+}
+
+
+
+
+
+void cSlotAreaAnvil::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
+{
+ ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
+ if (a_SlotNum != 2)
+ {
+ super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
+ UpdateResult(a_Player);
+ return;
+ }
+
+ bool bAsync = false;
+ if (GetSlot(a_SlotNum, a_Player) == NULL)
+ {
+ LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum);
+ return;
+ }
+
+ if (a_ClickAction == caDblClick)
+ {
+ return;
+ }
+
+ if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick))
+ {
+ ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
+ return;
+ }
+
+ cItem Slot(*GetSlot(a_SlotNum, a_Player));
+ if (!Slot.IsSameType(a_ClickedItem))
+ {
+ LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
+ LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
+ LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
+ bAsync = true;
+ }
+ cItem & DraggingItem = a_Player.GetDraggingItem();
+
+ if (Slot.IsEmpty())
+ {
+ return;
+ }
+ if (!DraggingItem.IsEmpty())
+ {
+ if (!(DraggingItem.IsEqual(Slot) && ((DraggingItem.m_ItemCount + Slot.m_ItemCount) <= cItemHandler::GetItemHandler(Slot)->GetMaxStackSize())))
+ {
+ return;
+ }
+ }
+
+ if (!CanTakeResultItem(a_Player))
+ {
+ return;
+ }
+
+ cItem NewItem = cItem(Slot);
+ NewItem.m_ItemCount += DraggingItem.m_ItemCount;
+
+ Slot.Empty();
+ DraggingItem.Empty();
+ SetSlot(a_SlotNum, a_Player, Slot);
+
+ DraggingItem = NewItem;
+ OnTakeResult(a_Player);
+
+ if (bAsync)
+ {
+ m_ParentWindow.BroadcastWholeWindow();
+ }
+}
+
+
+
+
+
+void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem)
+{
+ if (a_SlotNum != 2)
+ {
+ super::ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
+ UpdateResult(a_Player);
+ return;
+ }
+
+ // Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover:
+ cItem Slot(*GetSlot(a_SlotNum, a_Player));
+
+ if (Slot.IsEmpty() || !CanTakeResultItem(a_Player))
+ {
+ return;
+ }
+
+ m_ParentWindow.DistributeStack(Slot, a_Player, this, true);
+ if (Slot.IsEmpty())
+ {
+ Slot.Empty();
+ OnTakeResult(a_Player);
+ }
+ SetSlot(a_SlotNum, a_Player, Slot);
+
+ // Some clients try to guess our actions and not always right (armor slots in 1.2.5), so we fix them:
+ m_ParentWindow.BroadcastWholeWindow();
+}
+
+
+
+
+
+void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ const cItem * Slot = GetSlot(i, a_Player);
+ if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
+ {
+ // Different items
+ continue;
+ }
+ int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount;
+ if (NumFit <= 0)
+ {
+ // Full stack already
+ continue;
+ }
+ if (NumFit > a_ItemStack.m_ItemCount)
+ {
+ NumFit = a_ItemStack.m_ItemCount;
+ }
+ if (a_ShouldApply)
+ {
+ cItem NewSlot(a_ItemStack);
+ NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
+ SetSlot(i, a_Player, NewSlot);
+ }
+ a_ItemStack.m_ItemCount -= NumFit;
+ if (a_ItemStack.IsEmpty())
+ {
+ UpdateResult(a_Player);
+ return;
+ }
+ } // for i - Slots
+ UpdateResult(a_Player);
+}
+
+
+
+
+
+void cSlotAreaAnvil::OnTakeResult(cPlayer & a_Player)
+{
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.DeltaExperience(cPlayer::XpForLevel(m_MaximumCost));
+ }
+ SetSlot(0, a_Player, cItem());
+
+ if (m_StackSizeToBeUsedInRepair > 0)
+ {
+ const cItem * Item = GetSlot(1, a_Player);
+ if (!Item->IsEmpty() && (Item->m_ItemCount > m_StackSizeToBeUsedInRepair))
+ {
+ cItem NewSecondItem(*Item);
+ NewSecondItem.m_ItemCount -= m_StackSizeToBeUsedInRepair;
+ SetSlot(1, a_Player, NewSecondItem);
+ }
+ else
+ {
+ SetSlot(1, a_Player, cItem());
+ }
+ }
+ else
+ {
+ SetSlot(1, a_Player, cItem());
+ }
+ m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player);
+
+ m_MaximumCost = 0;
+ ((cAnvilWindow*)&m_ParentWindow)->SetRepairedItemName("", NULL);
+
+ int PosX, PosY, PosZ;
+ ((cAnvilWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ);
+
+ BLOCKTYPE Block;
+ NIBBLETYPE BlockMeta;
+ a_Player.GetWorld()->GetBlockTypeMeta(PosX, PosY, PosZ, Block, BlockMeta);
+
+ cFastRandom Random;
+ if (!a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && (Random.NextFloat(1.0F) < 0.12F))
+ {
+ NIBBLETYPE Orientation = BlockMeta & 0x3;
+ NIBBLETYPE AnvilDamage = BlockMeta >> 2;
+ ++AnvilDamage;
+
+ if (AnvilDamage > 2)
+ {
+ // Anvil will break
+ a_Player.GetWorld()->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, (NIBBLETYPE)0);
+ a_Player.GetWorld()->BroadcastSoundParticleEffect(1020, PosX, PosY, PosZ, 0);
+ a_Player.CloseWindow(false);
+ }
+ else
+ {
+ a_Player.GetWorld()->SetBlockMeta(PosX, PosY, PosZ, Orientation | (AnvilDamage << 2));
+ a_Player.GetWorld()->BroadcastSoundParticleEffect(1021, PosX, PosY, PosZ, 0);
+ }
+ }
+ else
+ {
+ a_Player.GetWorld()->BroadcastSoundParticleEffect(1021, PosX, PosY, PosZ, 0);
+ }
+}
+
+
+
+
+
+bool cSlotAreaAnvil::CanTakeResultItem(cPlayer & a_Player)
+{
+ return (
+ (
+ a_Player.IsGameModeCreative() || // Is the player in gamemode?
+ (a_Player.GetXpLevel() >= m_MaximumCost) // or the player have enough exp?
+ ) &&
+ (!GetSlot(2, a_Player)->IsEmpty()) && // Is a item in the result slot?
+ (m_MaximumCost > 0) // When no maximum cost is set, the item isn't set from the UpdateResult() method and can't be a valid enchanting result.
+ );
+}
+
+
+
+
+
+void cSlotAreaAnvil::OnPlayerRemoved(cPlayer & a_Player)
+{
+ TossItems(a_Player, 0, 2);
+ super::OnPlayerRemoved(a_Player);
+}
+
+
+
+
+
+void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player)
+{
+ cItem Input(*GetSlot(0, a_Player));
+ cItem SecondInput(*GetSlot(1, a_Player));
+ cItem Output(*GetSlot(2, a_Player));
+
+ if (Input.IsEmpty() && !Output.IsEmpty())
+ {
+ Output.Empty();
+ SetSlot(2, a_Player, Output);
+ m_ParentWindow.SetProperty(0, 0, a_Player);
+ return;
+ }
+
+ m_MaximumCost = 0;
+ m_StackSizeToBeUsedInRepair = 0;
+ int RepairCost = cItemHandler::GetItemHandler(Input)->GetRepairCost();
+ int NeedExp = 0;
+ if (!SecondInput.IsEmpty())
+ {
+ RepairCost += cItemHandler::GetItemHandler(SecondInput)->GetRepairCost();
+ if (Input.IsDamageable() && cItemHandler::GetItemHandler(Input)->CanRepairWithRawMaterial(SecondInput.m_ItemType))
+ {
+ // Tool and armor repair with special item (iron / gold / diamond / ...)
+ int DamageDiff = std::min((int)Input.m_ItemDamage, (int)Input.GetMaxDamage() / 4);
+ if (DamageDiff < 0)
+ {
+ // No enchantment
+ Output.Empty();
+ SetSlot(2, a_Player, Output);
+ m_ParentWindow.SetProperty(0, 0, a_Player);
+ return;
+ }
+
+ int x = 0;
+ while ((DamageDiff > 0) && (x < SecondInput.m_ItemCount))
+ {
+ Input.m_ItemDamage -= DamageDiff;
+ NeedExp += std::max(1, DamageDiff / 100) + Input.m_Enchantments.Count();
+ DamageDiff = std::min((int)Input.m_ItemDamage, (int)Input.GetMaxDamage() / 4);
+
+ ++x;
+ }
+ m_StackSizeToBeUsedInRepair = x;
+ }
+ else
+ {
+ // Tool and armor repair with two tools / armors
+ if (!Input.IsSameType(SecondInput) || !Input.IsDamageable())
+ {
+ // No enchantment
+ Output.Empty();
+ SetSlot(2, a_Player, Output);
+ m_ParentWindow.SetProperty(0, 0, a_Player);
+ return;
+ }
+
+ int FirstDamageDiff = Input.GetMaxDamage() - Input.m_ItemDamage;
+ int SecondDamageDiff = SecondInput.GetMaxDamage() - SecondInput.m_ItemDamage;
+ int Damage = SecondDamageDiff + Input.GetMaxDamage() * 12 / 100;
+
+ int NewItemDamage = Input.GetMaxDamage() - (FirstDamageDiff + Damage);
+ if (NewItemDamage > 0)
+ {
+ NewItemDamage = 0;
+ }
+
+ if (NewItemDamage < Input.m_ItemDamage)
+ {
+ Input.m_ItemDamage = NewItemDamage;
+ NeedExp += std::max(1, Damage / 100);
+ }
+
+ // TODO: Add enchantments.
+ }
+ }
+
+ int NameChangeExp = 0;
+ const AString & RepairedItemName = ((cAnvilWindow*)&m_ParentWindow)->GetRepairedItemName();
+ if (RepairedItemName.empty())
+ {
+ // Remove custom name
+ if (!Input.m_CustomName.empty())
+ {
+ NameChangeExp = (Input.IsDamageable()) ? 4 : (Input.m_ItemCount * 5);
+ NeedExp += NameChangeExp;
+ Input.m_CustomName = "";
+ }
+ }
+ else if (RepairedItemName != Input.m_CustomName)
+ {
+ // Change custom name
+ NameChangeExp = (Input.IsDamageable()) ? 4 : (Input.m_ItemCount * 5);
+ NeedExp += NameChangeExp;
+
+ if (!Input.m_CustomName.empty())
+ {
+ RepairCost += NameChangeExp / 2;
+ }
+
+ Input.m_CustomName = RepairedItemName;
+ }
+
+ // TODO: Add enchantment exp cost.
+
+ m_MaximumCost = RepairCost + NeedExp;
+
+ if (NeedExp < 0)
+ {
+ Input.Empty();
+ }
+
+ if (NameChangeExp == NeedExp && NameChangeExp > 0 && m_MaximumCost >= 40)
+ {
+ m_MaximumCost = 39;
+ }
+ if (m_MaximumCost >= 40 && !a_Player.IsGameModeCreative())
+ {
+ Input.Empty();
+ }
+
+ /* TODO: Add repair cost to cItem and not ItemHandler. This is required for this function!
+ if (!Input.IsEmpty())
+ {
+ RepairCost = max(cItemHandler::GetItemHandler(Input)->GetRepairCost(), cItemHandler::GetItemHandler(SecondInput)->GetRepairCost());
+ if (!Input.m_CustomName.empty())
+ {
+ RepairCost -= 9;
+ }
+ RepairCost = max(RepairCost, 0);
+ RepairCost += 2;
+ }*/
+
+ SetSlot(2, a_Player, Input);
+ m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player);
+}
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaEnchanting:
cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) :
diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h
index 254722822..4da6a672f 100644
--- a/src/UI/SlotArea.h
+++ b/src/UI/SlotArea.h
@@ -9,6 +9,7 @@
#pragma once
#include "../Inventory.h"
+#include "Window.h"
@@ -259,6 +260,43 @@ protected:
+class cSlotAreaAnvil :
+ public cSlotAreaTemporary
+{
+ typedef cSlotAreaTemporary super;
+
+public:
+ cSlotAreaAnvil(cAnvilWindow & a_ParentWindow);
+
+ // cSlotArea overrides:
+ virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
+ virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+
+ // cSlotAreaTemporary overrides:
+ virtual void OnPlayerRemoved(cPlayer & a_Player) override;
+
+ /** Can the player take the item from the slot? */
+ bool CanTakeResultItem(cPlayer & a_Player);
+
+ /** This function will call, when the player take the item from the slot. */
+ void OnTakeResult(cPlayer & a_Player);
+
+ /** Handles a click in the item slot. */
+ void UpdateResult(cPlayer & a_Player);
+
+protected:
+ /** The maximum cost of repairing/renaming in the anvil. */
+ int m_MaximumCost;
+
+ /** The stack size of the second item where was used for repair */
+ char m_StackSizeToBeUsedInRepair;
+} ;
+
+
+
+
+
class cSlotAreaEnchanting :
public cSlotAreaTemporary
{
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index 0a78578fc..4991f0147 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -805,6 +805,51 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cAnvilWindow:
+
+cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtAnvil, "Repair"),
+ m_RepairedItemName(""),
+ m_BlockX(a_BlockX),
+ m_BlockY(a_BlockY),
+ m_BlockZ(a_BlockZ)
+{
+ m_AnvilSlotArea = new cSlotAreaAnvil(*this);
+ m_SlotAreas.push_back(m_AnvilSlotArea);
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player)
+{
+ m_RepairedItemName = a_Name;
+
+ if (a_Player != NULL)
+ {
+ m_AnvilSlotArea->UpdateResult(*a_Player);
+ }
+}
+
+
+
+
+
+void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
+{
+ a_PosX = m_BlockX;
+ a_PosY = m_BlockY;
+ a_PosZ = m_BlockZ;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cEnchantingWindow:
cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
diff --git a/src/UI/Window.h b/src/UI/Window.h
index 1ca67bfd8..542dccb88 100644
--- a/src/UI/Window.h
+++ b/src/UI/Window.h
@@ -24,6 +24,7 @@ class cEnderChestEntity;
class cFurnaceEntity;
class cHopperEntity;
class cSlotArea;
+class cSlotAreaAnvil;
class cWorld;
typedef std::list<cPlayer *> cPlayerList;
@@ -231,6 +232,32 @@ public:
+class cAnvilWindow :
+ public cWindow
+{
+ typedef cWindow super;
+public:
+ cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /** Gets the repaired item name. */
+ AString GetRepairedItemName(void) const { return m_RepairedItemName; }
+
+ /** Set the repaired item name. */
+ void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player);
+
+ /** Gets the Position from the Anvil */
+ void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
+
+protected:
+ cSlotAreaAnvil * m_AnvilSlotArea;
+ AString m_RepairedItemName;
+ int m_BlockX, m_BlockY, m_BlockZ;
+} ;
+
+
+
+
+
class cEnchantingWindow :
public cWindow
{
@@ -243,7 +270,7 @@ public:
/** Return the Value of a Property */
int GetPropertyValue(int a_Property);
- /** Set the Position Values to the Position of the Enchantment Table */
+ /** Get the Position from the Enchantment Table */
void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
cSlotArea * m_SlotArea;