Refactored cInventory to use cItemGrid for the actual Storage
This makes the API more orthogonal and is easier to use in the plugins. Also changes in the inventory are now propagated to the needed places (armor updates to BroadcastEntityEquipment etc.) even when the inventory is changed by a plugin. git-svn-id: http://mc-server.googlecode.com/svn/trunk@1503 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
3b429a9bdf
commit
cf87169737
@ -1,36 +1,39 @@
|
||||
function HandleItemCommand(Split, Player)
|
||||
if( #Split ~= 2 and #Split ~=3 ) then
|
||||
Player:SendMessage( cChatColor.Green .. "Usage: /item [ItemType/Name:Dmg] <Amount>" )
|
||||
return true
|
||||
if ((#Split ~= 2) and (#Split ~=3)) then
|
||||
Player:SendMessage(cChatColor.Green .. "Usage: /item [ItemType/Name:Dmg] <Amount>");
|
||||
return true;
|
||||
end
|
||||
|
||||
local Item = cItem(E_ITEM_EMPTY, 1)
|
||||
local FoundItem = StringToItem( Split[2], Item )
|
||||
local Item = cItem(E_ITEM_EMPTY, 1);
|
||||
local FoundItem = StringToItem(Split[2], Item);
|
||||
|
||||
if( IsValidItem( Item.m_ItemType ) == false ) then -- StringToItem does not check if item is valid
|
||||
if not(IsValidItem(Item.m_ItemType)) then -- StringToItem does not check if item is valid
|
||||
FoundItem = false
|
||||
end
|
||||
|
||||
if( FoundItem == false ) then
|
||||
if not(FoundItem) then
|
||||
Player:SendMessage( cChatColor.Green .. "Invalid Item type / name !" )
|
||||
return true
|
||||
end
|
||||
|
||||
local ItemAmount = 1;
|
||||
if (#Split == 3) then
|
||||
ItemAmount = tonumber( Split[3] )
|
||||
if( ItemAmount == nil or ItemAmount < 1 or ItemAmount > 512 ) then
|
||||
Player:SendMessage( cChatColor.Green .. "Invalid Amount !" )
|
||||
return true
|
||||
else
|
||||
Item.m_ItemCount = ItemAmount
|
||||
ItemAmount = tonumber(Split[3]);
|
||||
if ((ItemAmount == nil) or (ItemAmount < 1) or (ItemAmount > 512)) then
|
||||
Player:SendMessage(cChatColor.Green .. "Invalid Amount!");
|
||||
return true;
|
||||
end
|
||||
end
|
||||
|
||||
if( Player:GetInventory():AddItem( Item ) == true ) then
|
||||
Player:SendMessage( cChatColor.Green .. "There you go !" )
|
||||
LOG("Gave " .. Player:GetName() .. " " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage)
|
||||
Item.m_ItemCount = ItemAmount;
|
||||
|
||||
local ItemsGiven = Player:GetInventory():AddItem(Item);
|
||||
if (ItemsGiven == ItemAmount) then
|
||||
Player:SendMessage( cChatColor.Green .. "There you go !");
|
||||
LOG("Gave " .. Player:GetName() .. " " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage);
|
||||
else
|
||||
Player:SendMessage( cChatColor.Green .. "Not enough space in inventory !" )
|
||||
Player:SendMessage(cChatColor.Green .. "Not enough space in inventory, only gave " .. ItemsGiven);
|
||||
LOG("Player " .. Player:GetName() .. " asked for " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage ..", but only could fit " .. ItemsGiven);
|
||||
end
|
||||
return true
|
||||
return true;
|
||||
end
|
@ -456,10 +456,10 @@ end
|
||||
|
||||
function HandleWoolCmd(Split, Player)
|
||||
local Wool = cItem(E_BLOCK_WOOL, 1, E_META_WOOL_BLUE);
|
||||
Player:GetInventory():SetSlot(5, Wool);
|
||||
Player:GetInventory():SetSlot(6, Wool);
|
||||
Player:GetInventory():SetSlot(7, Wool);
|
||||
Player:GetInventory():SetSlot(8, Wool);
|
||||
Player:GetInventory():SetArmorSlot(0, Wool);
|
||||
Player:GetInventory():SetArmorSlot(1, Wool);
|
||||
Player:GetInventory():SetArmorSlot(2, Wool);
|
||||
Player:GetInventory():SetArmorSlot(3, Wool);
|
||||
Player:SendMessage("You have been bluewooled :)");
|
||||
return true;
|
||||
end
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
** Lua binding: AllToLua
|
||||
** Generated automatically by tolua++-1.0.92 on 05/21/13 14:54:11.
|
||||
** Generated automatically by tolua++-1.0.92 on 05/24/13 09:11:00.
|
||||
*/
|
||||
|
||||
/* Exported function */
|
||||
|
@ -29,8 +29,7 @@ public:
|
||||
case E_ITEM_WATER_BUCKET:
|
||||
{
|
||||
a_World->SetBlockMeta( a_BlockX, a_BlockY, a_BlockZ, 3 );
|
||||
cItem Item(a_Player->GetEquippedItem().m_ItemType, 1);
|
||||
a_Player->GetInventory().RemoveItem(Item);
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
cItem NewItem(E_ITEM_BUCKET, 1);
|
||||
a_Player->GetInventory().AddItem(NewItem);
|
||||
break;
|
||||
@ -40,8 +39,7 @@ public:
|
||||
if( Meta > 0 )
|
||||
{
|
||||
a_World->SetBlockMeta( a_BlockX, a_BlockY, a_BlockZ, --Meta);
|
||||
cItem Item(a_Player->GetEquippedItem().m_ItemType, 1);
|
||||
a_Player->GetInventory().RemoveItem(Item);
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
cItem NewItem(E_ITEM_POTIONS, 1, 0);
|
||||
a_Player->GetInventory().AddItem(NewItem);
|
||||
}
|
||||
|
@ -86,10 +86,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (a_Player->GetGameMode() != eGameMode_Creative)
|
||||
if (a_Player->GetGameMode() != gmCreative)
|
||||
{
|
||||
cItem Item(a_Player->GetEquippedItem().m_ItemType, 1);
|
||||
a_Player->GetInventory().RemoveItem(Item);
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
|
||||
}
|
||||
|
@ -791,7 +791,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c
|
||||
if (ItemHandler->EatItem(m_Player, &Item))
|
||||
{
|
||||
ItemHandler->OnFoodEaten(World, m_Player, &Item);
|
||||
m_Player->GetInventory().RemoveItem(Item);
|
||||
m_Player->GetInventory().RemoveOneEquippedItem();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -877,10 +877,9 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c
|
||||
|
||||
// The actual block placement:
|
||||
World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
if (m_Player->GetGameMode() == eGameMode_Survival)
|
||||
if (m_Player->GetGameMode() != gmCreative)
|
||||
{
|
||||
cItem Item(m_Player->GetEquippedItem().m_ItemType, 1);
|
||||
m_Player->GetInventory().RemoveItem(Item);
|
||||
m_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
NewBlock->OnPlacedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
|
||||
|
||||
|
@ -18,12 +18,15 @@
|
||||
|
||||
|
||||
cInventory::cInventory(cPlayer & a_Owner) :
|
||||
m_ArmorSlots (1, 4), // 1 x 4 slots
|
||||
m_InventorySlots(9, 3), // 9 x 3 slots
|
||||
m_HotbarSlots (9, 1), // 9 x 1 slots
|
||||
m_Owner(a_Owner)
|
||||
{
|
||||
m_CraftSlots = m_Slots + c_CraftOffset;
|
||||
m_ArmorSlots = m_Slots + c_ArmorOffset;
|
||||
m_MainSlots = m_Slots + c_MainOffset;
|
||||
m_HotSlots = m_Slots + c_HotOffset;
|
||||
// Ask each ItemGrid to report changes to us:
|
||||
m_ArmorSlots.AddListener(*this);
|
||||
m_InventorySlots.AddListener(*this);
|
||||
m_HotbarSlots.AddListener(*this);
|
||||
|
||||
SetEquippedSlotNum(0);
|
||||
}
|
||||
@ -32,82 +35,130 @@ cInventory::cInventory(cPlayer & a_Owner) :
|
||||
|
||||
|
||||
|
||||
cInventory::~cInventory()
|
||||
void cInventory::Clear(void)
|
||||
{
|
||||
/*
|
||||
// TODO
|
||||
cWindow wnd = GetWindow();
|
||||
if (wnd != NULL)
|
||||
{
|
||||
wnd->Close(*m_Owner);
|
||||
}
|
||||
CloseWindow();
|
||||
*/
|
||||
m_ArmorSlots.Clear();
|
||||
m_InventorySlots.Clear();
|
||||
m_HotbarSlots.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cInventory::AddItem( cItem & a_Item )
|
||||
int cInventory::HowManyCanFit(const cItem & a_ItemStack, bool a_ConsiderEmptySlots)
|
||||
{
|
||||
cItem BackupSlots[c_NumSlots];
|
||||
memcpy( BackupSlots, m_Slots, c_NumSlots * sizeof( cItem ) );
|
||||
return HowManyCanFit(a_ItemStack, 0, invNumSlots - 1, a_ConsiderEmptySlots);
|
||||
}
|
||||
|
||||
bool ChangedSlots[c_NumSlots];
|
||||
memset( ChangedSlots, false, c_NumSlots * sizeof( bool ) );
|
||||
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_HotOffset, c_HotSlots, ChangedSlots, 0 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_MainOffset, c_MainSlots, ChangedSlots, 0 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_HotOffset, c_HotSlots, ChangedSlots, 2 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_MainOffset, c_MainSlots, ChangedSlots, 2 );
|
||||
|
||||
if( a_Item.m_ItemCount > 0 ) // Could not add all items
|
||||
|
||||
|
||||
int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots)
|
||||
{
|
||||
if ((a_BeginSlotNum < 0) || (a_BeginSlotNum >= invNumSlots))
|
||||
{
|
||||
LOGWARNING("%s: Bad BeginSlotNum, got %d, there are %d slots; correcting to 0.", __FUNCTION__, a_BeginSlotNum, invNumSlots - 1);
|
||||
a_BeginSlotNum = 0;
|
||||
}
|
||||
if ((a_EndSlotNum < 0) || (a_EndSlotNum >= invNumSlots))
|
||||
{
|
||||
LOGWARNING("%s: Bad EndSlotNum, got %d, there are %d slots; correcting to %d.", __FUNCTION__, a_BeginSlotNum, invNumSlots, invNumSlots - 1);
|
||||
a_EndSlotNum = invNumSlots - 1;
|
||||
}
|
||||
if (a_BeginSlotNum > a_EndSlotNum)
|
||||
{
|
||||
std::swap(a_BeginSlotNum, a_EndSlotNum);
|
||||
}
|
||||
|
||||
char NumLeft = a_ItemStack.m_ItemCount;
|
||||
int MaxStack = ItemHandler(a_ItemStack.m_ItemType)->GetMaxStackSize();
|
||||
for (int i = a_BeginSlotNum; i <= a_EndSlotNum; i++)
|
||||
{
|
||||
const cItem & Slot = GetSlot(i);
|
||||
if (Slot.IsEmpty())
|
||||
{
|
||||
NumLeft -= MaxStack;
|
||||
}
|
||||
else if (Slot.IsStackableWith(a_ItemStack))
|
||||
{
|
||||
NumLeft -= MaxStack - Slot.m_ItemCount;
|
||||
}
|
||||
if (NumLeft <= 0)
|
||||
{
|
||||
// All items fit
|
||||
return a_ItemStack.m_ItemCount;
|
||||
}
|
||||
} // for i - m_Slots[]
|
||||
return a_ItemStack.m_ItemCount - NumLeft;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks)
|
||||
{
|
||||
cItem ToAdd(a_Item);
|
||||
int res = 0;
|
||||
if (ItemCategory::IsArmor(a_Item.m_ItemType))
|
||||
{
|
||||
res = m_ArmorSlots.AddItem(ToAdd, a_AllowNewStacks);
|
||||
ToAdd.m_ItemCount -= res;
|
||||
if (ToAdd.m_ItemCount == 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
res += m_HotbarSlots.AddItem(ToAdd, a_AllowNewStacks);
|
||||
ToAdd.m_ItemCount = a_Item.m_ItemCount - res;
|
||||
if (ToAdd.m_ItemCount == 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
res += m_InventorySlots.AddItem(ToAdd, a_AllowNewStacks);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cInventory::AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks)
|
||||
{
|
||||
int TotalAdded = 0;
|
||||
for (cItems::iterator itr = a_ItemStackList.begin(); itr != a_ItemStackList.end();)
|
||||
{
|
||||
int NumAdded = AddItem(*itr, a_AllowNewStacks);
|
||||
if (itr->m_ItemCount == NumAdded)
|
||||
{
|
||||
itr = a_ItemStackList.erase(itr);
|
||||
}
|
||||
else
|
||||
{
|
||||
itr->m_ItemCount -= NumAdded;
|
||||
++itr;
|
||||
}
|
||||
TotalAdded += NumAdded;
|
||||
}
|
||||
return TotalAdded;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cInventory::RemoveOneEquippedItem(void)
|
||||
{
|
||||
if (m_HotbarSlots.GetSlot(m_EquippedSlotNum).IsEmpty())
|
||||
{
|
||||
// retore backup
|
||||
memcpy( m_Slots, BackupSlots, c_NumSlots * sizeof( cItem ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < c_NumSlots; i++)
|
||||
{
|
||||
if (ChangedSlots[i])
|
||||
{
|
||||
LOGD("cInventory::AddItem(): Item was added to %i ID:%i Count:%i", i, m_Slots[i].m_ItemType, m_Slots[i].m_ItemCount);
|
||||
SendSlot(i);
|
||||
}
|
||||
}
|
||||
|
||||
return (a_Item.m_ItemCount == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cInventory::AddItemAnyAmount( cItem & a_Item )
|
||||
{
|
||||
bool ChangedSlots[c_NumSlots];
|
||||
memset( ChangedSlots, false, c_NumSlots * sizeof( bool ) );
|
||||
|
||||
char StartCount = a_Item.m_ItemCount;
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_HotOffset, c_HotSlots, ChangedSlots, 0 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_MainOffset, c_MainSlots, ChangedSlots, 0 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_HotOffset, c_HotSlots, ChangedSlots, 2 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_MainOffset, c_MainSlots, ChangedSlots, 2 );
|
||||
|
||||
if (a_Item.m_ItemCount == StartCount)
|
||||
return false;
|
||||
|
||||
for (unsigned int i = 0; i < c_NumSlots; i++)
|
||||
{
|
||||
if (ChangedSlots[i])
|
||||
{
|
||||
LOGD("cInventory::AddItemAnyAmount(): Item was added to %i ID:%i Count:%i", i, m_Slots[i].m_ItemType, m_Slots[i].m_ItemCount);
|
||||
SendSlot(i);
|
||||
}
|
||||
}
|
||||
|
||||
m_HotbarSlots.ChangeSlotCount(m_EquippedSlotNum, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -115,68 +166,22 @@ bool cInventory::AddItemAnyAmount( cItem & a_Item )
|
||||
|
||||
|
||||
|
||||
// TODO: Right now if you dont have enough items, the items you did have are removed, and the function returns false anyway
|
||||
bool cInventory::RemoveItem(cItem & a_Item)
|
||||
int cInventory::HowManyItems(const cItem & a_Item)
|
||||
{
|
||||
// First check equipped slot
|
||||
if ((m_EquippedSlotNum >= 0) && (m_EquippedSlotNum < 9))
|
||||
{
|
||||
if (m_HotSlots[m_EquippedSlotNum].m_ItemType == a_Item.m_ItemType)
|
||||
{
|
||||
cItem & Item = m_HotSlots[m_EquippedSlotNum];
|
||||
if (Item.m_ItemCount > a_Item.m_ItemCount)
|
||||
{
|
||||
Item.m_ItemCount -= a_Item.m_ItemCount;
|
||||
SendSlot(m_EquippedSlotNum + c_HotOffset);
|
||||
return true;
|
||||
}
|
||||
else if (Item.m_ItemCount > 0)
|
||||
{
|
||||
a_Item.m_ItemCount -= Item.m_ItemCount;
|
||||
Item.Empty();
|
||||
SendSlot(m_EquippedSlotNum + c_HotOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then check other slotz
|
||||
if (a_Item.m_ItemCount > 0)
|
||||
{
|
||||
for (int i = 0; i < c_MainSlots; i++)
|
||||
{
|
||||
cItem & Item = m_MainSlots[i];
|
||||
if (Item.m_ItemType == a_Item.m_ItemType)
|
||||
{
|
||||
if (Item.m_ItemCount > a_Item.m_ItemCount)
|
||||
{
|
||||
Item.m_ItemCount -= a_Item.m_ItemCount;
|
||||
SendSlot(i + c_MainOffset);
|
||||
return true;
|
||||
}
|
||||
else if (Item.m_ItemCount > 0)
|
||||
{
|
||||
a_Item.m_ItemCount -= Item.m_ItemCount;
|
||||
Item.Empty();
|
||||
SendSlot(i + c_MainOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (a_Item.m_ItemCount == 0);
|
||||
return
|
||||
m_ArmorSlots.HowManyItems(a_Item) +
|
||||
m_InventorySlots.HowManyItems(a_Item) +
|
||||
m_HotbarSlots.HowManyItems(a_Item);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cInventory::Clear()
|
||||
bool cInventory::HasItems(const cItem & a_ItemStack)
|
||||
{
|
||||
for (unsigned int i = 0; i < ARRAYCOUNT(m_Slots); i++)
|
||||
{
|
||||
m_Slots[i].Empty();
|
||||
}
|
||||
// TODO: Broadcast / send the changes to wherever needed
|
||||
int CurrentlyHave = HowManyItems(a_ItemStack);
|
||||
return (CurrentlyHave >= a_ItemStack.m_ItemCount);
|
||||
}
|
||||
|
||||
|
||||
@ -185,29 +190,47 @@ void cInventory::Clear()
|
||||
|
||||
void cInventory::SetSlot(int a_SlotNum, const cItem & a_Item)
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= ARRAYCOUNT(m_Slots)))
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
|
||||
{
|
||||
LOGWARNING("%s requesting an invalid slot index: %d out of %d. Ignoring.", __FUNCTION__, a_SlotNum, ARRAYCOUNT(m_Slots));
|
||||
LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Ignoring.", __FUNCTION__, a_SlotNum, invNumSlots - 1);
|
||||
return;
|
||||
}
|
||||
m_Slots[a_SlotNum] = a_Item;
|
||||
|
||||
// If an armor slot was touched, broadcast an EntityEquipment packet
|
||||
if ((a_SlotNum >= c_ArmorOffset) && (a_SlotNum < c_MainOffset))
|
||||
int GridSlotNum = 0;
|
||||
cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum);
|
||||
if (Grid == NULL)
|
||||
{
|
||||
m_Owner.GetWorld()->BroadcastEntityEquipment(m_Owner, SlotNumToEntityEquipmentID(a_SlotNum), a_Item, m_Owner.GetClientHandle());
|
||||
LOGWARNING("%s(%d): requesting an invalid itemgrid. Ignoring.", __FUNCTION__, a_SlotNum);
|
||||
return;
|
||||
}
|
||||
|
||||
SendSlot(a_SlotNum);
|
||||
Grid->SetSlot(GridSlotNum, a_Item);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cInventory::SetHotBarSlot(int a_HotBarSlotNum, const cItem & a_Item)
|
||||
void cInventory::SetArmorSlot(int a_ArmorSlotNum, const cItem & a_Item)
|
||||
{
|
||||
SetSlot(a_HotBarSlotNum + c_HotSlots, a_Item);
|
||||
m_ArmorSlots.SetSlot(a_ArmorSlotNum, a_Item);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cInventory::SetInventorySlot(int a_InventorySlotNum, const cItem & a_Item)
|
||||
{
|
||||
m_InventorySlots.SetSlot(a_InventorySlotNum, a_Item);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cInventory::SetHotbarSlot(int a_HotBarSlotNum, const cItem & a_Item)
|
||||
{
|
||||
m_HotbarSlots.SetSlot(a_HotBarSlotNum, a_Item);
|
||||
}
|
||||
|
||||
|
||||
@ -216,27 +239,62 @@ void cInventory::SetHotBarSlot(int a_HotBarSlotNum, const cItem & a_Item)
|
||||
|
||||
const cItem & cInventory::GetSlot(int a_SlotNum) const
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= ARRAYCOUNT(m_Slots)))
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
|
||||
{
|
||||
LOGWARNING("%s requesting an invalid slot index: %d out of %d. Returning the first one instead.", __FUNCTION__, a_SlotNum, ARRAYCOUNT(m_Slots));
|
||||
return m_Slots[0];
|
||||
LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Returning the first inventory slot instead.", __FUNCTION__, a_SlotNum, invNumSlots - 1);
|
||||
return m_InventorySlots.GetSlot(0);
|
||||
}
|
||||
|
||||
return m_Slots[a_SlotNum];
|
||||
int GridSlotNum = 0;
|
||||
const cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum);
|
||||
if (Grid == NULL)
|
||||
{
|
||||
// Something went wrong, but we don't know what. We must return a value, so return the first inventory slot
|
||||
LOGWARNING("%s(%d): requesting an invalid ItemGrid, returning the first inventory slot instead.", __FUNCTION__, a_SlotNum);
|
||||
return m_InventorySlots.GetSlot(0);
|
||||
}
|
||||
return Grid->GetSlot(GridSlotNum);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const cItem & cInventory::GetHotBarSlot(int a_SlotNum) const
|
||||
const cItem & cInventory::GetArmorSlot(int a_ArmorSlotNum) const
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= 9))
|
||||
if ((a_ArmorSlotNum < 0) || (a_ArmorSlotNum >= invArmorCount))
|
||||
{
|
||||
LOGWARNING("%s requesting an invalid slot index: %d out of 9. Returning the first one instead", __FUNCTION__, a_SlotNum);
|
||||
return m_HotSlots[0];
|
||||
LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Returning the first one instead", __FUNCTION__, a_ArmorSlotNum, invArmorCount - 1);
|
||||
return m_ArmorSlots.GetSlot(0);
|
||||
}
|
||||
return m_HotSlots[a_SlotNum];
|
||||
return m_ArmorSlots.GetSlot(a_ArmorSlotNum);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const cItem & cInventory::GetInventorySlot(int a_InventorySlotNum) const
|
||||
{
|
||||
if ((a_InventorySlotNum < 0) || (a_InventorySlotNum >= invInventoryCount))
|
||||
{
|
||||
LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Returning the first one instead", __FUNCTION__, a_InventorySlotNum, invInventoryCount - 1);
|
||||
return m_InventorySlots.GetSlot(0);
|
||||
}
|
||||
return m_InventorySlots.GetSlot(a_InventorySlotNum);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const cItem & cInventory::GetHotbarSlot(int a_SlotNum) const
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= invHotbarCount))
|
||||
{
|
||||
LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Returning the first one instead", __FUNCTION__, a_SlotNum, invHotbarCount - 1);
|
||||
return m_HotbarSlots.GetSlot(0);
|
||||
}
|
||||
return m_HotbarSlots.GetSlot(a_SlotNum);
|
||||
}
|
||||
|
||||
|
||||
@ -245,7 +303,7 @@ const cItem & cInventory::GetHotBarSlot(int a_SlotNum) const
|
||||
|
||||
const cItem & cInventory::GetEquippedItem(void) const
|
||||
{
|
||||
return GetHotBarSlot(m_EquippedSlotNum);
|
||||
return GetHotbarSlot(m_EquippedSlotNum);
|
||||
}
|
||||
|
||||
|
||||
@ -254,14 +312,14 @@ const cItem & cInventory::GetEquippedItem(void) const
|
||||
|
||||
void cInventory::SetEquippedSlotNum(int a_SlotNum)
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= 9))
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= invHotbarCount))
|
||||
{
|
||||
LOGWARNING("%s requesting invalid slot index: %d out of 9. Setting 0 instead.", __FUNCTION__, a_SlotNum);
|
||||
LOGWARNING("%s: requesting invalid slot index: %d out of %d. Setting 0 instead.", __FUNCTION__, a_SlotNum, invHotbarCount - 1);
|
||||
m_EquippedSlotNum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_EquippedSlotNum = (short)a_SlotNum;
|
||||
m_EquippedSlotNum = a_SlotNum;
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,7 +329,7 @@ void cInventory::SetEquippedSlotNum(int a_SlotNum)
|
||||
|
||||
bool cInventory::DamageEquippedItem(short a_Amount)
|
||||
{
|
||||
return DamageItem(c_HotOffset + m_EquippedSlotNum, a_Amount);
|
||||
return DamageItem(invHotbarOffset + m_EquippedSlotNum, a_Amount);
|
||||
}
|
||||
|
||||
|
||||
@ -280,22 +338,27 @@ bool cInventory::DamageEquippedItem(short a_Amount)
|
||||
|
||||
bool cInventory::DamageItem(int a_SlotNum, short a_Amount)
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= ARRAYCOUNT(m_Slots)))
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
|
||||
{
|
||||
LOGWARNING("%s requesting an invalid slot index: %d out of %d", __FUNCTION__, a_SlotNum, ARRAYCOUNT(m_Slots));
|
||||
LOGWARNING("%s: requesting an invalid slot index: %d out of %d", __FUNCTION__, a_SlotNum, invNumSlots - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_Slots[a_SlotNum].DamageItem(a_Amount))
|
||||
int GridSlotNum = 0;
|
||||
cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum);
|
||||
if (Grid == NULL)
|
||||
{
|
||||
LOGWARNING("%s(%d, %d): requesting an invalid grid, ignoring.", __FUNCTION__, a_SlotNum, a_Amount);
|
||||
return false;
|
||||
}
|
||||
if (!Grid->DamageItem(GridSlotNum, a_Amount))
|
||||
{
|
||||
// The item has been damaged, but did not break yet
|
||||
return false;
|
||||
}
|
||||
|
||||
// The item has broken, remove it:
|
||||
m_Slots[a_SlotNum].Empty();
|
||||
SendSlot(a_SlotNum);
|
||||
|
||||
// TODO: If it was a special slot (armor / equipped), broadcast the change
|
||||
Grid->EmptySlot(a_SlotNum);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -303,6 +366,17 @@ bool cInventory::DamageItem(int a_SlotNum, short a_Amount)
|
||||
|
||||
|
||||
|
||||
void cInventory::CopyToItems(cItems & a_Items)
|
||||
{
|
||||
m_ArmorSlots.CopyToItems(a_Items);
|
||||
m_InventorySlots.CopyToItems(a_Items);
|
||||
m_HotbarSlots.CopyToItems(a_Items);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cInventory::SendWholeInventory(cClientHandle & a_Client)
|
||||
{
|
||||
a_Client.SendWholeInventory(*this);
|
||||
@ -320,35 +394,14 @@ void cInventory::SendSlot(int a_SlotNum)
|
||||
// Sanitize items that are not completely empty (ie. count == 0, but type != empty)
|
||||
Item.Empty();
|
||||
}
|
||||
m_Owner.GetClientHandle()->SendInventorySlot(0, a_SlotNum, Item);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cInventory::HowManyCanFit(short a_ItemType, short a_ItemDamage, int a_BeginSlot, int a_EndSlot)
|
||||
{
|
||||
int res = 0;
|
||||
for (int i = a_BeginSlot; i <= a_EndSlot; i++)
|
||||
{
|
||||
if (
|
||||
m_Slots[i].IsEmpty() ||
|
||||
((m_Slots[i].m_ItemType == a_ItemType) && (m_Slots[i].m_ItemDamage == a_ItemDamage))
|
||||
)
|
||||
{
|
||||
int MaxCount = ItemHandler(a_ItemType)->GetMaxStackSize();
|
||||
ASSERT(m_Slots[i].m_ItemCount <= MaxCount);
|
||||
res += MaxCount - m_Slots[i].m_ItemCount;
|
||||
}
|
||||
} // for i - m_Slots[]
|
||||
return res;
|
||||
m_Owner.GetClientHandle()->SendInventorySlot(0, a_SlotNum + 5, Item); // Slots in the client are numbered "+ 5" because of crafting grid and result
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
int cInventory::MoveItem(short a_ItemType, short a_ItemDamage, int a_Count, int a_BeginSlot, int a_EndSlot)
|
||||
{
|
||||
int res = 0;
|
||||
@ -378,21 +431,22 @@ int cInventory::MoveItem(short a_ItemType, short a_ItemDamage, int a_Count, int
|
||||
// No more space to distribute to
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cInventory::SlotNumToEntityEquipmentID(short a_SlotNum)
|
||||
int cInventory::ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum)
|
||||
{
|
||||
switch (a_SlotNum)
|
||||
switch (a_ArmorSlotNum)
|
||||
{
|
||||
case 5: return 4; // Helmet
|
||||
case 6: return 3; // Chestplate
|
||||
case 7: return 2; // Leggings
|
||||
case 8: return 1; // Boots
|
||||
case 0: return 4; // Helmet
|
||||
case 1: return 3; // Chestplate
|
||||
case 2: return 2; // Leggings
|
||||
case 3: return 1; // Boots
|
||||
}
|
||||
LOGWARN("%s: invalid slot number: %d", __FUNCTION__, a_SlotNum);
|
||||
LOGWARN("%s: invalid armor slot number: %d", __FUNCTION__, a_ArmorSlotNum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -400,6 +454,7 @@ int cInventory::SlotNumToEntityEquipmentID(short a_SlotNum)
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size, bool* a_bChangedSlots, int a_Mode /* = 0 */ )
|
||||
{
|
||||
// Fill already present stacks
|
||||
@ -447,6 +502,7 @@ bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size,
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -454,10 +510,36 @@ bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size,
|
||||
|
||||
void cInventory::SaveToJson(Json::Value & a_Value)
|
||||
{
|
||||
for(unsigned int i = 0; i < c_NumSlots; i++)
|
||||
// The JSON originally included the 4 crafting slots and the result, so we have to put empty items there, too:
|
||||
cItem EmptyItem;
|
||||
Json::Value EmptyItemJson;
|
||||
EmptyItem.GetJson(EmptyItemJson);
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
a_Value.append(EmptyItemJson);
|
||||
}
|
||||
|
||||
// The 4 armor slots follow:
|
||||
for (int i = 0; i < invArmorCount; i++)
|
||||
{
|
||||
Json::Value JSON_Item;
|
||||
m_Slots[i].GetJson( JSON_Item );
|
||||
m_ArmorSlots.GetSlot(i).GetJson(JSON_Item);
|
||||
a_Value.append(JSON_Item);
|
||||
}
|
||||
|
||||
// Next comes the main inventory:
|
||||
for (int i = 0; i < invInventoryCount; i++)
|
||||
{
|
||||
Json::Value JSON_Item;
|
||||
m_InventorySlots.GetSlot(i).GetJson(JSON_Item);
|
||||
a_Value.append(JSON_Item);
|
||||
}
|
||||
|
||||
// The hotbar is the last:
|
||||
for (int i = 0; i < invHotbarCount; i++)
|
||||
{
|
||||
Json::Value JSON_Item;
|
||||
m_HotbarSlots.GetSlot(i).GetJson(JSON_Item);
|
||||
a_Value.append(JSON_Item);
|
||||
}
|
||||
}
|
||||
@ -470,18 +552,124 @@ bool cInventory::LoadFromJson(Json::Value & a_Value)
|
||||
{
|
||||
int SlotIdx = 0;
|
||||
|
||||
for( Json::Value::iterator itr = a_Value.begin(); itr != a_Value.end(); ++itr )
|
||||
for (Json::Value::iterator itr = a_Value.begin(); itr != a_Value.end(); ++itr, SlotIdx++)
|
||||
{
|
||||
m_Slots[SlotIdx].FromJson( *itr );
|
||||
SlotIdx++;
|
||||
if (SlotIdx >= ARRAYCOUNT(m_Slots))
|
||||
cItem Item;
|
||||
Item.FromJson(*itr);
|
||||
|
||||
// The JSON originally included the 4 crafting slots and the result slot, so we need to skip the first 5 items:
|
||||
if (SlotIdx < 5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we loaded all the slots, stop now, even if the JSON has more:
|
||||
if (SlotIdx - 5 >= invNumSlots)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int GridSlotNum = 0;
|
||||
cItemGrid * Grid = GetGridForSlotNum(SlotIdx - 5, GridSlotNum);
|
||||
ASSERT(Grid != NULL);
|
||||
Grid->SetSlot(GridSlotNum, Item);
|
||||
} // for itr - a_Value[]
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const cItemGrid * cInventory::GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum) const
|
||||
{
|
||||
ASSERT(a_SlotNum >= 0);
|
||||
|
||||
if (a_SlotNum < invArmorCount)
|
||||
{
|
||||
a_GridSlotNum = a_SlotNum;
|
||||
return &m_ArmorSlots;
|
||||
}
|
||||
a_SlotNum -= invArmorCount;
|
||||
if (a_SlotNum < invInventoryCount)
|
||||
{
|
||||
a_GridSlotNum = a_SlotNum;
|
||||
return &m_InventorySlots;
|
||||
}
|
||||
a_GridSlotNum = a_SlotNum - invInventoryCount;
|
||||
return &m_HotbarSlots;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cItemGrid * cInventory::GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum)
|
||||
{
|
||||
ASSERT(a_SlotNum >= 0);
|
||||
|
||||
if (a_SlotNum < invArmorCount)
|
||||
{
|
||||
a_GridSlotNum = a_SlotNum;
|
||||
return &m_ArmorSlots;
|
||||
}
|
||||
a_SlotNum -= invArmorCount;
|
||||
if (a_SlotNum < invInventoryCount)
|
||||
{
|
||||
a_GridSlotNum = a_SlotNum;
|
||||
return &m_InventorySlots;
|
||||
}
|
||||
a_GridSlotNum = a_SlotNum - invInventoryCount;
|
||||
return &m_HotbarSlots;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cInventory::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
|
||||
{
|
||||
// Send the neccessary updates to whoever needs them
|
||||
|
||||
if (m_Owner.IsDestroyed())
|
||||
{
|
||||
// Owner is not (yet) valid, skip for now
|
||||
return;
|
||||
}
|
||||
|
||||
// Armor update needs broadcast to other players:
|
||||
cWorld * World = m_Owner.GetWorld();
|
||||
if ((a_ItemGrid == &m_ArmorSlots) && (World != NULL))
|
||||
{
|
||||
World->BroadcastEntityEquipment(
|
||||
m_Owner, ArmorSlotNumToEntityEquipmentID(a_SlotNum),
|
||||
m_ArmorSlots.GetSlot(a_SlotNum), m_Owner.GetClientHandle()
|
||||
);
|
||||
}
|
||||
|
||||
// Convert the grid-local a_SlotNum to our global SlotNum:
|
||||
int Base = 0;
|
||||
if (a_ItemGrid == &m_ArmorSlots)
|
||||
{
|
||||
Base = invArmorOffset;
|
||||
}
|
||||
else if (a_ItemGrid == &m_InventorySlots)
|
||||
{
|
||||
Base = invInventoryOffset;
|
||||
}
|
||||
else if (a_ItemGrid == &m_HotbarSlots)
|
||||
{
|
||||
Base = invHotbarOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(!"Unknown ItemGrid calling OnSlotChanged()");
|
||||
return;
|
||||
}
|
||||
|
||||
SendSlot(Base + a_SlotNum);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Item.h"
|
||||
#include "ItemGrid.h"
|
||||
|
||||
|
||||
|
||||
@ -18,36 +18,108 @@ class cPlayer;
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cInventory // tolua_export
|
||||
{ // tolua_export
|
||||
/** This class represents the player's inventory
|
||||
The slots are divided into three areas:
|
||||
- armor slots (1 x 4)
|
||||
- inventory slots (9 x 3)
|
||||
- hotbar slots (9 x 1)
|
||||
The generic GetSlot(), SetSlot() and HowManyCanFit() functions take the index of the slots,
|
||||
as if armor slots, inventory slots and then hotbar slots were put one after another.
|
||||
You can use the invArmorOffset, invInventoryOffset and invHotbarOffset constants.
|
||||
*/
|
||||
|
||||
class cInventory :
|
||||
public cItemGrid::cListener
|
||||
{
|
||||
public:
|
||||
|
||||
// Counts and offsets to individual parts of the inventory, as used by GetSlot() / SetSlot() / HowManyCanFit():
|
||||
enum
|
||||
{
|
||||
invArmorCount = 4,
|
||||
invInventoryCount = 9 * 3,
|
||||
invHotbarCount = 9,
|
||||
|
||||
invArmorOffset = 0,
|
||||
invInventoryOffset = invArmorOffset + invArmorCount,
|
||||
invHotbarOffset = invInventoryOffset + invInventoryCount,
|
||||
invNumSlots = invHotbarOffset + invHotbarCount
|
||||
} ;
|
||||
|
||||
// tolua_end
|
||||
|
||||
cInventory(cPlayer & a_Owner);
|
||||
~cInventory();
|
||||
|
||||
void Clear(); // tolua_export
|
||||
// tolua_begin
|
||||
|
||||
// cItem * GetSlotsForType( int a_Type );
|
||||
// int GetSlotCountForType( int a_Type );
|
||||
/// Removes all items from the entire inventory
|
||||
void Clear(void);
|
||||
|
||||
bool AddItem( cItem & a_Item ); // tolua_export
|
||||
bool AddItemAnyAmount( cItem & a_Item ); // tolua_export
|
||||
bool RemoveItem( cItem & a_Item ); // tolua_export
|
||||
/// Returns number of items out of a_ItemStack that can fit in the storage
|
||||
int HowManyCanFit(const cItem & a_ItemStack, bool a_ConsiderEmptySlots);
|
||||
|
||||
void SaveToJson(Json::Value & a_Value);
|
||||
bool LoadFromJson(Json::Value & a_Value);
|
||||
/// Returns how many items of the specified type would fit into the slot range specified
|
||||
int HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots);
|
||||
|
||||
/** 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.
|
||||
Returns the number of items that fit.
|
||||
*/
|
||||
int AddItem(const cItem & a_ItemStack, bool a_AllowNewStacks = true);
|
||||
|
||||
/** Same as AddItem, but works on an entire list of item stacks.
|
||||
The a_ItemStackList is modified to reflect the leftover items.
|
||||
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
|
||||
Returns the total number of items that fit.
|
||||
*/
|
||||
int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks);
|
||||
|
||||
/// Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed
|
||||
bool RemoveOneEquippedItem(void);
|
||||
|
||||
/// Returns the number of items of type a_Item that are stored
|
||||
int HowManyItems(const cItem & a_Item);
|
||||
|
||||
/// Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack
|
||||
bool HasItems(const cItem & a_ItemStack);
|
||||
|
||||
/// Returns the cItemGrid object representing the armor slots
|
||||
cItemGrid & GetArmorGrid(void) { return m_ArmorSlots; }
|
||||
|
||||
/// Returns the cItemGrid object representing the main inventory slots
|
||||
cItemGrid & GetInventoryGrid(void) { return m_InventorySlots; }
|
||||
|
||||
/// Returns the cItemGrid object representing the hotbar slots
|
||||
cItemGrid & GetHotbarGrid(void) { return m_HotbarSlots; }
|
||||
|
||||
/// Returns the player associated with this inventory
|
||||
cPlayer & GetOwner(void) { return m_Owner; }
|
||||
|
||||
/// Copies the non-empty slots into a_ItemStacks; preserves the original a_Items contents
|
||||
void CopyToItems(cItems & a_Items);
|
||||
|
||||
// tolua_end
|
||||
|
||||
void SendWholeInventory(cClientHandle & a_Client);
|
||||
|
||||
const cItem * GetSlots(void) const { return m_Slots; }
|
||||
/// Returns the player associated with this inventory (const version)
|
||||
const cPlayer & GetOwner(void) const { return m_Owner; }
|
||||
|
||||
// tolua_begin
|
||||
|
||||
const cItem & GetSlot(int a_SlotNum) const;
|
||||
const cItem & GetHotBarSlot(int a_HotBarSlotNum) const;
|
||||
const cItem & GetArmorSlot(int a_ArmorSlotNum) const;
|
||||
const cItem & GetInventorySlot(int a_InventorySlotNum) const;
|
||||
const cItem & GetHotbarSlot(int a_HotBarSlotNum) const;
|
||||
const cItem & GetEquippedItem(void) const;
|
||||
void SetSlot(int a_SlotNum, const cItem & a_Item);
|
||||
void SetHotBarSlot(int a_HotBarSlotNum, const cItem & a_Item);
|
||||
void SetArmorSlot(int a_ArmorSlotNum, const cItem & a_Item);
|
||||
void SetInventorySlot(int a_InventorySlotNum, const cItem & a_Item);
|
||||
void SetHotbarSlot(int a_HotBarSlotNum, const cItem & a_Item);
|
||||
|
||||
void SetEquippedSlotNum(int a_SlotNum);
|
||||
int GetEquippedSlotNum(void) { return m_EquippedSlotNum; }
|
||||
@ -58,48 +130,41 @@ public:
|
||||
/// Adds the specified damage to the currently held item; deletes the item and returns true if the item broke.
|
||||
bool DamageEquippedItem(short a_Amount = 1);
|
||||
|
||||
const cItem & GetEquippedHelmet (void) const { return m_Slots[c_ArmorOffset]; }
|
||||
const cItem & GetEquippedChestplate(void) const { return m_Slots[c_ArmorOffset + 1]; }
|
||||
const cItem & GetEquippedLeggings (void) const { return m_Slots[c_ArmorOffset + 2]; }
|
||||
const cItem & GetEquippedBoots (void) const { return m_Slots[c_ArmorOffset + 3]; }
|
||||
const cItem & GetEquippedHelmet (void) const { return m_ArmorSlots.GetSlot(0); }
|
||||
const cItem & GetEquippedChestplate(void) const { return m_ArmorSlots.GetSlot(1); }
|
||||
const cItem & GetEquippedLeggings (void) const { return m_ArmorSlots.GetSlot(2); }
|
||||
const cItem & GetEquippedBoots (void) const { return m_ArmorSlots.GetSlot(3); }
|
||||
|
||||
/// Sends the slot contents to the owner
|
||||
void SendSlot(int a_SlotNum);
|
||||
|
||||
// tolua_end
|
||||
|
||||
void SendSlot( int a_SlotNum ); // tolua_export
|
||||
/// Converts an armor slot number into the ID for the EntityEquipment packet
|
||||
static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum);
|
||||
|
||||
/// Returns how many items of the specified type would fit into the slot range specified
|
||||
int HowManyCanFit(short a_ItemType, short a_ItemDamage, int a_BeginSlot, int a_EndSlot);
|
||||
|
||||
/// Moves items, fitting them into the slot range specified, up to a_Count items. Returns the number of items moved
|
||||
int MoveItem(short a_ItemType, short a_ItemDamage, int a_Count, int a_BeginSlot, int a_EndSlot);
|
||||
|
||||
static const unsigned int c_NumSlots = 45;
|
||||
static const unsigned int c_MainSlots = 27;
|
||||
static const unsigned int c_HotSlots = 9;
|
||||
static const unsigned int c_CraftSlots = 4;
|
||||
static const unsigned int c_ArmorSlots = 4;
|
||||
|
||||
static const unsigned int c_CraftOffset = 0;
|
||||
static const unsigned int c_ArmorOffset = 5;
|
||||
static const unsigned int c_MainOffset = 9;
|
||||
static const unsigned int c_HotOffset = 36;
|
||||
|
||||
/// Converts a slot number into the ID for the EntityEquipment packet
|
||||
static int SlotNumToEntityEquipmentID(short a_SlotNum);
|
||||
void SaveToJson(Json::Value & a_Value);
|
||||
bool LoadFromJson(Json::Value & a_Value);
|
||||
|
||||
protected:
|
||||
bool AddToBar( cItem & a_Item, const int a_Offset, const int a_Size, bool* a_bChangedSlots, int a_Mode = 0 );
|
||||
|
||||
cItem m_Slots[c_NumSlots];
|
||||
|
||||
cItem * m_MainSlots;
|
||||
cItem * m_CraftSlots;
|
||||
cItem * m_ArmorSlots;
|
||||
cItem * m_HotSlots;
|
||||
cItemGrid m_ArmorSlots;
|
||||
cItemGrid m_InventorySlots;
|
||||
cItemGrid m_HotbarSlots;
|
||||
|
||||
int m_EquippedSlotNum;
|
||||
|
||||
cPlayer & m_Owner;
|
||||
|
||||
/// Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum
|
||||
const cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum) const;
|
||||
|
||||
/// Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum
|
||||
cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum);
|
||||
|
||||
// cItemGrid::cListener override:
|
||||
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
|
||||
}; // tolua_export
|
||||
|
||||
|
||||
|
@ -75,7 +75,7 @@ bool cItem::DamageItem(short a_Amount)
|
||||
|
||||
|
||||
|
||||
bool cItem::IsStackableWith(const cItem & a_OtherStack)
|
||||
bool cItem::IsStackableWith(const cItem & a_OtherStack) const
|
||||
{
|
||||
if (a_OtherStack.m_ItemType != m_ItemType)
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
inline bool IsDamageable(void) const { return (GetMaxDamage() > 0); }
|
||||
|
||||
/// Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored!
|
||||
bool IsStackableWith(const cItem & a_OtherStack);
|
||||
bool IsStackableWith(const cItem & a_OtherStack) const;
|
||||
|
||||
// tolua_end
|
||||
void GetJson( Json::Value & a_OutValue ) const;
|
||||
|
@ -16,7 +16,8 @@ cItemGrid::cItemGrid(int a_Width, int a_Height) :
|
||||
m_Width(a_Width),
|
||||
m_Height(a_Height),
|
||||
m_NumSlots(a_Width * a_Height),
|
||||
m_Slots(new cItem[a_Width * a_Height])
|
||||
m_Slots(new cItem[a_Width * a_Height]),
|
||||
m_IsInTriggerListeners(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -149,6 +150,7 @@ void cItemGrid::SetSlot(int a_SlotNum, const cItem & a_Item)
|
||||
return;
|
||||
}
|
||||
m_Slots[a_SlotNum] = a_Item;
|
||||
TriggerListeners(a_SlotNum);
|
||||
}
|
||||
|
||||
|
||||
@ -164,11 +166,46 @@ void cItemGrid::SetSlot(int a_SlotNum, short a_ItemType, char a_ItemCount, short
|
||||
|
||||
|
||||
|
||||
void cItemGrid::EmptySlot(int a_X, int a_Y)
|
||||
{
|
||||
EmptySlot(GetSlotNum(a_X, a_Y));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cItemGrid::EmptySlot(int a_SlotNum)
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= m_NumSlots))
|
||||
{
|
||||
LOGWARNING("%s: Invalid slot number %d out of %d slots",
|
||||
__FUNCTION__, a_SlotNum, m_NumSlots
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if already empty:
|
||||
if (m_Slots[a_SlotNum].IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty and notify
|
||||
m_Slots[a_SlotNum].Empty();
|
||||
TriggerListeners(a_SlotNum);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cItemGrid::Clear(void)
|
||||
{
|
||||
for (int i = 0; i < m_NumSlots; i++)
|
||||
{
|
||||
m_Slots[i].Empty();
|
||||
TriggerListeners(i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,10 +240,33 @@ int cItemGrid::HowManyCanFit(const cItem & a_ItemStack)
|
||||
|
||||
|
||||
|
||||
bool cItemGrid::AddItem(cItem & a_ItemStack)
|
||||
int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks)
|
||||
{
|
||||
int NumLeft = a_ItemStack.m_ItemCount;
|
||||
int MaxStack = ItemHandler(a_ItemStack.m_ItemType)->GetMaxStackSize();
|
||||
|
||||
// Scan existing stacks:
|
||||
for (int i = m_NumSlots - 1; i >= 0; i--)
|
||||
{
|
||||
if (m_Slots[i].IsStackableWith(a_ItemStack))
|
||||
{
|
||||
int PrevCount = m_Slots[i].m_ItemCount;
|
||||
m_Slots[i].m_ItemCount = std::min(MaxStack, PrevCount + NumLeft);
|
||||
NumLeft -= m_Slots[i].m_ItemCount - PrevCount;
|
||||
TriggerListeners(i);
|
||||
}
|
||||
if (NumLeft <= 0)
|
||||
{
|
||||
// All items fit
|
||||
return a_ItemStack.m_ItemCount;
|
||||
}
|
||||
} // for i - m_Slots[]
|
||||
|
||||
if (!a_AllowNewStacks)
|
||||
{
|
||||
return (a_ItemStack.m_ItemCount - NumLeft);
|
||||
}
|
||||
|
||||
for (int i = m_NumSlots - 1; i >= 0; i--)
|
||||
{
|
||||
if (m_Slots[i].IsEmpty())
|
||||
@ -214,40 +274,87 @@ bool cItemGrid::AddItem(cItem & a_ItemStack)
|
||||
m_Slots[i] = a_ItemStack;
|
||||
m_Slots[i].m_ItemCount = std::min(MaxStack, NumLeft);
|
||||
NumLeft -= m_Slots[i].m_ItemCount;
|
||||
}
|
||||
else if (m_Slots[i].IsStackableWith(a_ItemStack))
|
||||
{
|
||||
int PrevCount = m_Slots[i].m_ItemCount;
|
||||
m_Slots[i].m_ItemCount = std::min(MaxStack, PrevCount + NumLeft);
|
||||
NumLeft -= m_Slots[i].m_ItemCount - PrevCount;
|
||||
TriggerListeners(i);
|
||||
}
|
||||
if (NumLeft <= 0)
|
||||
{
|
||||
// All items fit
|
||||
return true;
|
||||
return a_ItemStack.m_ItemCount;
|
||||
}
|
||||
} // for i - m_Slots[]
|
||||
return (a_ItemStack.m_ItemCount > NumLeft);
|
||||
return (a_ItemStack.m_ItemCount - NumLeft);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cItemGrid::AddItems(cItems & a_ItemStackList)
|
||||
int cItemGrid::AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks)
|
||||
{
|
||||
bool res;
|
||||
int TotalAdded = 0;
|
||||
for (cItems::iterator itr = a_ItemStackList.begin(); itr != a_ItemStackList.end();)
|
||||
{
|
||||
res = AddItem(*itr) | res;
|
||||
if (itr->IsEmpty())
|
||||
int NumAdded = AddItem(*itr, a_AllowNewStacks);
|
||||
if (itr->m_ItemCount == NumAdded)
|
||||
{
|
||||
itr = a_ItemStackList.erase(itr);
|
||||
}
|
||||
else
|
||||
{
|
||||
itr->m_ItemCount -= NumAdded;
|
||||
++itr;
|
||||
}
|
||||
TotalAdded += NumAdded;
|
||||
}
|
||||
return TotalAdded;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cItemGrid::ChangeSlotCount(int a_SlotNum, int a_AddToCount)
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= m_NumSlots))
|
||||
{
|
||||
LOGWARNING("%s: Invalid slot number %d out of %d slots, ignoring the call, returning empty item",
|
||||
__FUNCTION__, a_SlotNum, m_NumSlots
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_Slots[a_SlotNum].IsEmpty())
|
||||
{
|
||||
// The item is empty, it's not gonna change
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
m_Slots[a_SlotNum].m_ItemCount += a_AddToCount;
|
||||
TriggerListeners(a_SlotNum);
|
||||
return m_Slots[a_SlotNum].m_ItemCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cItemGrid::HowManyItems(const cItem & a_Item)
|
||||
{
|
||||
int res = 0;
|
||||
for (int i = 0; i < m_NumSlots; i++)
|
||||
{
|
||||
if (m_Slots[i].IsStackableWith(a_Item))
|
||||
{
|
||||
res += m_Slots[i].m_ItemCount;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -256,6 +363,16 @@ bool cItemGrid::AddItems(cItems & a_ItemStackList)
|
||||
|
||||
|
||||
|
||||
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);
|
||||
@ -312,6 +429,20 @@ void cItemGrid::CopyToItems(cItems & a_Items) const
|
||||
|
||||
|
||||
|
||||
bool cItemGrid::DamageItem(int a_SlotNum, short a_Amount)
|
||||
{
|
||||
if ((a_SlotNum < 0) || (a_SlotNum >= m_NumSlots))
|
||||
{
|
||||
LOGWARNING("%s: invalid slot number %d out of %d slots, ignoring.", __FUNCTION__, a_SlotNum, m_NumSlots);
|
||||
return false;
|
||||
}
|
||||
return m_Slots[a_SlotNum].DamageItem(a_Amount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, int a_CountLootProbabs, int a_NumSlots, int a_Seed)
|
||||
{
|
||||
// Calculate the total weight:
|
||||
@ -347,3 +478,47 @@ void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, i
|
||||
|
||||
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
cCSLock Lock(m_CSListeners);
|
||||
m_IsInTriggerListeners = true;
|
||||
for (cListeners::iterator itr = m_Listeners.begin(), end = m_Listeners.end(); itr != end; ++itr)
|
||||
{
|
||||
(*itr)->OnSlotChanged(this, a_SlotNum);
|
||||
} // for itr - m_Listeners[]
|
||||
m_IsInTriggerListeners = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -19,6 +19,16 @@ class cItemGrid
|
||||
{
|
||||
public:
|
||||
// tolua_end
|
||||
|
||||
/// This class is used as a callback for when a slot changes
|
||||
class cListener
|
||||
{
|
||||
public:
|
||||
/// Called whenever a slot changes
|
||||
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) = 0;
|
||||
} ;
|
||||
typedef std::vector<cListener *> cListeners;
|
||||
|
||||
cItemGrid(int a_Width, int a_Height);
|
||||
|
||||
~cItemGrid();
|
||||
@ -48,17 +58,42 @@ public:
|
||||
void SetSlot(int a_SlotNum, const cItem & a_Item);
|
||||
void SetSlot(int a_SlotNum, short a_ItemType, char a_ItemCount, short a_ItemDamage);
|
||||
|
||||
// Empty the specified slot; Logs warning and doesn't set on invalid coords / slotnum
|
||||
void EmptySlot(int a_X, int a_Y);
|
||||
void EmptySlot(int a_SlotNum);
|
||||
|
||||
/// Sets all items as empty
|
||||
void Clear(void);
|
||||
|
||||
/// Returns number of items out of a_ItemStack that can fit in the storage
|
||||
int HowManyCanFit(const cItem & a_ItemStack);
|
||||
|
||||
/// Adds as many items out of a_ItemStack as can fit; the rest is left in a_ItemStack; returns true if any items fit.
|
||||
bool AddItem(cItem & a_ItemStack);
|
||||
/** 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
|
||||
Returns the number of items that fit.
|
||||
*/
|
||||
int AddItem(cItem & a_ItemStack, bool a_AllowNewStacks);
|
||||
|
||||
/// Same as AddItem, but works on an entire list of item stacks
|
||||
bool AddItems(cItems & a_ItemStackList);
|
||||
/** Same as AddItem, but works on an entire list of item stacks.
|
||||
The a_ItemStackList is modified to reflect the leftover items.
|
||||
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
|
||||
Returns the total number of items that fit.
|
||||
*/
|
||||
int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks);
|
||||
|
||||
/** Adds (or subtracts, if a_AddToCount is negative) to the count of items in the specified slot.
|
||||
If the slot is empty, ignores the call.
|
||||
Returns the new count.
|
||||
*/
|
||||
int ChangeSlotCount(int a_SlotNum, int a_AddToCount);
|
||||
|
||||
/// Returns the number of items of type a_Item that are stored
|
||||
int HowManyItems(const cItem & a_Item);
|
||||
|
||||
/// Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack
|
||||
bool HasItems(const cItem & a_ItemStack);
|
||||
|
||||
/// Returns the index of the first empty slot; -1 if all full
|
||||
int GetFirstEmptySlot(void) const;
|
||||
@ -69,17 +104,27 @@ public:
|
||||
/// Returns the index of the first empty slot following a_StartFrom (a_StartFrom is not checked)
|
||||
int GetNextEmptySlot(int a_StartFrom) const;
|
||||
|
||||
/// Copies the contents into a cItems object
|
||||
/// Copies the contents into a cItems object; preserves the original a_Items contents
|
||||
void CopyToItems(cItems & a_Items) const;
|
||||
|
||||
/// Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact)
|
||||
bool DamageItem(int a_SlotNum, short a_Amount);
|
||||
|
||||
// tolua_end
|
||||
|
||||
|
||||
/** Generates random loot from the specified loot probability table, with a chance of enchanted books added.
|
||||
A total of a_NumSlots are taken by the loot.
|
||||
Cannot export to Lua due to raw array a_LootProbabs.
|
||||
Cannot export to Lua due to raw array a_LootProbabs. TODO: Make this exportable / export through ManualBindings.cpp with a Lua table as LootProbabs
|
||||
*/
|
||||
void GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, int a_CountLootProbabs, int a_NumSlots, int a_Seed);
|
||||
|
||||
/// Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback!
|
||||
void AddListener(cListener & a_Listener);
|
||||
|
||||
/// Removes a slot-change-callback. Must not be called from within the listener callback!
|
||||
void RemoveListener(cListener & a_Listener);
|
||||
|
||||
// tolua_begin
|
||||
|
||||
protected:
|
||||
@ -87,6 +132,13 @@ protected:
|
||||
int m_Height;
|
||||
int m_NumSlots; // m_Width * m_Height, for easier validity checking in the access functions
|
||||
cItem * m_Slots; // x + m_Width * y
|
||||
|
||||
cListeners m_Listeners; ///< Listeners which should be notified on slot changes; the pointers are not owned by this object
|
||||
cCriticalSection m_CSListeners; ///< CS that guards the m_Listeners against multi-thread access
|
||||
bool m_IsInTriggerListeners; ///< Set to true while TriggerListeners is running, to detect attempts to manipulate listener list while triggerring
|
||||
|
||||
/// Calls all m_Listeners for the specified slot number
|
||||
void TriggerListeners(int a_SlotNum);
|
||||
} ;
|
||||
// tolua_end
|
||||
|
||||
|
@ -81,8 +81,7 @@ public:
|
||||
}
|
||||
|
||||
// Remove the bucket from the inventory
|
||||
cItem Item(a_Item.m_ItemType, 1);
|
||||
if (!a_Player->GetInventory().RemoveItem(Item))
|
||||
if (!a_Player->GetInventory().RemoveOneEquippedItem())
|
||||
{
|
||||
LOG("Clicked with an empty bucket, but cannot remove one from the inventory? WTF?");
|
||||
ASSERT(!"Inventory bucket mismatch");
|
||||
@ -90,8 +89,7 @@ public:
|
||||
}
|
||||
|
||||
// Give new bucket, filled with fluid:
|
||||
Item.m_ItemType = NewItem;
|
||||
Item.m_ItemCount = 1;
|
||||
cItem Item(NewItem, 1);
|
||||
a_Player->GetInventory().AddItem(Item);
|
||||
|
||||
// Remove water / lava block
|
||||
@ -131,15 +129,13 @@ public:
|
||||
if (a_Player->GetGameMode() != gmCreative)
|
||||
{
|
||||
// Remove fluid bucket, add empty bucket:
|
||||
cItem Item(a_Item.m_ItemType, 1);
|
||||
if (!a_Player->GetInventory().RemoveItem(Item))
|
||||
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;
|
||||
}
|
||||
Item.m_ItemType = E_ITEM_BUCKET;
|
||||
Item.m_ItemCount = 1;
|
||||
cItem Item(E_ITEM_BUCKET, 1);
|
||||
if (!a_Player->GetInventory().AddItem(Item))
|
||||
{
|
||||
return false;
|
||||
|
@ -22,15 +22,15 @@ public:
|
||||
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
|
||||
{
|
||||
// TODO: Handle coloring the sheep, too (OnItemUseOnEntity maybe)
|
||||
|
||||
// Handle growing the plants:
|
||||
if (a_Item.m_ItemDamage == E_META_DYE_WHITE)
|
||||
{
|
||||
if (a_World->GrowRipePlant(a_BlockX, a_BlockY, a_BlockZ, true))
|
||||
{
|
||||
if (a_Player->GetGameMode() != eGameMode_Creative)
|
||||
if (a_Player->GetGameMode() != gmCreative)
|
||||
{
|
||||
cItem Item(a_Item.m_ItemType, 1, a_Item.m_ItemDamage);
|
||||
a_Player->GetInventory().RemoveItem(Item);
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
cItem Item(a_Item.m_ItemType, 1);
|
||||
if (a_Player->GetInventory().RemoveItem(Item))
|
||||
if (a_Player->GetInventory().RemoveOneEquippedItem())
|
||||
{
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, Block - 1, Meta); // Block - 1 simple hack to save one if statement
|
||||
return true;
|
||||
|
@ -38,8 +38,7 @@ public:
|
||||
if (a_Player->GetGameMode() != 1)
|
||||
{
|
||||
// The mob was spawned, "use" the item:
|
||||
cItem Equipped(a_Player->GetEquippedItem());
|
||||
a_Player->GetInventory().RemoveItem(Equipped);
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -40,8 +40,7 @@ void cJukeboxEntity::UsedBy(cPlayer * a_Player)
|
||||
if (HeldItem.m_ItemType >= 2256 && HeldItem.m_ItemType <= 2267)
|
||||
{
|
||||
m_Record = HeldItem.m_ItemType;
|
||||
cItem Equipped(a_Player->GetInventory().GetEquippedItem());
|
||||
a_Player->GetInventory().RemoveItem(Equipped);
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
PlayRecord();
|
||||
}
|
||||
}
|
||||
|
@ -149,17 +149,17 @@ bool cPickup::CollectedBy(cPlayer * a_Dest)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a_Dest->GetInventory().AddItemAnyAmount(m_Item))
|
||||
int NumAdded = a_Dest->GetInventory().AddItem(m_Item);
|
||||
if (NumAdded > 0)
|
||||
{
|
||||
m_Item.m_ItemCount -= NumAdded;
|
||||
m_World->BroadcastCollectPickup(*this, *a_Dest);
|
||||
m_bCollected = true;
|
||||
m_Timer = 0;
|
||||
if (m_Item.m_ItemCount != 0)
|
||||
if (m_Item.m_ItemCount == 0)
|
||||
{
|
||||
cItems Pickup;
|
||||
Pickup.push_back(cItem(m_Item));
|
||||
m_World->SpawnItemPickups(Pickup, GetPosX(), GetPosY(), GetPosZ());
|
||||
// All of the pickup has been collected, schedule the pickup for destroying
|
||||
m_bCollected = true;
|
||||
}
|
||||
m_Timer = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -360,15 +360,8 @@ void cPlayer::KilledBy(cPawn * a_Killer)
|
||||
m_bVisible = false; // So new clients don't see the player
|
||||
|
||||
// Puke out all the items
|
||||
const cItem * Items = m_Inventory.GetSlots();
|
||||
cItems Pickups;
|
||||
for (unsigned int i = 1; i < m_Inventory.c_NumSlots; ++i)
|
||||
{
|
||||
if (!Items[i].IsEmpty())
|
||||
{
|
||||
Pickups.push_back(Items[i]);
|
||||
}
|
||||
}
|
||||
m_Inventory.CopyToItems(Pickups);
|
||||
m_Inventory.Clear();
|
||||
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
|
||||
SaveToDisk(); // Save it, yeah the world is a tough place !
|
||||
@ -378,7 +371,7 @@ void cPlayer::KilledBy(cPawn * a_Killer)
|
||||
|
||||
|
||||
|
||||
void cPlayer::Respawn()
|
||||
void cPlayer::Respawn(void)
|
||||
{
|
||||
m_Health = GetMaxHealth();
|
||||
|
||||
@ -768,7 +761,7 @@ void cPlayer::TossItem(
|
||||
)
|
||||
{
|
||||
cItems Drops;
|
||||
if (a_CreateType)
|
||||
if (a_CreateType != 0)
|
||||
{
|
||||
// Just create item without touching the inventory (used in creative mode)
|
||||
Drops.push_back(cItem(a_CreateType, a_Amount, a_CreateHealth));
|
||||
@ -800,8 +793,7 @@ void cPlayer::TossItem(
|
||||
cItem DroppedItem(GetInventory().GetEquippedItem());
|
||||
if (!DroppedItem.IsEmpty())
|
||||
{
|
||||
DroppedItem.m_ItemCount = 1;
|
||||
if (GetInventory().RemoveItem(DroppedItem))
|
||||
if (GetInventory().RemoveOneEquippedItem())
|
||||
{
|
||||
DroppedItem.m_ItemCount = 1; // RemoveItem decreases the count, so set it to 1 again
|
||||
Drops.push_back(DroppedItem);
|
||||
|
@ -81,10 +81,12 @@ public:
|
||||
void LoginSetGameMode( eGameMode a_GameMode );
|
||||
void SetIP(const AString & a_IP);
|
||||
|
||||
// Tries to move to a new position, with collision checks and stuff
|
||||
/// Tries to move to a new position, with collision checks and stuff
|
||||
virtual void MoveTo( const Vector3d & a_NewPos ); // tolua_export
|
||||
|
||||
cWindow* GetWindow() { return m_CurrentWindow; }
|
||||
cWindow * GetWindow(void) { return m_CurrentWindow; }
|
||||
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
|
||||
|
||||
void OpenWindow( cWindow* a_Window );
|
||||
void CloseWindow(char a_WindowType);
|
||||
|
||||
|
@ -874,8 +874,7 @@ void cProtocol125::SendWeather(eWeather a_Weather)
|
||||
|
||||
void cProtocol125::SendWholeInventory(const cInventory & a_Inventory)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
SendWindowSlots(0, a_Inventory.c_NumSlots, a_Inventory.GetSlots());
|
||||
SendWholeInventory(*(a_Inventory.GetOwner().GetWindow()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -438,14 +438,24 @@ void cProtocol132::SendWholeInventory(const cWindow & a_Window)
|
||||
{
|
||||
// 1.3.2 requires player inventory slots to be sent as SetSlot packets,
|
||||
// otherwise it sometimes fails to update the window
|
||||
|
||||
// Send the entire window:
|
||||
super::SendWholeInventory(a_Window);
|
||||
const cItem * Slots = m_Client->GetPlayer()->GetInventory().GetSlots();
|
||||
int BaseOffset = a_Window.GetNumSlots() - cInventory::c_NumSlots + cInventory::c_MainOffset; // the number of non-inventory slots the window has; inventory follows
|
||||
|
||||
// Send the player inventory and hotbar:
|
||||
const cInventory & Inventory = m_Client->GetPlayer()->GetInventory();
|
||||
int BaseOffset = a_Window.GetNumSlots() - (cInventory::invNumSlots - cInventory::invInventoryOffset); // Number of non-inventory slots
|
||||
char WindowID = a_Window.GetWindowID();
|
||||
for (int i = 0; i < cInventory::c_NumSlots - cInventory::c_MainOffset; i++)
|
||||
for (int i = 0; i < cInventory::invInventoryCount; i++)
|
||||
{
|
||||
SendInventorySlot(WindowID, BaseOffset + i, Slots[i + cInventory::c_MainOffset]);
|
||||
} // for i - Slots[]
|
||||
SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetInventorySlot(i));
|
||||
} // for i - Inventory[]
|
||||
BaseOffset += cInventory::invInventoryCount;
|
||||
for (int i = 0; i < cInventory::invHotbarCount; i++)
|
||||
{
|
||||
SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetHotbarSlot(i));
|
||||
} // for i - Hotbar[]
|
||||
|
||||
// Send even the item being dragged:
|
||||
SendInventorySlot(-1, -1, m_Client->GetPlayer()->GetDraggingItem());
|
||||
}
|
||||
|
@ -613,7 +613,7 @@ void cSlotAreaInventoryBase::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAc
|
||||
|
||||
const cItem * cSlotAreaInventoryBase::GetSlot(int a_SlotNum, cPlayer & a_Player)
|
||||
{
|
||||
// a_SlotNum ranges from 0 to 35, map that to the player's inventory slots 9 to 44
|
||||
// a_SlotNum ranges from 0 to 35, map that to the player's inventory slots according to the internal offset
|
||||
return &a_Player.GetInventory().GetSlot(a_SlotNum + m_SlotOffset);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Item.h"
|
||||
#include "../Inventory.h"
|
||||
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ class cSlotAreaInventory :
|
||||
|
||||
public:
|
||||
cSlotAreaInventory(cWindow & a_ParentWindow) :
|
||||
cSlotAreaInventoryBase(27, 9, a_ParentWindow) // 27 slots, starting at inventory index 9
|
||||
cSlotAreaInventoryBase(cInventory::invInventoryCount, cInventory::invInventoryOffset, a_ParentWindow)
|
||||
{
|
||||
}
|
||||
} ;
|
||||
@ -114,7 +114,7 @@ class cSlotAreaHotBar :
|
||||
|
||||
public:
|
||||
cSlotAreaHotBar(cWindow & a_ParentWindow) :
|
||||
cSlotAreaInventoryBase(9, 36, a_ParentWindow)
|
||||
cSlotAreaInventoryBase(cInventory::invHotbarCount, cInventory::invHotbarOffset, a_ParentWindow)
|
||||
{
|
||||
}
|
||||
} ;
|
||||
@ -129,7 +129,7 @@ class cSlotAreaArmor :
|
||||
{
|
||||
public:
|
||||
cSlotAreaArmor(cWindow & a_ParentWindow) :
|
||||
cSlotAreaInventoryBase(4, 5, a_ParentWindow)
|
||||
cSlotAreaInventoryBase(cInventory::invArmorCount, cInventory::invArmorOffset, a_ParentWindow)
|
||||
{
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user