// **************************************************************************** CInventoryBase::TInventoryOpResult CRefInventory::doInsertItem(CGameItemPtr &item, uint32 slot, bool autoStack, bool ignoreWeightAndBulk) { nlassert(item != NULL); nlassert(item->getRefInventory() == NULL); nlassert(slot < _Items.size() || slot == INVENTORIES::INVALID_INVENTORY_SLOT); if (!ignoreWeightAndBulk) { if (item->getStackWeight() + getInventoryWeight() > getMaxWeight()) return ior_overweight; if (item->getStackBulk() + getInventoryBulk() > getMaxBulk()) return ior_overbulk; } // check that we still have a free slot if (getFreeSlotCount() == 0) return ior_no_free_slot; if (slot == INVENTORIES::INSERT_IN_FIRST_FREE_SLOT) slot = getFirstFreeSlot(); // remove any item referenced here removeItem(slot); // insert and link the new item _Items[slot] = item; item->setRefInventory(CInventoryPtr(this), slot); updateWeightAndBulk(item, item->getStackSize()); --_FreeSlotCount; // callbacks for derived class onItemChanged(slot, INVENTORIES::itc_inserted); // callback views /*TViewCont::iterator first(_InventoryViews.begin()), last(_InventoryViews.end()); for (; first != last; ++first) { CInventoryViewPtr view = *first; view->onItemChanged(slot, itc_inserted); }*/ return ior_ok; }
// **************************************************************************** CInventoryBase::TInventoryOpResult CInventoryBase::doInsertItem(CGameItemPtr &item, uint32 slot, bool autoStack, bool ignoreWeightAndBulk) { H_AUTO(doInsertItem); nlassert(item != NULL); nlassert(item->getInventory() == NULL); nlassert(slot < _Items.size() || slot == INVENTORIES::INSERT_IN_FIRST_FREE_SLOT); if (!ignoreWeightAndBulk) { if (item->getStackWeight() + getInventoryWeight() > getMaxWeight()) return ior_overweight; if (item->getStackBulk() + getInventoryBulk() > getMaxBulk()) return ior_overbulk; } if (autoStack) { H_AUTO(AutoStack); // If slot provided check we can stack if we can't find an empty slot if (slot != INVENTORIES::INSERT_IN_FIRST_FREE_SLOT) if (canStackItem(item, slot) != ior_ok) slot = INVENTORIES::INSERT_IN_FIRST_FREE_SLOT; uint32 slotBegin = slot; uint32 slotSearch; uint32 itemStackSize = item->getStackSize(); // get first compatible stack if (slot == INVENTORIES::INSERT_IN_FIRST_FREE_SLOT) slotBegin = 0; slotSearch = slotBegin; // Modification to do : (slot to put item, stack size to put) vector< pair<uint32,uint32> > Modifs; // If slot provided is NULL directly insert item in it if (_Items[slotBegin] == NULL) { Modifs.push_back(make_pair(slotBegin, itemStackSize)); } else { // do the following until all items in the stack are transfered to stacks (and empty slot) while (1) { // Search for a compatible stack (not null slot, not full slot) bool bFound = false; do { if ( (_Items[slotSearch] != NULL) && (_Items[slotSearch]->getStackSize() < _Items[slotSearch]->getMaxStackSize()) && (CGameItem::areStackable(item, _Items[slotSearch]))) // no check on stack size here { bFound = true; break; } slotSearch++; if (slotSearch == getSlotCount()) slotSearch = 0; } while (slotSearch != slotBegin); if (bFound) { // We found a slot with an existing stack that is compatible // Try to put as much as we can into this stack if (itemStackSize > _Items[slotSearch]->getMaxStackSize() - _Items[slotSearch]->getStackSize()) { uint32 sizePut = _Items[slotSearch]->getMaxStackSize() - _Items[slotSearch]->getStackSize(); itemStackSize -= sizePut; Modifs.push_back(make_pair(slotSearch, sizePut)); slotSearch++; if (slotSearch == getSlotCount()) slotSearch = 0; if (slotSearch != slotBegin) continue; // if we have not finished the loop try the next slot } else { Modifs.push_back(make_pair(slotSearch, itemStackSize)); break; // finished } } // Can't insert item in an already existing stack if (getFreeSlotCount() == 0) return ior_no_free_slot; // No more empty slot in this inventory !!! slotSearch = getFirstFreeSlot(); Modifs.push_back(make_pair(slotSearch, itemStackSize)); break; // finished } } // Apply all modifs to the inventory bool bInserted = false; for (uint32 i = 0; i < Modifs.size(); ++i) { uint32 slotModif = Modifs[i].first; uint32 sizeModif = Modifs[i].second; if (_Items[slotModif] == NULL) { // set stack size before we add the item to the inventory to avoid the callback onItemStackSizeChanged() // which update weight and bulk item->setStackSize(sizeModif); // update weight and bulk "manually" updateWeightAndBulk(item, sizeModif); // put the item in the inventory _Items[slotModif] = item; item->setInventory(CInventoryPtr(this), slotModif); --_FreeSlotCount; onItemChanged(slotModif, INVENTORIES::itc_inserted); bInserted = true; } else { // callbacks are called in setStackSize (inventory onItemStackSizeChanged) _Items[slotModif]->setStackSize(_Items[slotModif]->getStackSize()+sizeModif); } } INVENTORIES::TInventoryChangeFlags flagInvChg(INVENTORIES::ic_total_bulk); flagInvChg.setEnumValue(INVENTORIES::ic_total_weight); flagInvChg.setEnumValue(INVENTORIES::ic_item_list); onInventoryChanged(flagInvChg); // If the item is not inserted into the inventory it has no more reason to exist because // it was fully splitted into all the stacks of the inventory if (!bInserted) { item.deleteItem(); item = NULL; } } else { H_AUTO(NoneStackableItem); // check that we still have a free slot if (getFreeSlotCount() == 0) return ior_no_free_slot; if (slot == INVENTORIES::INSERT_IN_FIRST_FREE_SLOT) slot = getFirstFreeSlot(); // delete any item on this slot if (_Items[slot] != NULL) { deleteItem(slot); } _Items[slot] = item; item->setInventory(CInventoryPtr(this), slot); updateWeightAndBulk(item, item->getStackSize()); --_FreeSlotCount; // callback all the views : 2 messages : // * item inserted // * inventory change bulk, weight and list INVENTORIES::TInventoryChangeFlags flagInvChg(INVENTORIES::ic_total_bulk); flagInvChg.setEnumValue(INVENTORIES::ic_total_weight); flagInvChg.setEnumValue(INVENTORIES::ic_item_list); INVENTORIES::TItemChangeFlags flagItemChg(INVENTORIES::itc_inserted); TViewCont::iterator first(_InventoryViews.begin()), last(_InventoryViews.end()); for (; first!= last; ++first) { CInventoryViewPtr view = *first; view->onInventoryChanged(flagInvChg); view->onItemChanged(slot, flagItemChg); } } return ior_ok; }