summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpeterbell10 <peterbell10@live.co.uk>2017-10-21 18:56:09 +0200
committerAlexander Harkness <me@bearbin.net>2017-10-21 18:56:09 +0200
commit0bacda32692729e4b9743f91d92cd329e198d73a (patch)
tree6d5780aafb44679125145f3bc255a200a840c3c2
parentFixed some small passive mob issues (#4057) (diff)
downloadcuberite-0bacda32692729e4b9743f91d92cd329e198d73a.tar
cuberite-0bacda32692729e4b9743f91d92cd329e198d73a.tar.gz
cuberite-0bacda32692729e4b9743f91d92cd329e198d73a.tar.bz2
cuberite-0bacda32692729e4b9743f91d92cd329e198d73a.tar.lz
cuberite-0bacda32692729e4b9743f91d92cd329e198d73a.tar.xz
cuberite-0bacda32692729e4b9743f91d92cd329e198d73a.tar.zst
cuberite-0bacda32692729e4b9743f91d92cd329e198d73a.zip
-rw-r--r--Server/Plugins/APIDump/APIDesc.lua18
-rw-r--r--src/ClientHandle.cpp12
-rw-r--r--src/ClientHandle.h4
-rw-r--r--src/Defines.h19
-rw-r--r--src/Entities/Player.cpp30
-rw-r--r--src/Entities/Player.h4
-rw-r--r--src/Mobs/Horse.cpp134
-rw-r--r--src/Mobs/Horse.h28
-rw-r--r--src/Protocol/Protocol_1_8.cpp5
-rw-r--r--src/Protocol/Protocol_1_9.cpp5
-rw-r--r--src/UI/CMakeLists.txt2
-rw-r--r--src/UI/HorseWindow.cpp61
-rw-r--r--src/UI/HorseWindow.h34
-rw-r--r--src/UI/SlotArea.cpp119
-rw-r--r--src/UI/SlotArea.h25
15 files changed, 473 insertions, 27 deletions
diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua
index 1548cf97d..3b37f2fdf 100644
--- a/Server/Plugins/APIDump/APIDesc.lua
+++ b/Server/Plugins/APIDump/APIDesc.lua
@@ -16977,6 +16977,24 @@ end
},
Notes = "Returns true if the specified item type is any kind of a hoe.",
},
+ IsHorseArmor=
+ {
+ IsStatic = true,
+ Params =
+ {
+ {
+ Name = "ItemType",
+ Type = "number",
+ },
+ },
+ Returns =
+ {
+ {
+ Type = "boolean",
+ },
+ },
+ Notes = "Returns true if the specified item type is any kind of a horse armor.",
+ },
IsLeggings =
{
IsStatic = true,
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 020707238..8ed3a6056 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -678,6 +678,18 @@ void cClientHandle::HandleNPCTrade(int a_SlotNum)
+void cClientHandle::HandleOpenHorseInventory(UInt32 a_EntityID)
+{
+ if (m_Player->GetUniqueID() == a_EntityID)
+ {
+ m_Player->OpenHorseInventory();
+ }
+}
+
+
+
+
+
void cClientHandle::HandlePing(void)
{
/* TODO: unused function, handles Legacy Server List Ping
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 8ded5a5ad..42e2ee10a 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -338,6 +338,10 @@ public: // tolua_export
the NPC UI. */
void HandleNPCTrade(int a_SlotNum);
+ /** Handles a player opening their inventory while riding a horse.
+ @param a_EntityID ID of the player that is to open the inventory. Should be the same as GetPlayer()->GetUniqueID(). */
+ void HandleOpenHorseInventory(UInt32 a_EntityID);
+
void HandlePing (void);
void HandlePlayerAbilities (bool a_CanFly, bool a_IsFlying, float FlyingSpeed, float WalkingSpeed);
void HandlePlayerLook (float a_Rotation, float a_Pitch, bool a_IsOnGround);
diff --git a/src/Defines.h b/src/Defines.h
index a3222f73a..7a7f4c598 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -1175,6 +1175,25 @@ namespace ItemCategory
IsBoots(a_ItemType)
);
}
+
+
+
+ inline bool IsHorseArmor(short a_ItemType)
+ {
+ switch (a_ItemType)
+ {
+ case E_ITEM_IRON_HORSE_ARMOR:
+ case E_ITEM_GOLD_HORSE_ARMOR:
+ case E_ITEM_DIAMOND_HORSE_ARMOR:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
}
// tolua_end
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 0769499b1..22f0655f2 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -5,6 +5,7 @@
#include "Player.h"
#include "Mobs/Wolf.h"
+#include "Mobs/Horse.h"
#include "../BoundingBox.h"
#include "../ChatColor.h"
#include "../Server.h"
@@ -2202,6 +2203,35 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
+void cPlayer::OpenHorseInventory()
+{
+ if (
+ (m_AttachedTo == nullptr) ||
+ !m_AttachedTo->IsMob()
+ )
+ {
+ return;
+ }
+
+ auto & Mob = static_cast<cMonster &>(*m_AttachedTo);
+
+ if (Mob.GetMobType() != mtHorse)
+ {
+ return;
+ }
+
+ auto & Horse = static_cast<cHorse &>(Mob);
+ // The client sends requests for untame horses as well but shouldn't actually open
+ if (Horse.IsTame())
+ {
+ Horse.PlayerOpenWindow(*this);
+ }
+}
+
+
+
+
+
bool cPlayer::SaveToDisk()
{
cFile::CreateFolder(FILE_IO_PREFIX + AString("players/")); // Create the "players" folder, if it doesn't exist yet (#1268)
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 2685622ad..f56841613 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -409,6 +409,10 @@ public:
const AString & GetLoadedWorldName() { return m_LoadedWorldName; }
+ /** Opens the inventory of any tame horse the player is riding.
+ If the player is not riding a horse or if the horse is untamed, does nothing. */
+ void OpenHorseInventory();
+
void UseEquippedItem(int a_Amount = 1);
void SendHealth(void);
diff --git a/src/Mobs/Horse.cpp b/src/Mobs/Horse.cpp
index 07d3f7481..77edc0d27 100644
--- a/src/Mobs/Horse.cpp
+++ b/src/Mobs/Horse.cpp
@@ -5,6 +5,7 @@
#include "../EffectID.h"
#include "../Entities/Player.h"
#include "Broadcaster.h"
+#include "UI/HorseWindow.h"
@@ -12,16 +13,15 @@
cHorse::cHorse(int Type, int Color, int Style, int TameTimes) :
super("Horse", mtHorse, "entity.horse.hurt", "entity.horse.death", 1.4, 1.6),
+ cEntityWindowOwner(this),
m_bHasChest(false),
m_bIsEating(false),
m_bIsRearing(false),
m_bIsMouthOpen(false),
m_bIsTame(false),
- m_bIsSaddled(false),
m_Type(Type),
m_Color(Color),
m_Style(Style),
- m_Armour(0),
m_TimesToTame(TameTimes),
m_TameAttemptTimes(0),
m_RearTickCount(0),
@@ -33,6 +33,19 @@ cHorse::cHorse(int Type, int Color, int Style, int TameTimes) :
+cHorse::~cHorse()
+{
+ auto Window = GetWindow();
+ if (Window != nullptr)
+ {
+ Window->OwnerDestroyed();
+ }
+}
+
+
+
+
+
void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
@@ -108,22 +121,24 @@ void cHorse::OnRightClicked(cPlayer & a_Player)
if (m_bIsTame)
{
- if (!m_bIsSaddled)
+ if (a_Player.IsCrouched())
{
- if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SADDLE)
- {
- // Saddle the horse:
- if (!a_Player.IsGameModeCreative())
- {
- a_Player.GetInventory().RemoveOneEquippedItem();
- }
- m_bIsSaddled = true;
- m_World->BroadcastEntityMetadata(*this);
- }
- else
- {
- a_Player.AttachTo(this);
- }
+ PlayerOpenWindow(a_Player);
+ return;
+ }
+
+ auto EquipedItemType = a_Player.GetEquippedItem().m_ItemType;
+
+ if (
+ !IsSaddled() &&
+ (
+ (EquipedItemType == E_ITEM_SADDLE) ||
+ ItemCategory::IsHorseArmor(EquipedItemType)
+ )
+ )
+ {
+ // Player is holding a horse inventory item, open the window:
+ PlayerOpenWindow(a_Player);
}
else
{
@@ -167,6 +182,65 @@ void cHorse::OnRightClicked(cPlayer & a_Player)
+void cHorse::SetHorseSaddle(cItem a_Saddle)
+{
+ if (a_Saddle.m_ItemType == E_ITEM_SADDLE)
+ {
+ m_World->BroadcastSoundEffect("entity.horse.saddle", GetPosition(), 1.0f, 0.8f);
+ }
+ else if (!a_Saddle.IsEmpty())
+ {
+ return; // Invalid item
+ }
+
+ m_Saddle = std::move(a_Saddle);
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+void cHorse::SetHorseArmor(cItem a_Armor)
+{
+ if (ItemCategory::IsHorseArmor(a_Armor.m_ItemType))
+ {
+ m_World->BroadcastSoundEffect("entity.horse.armor", GetPosition(), 1.0f, 0.8f);
+ }
+ else if (!a_Armor.IsEmpty())
+ {
+ return; // Invalid item
+ }
+
+ m_Armor = std::move(a_Armor);
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+int cHorse::GetHorseArmour(void) const
+{
+ switch (m_Armor.m_ItemType)
+ {
+ case E_ITEM_EMPTY: return 0;
+ case E_ITEM_IRON_HORSE_ARMOR: return 1;
+ case E_ITEM_GOLD_HORSE_ARMOR: return 2;
+ case E_ITEM_DIAMOND_HORSE_ARMOR: return 3;
+
+ default:
+ {
+ LOGWARN("cHorse::GetHorseArmour: Invalid armour item (%d)", m_Armor.m_ItemType);
+ return 0;
+ }
+ }
+}
+
+
+
+
+
void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
if (IsBaby())
@@ -180,9 +254,13 @@ void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer)
LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
}
AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_LEATHER);
- if (m_bIsSaddled)
+ if (IsSaddled())
{
- a_Drops.push_back(cItem(E_ITEM_SADDLE, 1));
+ a_Drops.push_back(m_Saddle);
+ }
+ if (!m_Armor.IsEmpty())
+ {
+ a_Drops.push_back(m_Armor);
}
}
@@ -205,8 +283,24 @@ void cHorse::InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cHorse::HandleSpeedFromAttachee(float a_Forward, float a_Sideways)
{
- if ((m_bIsTame) && (m_bIsSaddled))
+ if ((m_bIsTame) && IsSaddled())
{
super::HandleSpeedFromAttachee(a_Forward * m_MaxSpeed, a_Sideways * m_MaxSpeed);
}
}
+
+
+
+
+
+void cHorse::PlayerOpenWindow(cPlayer & a_Player)
+{
+ auto Window = GetWindow();
+ if (Window == nullptr)
+ {
+ Window = new cHorseWindow(*this);
+ OpenWindow(Window);
+ }
+
+ a_Player.OpenWindow(*Window);
+}
diff --git a/src/Mobs/Horse.h b/src/Mobs/Horse.h
index 82026a0ee..38625001e 100644
--- a/src/Mobs/Horse.h
+++ b/src/Mobs/Horse.h
@@ -2,18 +2,21 @@
#pragma once
#include "PassiveMonster.h"
+#include "UI/WindowOwner.h"
class cHorse :
- public cPassiveMonster
+ public cPassiveMonster,
+ public cEntityWindowOwner
{
typedef cPassiveMonster super;
public:
cHorse(int Type, int Color, int Style, int TameTimes);
+ virtual ~cHorse() override;
CLASS_PROTODEF(cHorse)
@@ -23,7 +26,7 @@ public:
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
- bool IsSaddled (void) const {return m_bIsSaddled; }
+ bool IsSaddled (void) const {return !m_Saddle.IsEmpty(); }
bool IsChested (void) const {return m_bHasChest; }
bool IsEating (void) const {return m_bIsEating; }
bool IsRearing (void) const {return m_bIsRearing; }
@@ -32,7 +35,18 @@ public:
int GetHorseType (void) const {return m_Type; }
int GetHorseColor (void) const {return m_Color; }
int GetHorseStyle (void) const {return m_Style; }
- int GetHorseArmour (void) const {return m_Armour;}
+ int GetHorseArmour (void) const;
+
+ /** Set the horse's saddle to the given item.
+ @param a_SaddleItem should be either a saddle or empty. */
+ void SetHorseSaddle(cItem a_SaddleItem);
+
+ /** Set the horse's armor slot to the given item.
+ @param a_SaddleItem should be either a type of horse armor or empty. */
+ void SetHorseArmor(cItem a_ArmorItem);
+
+ const cItem & GetHorseSaddle() const { return m_Saddle; }
+ const cItem & GetHorseArmorItem() const { return m_Armor; }
virtual void GetBreedingItems(cItems & a_Items) override
{
@@ -40,11 +54,15 @@ public:
a_Items.Add(E_ITEM_GOLDEN_APPLE);
}
+ void PlayerOpenWindow(cPlayer & a_Player);
+
private:
- bool m_bHasChest, m_bIsEating, m_bIsRearing, m_bIsMouthOpen, m_bIsTame, m_bIsSaddled;
- int m_Type, m_Color, m_Style, m_Armour, m_TimesToTame, m_TameAttemptTimes, m_RearTickCount;
+ bool m_bHasChest, m_bIsEating, m_bIsRearing, m_bIsMouthOpen, m_bIsTame;
+ int m_Type, m_Color, m_Style, m_TimesToTame, m_TameAttemptTimes, m_RearTickCount;
float m_MaxSpeed;
+ cItem m_Saddle;
+ cItem m_Armor;
} ;
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index c384f85b9..e7f197d3d 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -39,6 +39,7 @@ Implements the 1.8 protocol classes:
#include "../Mobs/IncludeAllMonsters.h"
#include "../UI/Window.h"
+#include "../UI/HorseWindow.h"
#include "../BlockEntities/BeaconEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
@@ -1678,7 +1679,8 @@ void cProtocol_1_8_0::SendWindowOpen(const cWindow & a_Window)
if (a_Window.GetWindowType() == cWindow::wtAnimalChest)
{
- Pkt.WriteBEInt32(0); // TODO: The animal's EntityID
+ UInt32 HorseID = static_cast<const cHorseWindow &>(a_Window).GetHorseID();
+ Pkt.WriteBEInt32(static_cast<Int32>(HorseID));
}
}
@@ -2428,6 +2430,7 @@ void cProtocol_1_8_0::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
case 2: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed
case 3: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting
case 4: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting
+ case 6: m_Client->HandleOpenHorseInventory(PlayerID); break; // Open horse inventory
}
}
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index fcfc6674a..9dcf8e3aa 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -48,6 +48,7 @@ Implements the 1.9 protocol classes:
#include "../Mobs/IncludeAllMonsters.h"
#include "../UI/Window.h"
+#include "../UI/HorseWindow.h"
#include "../BlockEntities/BeaconEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
@@ -1723,7 +1724,8 @@ void cProtocol_1_9_0::SendWindowOpen(const cWindow & a_Window)
if (a_Window.GetWindowType() == cWindow::wtAnimalChest)
{
- Pkt.WriteBEInt32(0); // TODO: The animal's EntityID
+ UInt32 HorseID = static_cast<const cHorseWindow &>(a_Window).GetHorseID();
+ Pkt.WriteBEInt32(static_cast<Int32>(HorseID));
}
}
@@ -2517,6 +2519,7 @@ void cProtocol_1_9_0::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
case 2: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed
case 3: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting
case 4: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting
+ case 7: m_Client->HandleOpenHorseInventory(PlayerID); break; // Open horse inventory
}
}
diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt
index 54236a929..6477882b3 100644
--- a/src/UI/CMakeLists.txt
+++ b/src/UI/CMakeLists.txt
@@ -15,6 +15,7 @@ SET (SRCS
EnderChestWindow.cpp
FurnaceWindow.cpp
HopperWindow.cpp
+ HorseWindow.cpp
InventoryWindow.cpp)
SET (HDRS
@@ -30,6 +31,7 @@ SET (HDRS
EnderChestWindow.h
FurnaceWindow.h
HopperWindow.h
+ HorseWindow.h
InventoryWindow.h
MinecartWithChestWindow.h
WindowOwner.h)
diff --git a/src/UI/HorseWindow.cpp b/src/UI/HorseWindow.cpp
new file mode 100644
index 000000000..ab060609d
--- /dev/null
+++ b/src/UI/HorseWindow.cpp
@@ -0,0 +1,61 @@
+
+// HorseWindow.cpp
+
+// Representing the UI window for a horse entity
+
+#include "Globals.h"
+#include "Mobs/Horse.h"
+#include "UI/HorseWindow.h"
+#include "UI/SlotArea.h"
+
+
+
+
+
+cHorseWindow::cHorseWindow(cHorse & a_Horse):
+ Super(wtAnimalChest, "Horse"),
+ m_Horse(a_Horse)
+{
+ m_SlotAreas.push_back(new cSlotAreaHorse(a_Horse, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cHorseWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Horse Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ Super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Inventory or Hotbar
+ if (ItemCategory::IsHorseArmor(a_ItemStack.m_ItemType) || (a_ItemStack.m_ItemType == E_ITEM_SADDLE))
+ {
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Horse */
+ Super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+ }
+}
+
+
+
+
+
+UInt32 cHorseWindow::GetHorseID() const
+{
+ return m_Horse.GetUniqueID();
+}
+
+
+
+
diff --git a/src/UI/HorseWindow.h b/src/UI/HorseWindow.h
new file mode 100644
index 000000000..77bc2d627
--- /dev/null
+++ b/src/UI/HorseWindow.h
@@ -0,0 +1,34 @@
+
+// HorseWindow.h
+
+// Representing the UI window for a horse entity
+
+#pragma once
+
+#include "Window.h"
+
+class cHorse;
+
+
+
+
+
+class cHorseWindow :
+ public cWindow
+{
+ using Super = cWindow;
+public:
+ cHorseWindow(cHorse & a_Horse);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+ /** Returns the horse's entity ID. */
+ UInt32 GetHorseID() const;
+
+private:
+ cHorse & m_Horse;
+};
+
+
+
+
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index 865e9cb44..d093bb337 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -21,6 +21,7 @@
#include "../BlockArea.h"
#include "../EffectID.h"
#include "../ClientHandle.h"
+#include "Mobs/Horse.h"
@@ -2596,3 +2597,121 @@ cItem * cSlotAreaTemporary::GetPlayerSlots(cPlayer & a_Player)
+////////////////////////////////////////////////////////////////////////////////
+// cSlotAreaHorse:
+
+cSlotAreaHorse::cSlotAreaHorse(cHorse & a_Horse, cWindow & a_ParentWindow) :
+ cSlotArea(2, a_ParentWindow),
+ m_Horse(a_Horse)
+{
+}
+
+
+
+
+
+void cSlotAreaHorse::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
+{
+ cItem & DraggingItem = a_Player.GetDraggingItem();
+
+ switch (a_ClickAction)
+ {
+ case caLeftClick:
+ case caRightClick:
+ case caDblClick:
+ {
+ // Check for invalid item types
+ if (DraggingItem.IsEmpty())
+ {
+ break;
+ }
+
+ switch (a_SlotNum)
+ {
+ case SaddleSlot:
+ {
+ if (DraggingItem.m_ItemType != E_ITEM_SADDLE)
+ {
+ return;
+ }
+ }
+ case ArmorSlot:
+ {
+ if (!ItemCategory::IsHorseArmor(DraggingItem.m_ItemType))
+ {
+ return;
+ }
+ }
+ default: break;
+ }
+ }
+ default: break;
+ }
+
+ cSlotArea::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
+}
+
+
+
+
+
+const cItem * cSlotAreaHorse::GetSlot(int a_SlotNum, cPlayer & a_Player) const
+{
+ static const cItem InvalidItem;
+ switch (a_SlotNum)
+ {
+ case SaddleSlot: return &m_Horse.GetHorseSaddle();
+ case ArmorSlot: return &m_Horse.GetHorseArmorItem();
+ default:
+ {
+ LOGWARN("cSlotAreaHorse::GetSlot: Invalid slot number %d", a_SlotNum);
+ return &InvalidItem;
+ }
+ }
+}
+
+
+
+
+
+void cSlotAreaHorse::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
+{
+ switch (a_SlotNum)
+ {
+ case SaddleSlot: m_Horse.SetHorseSaddle(a_Item); break;
+ case ArmorSlot: m_Horse.SetHorseArmor(a_Item); break;
+ default:
+ {
+ LOGWARN("cSlotAreaHorse::SetSlot: Invalid slot number %d", a_SlotNum);
+ }
+ }
+}
+
+
+
+
+
+void cSlotAreaHorse::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
+{
+ if (ItemCategory::IsHorseArmor(a_ItemStack.m_ItemType) && m_Horse.GetHorseArmorItem().IsEmpty())
+ {
+ if (a_ShouldApply)
+ {
+ m_Horse.SetHorseArmor(a_ItemStack.CopyOne());
+ }
+ --a_ItemStack.m_ItemCount;
+ }
+ else if ((a_ItemStack.m_ItemType == E_ITEM_SADDLE) && !m_Horse.IsSaddled())
+ {
+ if (a_ShouldApply)
+ {
+ m_Horse.SetHorseSaddle(a_ItemStack.CopyOne());
+ }
+ --a_ItemStack.m_ItemCount;
+ }
+}
+
+
+
+
+
diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h
index be21cdada..4463cb315 100644
--- a/src/UI/SlotArea.h
+++ b/src/UI/SlotArea.h
@@ -14,6 +14,7 @@
+class cHorse;
class cWindow;
class cPlayer;
class cBeaconEntity;
@@ -520,3 +521,27 @@ protected:
+
+/** Slot area holding horse saddle and armor. */
+class cSlotAreaHorse:
+ public cSlotArea
+{
+public:
+ enum
+ {
+ SaddleSlot,
+ ArmorSlot
+ };
+
+ cSlotAreaHorse(cHorse & a_Horse, cWindow & a_ParentWindow);
+ virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
+ virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override;
+ virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override;
+private:
+ cHorse & m_Horse;
+};
+
+
+
+