unsigned Inventory::insert(unsigned itemId, unsigned amount) { if (!itemId || !amount) return 0; MessageOut invMsg(GPMSG_INVENTORY); ItemClass *item = itemManager->getItem(itemId); if (!item) { LOG_ERROR("Inventory: Trying to insert invalid item id " << itemId << " (amount: " << amount << ")"); return amount; } unsigned maxPerSlot = item->getMaxPerSlot(); LOG_DEBUG("Inventory: Inserting " << amount << " item(s) Id: " << itemId << " for character '" << mCharacter->getComponent<BeingComponent>()->getName() << "'."); InventoryData::iterator it, it_end = mPoss->inventory.end(); // Add to slots with existing items of this type first. for (it = mPoss->inventory.begin(); it != it_end; ++it) { if (it->second.itemId == itemId) { // If the slot is full, try the next slot if (it->second.amount >= maxPerSlot) continue; // Add everything that'll fit to the stack unsigned short spaceLeft = maxPerSlot - it->second.amount; if (spaceLeft >= amount) { it->second.amount += amount; amount = 0; LOG_DEBUG("Everything inserted at slot id: " << it->first); } else { it->second.amount += spaceLeft; amount -= spaceLeft; LOG_DEBUG(spaceLeft << " item(s) inserted at slot id: " << it->first); } invMsg.writeInt16(it->first); invMsg.writeInt16(itemId); invMsg.writeInt16(it->second.amount); if (!amount) break; } } int slot = 0; // We still have some left, so add to blank slots. for (it = mPoss->inventory.begin();; ++it) { if (!amount) break; int lim = (it == it_end) ? INVENTORY_SLOTS : it->first; while (amount && slot < lim) { int additions = std::min(amount, maxPerSlot); mPoss->inventory[slot].itemId = itemId; mPoss->inventory[slot].amount = additions; amount -= additions; LOG_DEBUG(additions << " item(s) inserted at slot id: " << slot); invMsg.writeInt16(slot++); // Last read, so also increment invMsg.writeInt16(itemId); invMsg.writeInt16(additions); } ++slot; // Skip the slot that the iterator points to if (it == it_end) break; } item->useTrigger(mCharacter, ITT_IN_INVY); // Send that first, before checking potential removals if (invMsg.getLength() > 2) gameHandler->sendTo(mCharacter, invMsg); return amount; }
void Inventory::initialize() { /* * Construct a set of item Ids to keep track of duplicate item Ids. */ std::set<unsigned> itemIds; /* * Construct a set of itemIds to keep track of duplicate itemIds. */ InventoryData::iterator it1; for (it1 = mPoss->inventory.begin(); it1 != mPoss->inventory.end();) { ItemClass *item = itemManager->getItem(it1->second.itemId); if (item) { // If the insertion succeeded, it's the first time we're // adding the item in the inventory. Hence, we can trigger // item presence in inventory effect. if (itemIds.insert(it1->second.itemId).second) item->useTrigger(mCharacter, ITT_IN_INVY); ++it1; } else { LOG_WARN("Inventory: deleting unknown item type " << it1->second.itemId << " from the inventory of '" << mCharacter->getComponent<BeingComponent>()->getName() << "'!"); mPoss->inventory.erase(it1++); } } itemIds.clear(); /* * Equipment effects can be cumulative if more than one item instance * is equipped, but we check to trigger the item presence in equipment * effect only based on the first item instance insertion. */ EquipData::iterator it2; for (it2 = mPoss->equipSlots.begin(); it2 != mPoss->equipSlots.end();) { ItemClass *item = itemManager->getItem(it2->second.itemId); if (item) { // TODO: Check equip conditions. // If not all needed slots are there, put the item back // in the inventory. } else { LOG_WARN("Equipment: deleting unknown item id " << it2->second.itemId << " from the equipment of '" << mCharacter->getComponent<BeingComponent>()->getName() << "'!"); mPoss->equipSlots.erase(it2++); continue; } /* * Apply all equip triggers at first item instance insertion */ if (itemIds.insert(it2->second.itemInstance).second) { itemManager->getItem(it2->second.itemId) ->useTrigger(mCharacter, ITT_EQUIP); } ++it2; } }
void Inventory::initialise() { assert(!mDelayed); InventoryData::iterator it1; EquipData::const_iterator it2, it2_end = mPoss->equipSlots.end(); /* * Apply all exists triggers. * Remove unknown inventory items. */ ItemIdSet itemIds; /* * Construct a set of itemIds to keep track of duplicate itemIds. */ for (it1 = mPoss->inventory.begin(); it1 != mPoss->inventory.end();) { ItemClass *item = itemManager->getItem(it1->second.itemId); if (item) { if (itemIds.insert(it1->second.itemId).second) item->useTrigger(mClient, ITT_IN_INVY); ++it1; } else { LOG_WARN("Inventory: deleting unknown item type " << it1->second.itemId << " from the inventory of '" << mClient->getName() << "'!"); mPoss->inventory.erase(it1++); } } itemIds.clear(); typedef std::set<unsigned int> SlotSet; SlotSet equipment; /* * Construct a set of slot references from equipment to keep track of * duplicate slot usage. */ for (it2 = mPoss->equipSlots.begin(); it2 != it2_end; ++it2) { if (equipment.insert(it2->second).second) { /* * Perform checks for equipped items - check that all needed slots are available. */ // TODO - Not needed for testing everything else right now, but // will be needed for production /* * Apply all equip triggers. */ itemManager->getItem(mPoss->inventory.at(it2->second).itemId) ->useTrigger(mClient, ITT_EQUIP); } } equipment.clear(); checkSize(); }