// **************************************************************************** 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; }
//--------------------------------------------------- // createItem : // //--------------------------------------------------- //CGameItemPtr CGameItemManager::createItem( CEntityId& id, CSheetId& sheetId, uint16 quality, sint16 slot, bool destroyable, bool dropable , const CEntityId &creatorId ) CGameItemPtr CGameItemManager::createItem( const CSheetId& sheetId, uint16 quality, bool destroyable, bool dropable , const CEntityId &creatorId ) { H_AUTO(GIM_createItem1); // test if the item already exists // map<CEntityId,CGameItemPtr>::iterator itIt = _Items.find( id ); // if( itIt != _Items.end() ) // { // nlwarning("<CGameItemManager::createItem> The item %s already exists",id.toString().c_str()); // return NULL; // } // MALKAV 22/01/03 : get owner, if owner not found, returns before creating the item and display a simple warning // CGameItemPtr ownerItem = NULL; // if( owner != CEntityId::Unknown ) // { // ownerItem = getItem( owner ); // BOMB_IF(ownerItem == NULL ,"Bad owner found for item",return NULL); // } // // create a new item // CGameItemPtr item = getNewItem( id, sheetId, quality, destroyable, dropable ); CGameItemPtr item = getNewItem(sheetId, quality, destroyable, dropable ); if( item != NULL ) { // nldebug("<CGameItemManager::createItem> create item %s with owner %s",id.toString().c_str(), owner.toString().c_str()); // (*item)->Owner = owner; (*item)->setCreator( creatorId ); // insert the item in the map // _Items.insert( make_pair(id,item) ); // _Items.insert( item ); // insert the item in the children of the owner // MALKAV 22/01/03 : test the owner existence sooner and use a warning instead of an nlerror to keep going // if( owner != CEntityId::Unknown ) // { // CGameItemPtr ownerItem = getItem( owner ); // if( ownerItem!=NULL ) // { // (*ownerItem)->addChild( item, slot ); // } // else // { // nlerror("<CGameItemManager::createItem> Can't find the owner item %s",owner.toString().c_str()); // } // } } else { // nlwarning("<CGameItemManager::createItem> Can't create the item %s with invalid sheet '%s'", id.toString().c_str(), sheetId.toString().c_str()); nlwarning("<CGameItemManager::createItem> Can't create an item with invalid sheet '%s'", sheetId.toString().c_str()); } log_Item_Create(item->getItemId(), item->getSheetId(), item->getStackSize(), item->quality()); return item; } // createItem //
// **************************************************************************** CGameItemPtr CRefInventory::removeItem(uint32 slot, uint32 quantity, TInventoryOpResult * res) { nlassert(slot < _Items.size()); CGameItemPtr ret = _Items[slot]; if (_Items[slot] != NULL) { // unlink the item _Items[slot]->setRefInventory(CInventoryPtr(NULL), INVENTORIES::INVALID_INVENTORY_SLOT); CGameItemPtr item = _Items[slot]; _Items[slot] = NULL; ++_FreeSlotCount; updateWeightAndBulk(ret, -sint32(ret->getStackSize())); // callbacks for derived class onItemChanged(slot, INVENTORIES::itc_removed); // callback views INVENTORIES::TInventoryChangeFlags flagInvChg(INVENTORIES::ic_total_bulk); flagInvChg.setEnumValue(INVENTORIES::ic_total_weight); flagInvChg.setEnumValue(INVENTORIES::ic_item_list); TViewCont::iterator first(_InventoryViews.begin()), last(_InventoryViews.end()); for (; first != last; ++first) { CInventoryViewPtr view = *first; view->onInventoryChanged(flagInvChg); view->onItemChanged(slot, INVENTORIES::itc_removed); } } if (res != NULL) *res = ior_ok; return ret; }
/// test if we can stack an item on an existing one // **************************************************************************** CInventoryBase::TInventoryOpResult CInventoryBase::canStackItem(const CGameItemPtr &item, uint32 slotDst) { if (item == NULL || slotDst >= getSlotCount()) return ior_error; CGameItemPtr dstItem = getItem(slotDst); // ok if slot is empty if (dstItem == NULL) return ior_ok; // check item sheet and craft params if (!CGameItem::areStackable(item, dstItem)) return ior_item_incompatible; const CStaticItem *srcForm = CSheets::getForm(item->getSheetId()); if (dstItem->getStackSize() + item->getStackSize() > dstItem->getMaxStackSize()) return ior_stack_oversize; return ior_ok; }
// **************************************************************************** void CInventoryBase::onItemStackSizeChanged(uint32 slot, uint32 previousStackSize) { CGameItemPtr item = getItem(slot); sint32 deltaSize = item->getStackSize() - previousStackSize; updateWeightAndBulk(item, deltaSize); // callback all the views TViewCont::iterator first(_InventoryViews.begin()), last(_InventoryViews.end()); for (; first!= last; ++first) { CInventoryViewPtr view = *first; view->onItemStackSizeChanged(slot, previousStackSize); } }
// **************************************************************************** void CCharacterInvView::updateClientSlot(uint32 slot, const CGameItemPtr item) { // do nothing if client is not ready if (!getCharacter()->getEnterFlag()) return; if (item != NULL) { uint32 price; RM_FABER_STAT_TYPE::TRMStatType itemBestStat; getCharacter()->queryItemPrice( item, price ); itemBestStat = item->getCraftParameters() == 0 ? RM_FABER_STAT_TYPE::Unknown : item->getCraftParameters()->getBestItemStat(); BOTCHATTYPE::TBotChatResaleFlag resaleFlag = (item->durability() == item->maxDurability() ? BOTCHATTYPE::ResaleOk : BOTCHATTYPE::ResaleKOBroken); if (item->getLockedByOwner()) { resaleFlag = BOTCHATTYPE::ResaleKOLockedByOwner; } INVENTORIES::CItemSlot itemSlot( slot ); itemSlot.setItemProp( INVENTORIES::Sheet, item->getSheetId().asInt() ); itemSlot.setItemProp( INVENTORIES::Quality, item->quality() ); itemSlot.setItemProp( INVENTORIES::Quantity, item->getStackSize() ); itemSlot.setItemProp( INVENTORIES::UserColor, item->color() ); itemSlot.setItemProp( INVENTORIES::Locked, item->getLockCount() ); itemSlot.setItemProp( INVENTORIES::Weight, item->weight() / 10 ); itemSlot.setItemProp( INVENTORIES::NameId, item->sendNameId(getCharacter()) ); itemSlot.setItemProp( INVENTORIES::Enchant, item->getClientEnchantValue() ); itemSlot.setItemProp( INVENTORIES::Price, price ); itemSlot.setItemProp( INVENTORIES::ResaleFlag, resaleFlag ); itemSlot.setItemProp( INVENTORIES::ItemClass, item->getItemClass() ); itemSlot.setItemProp( INVENTORIES::ItemBestStat, itemBestStat ); itemSlot.setItemProp( INVENTORIES::PrerequisitValid, getCharacter()->checkPreRequired( item ) ); itemSlot.setItemProp( INVENTORIES::Worned, (item->getItemWornState()==ITEM_WORN_STATE::Worned)); getCharacter()->_InventoryUpdater.setItemProps( getInventory()->getInventoryId(), itemSlot ); } else { // empty slot getCharacter()->_InventoryUpdater.resetItem( getInventory()->getInventoryId(), slot ); } // send slot update to the client getCharacter()->_InventoryUpdater.incInfoVersion(getInventory()->getInventoryId(), slot); }
// **************************************************************************** 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; }
/// 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; }