Пример #1
0
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr)
{
    int type = getType(ptr);

    const MWWorld::ESMStore &esmStore =
        MWBase::Environment::get().getWorld()->getStore();

    // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001
    // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold)
    if (MWWorld::Class::get(ptr).getName(ptr) == esmStore.get<ESM::GameSetting>().find("sGold")->getString())
    {
        MWWorld::LiveCellRef<ESM::Miscellaneous> *gold =
            ptr.get<ESM::Miscellaneous>();

        if (compare_string_ci(gold->mRef.mRefID, "gold_001")
            || compare_string_ci(gold->mRef.mRefID, "gold_005")
            || compare_string_ci(gold->mRef.mRefID, "gold_010")
            || compare_string_ci(gold->mRef.mRefID, "gold_025")
            || compare_string_ci(gold->mRef.mRefID, "gold_100"))
        {
            MWWorld::ManualRef ref(esmStore, "Gold_001");

            int count = (ptr.getRefData().getCount() == 1) ? gold->mBase->mData.mValue : ptr.getRefData().getCount();
            ref.getPtr().getRefData().setCount(count);
            for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter)
            {
                if (compare_string_ci((*iter).get<ESM::Miscellaneous>()->mRef.mRefID, "gold_001"))
                {
                    (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count);
                    flagAsModified();
                    return iter;
                }
            }

            return addImpl(ref.getPtr());
        }
    }

    // determine whether to stack or not
    for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter)
    {
        if (stacks(*iter, ptr))
        {
            // stack
            iter->getRefData().setCount( iter->getRefData().getCount() + ptr.getRefData().getCount() );

            flagAsModified();
            return iter;
        }
    }
    // if we got here, this means no stacking
    return addImpl(ptr);
}
Пример #2
0
void MWWorld::ContainerStore::clear()
{
    for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter)
        iter->getRefData().setCount (0);

    flagAsModified();
}
Пример #3
0
void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& iterator, const Ptr& actor)
{
    if (iterator == end())
        throw std::runtime_error ("can't equip end() iterator, use unequip function instead");

    if (slot<0 || slot>=static_cast<int> (mSlots.size()))
        throw std::runtime_error ("slot number out of range");

    if (iterator.getContainerStore()!=this)
        throw std::runtime_error ("attempt to equip an item that is not in the inventory");

    std::pair<std::vector<int>, bool> slots_;

    slots_ = iterator->getClass().getEquipmentSlots (*iterator);

    if (std::find (slots_.first.begin(), slots_.first.end(), slot)==slots_.first.end())
        throw std::runtime_error ("invalid slot");

    if (mSlots[slot] != end())
        unequipSlot(slot, actor);

    // unstack item pointed to by iterator if required
    if (iterator!=end() && !slots_.second && iterator->getRefData().getCount() > 1) // if slots.second is true, item can stay stacked when equipped
    {
        unstack(*iterator, actor);
    }

    mSlots[slot] = iterator;

    flagAsModified();

    fireEquipmentChangedEvent(actor);

    updateMagicEffects(actor);
}
Пример #4
0
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const ConstPtr& ptr, int count)
{
    ContainerStoreIterator it = begin();

    switch (getType(ptr))
    {
        case Type_Potion: potions.mList.push_back (*ptr.get<ESM::Potion>()); it = ContainerStoreIterator(this, --potions.mList.end()); break;
        case Type_Apparatus: appas.mList.push_back (*ptr.get<ESM::Apparatus>()); it = ContainerStoreIterator(this, --appas.mList.end()); break;
        case Type_Armor: armors.mList.push_back (*ptr.get<ESM::Armor>()); it = ContainerStoreIterator(this, --armors.mList.end()); break;
        case Type_Book: books.mList.push_back (*ptr.get<ESM::Book>()); it = ContainerStoreIterator(this, --books.mList.end()); break;
        case Type_Clothing: clothes.mList.push_back (*ptr.get<ESM::Clothing>()); it = ContainerStoreIterator(this, --clothes.mList.end()); break;
        case Type_Ingredient: ingreds.mList.push_back (*ptr.get<ESM::Ingredient>()); it = ContainerStoreIterator(this, --ingreds.mList.end()); break;
        case Type_Light: lights.mList.push_back (*ptr.get<ESM::Light>()); it = ContainerStoreIterator(this, --lights.mList.end()); break;
        case Type_Lockpick: lockpicks.mList.push_back (*ptr.get<ESM::Lockpick>()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break;
        case Type_Miscellaneous: miscItems.mList.push_back (*ptr.get<ESM::Miscellaneous>()); it = ContainerStoreIterator(this, --miscItems.mList.end()); break;
        case Type_Probe: probes.mList.push_back (*ptr.get<ESM::Probe>()); it = ContainerStoreIterator(this, --probes.mList.end()); break;
        case Type_Repair: repairs.mList.push_back (*ptr.get<ESM::Repair>()); it = ContainerStoreIterator(this, --repairs.mList.end()); break;
        case Type_Weapon: weapons.mList.push_back (*ptr.get<ESM::Weapon>()); it = ContainerStoreIterator(this, --weapons.mList.end()); break;
    }

    it->getRefData().setCount(count);

    flagAsModified();
    return it;
}
Пример #5
0
int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor)
{
    assert(this == item.getContainerStore());

    int toRemove = count;
    RefData& itemRef = item.getRefData();

    if (itemRef.getCount() <= toRemove)
    {
        toRemove -= itemRef.getCount();
        itemRef.setCount(0);
    }
    else
    {
        itemRef.setCount(itemRef.getCount() - toRemove);
        toRemove = 0;
    }

    flagAsModified();

    if (mListener)
        mListener->itemRemoved(item, count - toRemove);

    // number of removed items
    return count - toRemove;
}
Пример #6
0
void CSVRender::PreviewWidget::ReferenceDataChanged (const QModelIndex& topLeft,
    const QModelIndex& bottomRight)
{
    if (mReferenceId.empty())
        return;

    CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
        *mData.getTableModel (CSMWorld::UniversalId::Type_References));

    int columnIndex = references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId);

    QModelIndex index = references.getModelIndex (mReferenceId, columnIndex);

    if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
    {
        /// \todo possible optimisation; check columns and only update if relevant columns have
        /// changed
        adjust();

        if (index.column()>=topLeft.column() && index.column()<=bottomRight.row())
        {
            mReferenceableId = references.data (index).toString().toUtf8().constData();
            emit referenceableIdChanged (mReferenceableId);
            setModel();
        }

        flagAsModified();
    }
}
Пример #7
0
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
{
    TSlots slots_;
    initSlots (slots_);

    // Disable model update during auto-equip
    mUpdatesEnabled = false;

    // Autoequip clothing, armor and weapons.
    // Equipping lights is handled in Actors::updateEquippedLight based on environment light.
    // Note: creatures do not use the armor mitigation and can equip only shields
    // Use a custom logic for them - select shield based on its health instead of armor rating (since it useless for creatures)
    autoEquipWeapon(actor, slots_);
    autoEquipArmor(actor, slots_);

    bool changed = false;

    for (std::size_t i=0; i<slots_.size(); ++i)
    {
        if (slots_[i] != mSlots[i])
        {
            changed = true;
            break;
        }
    }
    mUpdatesEnabled = true;

    if (changed)
    {
        mSlots.swap (slots_);
        fireEquipmentChangedEvent(actor);
        updateMagicEffects(actor);
        flagAsModified();
    }
}
Пример #8
0
void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& parent, int start,
    int end)
{
    if (mCell.get())
        if (mCell.get()->referenceAdded (parent, start, end))
            flagAsModified();
}
Пример #9
0
void CSVRender::PreviewWidget::ReferenceableAboutToBeRemoved (const QModelIndex& parent, int start,
    int end)
{
    if (mReferenceableId.empty())
        return;

    CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
        *mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables));

    QModelIndex index = referenceables.getModelIndex (mReferenceableId, 0);

    if (index.row()>=start && index.row()<=end)
    {
        if (mReferenceId.empty())
        {
            // this is a preview for a referenceble
            emit closeRequest();
        }
        else
        {
            // this is a preview for a reference
            mObject.setNull();
            flagAsModified();
        }
    }
}
Пример #10
0
void CSVRender::UnpagedWorldspaceWidget::referenceDataChanged (const QModelIndex& topLeft,
    const QModelIndex& bottomRight)
{
    if (mCell.get())
        if (mCell.get()->referenceDataChanged (topLeft, bottomRight))
            flagAsModified();
}
Пример #11
0
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, int count)
{
    int type = getType(ptr);

    const MWWorld::ESMStore &esmStore =
        MWBase::Environment::get().getWorld()->getStore();

    // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001
    // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold)
    if(ptr.getClass().isGold(ptr))
    {
        int realCount = count * ptr.getClass().getValue(ptr);

        for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter)
        {
            if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
            {
                iter->getRefData().setCount(iter->getRefData().getCount() + realCount);
                flagAsModified();
                return iter;
            }
        }

        MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount);
        return addNewStack(ref.getPtr(), realCount);
    }

    // determine whether to stack or not
    for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter)
    {
        if (stacks(*iter, ptr))
        {
            // stack
            iter->getRefData().setCount( iter->getRefData().getCount() + count );

            flagAsModified();
            return iter;
        }
    }
    // if we got here, this means no stacking
    return addNewStack(ptr, count);
}
Пример #12
0
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const MWWorld::ESMStore& store)
{
    for (std::vector<ESM::ContItem>::const_iterator iter (items.mList.begin()); iter!=items.mList.end();
        ++iter)
    {
        std::string id = iter->mItem.toString();
        addInitialItem(id, owner, iter->mCount);
    }

    flagAsModified();
}
Пример #13
0
void CSVRender::UnpagedWorldspaceWidget::update()
{
    const CSMWorld::Record<CSMWorld::Cell>& record =
        dynamic_cast<const CSMWorld::Record<CSMWorld::Cell>&> (mCellsModel->getRecord (mCellId));

    osg::Vec4f colour = SceneUtil::colourFromRGB(record.get().mAmbi.mAmbient);

    setDefaultAmbient (colour);

    /// \todo deal with mSunlight and mFog/mForDensity

    flagAsModified();
}
Пример #14
0
void CSVRender::UnpagedWorldspaceWidget::referenceableAdded (const QModelIndex& parent,
    int start, int end)
{
    if (mCell.get())
    {
        QModelIndex topLeft = mReferenceablesModel->index (start, 0);
        QModelIndex bottomRight =
            mReferenceablesModel->index (end, mReferenceablesModel->columnCount());

        if (mCell.get()->referenceableDataChanged (topLeft, bottomRight))
            flagAsModified();
    }
}
Пример #15
0
int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor)
{
    int toRemove = count;

    for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter)
        if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId))
            toRemove -= remove(*iter, toRemove, actor);

    flagAsModified();

    // number of removed items
    return count - toRemove;
}
Пример #16
0
void SceneWidget::setLighting(Lighting *lighting)
{
    if (mLighting)
        mLighting->deactivate();

    mLighting = lighting;
    mLighting->activate (mRootNode);

    osg::Vec4f ambient = mLighting->getAmbientColour(mHasDefaultAmbient ? &mDefaultAmbient : 0);
    setAmbient(ambient);

    flagAsModified();
}
Пример #17
0
void CSVRender::PreviewWidget::ReferenceableDataChanged (const QModelIndex& topLeft,
    const QModelIndex& bottomRight)
{
    if (mReferenceableId.empty())
        return;

    CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
        *mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables));

    QModelIndex index = referenceables.getModelIndex (mReferenceableId, 0);

    if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
    {
        /// \todo possible optimisation; check columns and only update if relevant columns have
        /// changed
        setModel();
        flagAsModified();
    }
}
Пример #18
0
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS::ESMStore& store)
{
    for (std::vector<ESM::ContItem>::const_iterator iter (items.mList.begin()); iter!=items.mList.end();
        ++iter)
    {
        ManualRef ref (store, iter->mItem.toString());

        if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
        {
            /// \todo implement leveled item lists
            continue;
        }

        ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count)
        add (ref.getPtr());
    }

    flagAsModified();
}
Пример #19
0
void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& iterator)
{
    if (slot<0 || slot>=static_cast<int> (mSlots.size()))
        throw std::runtime_error ("slot number out of range");

    if (iterator.getContainerStore()!=this)
        throw std::runtime_error ("attempt to equip an item that is not in the inventory");

    if (iterator!=end())
    {
        std::pair<std::vector<int>, bool> slots = Class::get (*iterator).getEquipmentSlots (*iterator);

        if (std::find (slots.first.begin(), slots.first.end(), slot)==slots.first.end())
            throw std::runtime_error ("invalid slot");
    }

    /// \todo restack item previously in this slot (if required)

    /// \todo unstack item pointed to by iterator if required)

    mSlots[slot] = iterator;

    flagAsModified();
}
Пример #20
0
void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats)
{
    TSlots slots;
    initSlots (slots);

    for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter)
    {
        Ptr test = *iter;
        int testSkill = MWWorld::Class::get (test).getEquipmentSkill (test);

        std::pair<std::vector<int>, bool> itemsSlots =
            MWWorld::Class::get (*iter).getEquipmentSlots (*iter);

        for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
            iter2!=itemsSlots.first.end(); ++iter2)
        {
            bool use = false;

            if (slots.at (*iter2)==end())
                use = true; // slot was empty before -> skill all further checks
            else
            {
                Ptr old = *slots.at (*iter2);

                if (!use)
                {
                    // check skill
                    int oldSkill =
                        MWWorld::Class::get (old).getEquipmentSkill (old);

                    if (testSkill!=-1 || oldSkill!=-1 || testSkill!=oldSkill)
                    {
                        if (stats.mSkill[oldSkill].getModified()>stats.mSkill[testSkill].getModified())
                            continue; // rejected, because old item better matched the NPC's skills.

                        if (stats.mSkill[oldSkill].getModified()<stats.mSkill[testSkill].getModified())
                            use = true;
                    }
                }

                if (!use)
                {
                    // check value
                    if (MWWorld::Class::get (old).getValue (old)>=
                        MWWorld::Class::get (test).getValue (test))
                    {
                        continue;
                    }

                    use = true;
                }
            }

            /// \todo unstack, if reqquired (itemsSlots.second)

            slots[*iter2] = iter;
            break;
        }
    }

    bool changed = false;

    for (std::size_t i=0; i<slots.size(); ++i)
        if (slots[i]!=mSlots[i])
        {
            changed = true;
        }

    if (changed)
    {
        mSlots.swap (slots);
        flagAsModified();
    }
}
Пример #21
0
void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask)
{
    mCell->setSelection (elementMask, Cell::Selection_Clear);
    flagAsModified();
}
Пример #22
0
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
{
    TSlots slots_;
    initSlots (slots_);

    // Disable model update during auto-equip
    mUpdatesEnabled = false;

    for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter)
    {
        Ptr test = *iter;

        // Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light.
        if (test.getTypeName() == typeid(ESM::Light).name())
        {
            continue;
        }

        // Only autoEquip if we are the original owner of the item.
        // This stops merchants from auto equipping anything you sell to them.
        // ...unless this is a companion, he should always equip items given to him.
        if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) &&
                (actor.getClass().getScript(actor).empty() ||
                !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))
                && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired
                )
        {
            continue;
        }
        int testSkill = test.getClass().getEquipmentSkill (test);

        std::pair<std::vector<int>, bool> itemsSlots =
            iter->getClass().getEquipmentSlots (*iter);

        for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
            iter2!=itemsSlots.first.end(); ++iter2)
        {
            if (*iter2 == Slot_CarriedRight) // Items in right hand are situational use, so don't equip them.
                // Equipping weapons is handled by AiCombat. Anything else (lockpicks, probes) can't be used by NPCs anyway (yet)
                continue;

            if (iter.getType() == MWWorld::ContainerStore::Type_Weapon)
                continue;

            if (slots_.at (*iter2)!=end())
            {
                Ptr old = *slots_.at (*iter2);

                // check skill
                int oldSkill = old.getClass().getEquipmentSkill (old);

                bool use = false;
                if (testSkill!=-1 && oldSkill==-1)
                    use = true;
                else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill)
                {
                    if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill))
                        continue; // rejected, because old item better matched the NPC's skills.

                    if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill))
                        use = true;
                }

                if (!use)
                {
                    // check value
                    if (old.getClass().getValue (old)>=
                        test.getClass().getValue (test))
                    {
                        continue;
                    }
                }
            }

            switch(test.getClass().canBeEquipped (test, actor).first)
            {
                case 0:
                    continue;
                default:
                    break;
            }

            if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
            {
                // unstack item pointed to by iterator if required
                if (iter->getRefData().getCount() > 1)
                {
                    unstack(*iter, actor);
                }
            }

            slots_[*iter2] = iter;
            break;
        }
    }

    bool changed = false;

    for (std::size_t i=0; i<slots_.size(); ++i)
    {
        if (slots_[i] != mSlots[i])
        {
            changed = true;
            break;
        }
    }
    mUpdatesEnabled = true;

    if (changed)
    {
        mSlots.swap (slots_);
        fireEquipmentChangedEvent(actor);
        updateMagicEffects(actor);
        flagAsModified();
    }
}
Пример #23
0
void CSVRender::WorldspaceWidget::elementSelectionChanged()
{
    setVisibilityMask (getVisibilityMask());
    flagAsModified();
    updateOverlay();
}
Пример #24
0
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
{
    TSlots slots_;
    initSlots (slots_);

    // Disable model update during auto-equip
    mUpdatesEnabled = false;

    for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter)
    {
        Ptr test = *iter;

        // Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light.
        if (test.getTypeName() == typeid(ESM::Light).name())
        {
            continue;
        }

        // Don't auto-equip probes or lockpicks. NPCs can't use them (yet). And AiCombat would attempt to "attack" with them.
        // NOTE: In the future AiCombat should handle equipping appropriate weapons
        if (test.getTypeName() == typeid(ESM::Lockpick).name() || test.getTypeName() == typeid(ESM::Probe).name())
            continue;

        // Only autoEquip if we are the original owner of the item.
        // This stops merchants from auto equipping anything you sell to them.
        // ...unless this is a companion, he should always equip items given to him.
        if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) &&
                (actor.getClass().getScript(actor).empty() ||
                !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")))
            continue;

        int testSkill = test.getClass().getEquipmentSkill (test);

        std::pair<std::vector<int>, bool> itemsSlots =
            iter->getClass().getEquipmentSlots (*iter);

        for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
            iter2!=itemsSlots.first.end(); ++iter2)
        {
            bool use = false;

            if (slots_.at (*iter2)==end())
                use = true; // slot was empty before -> skip all further checks
            else
            {
                Ptr old = *slots_.at (*iter2);

                if (!use)
                {
                    // check skill
                    int oldSkill =
                        old.getClass().getEquipmentSkill (old);

                    if (testSkill!=-1 && oldSkill==-1)
                        use = true;
                    else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill)
                    {
                        if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill))
                            continue; // rejected, because old item better matched the NPC's skills.

                        if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill))
                            use = true;
                    }
                }

                if (!use)
                {
                    // check value
                    if (old.getClass().getValue (old)>=
                        test.getClass().getValue (test))
                    {
                        continue;
                    }

                    use = true;
                }
            }

            switch(test.getClass().canBeEquipped (test, actor).first)
            {
                case 0:
                    continue;
                case 2:
                    slots_[MWWorld::InventoryStore::Slot_CarriedLeft] = end();
                    break;
                case 3:
                    // Prefer keeping twohanded weapon
                    break;
            }

            if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
            {
                // unstack item pointed to by iterator if required
                if (iter->getRefData().getCount() > 1)
                {
                    unstack(*iter, actor);
                }
            }

            slots_[*iter2] = iter;
            break;
        }
    }

    bool changed = false;

    for (std::size_t i=0; i<slots_.size(); ++i)
        if (slots_[i]!=mSlots[i])
        {
            changed = true;
        }

    mUpdatesEnabled = true;

    if (changed)
    {
        mSlots.swap (slots_);
        fireEquipmentChangedEvent();
        updateMagicEffects(actor);
        flagAsModified();
    }
}
Пример #25
0
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)
{
    //allowedForReplace - Holds information about how many items from the list were not sold;
    //                    Hence, tells us how many items we don't need to restock.
    //allowedForReplace[list] <- How many items we should generate(how many of these were sold)
    std::map<std::string, int> allowedForReplace;

    //Check which lists need restocking:
    for (std::map<std::pair<std::string, std::string>, int>::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end();)
    {
        int spawnedCount = it->second; //How many items should be in shop originally
        int itemCount = restockCount(it->first.first); //How many items are there in shop now
        //If something was not sold
        if(itemCount >= spawnedCount)
        {
            const std::string& parent = it->first.second;
            // Security check for old saves:
            //If item is imported from old save(doesn't have an parent) and wasn't sold
            if(parent == "")
            {
                //Remove it, from shop,
                remove(it->first.first, itemCount, ptr);//ptr is the NPC
                //And remove it from map, so that when we restock, the new item will have proper parent.
                mLevelledItemMap.erase(it++);
                continue;
            }
            //Create the entry if it does not exist yet
            std::map<std::string, int>::iterator listInMap = allowedForReplace.insert(
                std::make_pair(it->first.second, 0)).first;
            //And signal that we don't need to restock item from this list
            listInMap->second += std::abs(itemCount);
        }
        //If every of the item was sold
        else if (itemCount == 0)
        {
            mLevelledItemMap.erase(it++);
            continue;
        }
        //If some was sold, but some remain
        else
        {
            //Create entry if it does not exist yet
            std::map<std::string, int>::iterator listInMap = allowedForReplace.insert(
                std::make_pair(it->first.second, 0)).first;
            //And signal that we don't need to restock all items from this list
            listInMap->second += std::abs(itemCount);
            //And update itemCount so we don't mistake it next time.
            it->second = itemCount;
        }
        ++it;
    }

    //Restock:
    //For every item that NPC could have
    for (std::vector<ESM::ContItem>::const_iterator it = items.mList.begin(); it != items.mList.end(); ++it)
    {
        //If he shouldn't have it restocked, don't restock it.
        if (it->mCount >= 0)
            continue;

        std::string itemOrList = Misc::StringUtils::lowerCase(it->mItem.toString());

        //If it's levelled list, restock if there's need to do so.
        if (MWBase::Environment::get().getWorld()->getStore().get<ESM::ItemLevList>().search(it->mItem.toString()))
        {
            std::map<std::string, int>::iterator listInMap = allowedForReplace.find(itemOrList);

            int restockNum = std::abs(it->mCount);
            //If we know we must restock less, take it into account
            if(listInMap != allowedForReplace.end())
                restockNum -= std::min(restockNum, listInMap->second);
            //restock
            addInitialItem(itemOrList, owner, -restockNum, true);
        }
        else
        {
            //Restocking static item - just restock to the max count
            int currentCount = restockCount(itemOrList);
            if (currentCount < std::abs(it->mCount))
                addInitialItem(itemOrList, owner, -(std::abs(it->mCount) - currentCount), true);
        }
    }
    flagAsModified();
}
Пример #26
0
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
{
    const MWBase::World *world = MWBase::Environment::get().getWorld();
    const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
    MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor);

    static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
    static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
    int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified();

    float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);

    TSlots slots_;
    initSlots (slots_);

    // Disable model update during auto-equip
    mUpdatesEnabled = false;

    // Autoequip clothing, armor and weapons.
    // Equipping lights is handled in Actors::updateEquippedLight based on environment light.
    for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter)
    {
        Ptr test = *iter;

        if (!canActorAutoEquip(actor, test))
            continue;

        switch(test.getClass().canBeEquipped (test, actor).first)
        {
            case 0:
                continue;
            default:
                break;
        }

        if (iter.getType() == ContainerStore::Type_Armor &&
                test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f))
        {
            continue;
        }

        std::pair<std::vector<int>, bool> itemsSlots =
            iter->getClass().getEquipmentSlots (*iter);

        // checking if current item poited by iter can be equipped
        for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
            iter2!=itemsSlots.first.end(); ++iter2)
        {
            // if true then it means slot is equipped already
            // check if slot may require swapping if current item is more valueable
            if (slots_.at (*iter2)!=end())
            {
                Ptr old = *slots_.at (*iter2);

                if (iter.getType() == ContainerStore::Type_Armor)
                {
                    if (old.getTypeName() == typeid(ESM::Armor).name())
                    {
                        if (old.get<ESM::Armor>()->mBase->mData.mType < test.get<ESM::Armor>()->mBase->mData.mType)
                            continue;

                        if (old.get<ESM::Armor>()->mBase->mData.mType == test.get<ESM::Armor>()->mBase->mData.mType)
                        {
                            if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor))
                                // old armor had better armor rating
                                continue;
                        }
                    }
                    // suitable armor should replace already equipped clothing
                }
                else if (iter.getType() == ContainerStore::Type_Clothing)
                {
                    // if left ring is equipped
                    if (*iter2 == Slot_LeftRing)
                    {
                        // if there is a place for right ring dont swap it
                        if (slots_.at(Slot_RightRing) == end())
                        {
                            continue;
                        }
                        else // if right ring is equipped too
                        {
                            Ptr rightRing = *slots_.at(Slot_RightRing);

                            // we want to swap cheaper ring only if both are equipped
                            if (old.getClass().getValue (old) >= rightRing.getClass().getValue (rightRing))
                                continue;
                        }
                    }

                    if (old.getTypeName() == typeid(ESM::Clothing).name())
                    {
                        // check value
                        if (old.getClass().getValue (old) >= test.getClass().getValue (test))
                            // old clothing was more valuable
                            continue;
                    }
                    else
                        // suitable clothing should NOT replace already equipped armor
                        continue;
                }
            }

            if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
            {
                // unstack item pointed to by iterator if required
                if (iter->getRefData().getCount() > 1)
                {
                    unstack(*iter, actor);
                }
            }

            // if we are here it means item can be equipped or swapped
            slots_[*iter2] = iter;
            break;
        }
    }

    static const ESM::Skill::SkillEnum weaponSkills[] =
    {
        ESM::Skill::LongBlade,
        ESM::Skill::Axe,
        ESM::Skill::Spear,
        ESM::Skill::ShortBlade,
        ESM::Skill::Marksman,
        ESM::Skill::BluntWeapon
    };
    const size_t weaponSkillsLength = sizeof(weaponSkills) / sizeof(weaponSkills[0]);

    bool weaponSkillVisited[weaponSkillsLength] = { false };

    for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
    {
        int max = 0;
        int maxWeaponSkill = -1;

        for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
        {
            int skillValue = stats.getSkill(static_cast<int>(weaponSkills[j])).getModified();

            if (skillValue > max && !weaponSkillVisited[j])
            {
                max = skillValue;
                maxWeaponSkill = j;
            }
        }

        if (maxWeaponSkill == -1)
            break;

        max = 0;
        ContainerStoreIterator weapon(end());

        for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter)
        {
            if (!canActorAutoEquip(actor, *iter))
                continue;

            const ESM::Weapon* esmWeapon = iter->get<ESM::Weapon>()->mBase;

            if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt)
                continue;

            if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill])
            {
                if (esmWeapon->mData.mChop[1] >= max)
                {
                    max = esmWeapon->mData.mChop[1];
                    weapon = iter;
                }

                if (esmWeapon->mData.mSlash[1] >= max)
                {
                    max = esmWeapon->mData.mSlash[1];
                    weapon = iter;
                }

                if (esmWeapon->mData.mThrust[1] >= max)
                {
                    max = esmWeapon->mData.mThrust[1];
                    weapon = iter;
                }
            }
        }

        if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first)
        {
            std::pair<std::vector<int>, bool> itemsSlots =
                weapon->getClass().getEquipmentSlots (*weapon);

            if (!itemsSlots.first.empty())
            {
                if (!itemsSlots.second)
                {
                    if (weapon->getRefData().getCount() > 1)
                    {
                        unstack(*weapon, actor);
                    }
                }

                int slot = itemsSlots.first.front();
                slots_[slot] = weapon;
            }

            break;
        }

        weaponSkillVisited[maxWeaponSkill] = true;
    }

    bool changed = false;

    for (std::size_t i=0; i<slots_.size(); ++i)
    {
        if (slots_[i] != mSlots[i])
        {
            changed = true;
            break;
        }
    }
    mUpdatesEnabled = true;

    if (changed)
    {
        mSlots.swap (slots_);
        fireEquipmentChangedEvent(actor);
        updateMagicEffects(actor);
        flagAsModified();
    }
}