forked from teamnwah/openmw-tes3coop
Store selected enchant item in savegame (Fixes #1702)
This commit is contained in:
parent
e484a91708
commit
79d2eebe54
7 changed files with 145 additions and 100 deletions
|
@ -7,6 +7,7 @@ namespace ESSImport
|
|||
|
||||
void convertInventory(const Inventory &inventory, ESM::InventoryState &state)
|
||||
{
|
||||
int index = 0;
|
||||
for (std::vector<Inventory::InventoryItem>::const_iterator it = inventory.mItems.begin();
|
||||
it != inventory.mItems.end(); ++it)
|
||||
{
|
||||
|
@ -16,7 +17,13 @@ namespace ESSImport
|
|||
objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId);
|
||||
objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile
|
||||
// openmw handles them differently, so no need to set any flags
|
||||
state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot));
|
||||
state.mItems.push_back(objstate);
|
||||
if (it->mRelativeEquipmentSlot != -1)
|
||||
// Note we should really write the absolute slot here, which we do not know about
|
||||
// Not a big deal, OpenMW will auto-correct to a valid slot, the only problem is when
|
||||
// an item could be equipped in two different slots (e.g. equipped two rings)
|
||||
state.mEquipmentSlots[index] = it->mRelativeEquipmentSlot;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState (CellRefList<T
|
|||
return ContainerStoreIterator (this, --collection.mList.end());
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::storeEquipmentState(const MWWorld::LiveCellRefBase &ref, int index, ESM::InventoryState &inventory) const
|
||||
{
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::readEquipmentState(const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState &inventory)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MWWorld::ContainerStore::storeState (const LiveCellRef<T>& ref, ESM::ObjectState& state) const
|
||||
{
|
||||
|
@ -87,7 +95,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef<T>& ref, ESM::Object
|
|||
|
||||
template<typename T>
|
||||
void MWWorld::ContainerStore::storeStates (CellRefList<T>& collection,
|
||||
std::vector<std::pair<ESM::ObjectState, int> >& states, bool equipable) const
|
||||
ESM::InventoryState& inventory, int& index, bool equipable) const
|
||||
{
|
||||
for (typename CellRefList<T>::List::const_iterator iter (collection.mList.begin());
|
||||
iter!=collection.mList.end(); ++iter)
|
||||
|
@ -96,18 +104,13 @@ void MWWorld::ContainerStore::storeStates (CellRefList<T>& collection,
|
|||
continue;
|
||||
ESM::ObjectState state;
|
||||
storeState (*iter, state);
|
||||
int slot = equipable ? getSlot (*iter) : -1;
|
||||
states.push_back (std::make_pair (state, slot));
|
||||
if (equipable)
|
||||
storeEquipmentState(*iter, index, inventory);
|
||||
inventory.mItems.push_back (state);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {}
|
||||
|
||||
const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
|
||||
|
||||
MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {}
|
||||
|
@ -645,49 +648,51 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state)
|
|||
{
|
||||
state.mItems.clear();
|
||||
|
||||
storeStates (potions, state.mItems);
|
||||
storeStates (appas, state.mItems);
|
||||
storeStates (armors, state.mItems, true);
|
||||
storeStates (books, state.mItems);
|
||||
storeStates (clothes, state.mItems, true);
|
||||
storeStates (ingreds, state.mItems);
|
||||
storeStates (lockpicks, state.mItems, true);
|
||||
storeStates (miscItems, state.mItems);
|
||||
storeStates (probes, state.mItems, true);
|
||||
storeStates (repairs, state.mItems);
|
||||
storeStates (weapons, state.mItems, true);
|
||||
storeStates (lights, state.mItems, true);
|
||||
int index = 0;
|
||||
storeStates (potions, state, index);
|
||||
storeStates (appas, state, index);
|
||||
storeStates (armors, state, index, true);
|
||||
storeStates (books, state, index, true); // not equipable as such, but for selectedEnchantItem
|
||||
storeStates (clothes, state, index, true);
|
||||
storeStates (ingreds, state, index);
|
||||
storeStates (lockpicks, state, index, true);
|
||||
storeStates (miscItems, state, index);
|
||||
storeStates (probes, state, index, true);
|
||||
storeStates (repairs, state, index);
|
||||
storeStates (weapons, state, index, true);
|
||||
storeStates (lights, state, index, true);
|
||||
|
||||
state.mLevelledItemMap = mLevelledItemMap;
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::readState (const ESM::InventoryState& state)
|
||||
void MWWorld::ContainerStore::readState (const ESM::InventoryState& inventory)
|
||||
{
|
||||
clear();
|
||||
|
||||
for (std::vector<std::pair<ESM::ObjectState, int> >::const_iterator
|
||||
iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter)
|
||||
int index = 0;
|
||||
for (std::vector<ESM::ObjectState>::const_iterator
|
||||
iter (inventory.mItems.begin()); iter!=inventory.mItems.end(); ++iter)
|
||||
{
|
||||
int slot = iter->second;
|
||||
|
||||
const ESM::ObjectState& state = iter->first;
|
||||
const ESM::ObjectState& state = *iter;
|
||||
|
||||
int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID);
|
||||
|
||||
int thisIndex = index++;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ESM::REC_ALCH: getState (potions, iter->first); break;
|
||||
case ESM::REC_APPA: getState (appas, iter->first); break;
|
||||
case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break;
|
||||
case ESM::REC_BOOK: getState (books, iter->first); break;
|
||||
case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break;
|
||||
case ESM::REC_INGR: getState (ingreds, iter->first); break;
|
||||
case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break;
|
||||
case ESM::REC_MISC: getState (miscItems, iter->first); break;
|
||||
case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break;
|
||||
case ESM::REC_REPA: getState (repairs, iter->first); break;
|
||||
case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break;
|
||||
case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break;
|
||||
case ESM::REC_ALCH: getState (potions, state); break;
|
||||
case ESM::REC_APPA: getState (appas, state); break;
|
||||
case ESM::REC_ARMO: readEquipmentState (getState (armors, state), thisIndex, inventory); break;
|
||||
case ESM::REC_BOOK: readEquipmentState (getState (books, state), thisIndex, inventory); break; // not equipable as such, but for selectedEnchantItem
|
||||
case ESM::REC_CLOT: readEquipmentState (getState (clothes, state), thisIndex, inventory); break;
|
||||
case ESM::REC_INGR: getState (ingreds, state); break;
|
||||
case ESM::REC_LOCK: readEquipmentState (getState (lockpicks, state), thisIndex, inventory); break;
|
||||
case ESM::REC_MISC: getState (miscItems, state); break;
|
||||
case ESM::REC_PROB: readEquipmentState (getState (probes, state), thisIndex, inventory); break;
|
||||
case ESM::REC_REPA: getState (repairs, state); break;
|
||||
case ESM::REC_WEAP: readEquipmentState (getState (weapons, state), thisIndex, inventory); break;
|
||||
case ESM::REC_LIGH: readEquipmentState (getState (lights, state), thisIndex, inventory); break;
|
||||
case 0:
|
||||
std::cerr << "Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl;
|
||||
break;
|
||||
|
@ -698,7 +703,7 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state)
|
|||
}
|
||||
|
||||
|
||||
mLevelledItemMap = state.mLevelledItemMap;
|
||||
mLevelledItemMap = inventory.mLevelledItemMap;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -86,15 +86,12 @@ namespace MWWorld
|
|||
|
||||
template<typename T>
|
||||
void storeStates (CellRefList<T>& collection,
|
||||
std::vector<std::pair<ESM::ObjectState, int> >& states,
|
||||
ESM::InventoryState& inventory, int& index,
|
||||
bool equipable = false) const;
|
||||
|
||||
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const;
|
||||
///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot).
|
||||
|
||||
virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot);
|
||||
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
|
||||
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
|
||||
|
||||
virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory);
|
||||
public:
|
||||
|
||||
ContainerStore();
|
||||
|
|
|
@ -49,33 +49,47 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_)
|
|||
slots_.push_back (end());
|
||||
}
|
||||
|
||||
int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const
|
||||
void MWWorld::InventoryStore::storeEquipmentState(const MWWorld::LiveCellRefBase &ref, int index, ESM::InventoryState &inventory) const
|
||||
{
|
||||
for (int i = 0; i<static_cast<int> (mSlots.size()); ++i)
|
||||
if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref)
|
||||
return i;
|
||||
{
|
||||
inventory.mEquipmentSlots[index] = i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (mSelectedEnchantItem.getType()!=-1 && mSelectedEnchantItem->getBase() == &ref)
|
||||
inventory.mSelectedEnchantItem = index;
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot)
|
||||
void MWWorld::InventoryStore::readEquipmentState(const MWWorld::ContainerStoreIterator &iter, int index, const ESM::InventoryState &inventory)
|
||||
{
|
||||
if (relativeSlot < 0 || iter == end())
|
||||
return;
|
||||
if (index == inventory.mSelectedEnchantItem)
|
||||
mSelectedEnchantItem = iter;
|
||||
|
||||
// make sure the item can actually be equipped in this slot
|
||||
std::pair<std::vector<int>, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter);
|
||||
relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot);
|
||||
|
||||
// unstack if required
|
||||
if (!allowedSlots.second && iter->getRefData().getCount() > 1)
|
||||
std::map<int, int>::const_iterator found = inventory.mEquipmentSlots.find(index);
|
||||
if (found != inventory.mEquipmentSlots.end())
|
||||
{
|
||||
MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1);
|
||||
iter->getRefData().setCount(iter->getRefData().getCount()-1);
|
||||
mSlots[allowedSlots.first[relativeSlot]] = newIter;
|
||||
if (found->second < 0 || found->second >= MWWorld::InventoryStore::Slots)
|
||||
throw std::runtime_error("Invalid slot index in inventory state");
|
||||
|
||||
// make sure the item can actually be equipped in this slot
|
||||
int slot = found->second;
|
||||
std::pair<std::vector<int>, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter);
|
||||
if (!allowedSlots.first.size())
|
||||
return;
|
||||
if (std::find(allowedSlots.first.begin(), allowedSlots.first.end(), slot) == allowedSlots.first.end())
|
||||
slot = allowedSlots.first.front();
|
||||
|
||||
// unstack if required
|
||||
if (!allowedSlots.second && iter->getRefData().getCount() > 1)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1);
|
||||
iter->getRefData().setCount(iter->getRefData().getCount()-1);
|
||||
mSlots[slot] = newIter;
|
||||
}
|
||||
else
|
||||
mSlots[slot] = iter;
|
||||
}
|
||||
else
|
||||
mSlots[allowedSlots.first[relativeSlot]] = iter;
|
||||
}
|
||||
|
||||
MWWorld::InventoryStore::InventoryStore()
|
||||
|
|
|
@ -113,11 +113,8 @@ namespace MWWorld
|
|||
|
||||
void fireEquipmentChangedEvent();
|
||||
|
||||
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const;
|
||||
///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot).
|
||||
|
||||
virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot);
|
||||
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
|
||||
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
|
||||
virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -4,42 +4,33 @@
|
|||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
void read (ESM::ESMReader &esm, ESM::ObjectState& state, int& slot)
|
||||
{
|
||||
slot = -1;
|
||||
esm.getHNOT (slot, "SLOT");
|
||||
|
||||
state.mRef.loadId(esm, true);
|
||||
state.load (esm);
|
||||
}
|
||||
|
||||
void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, int slot)
|
||||
{
|
||||
int unused = 0;
|
||||
esm.writeHNT ("IOBJ", unused);
|
||||
|
||||
if (slot!=-1)
|
||||
esm.writeHNT ("SLOT", slot);
|
||||
|
||||
state.save (esm, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::InventoryState::load (ESMReader &esm)
|
||||
{
|
||||
int index = 0;
|
||||
while (esm.isNextSub ("IOBJ"))
|
||||
{
|
||||
int unused; // no longer used
|
||||
esm.getHT(unused);
|
||||
|
||||
ObjectState state;
|
||||
int slot;
|
||||
read (esm, state, slot);
|
||||
|
||||
// obsolete
|
||||
if (esm.isNextSub("SLOT"))
|
||||
{
|
||||
int slot;
|
||||
esm.getHT(slot);
|
||||
mEquipmentSlots[index] = slot;
|
||||
}
|
||||
|
||||
state.mRef.loadId(esm, true);
|
||||
state.load (esm);
|
||||
|
||||
if (state.mCount == 0)
|
||||
continue;
|
||||
mItems.push_back (std::make_pair (state, slot));
|
||||
|
||||
mItems.push_back (state);
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
while (esm.isNextSub("LEVM"))
|
||||
|
@ -64,12 +55,30 @@ void ESM::InventoryState::load (ESMReader &esm)
|
|||
}
|
||||
mPermanentMagicEffectMagnitudes[id] = params;
|
||||
}
|
||||
|
||||
while (esm.isNextSub("EQUI"))
|
||||
{
|
||||
esm.getSubHeader();
|
||||
int index;
|
||||
esm.getT(index);
|
||||
int slot;
|
||||
esm.getT(slot);
|
||||
mEquipmentSlots[index] = slot;
|
||||
}
|
||||
|
||||
mSelectedEnchantItem = -1;
|
||||
esm.getHNOT(mSelectedEnchantItem, "SELE");
|
||||
}
|
||||
|
||||
void ESM::InventoryState::save (ESMWriter &esm) const
|
||||
{
|
||||
for (std::vector<std::pair<ObjectState, int> >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter)
|
||||
write (esm, iter->first, iter->second);
|
||||
for (std::vector<ObjectState>::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter)
|
||||
{
|
||||
int unused = 0;
|
||||
esm.writeHNT ("IOBJ", unused);
|
||||
|
||||
iter->save (esm, true);
|
||||
}
|
||||
|
||||
for (std::map<std::string, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
|
||||
{
|
||||
|
@ -88,4 +97,15 @@ void ESM::InventoryState::save (ESMWriter &esm) const
|
|||
esm.writeHNT ("MULT", pIt->second);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<int, int>::const_iterator it = mEquipmentSlots.begin(); it != mEquipmentSlots.end(); ++it)
|
||||
{
|
||||
esm.startSubRecord("EQUI");
|
||||
esm.writeT(it->first);
|
||||
esm.writeT(it->second);
|
||||
esm.endRecord("EQUI");
|
||||
}
|
||||
|
||||
if (mSelectedEnchantItem != -1)
|
||||
esm.writeHNT ("SELE", mSelectedEnchantItem);
|
||||
}
|
||||
|
|
|
@ -15,14 +15,19 @@ namespace ESM
|
|||
/// \brief State for inventories and containers
|
||||
struct InventoryState
|
||||
{
|
||||
/// <ObjectState, relative equipment slot>
|
||||
std::vector<std::pair<ObjectState, int> > mItems;
|
||||
std::vector<ObjectState> mItems;
|
||||
|
||||
// <Index in mItems, equipment slot>
|
||||
std::map<int, int> mEquipmentSlots;
|
||||
|
||||
std::map<std::string, int> mLevelledItemMap;
|
||||
|
||||
typedef std::map<std::string, std::vector<std::pair<float, float> > > TEffectMagnitudes;
|
||||
TEffectMagnitudes mPermanentMagicEffectMagnitudes;
|
||||
|
||||
int mSelectedEnchantItem; // For inventories only
|
||||
|
||||
InventoryState() : mSelectedEnchantItem(-1) {}
|
||||
virtual ~InventoryState() {}
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
|
|
Loading…
Reference in a new issue