int cItemGrid::HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks) { char NumLeft = a_ItemStack.m_ItemCount; int MaxStack = ItemHandler(a_ItemStack.m_ItemType)->GetMaxStackSize(); for (int i = m_NumSlots - 1; i >= 0; i--) { if (m_Slots[i].IsEmpty()) { if (a_AllowNewStacks) { NumLeft -= MaxStack; } } else if (m_Slots[i].IsStackableWith(a_ItemStack)) { NumLeft -= MaxStack - m_Slots[i].m_ItemCount; } if (NumLeft <= 0) { // All items fit return a_ItemStack.m_ItemCount; } } // for i - m_Slots[] return a_ItemStack.m_ItemCount - NumLeft; }
void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) { for (int i = 0; i < 2; i++) { const cItem * Slot = GetSlot(i, a_Player); if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) { // Different items continue; } int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; if (NumFit <= 0) { // Full stack already continue; } if (NumFit > a_ItemStack.m_ItemCount) { NumFit = a_ItemStack.m_ItemCount; } if (a_ShouldApply) { cItem NewSlot(a_ItemStack); NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; SetSlot(i, a_Player, NewSlot); } a_ItemStack.m_ItemCount -= NumFit; if (a_ItemStack.IsEmpty()) { UpdateResult(a_Player); return; } } // for i - Slots UpdateResult(a_Player); }
World::World() : attackHandler_(AttackHandler(this)), movementHandler_(MovementHandler(this)), itemHandler_(ItemHandler(this)) { attackHandler_.watchNotifier(&combatNotifier_); movementHandler_.watchNotifier(&movementNotifier_); itemHandler_.watchNotifier(&itemNotifier_); }
void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player) { const cItem * ResultSlot = GetSlot(0, a_Player); cItem & DraggingItem = a_Player.GetDraggingItem(); // Get the current recipe: cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1; cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize); // If possible, craft: if (DraggingItem.IsEmpty()) { DraggingItem = Recipe.GetResult(); Recipe.ConsumeIngredients(Grid); Grid.CopyToItems(PlayerSlots); } else if (DraggingItem.IsEqual(Recipe.GetResult())) { cItemHandler * Handler = ItemHandler(Recipe.GetResult().m_ItemType); if (DraggingItem.m_ItemCount + Recipe.GetResult().m_ItemCount <= Handler->GetMaxStackSize()) { DraggingItem.m_ItemCount += Recipe.GetResult().m_ItemCount; Recipe.ConsumeIngredients(Grid); Grid.CopyToItems(PlayerSlots); } } // Get the new recipe and update the result slot: UpdateRecipe(a_Player); // We're done. Send all changes to the client and bail out: m_ParentWindow.BroadcastWholeWindow(); }
void cInventory::UpdateItems(void) { const cItem & Slot = GetEquippedItem(); if (!Slot.IsEmpty()) { ItemHandler(Slot.m_ItemType)->OnUpdate(m_Owner.GetWorld(), &m_Owner, Slot); } }
int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_PrioritarySlot) { int NumLeft = a_ItemStack.m_ItemCount; int MaxStack = ItemHandler(a_ItemStack.m_ItemType)->GetMaxStackSize(); // Try prioritarySlot first: if ( (a_PrioritarySlot != -1) && ( m_Slots[a_PrioritarySlot].IsEmpty() || m_Slots[a_PrioritarySlot].IsStackableWith(a_ItemStack) ) ) { NumLeft -= AddItemToSlot(a_ItemStack, a_PrioritarySlot, NumLeft, MaxStack); } // Scan existing stacks: for (int i = m_NumSlots - 1; i >= 0; i--) { if (m_Slots[i].IsStackableWith(a_ItemStack)) { NumLeft -= AddItemToSlot(a_ItemStack, i, NumLeft, MaxStack); } 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()) { 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); }
int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int a_NumToEachSlot, const cSlotNums & a_SlotNums) { if ((size_t)(a_Item.m_ItemCount) < a_SlotNums.size()) { LOGWARNING("%s: Distributing less items (%d) than slots (%u)", __FUNCTION__, (int)a_Item.m_ItemCount, a_SlotNums.size()); // This doesn't seem to happen with the 1.5.1 client, so we don't worry about it for now return 0; } // Distribute to individual slots, keep track of how many items were actually distributed (full stacks etc.) int NumDistributed = 0; for (cSlotNums::const_iterator itr = a_SlotNums.begin(), end = a_SlotNums.end(); itr != end; ++itr) { int LocalSlotNum = 0; cSlotArea * Area = GetSlotArea(*itr, LocalSlotNum); if (Area == NULL) { LOGWARNING("%s: Bad SlotArea for slot %d", __FUNCTION__, *itr); continue; } // Modify the item at the slot cItem AtSlot(*Area->GetSlot(LocalSlotNum, a_Player)); int MaxStack = ItemHandler(AtSlot.m_ItemType)->GetMaxStackSize(); if (AtSlot.IsEmpty()) { // Empty, just move all of it there: cItem ToStore(a_Item); ToStore.m_ItemCount = std::min(a_NumToEachSlot, (int)MaxStack); Area->SetSlot(LocalSlotNum, a_Player, ToStore); NumDistributed += ToStore.m_ItemCount; } else { // Occupied, add and cap at MaxStack: int CanStore = std::min(a_NumToEachSlot, (int)MaxStack - AtSlot.m_ItemCount); AtSlot.m_ItemCount += CanStore; Area->SetSlot(LocalSlotNum, a_Player, AtSlot); NumDistributed += CanStore; } } // for itr - SlotNums[] return NumDistributed; }
void cWindow::OnMiddlePaintEnd(cPlayer & a_Player) { if (!a_Player.IsGameModeCreative()) { // Midle click paint is only valid for creative mode return; } // Fill available slots with full stacks of the dragging item const auto & DraggingItem = a_Player.GetDraggingItem(); auto StackSize = ItemHandler(DraggingItem.m_ItemType)->GetMaxStackSize(); if (0 < DistributeItemToSlots(a_Player, DraggingItem, StackSize, a_Player.GetInventoryPaintSlots(), false)) { // If any items were distibuted, set dragging item empty a_Player.GetDraggingItem().Empty(); } SendWholeWindow(*a_Player.GetClientHandle()); }
void cInventory::UpdateItems(void) { const cItem & Slot = GetEquippedItem(); if (Slot.IsEmpty()) { return; } switch (Slot.m_ItemType) { case E_ITEM_MAP: { ItemHandler(Slot.m_ItemType)->OnUpdate(m_Owner.GetWorld(), &m_Owner, Slot); break; } default: break; } }
int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots) { UNUSED(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.IsEqual(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; }
void cWolf::OnRightClicked(cPlayer & a_Player) { const cItem & EquippedItem = a_Player.GetEquippedItem(); const int EquippedItemType = EquippedItem.m_ItemType; if (!IsTame() && !IsAngry()) { // If the player is holding a bone, try to tame the wolf: if (EquippedItemType == E_ITEM_BONE) { if (!a_Player.IsGameModeCreative()) { a_Player.GetInventory().RemoveOneEquippedItem(); } if (GetRandomProvider().RandBool(0.125)) { // Taming succeeded SetMaxHealth(20); SetIsTame(true); SetOwner(a_Player.GetName(), a_Player.GetUUID()); m_World->BroadcastEntityStatus(*this, esWolfTamed); m_World->BroadcastParticleEffect("heart", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5); } else { // Taming failed m_World->BroadcastEntityStatus(*this, esWolfTaming); m_World->BroadcastParticleEffect("smoke", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5); } } } else if (IsTame()) { // Feed the wolf, restoring its health, or dye its collar: switch (EquippedItemType) { case E_ITEM_RAW_BEEF: case E_ITEM_STEAK: case E_ITEM_RAW_PORKCHOP: case E_ITEM_COOKED_PORKCHOP: case E_ITEM_RAW_CHICKEN: case E_ITEM_COOKED_CHICKEN: case E_ITEM_ROTTEN_FLESH: { if (m_Health < m_MaxHealth) { Heal(ItemHandler(EquippedItemType)->GetFoodInfo(&EquippedItem).FoodLevel); if (!a_Player.IsGameModeCreative()) { a_Player.GetInventory().RemoveOneEquippedItem(); } } break; } case E_ITEM_DYE: { if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog? { SetCollarColor(EquippedItem.m_ItemDamage); if (!a_Player.IsGameModeCreative()) { a_Player.GetInventory().RemoveOneEquippedItem(); } } break; } default: { if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog? { SetIsSitting(!IsSitting()); } } } } m_World->BroadcastEntityMetadata(*this); }
bool cItem::IsFullStack(void) const { return (m_ItemCount >= ItemHandler(m_ItemType)->GetMaxStackSize()); }
/// Returns the cItemHandler responsible for this item type cItemHandler * cItem::GetHandler(void) const { return ItemHandler(m_ItemType); }
char cItem::GetMaxStackSize(void) const { return ItemHandler(m_ItemType)->GetMaxStackSize(); }
void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) { /* LOGD("Slot area with %d slots clicked at slot number %d, clicked item %s, slot item %s", GetNumSlots(), a_SlotNum, ItemToFullString(a_ClickedItem).c_str(), ItemToFullString(*GetSlot(a_SlotNum, a_Player)).c_str() ); */ ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); bool bAsync = false; if (GetSlot(a_SlotNum, a_Player) == NULL) { LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); return; } switch (a_ClickAction) { case caShiftLeftClick: case caShiftRightClick: { ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); return; } case caDblClick: { DblClicked(a_Player, a_SlotNum); return; } default: { break; } } cItem Slot(*GetSlot(a_SlotNum, a_Player)); if (!Slot.IsSameType(a_ClickedItem)) { LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); bAsync = true; } cItem & DraggingItem = a_Player.GetDraggingItem(); switch (a_ClickAction) { case caRightClick: { if (DraggingItem.m_ItemType <= 0) // Empty-handed? { DraggingItem = Slot.CopyOne(); // Obtain copy of slot to preserve lore, enchantments, etc. DraggingItem.m_ItemCount = (char)(((float)Slot.m_ItemCount) / 2.f + 0.5f); Slot.m_ItemCount -= DraggingItem.m_ItemCount; if (Slot.m_ItemCount <= 0) { Slot.Empty(); } } else if ((Slot.m_ItemType <= 0) || DraggingItem.IsEqual(Slot)) { // Drop one item in slot cItemHandler * Handler = ItemHandler(Slot.m_ItemType); if ((DraggingItem.m_ItemCount > 0) && (Slot.m_ItemCount < Handler->GetMaxStackSize())) { char OldSlotCount = Slot.m_ItemCount; Slot = DraggingItem.CopyOne(); // See above OldSlotCount++; Slot.m_ItemCount = OldSlotCount; DraggingItem.m_ItemCount--; } if (DraggingItem.m_ItemCount <= 0) { DraggingItem.Empty(); } } else if (!DraggingItem.IsEqual(Slot)) { // Swap contents cItem tmp(DraggingItem); DraggingItem = Slot; Slot = tmp; } break; } case caLeftClick: { // Left-clicked if (!DraggingItem.IsEqual(Slot)) { // Switch contents cItem tmp(DraggingItem); DraggingItem = Slot; Slot = tmp; } else { // Same type, add items: cItemHandler * Handler = ItemHandler(DraggingItem.m_ItemType); int FreeSlots = Handler->GetMaxStackSize() - Slot.m_ItemCount; if (FreeSlots < 0) { ASSERT(!"Bad item stack size - where did we get more items in a slot than allowed?"); FreeSlots = 0; } int Filling = (FreeSlots > DraggingItem.m_ItemCount) ? DraggingItem.m_ItemCount : FreeSlots; Slot.m_ItemCount += (char)Filling; DraggingItem.m_ItemCount -= (char)Filling; if (DraggingItem.m_ItemCount <= 0) { DraggingItem.Empty(); } } break; } default: { LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction)); m_ParentWindow.BroadcastWholeWindow(); return; } } // switch (a_ClickAction SetSlot(a_SlotNum, a_Player, Slot); if (bAsync) { m_ParentWindow.BroadcastWholeWindow(); } }