// **************************************************************************** uint32 CInventoryBase::deleteStackItem(uint32 slot, uint32 quantity, TInventoryOpResult * res) { nlassert(slot < _Items.size()); uint32 nbDeletedItem = 0; CGameItemPtr item = getItem(slot); if(item->getStackSize() > quantity) { nbDeletedItem = quantity; item->setStackSize( item->getStackSize() - quantity ); // log_Item_UpdateQuantity(item->getItemId(), item->getStackSize(), item->getStackSize() - quantity); if( res != NULL ) *res = ior_ok; } else { nbDeletedItem = item->getStackSize(); deleteItem(slot); if( res != NULL ) { if( quantity == nbDeletedItem ) *res = ior_ok; else *res = ior_stack_undersize; } } return nbDeletedItem; }
//----------------------------------------------- // createInGameItem //----------------------------------------------- CGameItemPtr CGameItemManager::createInGameItem( uint16 quality, uint32 quantity, const NLMISC::CSheetId &sheet, const CEntityId &creatorId , const std::string * phraseId) { H_AUTO(GIM_createInGameItem); static const CSheetId preorderSheetId("pre_order.sitem"); if ( quantity == 0 || quality ==0 ) return NULL; // static const CSheetId idSheetStack("stack.sitem"); const CStaticItem* form = CSheets::getForm( sheet ); if (!form) { nlwarning("<CCharacter::createInGameItem> Cannot find form of item %s", sheet.toString().c_str()); return NULL; } CGameItemPtr item; CGameItemPtr sellingItem; // if item can be sold, get it in the sold items list if ( form->Family != ITEMFAMILY::RAW_MATERIAL && form->Family != ITEMFAMILY::HARVEST_TOOL && form->Family != ITEMFAMILY::CRAFTING_TOOL && form->Family != ITEMFAMILY::CRYSTALLIZED_SPELL && form->Family != ITEMFAMILY::ITEM_SAP_RECHARGE && form->Family != ITEMFAMILY::FOOD ) { vector< CGameItemPtr >::const_iterator it; const vector< CGameItemPtr >::const_iterator itEnd = CStaticItems::getStaticItems().end(); for( it = CStaticItems::getStaticItems().begin(); it != itEnd; ++it ) { if( (*it)->getSheetId() == sheet ) { sellingItem = *it; break; } } } switch( form->Family ) { case ITEMFAMILY::CRAFTING_TOOL: case ITEMFAMILY::HARVEST_TOOL: case ITEMFAMILY::RAW_MATERIAL: case ITEMFAMILY::TELEPORT: case ITEMFAMILY::CRYSTALLIZED_SPELL: case ITEMFAMILY::ITEM_SAP_RECHARGE: case ITEMFAMILY::MISSION_ITEM: case ITEMFAMILY::PET_ANIMAL_TICKET: case ITEMFAMILY::HANDLED_ITEM: case ITEMFAMILY::CONSUMABLE: case ITEMFAMILY::XP_CATALYSER: case ITEMFAMILY::SCROLL: case ITEMFAMILY::FOOD: case ITEMFAMILY::SCROLL_R2: case ITEMFAMILY::GENERIC_ITEM: { item = GameItemManager.createItem( const_cast< CSheetId& > ( sheet ), quality, true, true, creatorId); } break; default: { if( sellingItem != NULL ) { item = sellingItem->getItemCopy(); item->quality( quality ); if ( phraseId ) item->setPhraseId(*phraseId); } else if (sheet == preorderSheetId) { item = GameItemManager.createItem(sheet, quality, true, form->DropOrSell, creatorId); } } if( item == NULL) { nlwarning("<CCharacter::createInGameItem> Error while creating item : NULL pointer"); return NULL; } } quantity = min(quantity, item->getMaxStackSize()); item->setStackSize(quantity); return item; } // createInGameItem //
/// Remove the nth item from this inventory // **************************************************************************** CGameItemPtr CInventoryBase::removeItem(uint32 slot, uint32 quantity, TInventoryOpResult * res) { nlassert(slot < _Items.size()); CGameItemPtr ret = _Items[slot]; if (quantity == 0) { if (res != NULL) *res = ior_ok; return NULL; } if (_Items[slot] != NULL) { if (quantity > _Items[slot]->getStackSize()) quantity = _Items[slot]->getStackSize(); // if we try to remove more items than available do not remove anything if (quantity > _Items[slot]->getNonLockedStackSize()) { if (res != NULL) *res = ior_item_locked; return NULL; } INVENTORIES::TInventoryChangeFlags flagInvChg(INVENTORIES::ic_total_bulk); flagInvChg.setEnumValue(INVENTORIES::ic_total_weight); flagInvChg.setEnumValue(INVENTORIES::ic_item_list); // If we want to remove the whole stack if (quantity == _Items[slot]->getStackSize()) { // callback all the views : 2 messages : // * item removed // * inventory change bulk, weight and list INVENTORIES::TItemChangeFlags flagItemChg(INVENTORIES::itc_removed); TViewCont::iterator first(_InventoryViews.begin()), last(_InventoryViews.end()); for (; first != last; ++first) { CInventoryViewPtr view = *first; view->onInventoryChanged(flagInvChg); view->onItemChanged(slot, flagItemChg); } // unlink from ref inventory if (_Items[slot]->getRefInventory() != NULL) { _Items[slot]->getRefInventory()->removeItem(_Items[slot]->getRefInventorySlot()); } // unlink the item _Items[slot]->setInventory(CInventoryPtr(NULL), INVENTORIES::INVALID_INVENTORY_SLOT); _Items[slot] = NULL; ++_FreeSlotCount; updateWeightAndBulk(ret, -sint32(ret->getStackSize())); } else // we want to remove a part of a stack { // create a new item ret = _Items[slot]->getItemCopy(); ret->setStackSize(quantity); _Items[slot]->setStackSize(_Items[slot]->getStackSize()-quantity); // Done at the end because the item is not completly removed // callback all the views : 1 message : // * inventory change bulk, weight and list TViewCont::iterator first(_InventoryViews.begin()), last(_InventoryViews.end()); for (; first != last; ++first) { CInventoryViewPtr view = *first; view->onInventoryChanged(flagInvChg); } // update ref inventory if some if (_Items[slot]->getRefInventory() != NULL) { _Items[slot]->getRefInventory()->onInventoryChanged(flagInvChg); } } } if (res != NULL) *res = ior_ok; // may be null return ret; }
// **************************************************************************** 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; }