summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Server/Plugins/APIDump/APIDesc.lua66
-rw-r--r--src/Blocks/BlockCauldron.h40
-rw-r--r--src/ClientHandle.cpp6
-rw-r--r--src/Entities/Player.cpp19
-rw-r--r--src/Entities/Player.h7
-rw-r--r--src/Inventory.cpp92
-rw-r--r--src/Inventory.h10
-rw-r--r--src/Items/ItemArmor.h2
-rw-r--r--src/Items/ItemBottle.h7
-rw-r--r--src/Items/ItemBucket.h32
-rw-r--r--src/Items/ItemPotion.h3
-rw-r--r--src/Mobs/Cow.cpp4
-rw-r--r--src/Mobs/Mooshroom.cpp8
13 files changed, 222 insertions, 74 deletions
diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua
index 8adda34a7..69e7cd75b 100644
--- a/Server/Plugins/APIDump/APIDesc.lua
+++ b/Server/Plugins/APIDump/APIDesc.lua
@@ -6223,7 +6223,7 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
Type = "number",
},
},
- Notes = "Adds an item to the storage; if AllowNewStacks is true (default), will also create new stacks in empty slots. Returns the number of items added",
+ Notes = "Adds an item to the storage; if AllowNewStacks is true (default), will also create new stacks in empty slots. Fills existing stacks first and fills the hotbar before the main inventory. Returns the number of items added",
},
AddItems =
{
@@ -6617,6 +6617,28 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
},
Notes = "Removes one item from the hotbar's currently selected slot. Returns true on success.",
},
+ ReplaceOneEquippedItem =
+ {
+ Params =
+ {
+ {
+ Name = "Item",
+ Type = "cItem",
+ },
+ {
+ Name = "TryOtherSlots",
+ Type = "boolean",
+ IsOptional = true,
+ },
+ },
+ Returns =
+ {
+ {
+ Type = "number",
+ },
+ },
+ Notes = "Removes one item from the the current equipped item stack, and attempts to add the specified item stack back to the same slot. If it is not possible to place the item in the same slot, optionally (default true) tries to place the specified item elsewhere in the inventory. Returns the number of items successfully added. If the currently equipped slot is empty, its contents are simply set to the given Item.",
+ },
SendEquippedSlot =
{
Notes = "Sends the equipped item slot to the client",
@@ -6662,31 +6684,31 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
},
Notes = "Sets the specified hotbar slot contents",
},
- SetShieldSlot =
+ SetInventorySlot =
{
Params =
{
{
- Name = "Item",
+ Name = "InventorySlotNum",
+ Type = "number",
+ },
+ {
+ Name = "cItem",
Type = "cItem",
},
},
- Notes = "Sets the shield slot content",
+ Notes = "Sets the specified main inventory slot contents",
},
- SetInventorySlot =
+ SetShieldSlot =
{
Params =
{
{
- Name = "InventorySlotNum",
- Type = "number",
- },
- {
- Name = "cItem",
+ Name = "Item",
Type = "cItem",
},
},
- Notes = "Sets the specified main inventory slot contents",
+ Notes = "Sets the shield slot content",
},
SetSlot =
{
@@ -6703,6 +6725,17 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
},
Notes = "Sets the specified slot contents",
},
+ SetEquippedItem =
+ {
+ Params =
+ {
+ {
+ Name = "Item",
+ Type = "cItem",
+ },
+ },
+ Notes = "Sets current item in the equipped hotbar slot",
+ },
},
Constants =
{
@@ -10712,6 +10745,17 @@ a_Player:OpenWindow(Window);
},
Notes = "Places a block while impersonating the player. The {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}} hook is called before the placement, and if it succeeds, the block is placed and the {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}} hook is called. Returns true iff the block is successfully placed. Assumes that the block is in a currently loaded chunk.",
},
+ ReplaceOneEquippedItemTossRest =
+ {
+ Params =
+ {
+ {
+ Name = "Item",
+ Type = "cItem",
+ },
+ },
+ Notes = "Removes one item from the the current equipped item stack, and attempts to add the specified item stack back to the same slot. If it is not possible to place the item in the same slot, tries to place the specified item elsewhere in the inventory. If this is not possible, then any remaining items are tossed. If the currently equipped slot is empty, its contents are simply set to the given Item.",
+ },
Respawn =
{
Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet.",
diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h
index 5b45b2828..d6ef721ad 100644
--- a/src/Blocks/BlockCauldron.h
+++ b/src/Blocks/BlockCauldron.h
@@ -27,17 +27,31 @@ public:
virtual bool 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
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
- switch (a_Player.GetEquippedItem().m_ItemType)
+ auto EquippedItem = a_Player.GetEquippedItem();
+ switch (EquippedItem.m_ItemType)
{
+ case E_ITEM_BUCKET:
+ {
+ if (Meta == 3)
+ {
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0);
+ // Give new bucket, filled with fluid when the gamemode is not creative:
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_WATER_BUCKET));
+ }
+ }
+ break;
+ }
case E_ITEM_WATER_BUCKET:
{
if (Meta < 3)
{
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 3);
+ // Give empty bucket back when the gamemode is not creative:
if (!a_Player.IsGameModeCreative())
{
- a_Player.GetInventory().RemoveOneEquippedItem();
- a_Player.GetInventory().AddItem(cItem(E_ITEM_BUCKET));
+ a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_BUCKET));
}
}
break;
@@ -47,11 +61,27 @@ public:
if (Meta > 0)
{
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, --Meta);
- a_Player.GetInventory().RemoveOneEquippedItem();
- a_Player.GetInventory().AddItem(cItem(E_ITEM_POTION));
+ // Give new potion when the gamemode is not creative:
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_POTION));
+ }
}
break;
}
+ case E_ITEM_POTION:
+ {
+ // Refill cauldron with water bottles.
+ if ((Meta < 3) && (EquippedItem.m_ItemDamage == 0))
+ {
+ a_ChunkInterface.SetBlockMeta(Vector3i(a_BlockX, a_BlockY, a_BlockZ), ++Meta);
+ // Give empty bottle when the gamemode is not creative:
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_GLASS_BOTTLE));
+ }
+ }
+ }
}
return true;
}
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index ef121cf12..9a92a3005 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1211,9 +1211,9 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
cItem EquippedItem = m_Player->GetEquippedItem();
cItem OffhandItem = m_Player->GetOffHandEquipedItem();
- cInventory & Intentory = m_Player->GetInventory();
- Intentory.SetShieldSlot(EquippedItem);
- Intentory.SetHotbarSlot(Intentory.GetEquippedSlotNum(), OffhandItem);
+ cInventory & Inventory = m_Player->GetInventory();
+ Inventory.SetShieldSlot(EquippedItem);
+ Inventory.SetEquippedItem(OffhandItem);
return;
}
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index b5d7f7c83..02cb7378d 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1959,6 +1959,25 @@ void cPlayer::TossEquippedItem(char a_Amount)
+void cPlayer::ReplaceOneEquippedItemTossRest(const cItem & a_Item)
+{
+ auto PlacedCount = GetInventory().ReplaceOneEquippedItem(a_Item);
+ char ItemCountToToss = a_Item.m_ItemCount - static_cast<char>(PlacedCount);
+
+ if (ItemCountToToss == 0)
+ {
+ return;
+ }
+
+ cItem Pickup = a_Item;
+ Pickup.m_ItemCount = ItemCountToToss;
+ TossPickup(Pickup);
+}
+
+
+
+
+
void cPlayer::TossHeldItem(char a_Amount)
{
cItems Drops;
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index fafdd04eb..3ba87f748 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -313,6 +313,13 @@ public:
/** tosses the item in the selected hotbar slot */
void TossEquippedItem(char a_Amount = 1);
+ /** Removes one item from the the current equipped item stack, and attempts to add the specified item stack
+ back to the same slot. If it is not possible to place the item in the same slot, tries to place the specified
+ item elsewhere in the inventory. If this is not possible, then any remaining items are tossed. If the currently
+ equipped slot is empty, its contents are simply set to the given Item.
+ */
+ void ReplaceOneEquippedItemTossRest(const cItem &);
+
/** tosses the item held in hand (when in UI windows) */
void TossHeldItem(char a_Amount = 1);
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index d8b67835e..42c243f17 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -121,35 +121,38 @@ int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks)
}
}
- for (int SlotIdx = 0; SlotIdx < m_InventorySlots.GetNumSlots(); ++SlotIdx)
+ // Add to existing stacks in the hotbar.
+ res += m_HotbarSlots.AddItem(ToAdd, false);
+ ToAdd.m_ItemCount = static_cast<char>(a_Item.m_ItemCount - res);
+ if (ToAdd.m_ItemCount == 0)
{
- auto & Slot = m_InventorySlots.GetSlot(SlotIdx);
- if (Slot.IsEqual(a_Item))
- {
- cItemHandler Handler(Slot.m_ItemType);
- int AmountToAdd = std::min(static_cast<char>(Handler.GetMaxStackSize() - Slot.m_ItemCount), ToAdd.m_ItemCount);
- res += AmountToAdd;
+ return res;
+ }
- cItem SlotAdjusted(Slot);
- SlotAdjusted.m_ItemCount += AmountToAdd;
- m_InventorySlots.SetSlot(SlotIdx, SlotAdjusted);
+ // Add to existing stacks in main inventory.
+ res += m_InventorySlots.AddItem(ToAdd, false);
+ ToAdd.m_ItemCount = static_cast<char>(a_Item.m_ItemCount - res);
+ if (ToAdd.m_ItemCount == 0)
+ {
+ return res;
+ }
- ToAdd.m_ItemCount -= AmountToAdd;
- if (ToAdd.m_ItemCount == 0)
- {
- return res;
- }
- }
+ // All existing stacks are now filled.
+ if (!a_AllowNewStacks)
+ {
+ return res;
}
- res += m_HotbarSlots.AddItem(ToAdd, a_AllowNewStacks);
+ // Try adding new stacks to the hotbar.
+ res += m_HotbarSlots.AddItem(ToAdd, true);
ToAdd.m_ItemCount = static_cast<char>(a_Item.m_ItemCount - res);
if (ToAdd.m_ItemCount == 0)
{
return res;
}
- res += m_InventorySlots.AddItem(ToAdd, a_AllowNewStacks);
+ // Try adding new stacks to the main inventory.
+ res += m_InventorySlots.AddItem(ToAdd, true);
return res;
}
@@ -219,6 +222,50 @@ bool cInventory::RemoveOneEquippedItem(void)
+int cInventory::ReplaceOneEquippedItem(const cItem & a_Item, bool a_TryOtherSlots)
+{
+ // Ignore whether there was an item in the slot to remove.
+ RemoveOneEquippedItem();
+
+ auto EquippedItem = GetEquippedItem();
+ if (EquippedItem.IsEmpty())
+ {
+ SetEquippedItem(a_Item);
+ return a_Item.m_ItemCount;
+ }
+
+ // Handle case when equipped item is the same as the replacement item.
+ cItem ItemsToAdd = a_Item;
+ if (EquippedItem.IsEqual(ItemsToAdd))
+ {
+ cItemHandler Handler(ItemsToAdd.m_ItemType);
+ auto AmountToAdd = std::min(static_cast<char>(Handler.GetMaxStackSize() - EquippedItem.m_ItemCount), ItemsToAdd.m_ItemCount);
+
+ EquippedItem.m_ItemCount += AmountToAdd;
+ SetEquippedItem(EquippedItem);
+ ItemsToAdd.m_ItemCount -= AmountToAdd;
+ }
+
+ auto ItemsAdded = a_Item.m_ItemCount - ItemsToAdd.m_ItemCount;
+
+ if (ItemsToAdd.m_ItemCount == 0)
+ {
+ return ItemsAdded;
+ }
+
+ if (!a_TryOtherSlots)
+ {
+ return ItemsAdded;
+ }
+
+ // Try the rest of the inventory.
+ return AddItem(ItemsToAdd) + ItemsAdded;
+}
+
+
+
+
+
int cInventory::HowManyItems(const cItem & a_Item)
{
return
@@ -300,6 +347,15 @@ void cInventory::SetShieldSlot(const cItem & a_Item)
+void cInventory::SetEquippedItem(const cItem & a_Item)
+{
+ SetHotbarSlot(GetEquippedSlotNum(), a_Item);
+}
+
+
+
+
+
void cInventory::SendEquippedSlot()
{
int EquippedSlotNum = cInventory::invArmorCount + cInventory::invInventoryCount + GetEquippedSlotNum();
diff --git a/src/Inventory.h b/src/Inventory.h
index b91b16c8b..7436d7528 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -71,6 +71,7 @@ public:
/** Adds as many items out of a_ItemStack as can fit.
If a_AllowNewStacks is set to false, only existing stacks can be topped up;
if a_AllowNewStacks is set to true, empty slots can be used for the rest.
+ Fills existing stacks first and fills the hotbar before the main inventory.
Returns the number of items that fit.
*/
int AddItem(const cItem & a_ItemStack, bool a_AllowNewStacks = true);
@@ -90,6 +91,13 @@ public:
/** Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed */
bool RemoveOneEquippedItem(void);
+ /** Removes one item from the the current equipped item stack, and attempts to add the specified item stack
+ back to the same slot. If it is not possible to place the item in the same slot, optionally (default true) tries to
+ place the specified item elsewhere in the inventory. Returns the number of items successfully added. If the
+ currently equipped slot is empty, its contents are simply set to the given Item.
+ */
+ int ReplaceOneEquippedItem(const cItem & a_Item, bool a_TryOtherSlots = true);
+
/** Returns the number of items of type a_Item that are stored */
int HowManyItems(const cItem & a_Item);
@@ -143,6 +151,8 @@ public:
void SetHotbarSlot(int a_HotBarSlotNum, const cItem & a_Item);
/** Sets current item in shield slot */
void SetShieldSlot(const cItem & a_Item);
+ /** Sets current item in the equipped hotbar slot */
+ void SetEquippedItem(const cItem & a_Item);
/** Sets equiped item to the a_SlotNum slot number */
void SetEquippedSlotNum(int a_SlotNum);
/** Returns slot number of equiped item */
diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h
index 906993a5b..d218c22b3 100644
--- a/src/Items/ItemArmor.h
+++ b/src/Items/ItemArmor.h
@@ -61,7 +61,7 @@ public:
{
Item.Empty();
}
- a_Player->GetInventory().SetHotbarSlot(a_Player->GetInventory().GetEquippedSlotNum(), Item);
+ a_Player->GetInventory().SetEquippedItem(Item);
return true;
}
diff --git a/src/Items/ItemBottle.h b/src/Items/ItemBottle.h
index b261937e5..18767dcde 100644
--- a/src/Items/ItemBottle.h
+++ b/src/Items/ItemBottle.h
@@ -83,8 +83,11 @@ public:
return false; // Nothing in range.
}
- a_Player->GetInventory().RemoveOneEquippedItem();
- a_Player->GetInventory().AddItem(cItem(E_ITEM_POTION));
+ // Give back a filled water bottle if gamemode is not creative:
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->ReplaceOneEquippedItemTossRest(cItem(E_ITEM_POTION));
+ }
return true;
}
} ;
diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h
index 7a91149d1..8affff6ca 100644
--- a/src/Items/ItemBucket.h
+++ b/src/Items/ItemBucket.h
@@ -70,15 +70,15 @@ public:
}
BLOCKTYPE Block = a_World->GetBlock(BlockPos.x, BlockPos.y, BlockPos.z);
- ENUM_ITEM_ID NewItem;
+ ENUM_ITEM_ID NewItemType;
if (IsBlockWater(Block))
{
- NewItem = E_ITEM_WATER_BUCKET;
+ NewItemType = E_ITEM_WATER_BUCKET;
}
else if (IsBlockLava(Block))
{
- NewItem = E_ITEM_LAVA_BUCKET;
+ NewItemType = E_ITEM_LAVA_BUCKET;
}
else
{
@@ -101,18 +101,7 @@ public:
// Give new bucket, filled with fluid when the gamemode is not creative:
if (!a_Player->IsGameModeCreative())
{
- // Remove the bucket from the inventory
- if (!a_Player->GetInventory().RemoveOneEquippedItem())
- {
- LOG("Clicked with an empty bucket, but cannot remove one from the inventory? WTF?");
- ASSERT(!"Inventory bucket mismatch");
- return true;
- }
- if (a_Player->GetInventory().AddItem(cItem(NewItem)) != 1)
- {
- // The bucket didn't fit, toss it as a pickup:
- a_Player->TossPickup(cItem(NewItem));
- }
+ a_Player->ReplaceOneEquippedItemTossRest(cItem(NewItemType));
}
return true;
@@ -154,19 +143,10 @@ public:
return false;
}
+ // Give back an empty bucket if the gamemode is not creative:
if (!a_Player->IsGameModeCreative())
{
- // Remove fluid bucket, add empty bucket:
- if (!a_Player->GetInventory().RemoveOneEquippedItem())
- {
- LOG("Clicked with a full bucket, but cannot remove one from the inventory? WTF?");
- ASSERT(!"Inventory bucket mismatch");
- return false;
- }
- if (!a_Player->GetInventory().AddItem(cItem(E_ITEM_BUCKET)))
- {
- return false;
- }
+ a_Player->ReplaceOneEquippedItemTossRest(cItem(E_ITEM_BUCKET));
}
// Wash away anything that was there prior to placing:
diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h
index 470a7c67f..86330d1c0 100644
--- a/src/Items/ItemPotion.h
+++ b/src/Items/ItemPotion.h
@@ -77,8 +77,7 @@ public:
if (!a_Player->IsGameModeCreative())
{
- a_Player->GetInventory().RemoveOneEquippedItem();
- a_Player->GetInventory().AddItem(cItem(E_ITEM_GLASS_BOTTLE));
+ a_Player->ReplaceOneEquippedItemTossRest(cItem(E_ITEM_GLASS_BOTTLE));
}
return true;
}
diff --git a/src/Mobs/Cow.cpp b/src/Mobs/Cow.cpp
index a7fb0d476..559b6caea 100644
--- a/src/Mobs/Cow.cpp
+++ b/src/Mobs/Cow.cpp
@@ -44,10 +44,10 @@ void cCow::OnRightClicked(cPlayer & a_Player)
short HeldItem = a_Player.GetEquippedItem().m_ItemType;
if (HeldItem == E_ITEM_BUCKET)
{
+ // Milk the cow.
if (!a_Player.IsGameModeCreative())
{
- a_Player.GetInventory().RemoveOneEquippedItem();
- a_Player.GetInventory().AddItem(cItem(E_ITEM_MILK));
+ a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_MILK));
}
}
}
diff --git a/src/Mobs/Mooshroom.cpp b/src/Mobs/Mooshroom.cpp
index 31a1b8978..135a8ba90 100644
--- a/src/Mobs/Mooshroom.cpp
+++ b/src/Mobs/Mooshroom.cpp
@@ -43,18 +43,18 @@ void cMooshroom::OnRightClicked(cPlayer & a_Player)
{
case E_ITEM_BUCKET:
{
+ // Milk the cow.
if (!a_Player.IsGameModeCreative())
{
- a_Player.GetInventory().RemoveOneEquippedItem();
- a_Player.GetInventory().AddItem(cItem(E_ITEM_MILK));
+ a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_MILK));
}
} break;
case E_ITEM_BOWL:
{
+ // Soup the cow.
if (!a_Player.IsGameModeCreative())
{
- a_Player.GetInventory().RemoveOneEquippedItem();
- a_Player.GetInventory().AddItem(cItem(E_ITEM_MUSHROOM_SOUP));
+ a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_MUSHROOM_SOUP));
}
} break;
case E_ITEM_SHEARS: