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;
    }
}
Beispiel #3
0
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();
}