2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
// ItemGrid.cpp
|
|
|
|
|
|
|
|
// Implements the cItemGrid class representing a storage for items in a XY grid (chests, dispensers, inventory etc.)
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
#include "ItemGrid.h"
|
|
|
|
#include "Items/ItemHandler.h"
|
2014-11-18 06:07:08 -05:00
|
|
|
#include "Noise/Noise.h"
|
2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
cItemGrid::cItemGrid(int a_Width, int a_Height):
|
2013-07-29 07:13:03 -04:00
|
|
|
m_Width(a_Width),
|
|
|
|
m_Height(a_Height),
|
2018-01-21 13:45:13 -05:00
|
|
|
m_Slots(a_Width * a_Height),
|
2013-07-29 07:13:03 -04:00
|
|
|
m_IsInTriggerListeners(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-07-09 16:54:56 -04:00
|
|
|
bool cItemGrid::IsValidSlotNum(int a_SlotNum) const
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
return ((a_SlotNum >= 0) && (a_SlotNum < m_Slots.size()));
|
2017-07-09 16:54:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cItemGrid::IsValidSlotCoords(int a_X, int a_Y) const
|
|
|
|
{
|
|
|
|
return (
|
|
|
|
(a_X >= 0) && (a_X < m_Width) &&
|
|
|
|
(a_Y >= 0) && (a_Y < m_Height)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
int cItemGrid::GetSlotNum(int a_X, int a_Y) const
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotCoords(a_X, a_Y))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: coords out of range: (%d, %d) in grid of size (%d, %d)",
|
|
|
|
__FUNCTION__, a_X, a_Y, m_Width, m_Height
|
|
|
|
);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return a_X + m_Width * a_Y;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::GetSlotCoords(int a_SlotNum, int & a_X, int & a_Y) const
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_SlotNum))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: SlotNum out of range: %d in grid of range %d",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_SlotNum, m_Slots.size()
|
2013-07-29 07:13:03 -04:00
|
|
|
);
|
|
|
|
a_X = -1;
|
|
|
|
a_Y = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
a_X = a_SlotNum % m_Width;
|
|
|
|
a_Y = a_SlotNum / m_Width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-06-15 09:32:33 -04:00
|
|
|
void cItemGrid::CopyFrom(const cItemGrid & a_Src)
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
m_Width = a_Src.m_Width;
|
|
|
|
m_Height = a_Src.m_Height;
|
|
|
|
m_Slots = a_Src.m_Slots;
|
2017-06-15 09:32:33 -04:00
|
|
|
|
|
|
|
// The listeners are not copied
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
const cItem & cItemGrid::GetSlot(int a_X, int a_Y) const
|
|
|
|
{
|
|
|
|
return GetSlot(GetSlotNum(a_X, a_Y));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const cItem & cItemGrid::GetSlot(int a_SlotNum) const
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_SlotNum))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number, %d out of %d slots",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_SlotNum, m_Slots.size()
|
2013-07-29 07:13:03 -04:00
|
|
|
);
|
2018-01-21 13:45:13 -05:00
|
|
|
a_SlotNum = 0;
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
2018-01-21 13:45:13 -05:00
|
|
|
return m_Slots.GetAt(a_SlotNum);
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::SetSlot(int a_X, int a_Y, const cItem & a_Item)
|
|
|
|
{
|
|
|
|
SetSlot(GetSlotNum(a_X, a_Y), a_Item);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::SetSlot(int a_X, int a_Y, short a_ItemType, char a_ItemCount, short a_ItemDamage)
|
|
|
|
{
|
|
|
|
SetSlot(GetSlotNum(a_X, a_Y), cItem(a_ItemType, a_ItemCount, a_ItemDamage));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::SetSlot(int a_SlotNum, const cItem & a_Item)
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_SlotNum))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_SlotNum, m_Slots.size()
|
2013-07-29 07:13:03 -04:00
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
2018-01-21 13:45:13 -05:00
|
|
|
|
|
|
|
if (!a_Item.IsEmpty() || m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
m_Slots[a_SlotNum] = a_Item;
|
|
|
|
}
|
2013-07-29 07:13:03 -04:00
|
|
|
TriggerListeners(a_SlotNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::SetSlot(int a_SlotNum, short a_ItemType, char a_ItemCount, short a_ItemDamage)
|
|
|
|
{
|
|
|
|
SetSlot(a_SlotNum, cItem(a_ItemType, a_ItemCount, a_ItemDamage));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::EmptySlot(int a_X, int a_Y)
|
|
|
|
{
|
|
|
|
EmptySlot(GetSlotNum(a_X, a_Y));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::EmptySlot(int a_SlotNum)
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_SlotNum))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_SlotNum, m_Slots.size()
|
2013-07-29 07:13:03 -04:00
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Check if already empty:
|
2018-01-21 13:45:13 -05:00
|
|
|
if (m_Slots.GetAt(a_SlotNum).IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Empty and notify
|
|
|
|
m_Slots[a_SlotNum].Empty();
|
|
|
|
TriggerListeners(a_SlotNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cItemGrid::IsSlotEmpty(int a_SlotNum) const
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_SlotNum))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_SlotNum, m_Slots.size()
|
2013-07-29 07:13:03 -04:00
|
|
|
);
|
|
|
|
return true;
|
|
|
|
}
|
2018-01-21 13:45:13 -05:00
|
|
|
return m_Slots.GetAt(a_SlotNum).IsEmpty();
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cItemGrid::IsSlotEmpty(int a_X, int a_Y) const
|
|
|
|
{
|
|
|
|
return IsSlotEmpty(GetSlotNum(a_X, a_Y));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::Clear(void)
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return; // Already clear
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < m_Slots.size(); i++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
m_Slots[i].Empty();
|
|
|
|
TriggerListeners(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-08-11 08:54:45 -04:00
|
|
|
int cItemGrid::HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
int NumLeft = a_ItemStack.m_ItemCount;
|
2013-07-29 07:13:03 -04:00
|
|
|
int MaxStack = ItemHandler(a_ItemStack.m_ItemType)->GetMaxStackSize();
|
2018-01-21 13:45:13 -05:00
|
|
|
|
|
|
|
if (!m_Slots.IsStorageAllocated())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
// Grid is empty, all slots are available
|
|
|
|
return a_AllowNewStacks ? std::min(NumLeft, m_Slots.size() * MaxStack) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto & Slot : m_Slots)
|
|
|
|
{
|
|
|
|
if (Slot.IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2013-08-11 08:54:45 -04:00
|
|
|
if (a_AllowNewStacks)
|
|
|
|
{
|
|
|
|
NumLeft -= MaxStack;
|
|
|
|
}
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
2018-01-21 13:45:13 -05:00
|
|
|
else if (Slot.IsEqual(a_ItemStack))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
NumLeft -= MaxStack - Slot.m_ItemCount;
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
if (NumLeft <= 0)
|
|
|
|
{
|
|
|
|
// All items fit
|
|
|
|
return a_ItemStack.m_ItemCount;
|
|
|
|
}
|
2018-01-21 13:45:13 -05:00
|
|
|
} // for Slot - m_Slots[]
|
2013-07-29 07:13:03 -04:00
|
|
|
return a_ItemStack.m_ItemCount - NumLeft;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::AddItemToSlot(const cItem & a_ItemStack, int a_Slot, int a_Num, int a_MaxStack)
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_Slot))
|
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_Slot, m_Slots.size()
|
2017-07-09 16:54:56 -04:00
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
int PrevCount = 0;
|
|
|
|
if (m_Slots[a_Slot].IsEmpty())
|
|
|
|
{
|
|
|
|
m_Slots[a_Slot] = a_ItemStack;
|
|
|
|
PrevCount = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PrevCount = m_Slots[a_Slot].m_ItemCount;
|
|
|
|
}
|
2015-07-29 11:04:03 -04:00
|
|
|
m_Slots[a_Slot].m_ItemCount = static_cast<char>(std::min(a_MaxStack, PrevCount + a_Num));
|
2013-07-29 07:13:03 -04:00
|
|
|
int toReturn = m_Slots[a_Slot].m_ItemCount - PrevCount;
|
|
|
|
TriggerListeners(a_Slot);
|
|
|
|
return toReturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_PrioritySlot)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
int NumLeft = a_ItemStack.m_ItemCount;
|
2014-07-17 19:02:25 -04:00
|
|
|
int MaxStack = a_ItemStack.GetMaxStackSize();
|
2013-07-29 07:13:03 -04:00
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
if ((a_PrioritySlot != -1) && !IsValidSlotNum(a_PrioritySlot))
|
2017-07-09 16:54:56 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_PrioritySlot, m_Slots.size()
|
2017-07-09 16:54:56 -04:00
|
|
|
);
|
2018-01-21 13:45:13 -05:00
|
|
|
a_PrioritySlot = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!a_AllowNewStacks && !m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return 0; // No existing stacks to add to
|
2017-07-09 16:54:56 -04:00
|
|
|
}
|
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
// Try prioritySlot first:
|
2013-07-29 07:13:03 -04:00
|
|
|
if (
|
2018-01-21 13:45:13 -05:00
|
|
|
(a_PrioritySlot != -1) &&
|
2013-07-29 07:13:03 -04:00
|
|
|
(
|
2018-01-21 13:45:13 -05:00
|
|
|
m_Slots[a_PrioritySlot].IsEmpty() ||
|
|
|
|
m_Slots[a_PrioritySlot].IsEqual(a_ItemStack)
|
2013-07-29 07:13:03 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
NumLeft -= AddItemToSlot(a_ItemStack, a_PrioritySlot, NumLeft, MaxStack);
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Scan existing stacks:
|
2018-01-21 13:45:13 -05:00
|
|
|
for (int i = 0; i < m_Slots.size(); i++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-01-16 14:00:49 -05:00
|
|
|
if (m_Slots[i].IsEqual(a_ItemStack))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
NumLeft -= AddItemToSlot(a_ItemStack, i, NumLeft, MaxStack);
|
|
|
|
}
|
|
|
|
if (NumLeft <= 0)
|
|
|
|
{
|
|
|
|
// All items fit
|
|
|
|
return a_ItemStack.m_ItemCount;
|
|
|
|
}
|
|
|
|
} // for i - m_Slots[]
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
if (!a_AllowNewStacks)
|
|
|
|
{
|
|
|
|
return (a_ItemStack.m_ItemCount - NumLeft);
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
for (int i = 0; i < m_Slots.size(); i++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
if (m_Slots[i].IsEmpty())
|
|
|
|
{
|
|
|
|
NumLeft -= AddItemToSlot(a_ItemStack, i, NumLeft, MaxStack);
|
|
|
|
}
|
|
|
|
if (NumLeft <= 0)
|
|
|
|
{
|
|
|
|
// All items fit
|
|
|
|
return a_ItemStack.m_ItemCount;
|
|
|
|
}
|
|
|
|
} // for i - m_Slots[]
|
|
|
|
return (a_ItemStack.m_ItemCount - NumLeft);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
int cItemGrid::AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks, int a_PrioritySlot)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
int TotalAdded = 0;
|
|
|
|
for (cItems::iterator itr = a_ItemStackList.begin(); itr != a_ItemStackList.end();)
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
int NumAdded = AddItem(*itr, a_AllowNewStacks, a_PrioritySlot);
|
2013-07-29 07:13:03 -04:00
|
|
|
if (itr->m_ItemCount == NumAdded)
|
|
|
|
{
|
|
|
|
itr = a_ItemStackList.erase(itr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
itr->m_ItemCount -= NumAdded;
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
TotalAdded += NumAdded;
|
|
|
|
}
|
|
|
|
return TotalAdded;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-18 17:11:59 -04:00
|
|
|
int cItemGrid::RemoveItem(const cItem & a_ItemStack)
|
|
|
|
{
|
|
|
|
int NumLeft = a_ItemStack.m_ItemCount;
|
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return 0; // No items to remove
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < m_Slots.size(); i++)
|
2014-07-18 17:11:59 -04:00
|
|
|
{
|
|
|
|
if (NumLeft <= 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Slots[i].IsEqual(a_ItemStack))
|
|
|
|
{
|
2015-05-24 07:56:56 -04:00
|
|
|
int NumToRemove = std::min(NumLeft, static_cast<int>(m_Slots[i].m_ItemCount));
|
2014-07-18 17:11:59 -04:00
|
|
|
NumLeft -= NumToRemove;
|
|
|
|
m_Slots[i].m_ItemCount -= NumToRemove;
|
|
|
|
|
|
|
|
if (m_Slots[i].m_ItemCount <= 0)
|
|
|
|
{
|
|
|
|
m_Slots[i].Empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
TriggerListeners(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (a_ItemStack.m_ItemCount - NumLeft);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-07-14 12:56:42 -04:00
|
|
|
cItem * cItemGrid::FindItem(const cItem & a_RecipeItem)
|
|
|
|
{
|
|
|
|
if (!m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < m_Slots.size(); i++)
|
|
|
|
{
|
|
|
|
// Items are equal if none is greater the other
|
|
|
|
auto compare = cItem::sItemCompare{};
|
|
|
|
if (!compare(a_RecipeItem, m_Slots[i]) &&
|
|
|
|
!compare(m_Slots[i], a_RecipeItem))
|
|
|
|
{
|
|
|
|
return &m_Slots[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
int cItemGrid::ChangeSlotCount(int a_SlotNum, int a_AddToCount)
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_SlotNum))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots, ignoring the call, returning -1",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_SlotNum, m_Slots.size()
|
2013-07-29 07:13:03 -04:00
|
|
|
);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
if (m_Slots.GetAt(a_SlotNum).IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
// The item is empty, it's not gonna change
|
|
|
|
return 0;
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
if (m_Slots[a_SlotNum].m_ItemCount <= -a_AddToCount)
|
|
|
|
{
|
|
|
|
// Trying to remove more items than there already are, make the item empty
|
|
|
|
m_Slots[a_SlotNum].Empty();
|
|
|
|
TriggerListeners(a_SlotNum);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
m_Slots[a_SlotNum].m_ItemCount += a_AddToCount;
|
2014-02-12 17:01:22 -05:00
|
|
|
|
|
|
|
cItemHandler * Handler = cItemHandler::GetItemHandler(m_Slots[a_SlotNum].m_ItemType);
|
|
|
|
if (m_Slots[a_SlotNum].m_ItemCount > Handler->GetMaxStackSize())
|
|
|
|
{
|
|
|
|
m_Slots[a_SlotNum].m_ItemCount = Handler->GetMaxStackSize();
|
|
|
|
}
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
TriggerListeners(a_SlotNum);
|
|
|
|
return m_Slots[a_SlotNum].m_ItemCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::ChangeSlotCount(int a_X, int a_Y, int a_AddToCount)
|
|
|
|
{
|
|
|
|
return ChangeSlotCount(GetSlotNum(a_X, a_Y), a_AddToCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cItem cItemGrid::RemoveOneItem(int a_SlotNum)
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_SlotNum))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots, ignoring the call, returning empty item",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_SlotNum, m_Slots.size()
|
2013-07-29 07:13:03 -04:00
|
|
|
);
|
|
|
|
return cItem();
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// If the slot is empty, return an empty item
|
2018-01-21 13:45:13 -05:00
|
|
|
if (m_Slots.GetAt(a_SlotNum).IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
return cItem();
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Make a copy of the item in slot, set count to 1 and remove one from the slot
|
|
|
|
cItem res = m_Slots[a_SlotNum];
|
|
|
|
res.m_ItemCount = 1;
|
|
|
|
m_Slots[a_SlotNum].m_ItemCount -= 1;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Emptying the slot correctly if appropriate
|
|
|
|
if (m_Slots[a_SlotNum].m_ItemCount == 0)
|
|
|
|
{
|
|
|
|
m_Slots[a_SlotNum].Empty();
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Notify everyone of the change
|
|
|
|
TriggerListeners(a_SlotNum);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Return the stored one item
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cItem cItemGrid::RemoveOneItem(int a_X, int a_Y)
|
|
|
|
{
|
|
|
|
return RemoveOneItem(GetSlotNum(a_X, a_Y));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::HowManyItems(const cItem & a_Item)
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
int res = 0;
|
2018-01-21 13:45:13 -05:00
|
|
|
for (auto & Slot : m_Slots)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (Slot.IsEqual(a_Item))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
res += Slot.m_ItemCount;
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cItemGrid::HasItems(const cItem & a_ItemStack)
|
|
|
|
{
|
|
|
|
int CurrentlyHave = HowManyItems(a_ItemStack);
|
|
|
|
return (CurrentlyHave >= a_ItemStack.m_ItemCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::GetFirstEmptySlot(void) const
|
|
|
|
{
|
|
|
|
return GetNextEmptySlot(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::GetFirstUsedSlot(void) const
|
|
|
|
{
|
|
|
|
return GetNextUsedSlot(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::GetLastEmptySlot(void) const
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
for (int i = m_Slots.size() - 1; i >= 0; i--)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (m_Slots.GetAt(i).IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::GetLastUsedSlot(void) const
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return -1; // No slots are used
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = m_Slots.size() - 1; i >= 0; i--)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!m_Slots.GetAt(i).IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::GetNextEmptySlot(int a_StartFrom) const
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if ((a_StartFrom != -1) && !IsValidSlotNum(a_StartFrom))
|
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_StartFrom, m_Slots.size()
|
2017-07-09 16:54:56 -04:00
|
|
|
);
|
|
|
|
a_StartFrom = -1;
|
|
|
|
}
|
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
for (int i = a_StartFrom + 1; i < m_Slots.size(); i++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (m_Slots.GetAt(i).IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cItemGrid::GetNextUsedSlot(int a_StartFrom) const
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if ((a_StartFrom != -1) && !IsValidSlotNum(a_StartFrom))
|
|
|
|
{
|
|
|
|
LOGWARNING("%s: Invalid slot number %d out of %d slots",
|
2018-01-21 13:45:13 -05:00
|
|
|
__FUNCTION__, a_StartFrom, m_Slots.size()
|
2017-07-09 16:54:56 -04:00
|
|
|
);
|
|
|
|
a_StartFrom = -1;
|
|
|
|
}
|
|
|
|
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return -1; // No slots are used
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = a_StartFrom + 1; i < m_Slots.size(); i++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!m_Slots.GetAt(i).IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::CopyToItems(cItems & a_Items) const
|
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return; // Nothing to copy
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto & Slot : m_Slots)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
if (!Slot.IsEmpty())
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
a_Items.push_back(Slot);
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
2018-01-21 13:45:13 -05:00
|
|
|
} // for Slot - m_Slots[]
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cItemGrid::DamageItem(int a_SlotNum, short a_Amount)
|
|
|
|
{
|
2017-07-09 16:54:56 -04:00
|
|
|
if (!IsValidSlotNum(a_SlotNum))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2018-01-21 13:45:13 -05:00
|
|
|
LOGWARNING("%s: invalid slot number %d out of %d slots, ignoring.", __FUNCTION__, a_SlotNum, m_Slots.size());
|
2013-07-29 07:13:03 -04:00
|
|
|
return false;
|
|
|
|
}
|
2018-01-21 13:45:13 -05:00
|
|
|
|
|
|
|
if (!m_Slots.IsStorageAllocated())
|
|
|
|
{
|
|
|
|
return false; // Nothing to damage
|
|
|
|
}
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
return m_Slots[a_SlotNum].DamageItem(a_Amount);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cItemGrid::DamageItem(int a_X, int a_Y, short a_Amount)
|
|
|
|
{
|
|
|
|
return DamageItem(GetSlotNum(a_X, a_Y), a_Amount);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-12-22 09:33:43 -05:00
|
|
|
void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
// Calculate the total weight:
|
|
|
|
int TotalProbab = 1;
|
2013-12-22 09:33:43 -05:00
|
|
|
for (size_t i = 0; i < a_CountLootProbabs; i++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
TotalProbab += a_LootProbabs[i].m_Weight;
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Pick the loot items:
|
|
|
|
cNoise Noise(a_Seed);
|
|
|
|
for (int i = 0; i < a_NumSlots; i++)
|
|
|
|
{
|
|
|
|
int Rnd = (Noise.IntNoise1DInt(i) / 7);
|
|
|
|
int LootRnd = Rnd % TotalProbab;
|
|
|
|
Rnd >>= 8;
|
2014-10-15 08:08:45 -04:00
|
|
|
cItem CurrentLoot = cItem(E_ITEM_ENCHANTED_BOOK, 1, 0);
|
|
|
|
|
|
|
|
// Choose the enchantments
|
|
|
|
cWeightedEnchantments Enchantments;
|
2021-07-09 13:45:53 -04:00
|
|
|
cEnchantments::AddItemEnchantmentWeights(Enchantments, E_ITEM_BOOK, static_cast<unsigned>(24 + Noise.IntNoise2DInt(a_Seed, TotalProbab) % 7));
|
2014-10-19 12:45:32 -04:00
|
|
|
int NumEnchantments = Noise.IntNoise3DInt(TotalProbab, Rnd, a_Seed) % 5; // The number of enchantments this book wil get.
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-10-15 09:25:48 -04:00
|
|
|
for (int j = 0; j <= NumEnchantments; j++)
|
2014-10-15 08:08:45 -04:00
|
|
|
{
|
2014-12-21 13:48:29 -05:00
|
|
|
cEnchantments Enchantment = cEnchantments::SelectEnchantmentFromVector(Enchantments, Noise.IntNoise2DInt(NumEnchantments, i));
|
2014-10-15 09:31:06 -04:00
|
|
|
CurrentLoot.m_Enchantments.Add(Enchantment);
|
2014-10-15 08:08:45 -04:00
|
|
|
cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment);
|
2014-10-15 09:44:52 -04:00
|
|
|
cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment);
|
2014-10-15 08:08:45 -04:00
|
|
|
}
|
|
|
|
|
2013-12-22 09:33:43 -05:00
|
|
|
for (size_t j = 0; j < a_CountLootProbabs; j++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-10-16 05:17:39 -04:00
|
|
|
LootRnd -= a_LootProbabs[j].m_Weight;
|
2013-07-29 07:13:03 -04:00
|
|
|
if (LootRnd < 0)
|
|
|
|
{
|
2014-10-16 05:17:39 -04:00
|
|
|
CurrentLoot = a_LootProbabs[j].m_Item;
|
|
|
|
if ((a_LootProbabs[j].m_MaxAmount - a_LootProbabs[j].m_MinAmount) > 0)
|
|
|
|
{
|
2015-07-29 11:04:03 -04:00
|
|
|
CurrentLoot.m_ItemCount = static_cast<char>(a_LootProbabs[j].m_MinAmount + (Rnd % (a_LootProbabs[j].m_MaxAmount - a_LootProbabs[j].m_MinAmount)));
|
2014-10-16 05:17:39 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-07-29 11:04:03 -04:00
|
|
|
CurrentLoot.m_ItemCount = static_cast<char>(a_LootProbabs[j].m_MinAmount);
|
2014-10-16 05:17:39 -04:00
|
|
|
}
|
2013-07-29 07:13:03 -04:00
|
|
|
Rnd >>= 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} // for j - a_LootProbabs[]
|
2018-01-21 13:45:13 -05:00
|
|
|
SetSlot(Rnd % m_Slots.size(), CurrentLoot);
|
2013-07-29 07:13:03 -04:00
|
|
|
} // for i - NumSlots
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::AddListener(cListener & a_Listener)
|
|
|
|
{
|
|
|
|
cCSLock Lock(m_CSListeners);
|
|
|
|
ASSERT(!m_IsInTriggerListeners); // Must not call this while in TriggerListeners()
|
|
|
|
m_Listeners.push_back(&a_Listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::RemoveListener(cListener & a_Listener)
|
|
|
|
{
|
|
|
|
cCSLock Lock(m_CSListeners);
|
|
|
|
ASSERT(!m_IsInTriggerListeners); // Must not call this while in TriggerListeners()
|
|
|
|
for (cListeners::iterator itr = m_Listeners.begin(), end = m_Listeners.end(); itr != end; ++itr)
|
|
|
|
{
|
|
|
|
if (*itr == &a_Listener)
|
|
|
|
{
|
|
|
|
m_Listeners.erase(itr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} // for itr - m_Listeners[]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cItemGrid::TriggerListeners(int a_SlotNum)
|
|
|
|
{
|
|
|
|
cListeners Listeners;
|
|
|
|
{
|
|
|
|
cCSLock Lock(m_CSListeners);
|
|
|
|
m_IsInTriggerListeners = true;
|
|
|
|
Listeners = m_Listeners;
|
|
|
|
}
|
|
|
|
for (cListeners::iterator itr = Listeners.begin(), end = Listeners.end(); itr != end; ++itr)
|
|
|
|
{
|
|
|
|
(*itr)->OnSlotChanged(this, a_SlotNum);
|
|
|
|
} // for itr - m_Listeners[]
|
|
|
|
m_IsInTriggerListeners = false;
|
|
|
|
}
|