예제 #1
0
void Inventory::checkSize()
{
    /*
     * Check that the inventory size is greater than or equal to the size
     *       needed.
     *       If not, forcibly delete (drop?) items from the end until it is.
     * Check that inventory capacity is greater than or equal to zero.
     *       If not, forcibly delete (drop?) items from the end until it is.
     */
    while (mPoss->inventory.size() > INVENTORY_SLOTS
           || mClient->getModifiedAttribute(ATTR_INV_CAPACITY) < 0)
    {
        LOG_WARN("Inventory: oversize inventory! Deleting '"
                 << mPoss->inventory.rbegin()->second.amount
                 << "' items of type '"
                 << mPoss->inventory.rbegin()->second.itemId
                 << "' from slot '"
                 << mPoss->inventory.rbegin()->first
                 << "' of character '"
                 << mClient->getName()
                 << "'!");
        // FIXME Should probably be dropped rather than deleted.
        removeFromSlot(mPoss->inventory.rbegin()->first,
                       mPoss->inventory.rbegin()->second.amount);
    }
}
예제 #2
0
bool Inventory::equip(int inventorySlot)
{
    // Test inventory slot existence
    InventoryData::iterator it;
    if ((it = mPoss->inventory.find(inventorySlot)) == mPoss->inventory.end())
    {
        LOG_DEBUG("No existing item in inventory at slot: " << inventorySlot);
        return false;
    }

    // Test the equipment scripted requirements
    if (!testEquipScriptRequirements(it->second.itemId))
        return false;

    // Test the equip requirements. If none, it's not an equipable item.
    const ItemEquipRequirement &equipReq =
        itemManager->getItem(it->second.itemId)->getItemEquipRequirement();
    if (!equipReq.equipSlotId)
    {
        LOG_DEBUG("No equip requirements for item id: " << it->second.itemId
            << " at slot: " << inventorySlot);
        return false;
    }

    // List of potential unique itemInstances to unequip first.
    std::set<unsigned> equipInstancesToUnequipFirst;

    // We first check the equipment slots for:
    // - 1. whether enough total equip slot space is available.
    // - 2. whether some other equipment is to be unequipped first.

    // If not enough total space in the equipment slot is available,
    // we cannot equip.
    if (itemManager->getEquipSlotCapacity(equipReq.equipSlotId)
            < equipReq.capacityRequired)
    {
        LOG_DEBUG("Not enough equip capacity at slot: " << equipReq.equipSlotId
                  << ", total available: "
                  << itemManager->getEquipSlotCapacity(equipReq.equipSlotId)
                  << ", required: " << equipReq.capacityRequired);
        return false;
    }

    // Test whether some item(s) is(are) to be unequipped first.
    if (!checkEquipmentCapacity(equipReq.equipSlotId,
                                equipReq.capacityRequired))
    {
        // And test whether the unequip action would succeed first.
        if (testUnequipScriptRequirements(equipReq.equipSlotId)
            && hasInventoryEnoughSpace(equipReq.equipSlotId))
        {
            // Then, we unequip each iteminstance of the equip slot
            for (EquipData::iterator iter =
                mPoss->equipSlots.begin();
                iter != mPoss->equipSlots.end(); ++iter)
            {
                if (iter->first == equipReq.equipSlotId
                    && iter->second.itemInstance)
                    equipInstancesToUnequipFirst.insert(
                                                     iter->second.itemInstance);
            }
        }
        else
        {
            // Some non-unequippable equipment is to be unequipped first.
            // Can be the case of cursed items,
            // or when the inventory is full, for instance.
            return false;
        }
    }

    // Potential Pre-unequipment process
    for (std::set<unsigned>::const_iterator it3 =
            equipInstancesToUnequipFirst.begin();
            it3 != equipInstancesToUnequipFirst.end(); ++it3)
    {
        if (!unequip(*it3))
        {
            // Something went wrong even when we tested the unequipment process.
            LOG_WARN("Unable to unequip even when unequip was tested. "
                     "Character : "
                    << mCharacter->getComponent<BeingComponent>()->getName()
                     << ", unequip slot: " << *it3);
            return false;
        }
    }

    // Actually equip the item now that the requirements has met.
    //W equip slot type count, W item id, { W equip slot, W capacity used}*
    MessageOut equipMsg(GPMSG_EQUIP);
    equipMsg.writeInt16(it->second.itemId); // Item Id
    equipMsg.writeInt16(1); // Number of equip slot changed.

    // Compute an unique equip item Instance id (unicity is per character only.)
    int itemInstance = getNewEquipItemInstance();

    unsigned capacityLeft = equipReq.capacityRequired;
    unsigned capacityUsed = 0;
    // Apply equipment changes
    for (EquipData::iterator it4 = mPoss->equipSlots.begin(),
         it4_end = mPoss->equipSlots.end(); it4 != it4_end; ++it4)
    {
        if (!capacityLeft)
            break;

        // We've found an existing equip slot
        if (it4->first == equipReq.equipSlotId)
        {
            // We've found an empty slot
            if (it4->second.itemInstance == 0)
            {
                it4->second.itemId = it->second.itemId;
                it4->second.itemInstance = itemInstance;
                --capacityLeft;
            }
            else // The slot is already in use.
            {
                ++capacityUsed;
            }
        }
    }

    // When there is still something to apply even when out of that loop,
    // It means that the equip multimapis missing empty slots.
    // Hence, we add them back
    if(capacityLeft)
    {
        unsigned maxCapacity =
            itemManager->getEquipSlotCapacity(equipReq.equipSlotId);

        // A should never happen case
        assert(maxCapacity >= capacityUsed + capacityLeft);

        while (capacityLeft)
        {
            EquipmentItem equipItem(it->second.itemId, itemInstance);
            mPoss->equipSlots.insert(
                    std::make_pair(equipReq.equipSlotId, equipItem));
            --capacityLeft;
        }
    }

    // Equip slot
    equipMsg.writeInt16(equipReq.equipSlotId);
    // Capacity used
    equipMsg.writeInt16(equipReq.capacityRequired);
    // Item instance
    equipMsg.writeInt16(itemInstance);

    // New item trigger
    updateEquipmentTrigger(0, it->second.itemId);

    // Remove item from inventory
    removeFromSlot(inventorySlot, 1);

    gameHandler->sendTo(mCharacter, equipMsg);

    // Update look when necessary
    checkLookchanges(equipReq.equipSlotId);

    return true;
}