void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { if (count == 0) return; //Don't restock with nothing. try { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { const ESM::ItemLevList* levItemList = ref.getPtr().get<ESM::ItemLevList>()->mBase; if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each) { for (int i=0; i<std::abs(count); ++i) addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItemList->mId); return; } else { std::string itemId = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false); if (itemId.empty()) return; addInitialItem(itemId, owner, count, false, levItemList->mId); } } else { // A negative count indicates restocking items // For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks if (!levItem.empty() && count < 0) { //If there is no item in map, insert it std::map<std::pair<std::string, std::string>, int>::iterator itemInMap = mLevelledItemMap.insert(std::make_pair(std::make_pair(id, levItem), 0)).first; //Update spawned count itemInMap->second += std::abs(count); } count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); addImp (ref.getPtr(), count); } } catch (const std::exception& e) { std::cerr << "Warning: MWWorld::ContainerStore::addInitialItem: " << e.what() << std::endl; } }
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(); }
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, unsigned char failChance, bool topLevel) { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) try { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { const ESM::ItemLevList* levItem = ref.getPtr().get<ESM::ItemLevList>()->mBase; const std::vector<ESM::LeveledListBase::LevelItem>& items = levItem->mList; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); failChance += levItem->mChanceNone; if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i<count; ++i) addInitialItem(id, owner, 1, failChance, false); return; } float random = static_cast<float> (std::rand()) / RAND_MAX; if (random >= failChance/100.f) { std::vector<std::string> candidates; int highestLevel = 0; for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->mLevel > highestLevel) highestLevel = it->mLevel; } std::pair<int, std::string> highest = std::make_pair(-1, ""); for (std::vector<ESM::LeveledListBase::LevelItem>::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, count, failChance, false); } } else { ref.getPtr().getRefData().setCount (count); ref.getPtr().getCellRef().mOwner = owner; addImp (ref.getPtr()); } } catch (std::logic_error& e) { // Vanilla doesn't fail on nonexistent items in levelled lists std::cerr << "Warning: ignoring nonexistent item '" << id << "'" << std::endl; return; } }
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(); }