Merge pull request #850 from MatthewRock/fix-2952-2

Fix for bug #2952: Enchantment Merchant Items reshuffled EVERY time 'barter' is clicked
openmw-38
scrawl 9 years ago
commit 57b7cac13f

@ -74,6 +74,7 @@ Programmers
Marco Melletti (mellotanica)
Marco Schulze
Mateusz Kołaczek (PL_kolek)
Mateusz Malisz (malice)
megaton
Michael Hogan (Xethik)
Michael Mc Donnell

@ -415,6 +415,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::
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);
@ -442,9 +443,11 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
// 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 (mLevelledItemMap.find(id) == mLevelledItemMap.end())
mLevelledItemMap[id] = 0;
mLevelledItemMap[id] += std::abs(count);
//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);
@ -461,30 +464,84 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)
{
// Remove the items already spawned by levelled items that will restock
for (std::map<std::string, int>::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
//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();)
{
if (count(it->first) >= it->second)
remove(it->first, it->second, ptr);
int spawnedCount = it->second; //How many items should be in shop originally
int itemCount = count(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;
}
mLevelledItemMap.clear();
//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 item = Misc::StringUtils::lowerCase(it->mItem.toString());
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()))
{
addInitialItem(item, owner, it->mCount, true);
std::map<std::string, int>::iterator listInMap = allowedForReplace.find(itemOrList);
int restockNum = it->mCount;
//If we know we must restock less, take it into account
if(listInMap != allowedForReplace.end())
restockNum += listInMap->second;//We add, because list items have negative count
//restock
addInitialItem(itemOrList, owner, restockNum, true);
}
else
{
int currentCount = count(item);
//Restocking static item - just restock to the max count
int currentCount = count(itemOrList);
if (currentCount < std::abs(it->mCount))
addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true);
addInitialItem(itemOrList, owner, std::abs(it->mCount) - currentCount, true);
}
}
flagAsModified();

@ -3,6 +3,7 @@
#include <iterator>
#include <map>
#include <utility>
#include <components/esm/loadalch.hpp>
#include <components/esm/loadappa.hpp>
@ -68,9 +69,9 @@ namespace MWWorld
MWWorld::CellRefList<ESM::Repair> repairs;
MWWorld::CellRefList<ESM::Weapon> weapons;
std::map<std::string, int> mLevelledItemMap;
///< Stores result of levelled item spawns. <refId, count>
/// This is used to remove the spawned item(s) if the levelled item is restocked.
std::map<std::pair<std::string, std::string>, int> mLevelledItemMap;
///< Stores result of levelled item spawns. <(refId, spawningGroup), count>
/// This is used to restock levelled items(s) if the old item was sold.
mutable float mCachedWeight;
mutable bool mWeightUpToDate;

@ -31,13 +31,20 @@ void ESM::InventoryState::load (ESMReader &esm)
++index;
}
//Next item is Levelled item
while (esm.isNextSub("LEVM"))
{
//Get its name
std::string id = esm.getHString();
int count;
std::string parentGroup = "";
//Then get its count
esm.getHNT (count, "COUN");
mLevelledItemMap[id] = count;
//Old save formats don't have information about parent group; check for that
if(esm.isNextSub("LGRP"))
//Newest saves contain parent group
parentGroup = esm.getHString();
mLevelledItemMap[std::make_pair(id, parentGroup)] = count;
}
while (esm.isNextSub("MAGI"))
@ -79,10 +86,11 @@ void ESM::InventoryState::save (ESMWriter &esm) const
iter->save (esm, true);
}
for (std::map<std::string, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
for (std::map<std::pair<std::string, std::string>, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
{
esm.writeHNString ("LEVM", it->first);
esm.writeHNString ("LEVM", it->first.first);
esm.writeHNT ("COUN", it->second);
esm.writeHNString("LGRP", it->first.second);
}
for (TEffectMagnitudes::const_iterator it = mPermanentMagicEffectMagnitudes.begin(); it != mPermanentMagicEffectMagnitudes.end(); ++it)

@ -20,7 +20,7 @@ namespace ESM
// <Index in mItems, equipment slot>
std::map<int, int> mEquipmentSlots;
std::map<std::string, int> mLevelledItemMap;
std::map<std::pair<std::string, std::string>, int> mLevelledItemMap;
typedef std::map<std::string, std::vector<std::pair<float, float> > > TEffectMagnitudes;
TEffectMagnitudes mPermanentMagicEffectMagnitudes;

Loading…
Cancel
Save