diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index eb5b71ec3..4da5e2997 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting - disease pickpocket + disease pickpocket levelledlist ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp new file mode 100644 index 000000000..af5f71f51 --- /dev/null +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -0,0 +1,78 @@ +#ifndef OPENMW_MECHANICS_LEVELLEDLIST_H +#define OPENMW_MECHANICS_LEVELLEDLIST_H + +#include "../mwworld/ptr.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwworld/class.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +namespace MWMechanics +{ + + /// @return ID of resulting item, or empty if none + std::string getLevelledItem (const ESM::LeveledListBase* levItem, unsigned char failChance=0) + { + const std::vector& items = levItem->mList; + + const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + int playerLevel = player.getClass().getCreatureStats(player).getLevel(); + + failChance += levItem->mChanceNone; + + float random = static_cast (std::rand()) / RAND_MAX; + if (random < failChance/100.f) + return std::string(); + + std::vector candidates; + int highestLevel = 0; + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (it->mLevel > highestLevel) + highestLevel = it->mLevel; + } + + std::pair highest = std::make_pair(-1, ""); + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (playerLevel >= it->mLevel + && (levItem->mFlags & ESM::LeveledListBase::AllLevels || it->mLevel == highestLevel)) + { + candidates.push_back(it->mId); + if (it->mLevel >= highest.first) + highest = std::make_pair(it->mLevel, it->mId); + } + + } + if (candidates.empty()) + return std::string(); + std::string item = candidates[std::rand()%candidates.size()]; + + // Is this another levelled item or a real item? + try + { + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, 1); + if (ref.getPtr().getTypeName() != typeid(ESM::ItemLevList).name() + && ref.getPtr().getTypeName() != typeid(ESM::CreatureLevList).name()) + { + return item; + } + else + { + if (ref.getPtr().getTypeName() == typeid(ESM::ItemLevList).name()) + return getLevelledItem(ref.getPtr().get()->mBase, failChance); + else + return getLevelledItem(ref.getPtr().get()->mBase, failChance); + } + } + catch (std::logic_error& e) + { + // Vanilla doesn't fail on nonexistent items in levelled lists + std::cerr << "Warning: ignoring nonexistent item '" << item << "'" << std::endl; + return std::string(); + } + } + +} + +#endif diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 744971985..864bb2a0d 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -5,17 +5,11 @@ #include #include -#include - -#include -#include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/scriptmanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/levelledlist.hpp" #include "manualref.hpp" #include "refdata.hpp" @@ -309,72 +303,35 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std:: } void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, - int count, unsigned char failChance, bool topLevel) + int count, bool topLevel) { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) - try + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); + + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); + const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { - const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - const std::vector& items = levItem->mList; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int playerLevel = player.getClass().getCreatureStats(player).getLevel(); - - failChance += levItem->mChanceNone; - - if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) - { - for (int i=0; i (std::rand()) / RAND_MAX; - if (random >= failChance/100.f) - { - std::vector candidates; - int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) - { - if (it->mLevel > highestLevel) - highestLevel = it->mLevel; - } - - std::pair highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) - { - if (playerLevel >= it->mLevel - && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) - { - candidates.push_back(it->mId); - if (it->mLevel >= highest.first) - highest = std::make_pair(it->mLevel, it->mId); - } - - } - if (candidates.empty()) - return; - std::string item = candidates[std::rand()%candidates.size()]; - addInitialItem(item, owner, faction, count, failChance, false); - } + for (int i=0; i()->mBase); + if (id.empty()) + return; + addInitialItem(id, owner, faction, count, false); } } - catch (std::logic_error& e) + else { - // Vanilla doesn't fail on nonexistent items in levelled lists - std::cerr << "Warning: ignoring nonexistent item '" << id << "'" << std::endl; - return; + ref.getPtr().getCellRef().mOwner = owner; + ref.getPtr().getCellRef().mFaction = faction; + addImp (ref.getPtr(), count); } } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 936468f8d..0a1728740 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -54,7 +54,7 @@ namespace MWWorld mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr, int count); - void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, unsigned char failChance=0, bool topLevel=true); + void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true); public: