mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-06 16:45:36 +00:00
Feature #1323: handle restocking levelled items
This commit is contained in:
parent
90ec19c3ac
commit
a872c9f83a
7 changed files with 85 additions and 41 deletions
|
@ -74,16 +74,8 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
||||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||||
for (std::vector<ESM::ContItem>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->mCount < 0)
|
|
||||||
{
|
|
||||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||||
int currentCount = store.count(it->mItem.toString());
|
store.restock(list, ptr, ptr.getCellRef().mOwner, ptr.getCellRef().mFaction);
|
||||||
if (currentCount < std::abs(it->mCount))
|
|
||||||
store.add (it->mItem.toString(), std::abs(it->mCount) - currentCount, ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
|
|
@ -843,16 +843,8 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||||
for (std::vector<ESM::ContItem>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->mCount < 0)
|
|
||||||
{
|
|
||||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||||
int currentCount = store.count(it->mItem.toString());
|
store.restock(list, ptr, ptr.getCellRef().mRefID, ptr.getCellRef().mFaction);
|
||||||
if (currentCount < std::abs(it->mCount))
|
|
||||||
store.add (it->mItem.toString(), std::abs(it->mCount) - currentCount, ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
||||||
|
|
|
@ -1334,16 +1334,8 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||||
for (std::vector<ESM::ContItem>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->mCount < 0)
|
|
||||||
{
|
|
||||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||||
int currentCount = store.count(it->mItem.toString());
|
store.restock(list, ptr, ptr.getCellRef().mRefID, ptr.getCellRef().mFaction);
|
||||||
if (currentCount < std::abs(it->mCount))
|
|
||||||
store.add (it->mItem.toString(), std::abs(it->mCount) - currentCount, ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
||||||
|
|
|
@ -366,7 +366,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::
|
||||||
for (std::vector<ESM::ContItem>::const_iterator iter (items.mList.begin()); iter!=items.mList.end();
|
for (std::vector<ESM::ContItem>::const_iterator iter (items.mList.begin()); iter!=items.mList.end();
|
||||||
++iter)
|
++iter)
|
||||||
{
|
{
|
||||||
std::string id = iter->mItem.toString();
|
std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString());
|
||||||
addInitialItem(id, owner, faction, iter->mCount);
|
addInitialItem(id, owner, faction, iter->mCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,21 +374,18 @@ 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,
|
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction,
|
||||||
int count, bool topLevel)
|
int count, bool topLevel, const std::string& levItem)
|
||||||
{
|
{
|
||||||
// A negative count indicates restocking items, but this is implemented elsewhere
|
|
||||||
count = std::abs(count);
|
|
||||||
|
|
||||||
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
||||||
|
|
||||||
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
||||||
{
|
{
|
||||||
const ESM::ItemLevList* levItem = ref.getPtr().get<ESM::ItemLevList>()->mBase;
|
const ESM::ItemLevList* levItem = ref.getPtr().get<ESM::ItemLevList>()->mBase;
|
||||||
|
|
||||||
if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each)
|
if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each)
|
||||||
{
|
{
|
||||||
for (int i=0; i<count; ++i)
|
for (int i=0; i<std::abs(count); ++i)
|
||||||
addInitialItem(id, owner, faction, 1);
|
addInitialItem(id, owner, faction, count > 0 ? 1 : -1, true, levItem->mId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -396,17 +393,58 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
|
||||||
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
|
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
|
||||||
if (id.empty())
|
if (id.empty())
|
||||||
return;
|
return;
|
||||||
addInitialItem(id, owner, faction, count, false);
|
addInitialItem(id, owner, faction, count, false, levItem->mId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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 (mLevelledItemMap.find(id) == mLevelledItemMap.end())
|
||||||
|
mLevelledItemMap[id] = 0;
|
||||||
|
mLevelledItemMap[id] += std::abs(count);
|
||||||
|
}
|
||||||
|
count = std::abs(count);
|
||||||
|
|
||||||
ref.getPtr().getCellRef().mOwner = owner;
|
ref.getPtr().getCellRef().mOwner = owner;
|
||||||
ref.getPtr().getCellRef().mFaction = faction;
|
ref.getPtr().getCellRef().mFaction = faction;
|
||||||
addImp (ref.getPtr(), count);
|
addImp (ref.getPtr(), count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction)
|
||||||
|
{
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
if (count(it->first) >= it->second)
|
||||||
|
remove(it->first, it->second, ptr);
|
||||||
|
}
|
||||||
|
mLevelledItemMap.clear();
|
||||||
|
|
||||||
|
for (std::vector<ESM::ContItem>::const_iterator it = items.mList.begin(); it != items.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->mCount >= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string item = Misc::StringUtils::lowerCase(it->mItem.toString());
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWorld()->getStore().get<ESM::ItemLevList>().search(it->mItem.toString()))
|
||||||
|
{
|
||||||
|
addInitialItem(item, owner, faction, it->mCount, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int currentCount = count(item);
|
||||||
|
if (currentCount < std::abs(it->mCount))
|
||||||
|
add (item, std::abs(it->mCount) - currentCount, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
void MWWorld::ContainerStore::clear()
|
void MWWorld::ContainerStore::clear()
|
||||||
{
|
{
|
||||||
for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter)
|
for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter)
|
||||||
|
@ -585,6 +623,8 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const
|
||||||
|
|
||||||
state.mLights.clear();
|
state.mLights.clear();
|
||||||
|
|
||||||
|
state.mLevelledItemMap = mLevelledItemMap;
|
||||||
|
|
||||||
for (MWWorld::CellRefList<ESM::Light>::List::const_iterator iter (lights.mList.begin());
|
for (MWWorld::CellRefList<ESM::Light>::List::const_iterator iter (lights.mList.begin());
|
||||||
iter!=lights.mList.end(); ++iter)
|
iter!=lights.mList.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
@ -628,6 +668,8 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state)
|
||||||
{
|
{
|
||||||
getState (lights, iter->first);
|
getState (lights, iter->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mLevelledItemMap = state.mLevelledItemMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define GAME_MWWORLD_CONTAINERSTORE_H
|
#define GAME_MWWORLD_CONTAINERSTORE_H
|
||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <components/esm/loadalch.hpp>
|
#include <components/esm/loadalch.hpp>
|
||||||
#include <components/esm/loadappa.hpp>
|
#include <components/esm/loadappa.hpp>
|
||||||
|
@ -65,10 +66,15 @@ namespace MWWorld
|
||||||
MWWorld::CellRefList<ESM::Probe> probes;
|
MWWorld::CellRefList<ESM::Probe> probes;
|
||||||
MWWorld::CellRefList<ESM::Repair> repairs;
|
MWWorld::CellRefList<ESM::Repair> repairs;
|
||||||
MWWorld::CellRefList<ESM::Weapon> weapons;
|
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.
|
||||||
|
|
||||||
mutable float mCachedWeight;
|
mutable float mCachedWeight;
|
||||||
mutable bool mWeightUpToDate;
|
mutable bool mWeightUpToDate;
|
||||||
ContainerStoreIterator addImp (const Ptr& ptr, int count);
|
ContainerStoreIterator addImp (const Ptr& ptr, int count);
|
||||||
void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true);
|
void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true, const std::string& levItem = "");
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ContainerStoreIterator getState (CellRefList<T>& collection,
|
ContainerStoreIterator getState (CellRefList<T>& collection,
|
||||||
|
@ -145,6 +151,8 @@ namespace MWWorld
|
||||||
void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, const MWWorld::ESMStore& store);
|
void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, const MWWorld::ESMStore& store);
|
||||||
///< Insert items into *this.
|
///< Insert items into *this.
|
||||||
|
|
||||||
|
void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction);
|
||||||
|
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
///< Empty container.
|
///< Empty container.
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,14 @@ void ESM::InventoryState::load (ESMReader &esm)
|
||||||
mItems.push_back (std::make_pair (state, std::make_pair (id, slot)));
|
mItems.push_back (std::make_pair (state, std::make_pair (id, slot)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (esm.isNextSub("LEVM"))
|
||||||
|
{
|
||||||
|
std::string id = esm.getHString();
|
||||||
|
int count;
|
||||||
|
esm.getHNT (count, "COUN");
|
||||||
|
mLevelledItemMap[id] = count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESM::InventoryState::save (ESMWriter &esm) const
|
void ESM::InventoryState::save (ESMWriter &esm) const
|
||||||
|
@ -57,4 +65,10 @@ void ESM::InventoryState::save (ESMWriter &esm) const
|
||||||
for (std::vector<std::pair<LightState, int> >::const_iterator iter (mLights.begin());
|
for (std::vector<std::pair<LightState, int> >::const_iterator iter (mLights.begin());
|
||||||
iter!=mLights.end(); ++iter)
|
iter!=mLights.end(); ++iter)
|
||||||
write (esm, iter->first, ESM::REC_LIGH, iter->second);
|
write (esm, iter->first, ESM::REC_LIGH, iter->second);
|
||||||
|
|
||||||
|
for (std::map<std::string, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.writeHNString ("LEVM", it->first);
|
||||||
|
esm.writeHNT ("COUN", it->second);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef OPENMW_ESM_INVENTORYSTATE_H
|
#ifndef OPENMW_ESM_INVENTORYSTATE_H
|
||||||
#define OPENMW_ESM_INVENTORYSTATE_H
|
#define OPENMW_ESM_INVENTORYSTATE_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "objectstate.hpp"
|
#include "objectstate.hpp"
|
||||||
#include "lightstate.hpp"
|
#include "lightstate.hpp"
|
||||||
|
|
||||||
|
@ -20,6 +22,8 @@ namespace ESM
|
||||||
// lights (slot)
|
// lights (slot)
|
||||||
std::vector<std::pair<LightState, int> > mLights;
|
std::vector<std::pair<LightState, int> > mLights;
|
||||||
|
|
||||||
|
std::map<std::string, int> mLevelledItemMap;
|
||||||
|
|
||||||
virtual void load (ESMReader &esm);
|
virtual void load (ESMReader &esm);
|
||||||
virtual void save (ESMWriter &esm) const;
|
virtual void save (ESMWriter &esm) const;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue