Change save format to store relative equipment index

Store the index for the allowedSlots vector instead of the absolute slot index. This will more gracefully handle edge cases like the available slots for an item having changed when loading the game, or the "allows stacking" property having changed. However the main reason this was done is to ease work on the essimporter.
openmw-35
scrawl 10 years ago
parent 142a138b75
commit 89d9649b50

@ -466,7 +466,7 @@ namespace MWWorld
// List moved references, from separately tracked list. // List moved references, from separately tracked list.
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
{ {
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it); const ESM::CellRef &ref = *it;
mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID));
} }

@ -85,28 +85,29 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef<T>& ref, ESM::Object
ref.save (state); ref.save (state);
} }
/// \todo make this method const once const-correct ContainerStoreIterators are available
template<typename T> template<typename T>
void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection, void MWWorld::ContainerStore::storeStates (CellRefList<T>& collection,
std::vector<std::pair<ESM::ObjectState, int> >& states, bool equipable) const std::vector<std::pair<ESM::ObjectState, int> >& states, bool equipable)
{ {
for (typename CellRefList<T>::List::const_iterator iter (collection.mList.begin()); for (typename CellRefList<T>::List::iterator iter (collection.mList.begin());
iter!=collection.mList.end(); ++iter) iter!=collection.mList.end(); ++iter)
{ {
if (iter->mData.getCount() == 0) if (iter->mData.getCount() == 0)
continue; continue;
ESM::ObjectState state; ESM::ObjectState state;
storeState (*iter, state); storeState (*iter, state);
int slot = equipable ? getSlot (*iter) : -1; int slot = equipable ? getRelativeSlot (MWWorld::ContainerStoreIterator(this, iter)) : -1;
states.push_back (std::make_pair (state, slot)); states.push_back (std::make_pair (state, slot));
} }
} }
int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const int MWWorld::ContainerStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const
{ {
return -1; return -1;
} }
void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} void MWWorld::ContainerStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {}
const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
@ -641,7 +642,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id)
return Ptr(); return Ptr();
} }
void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const void MWWorld::ContainerStore::writeState (ESM::InventoryState& state)
{ {
state.mItems.clear(); state.mItems.clear();
@ -678,16 +679,16 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state)
{ {
case ESM::REC_ALCH: getState (potions, iter->first); break; case ESM::REC_ALCH: getState (potions, iter->first); break;
case ESM::REC_APPA: getState (appas, 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_ARMO: setRelativeSlot (getState (armors, iter->first), slot); break;
case ESM::REC_BOOK: getState (books, iter->first); break; case ESM::REC_BOOK: getState (books, iter->first); break;
case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break; case ESM::REC_CLOT: setRelativeSlot (getState (clothes, iter->first), slot); break;
case ESM::REC_INGR: getState (ingreds, iter->first); break; case ESM::REC_INGR: getState (ingreds, iter->first); break;
case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break; case ESM::REC_LOCK: setRelativeSlot (getState (lockpicks, iter->first), slot); break;
case ESM::REC_MISC: getState (miscItems, iter->first); break; case ESM::REC_MISC: getState (miscItems, iter->first); break;
case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; case ESM::REC_PROB: setRelativeSlot (getState (probes, iter->first), slot); break;
case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_REPA: getState (repairs, iter->first); break;
case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; case ESM::REC_WEAP: setRelativeSlot (getState (weapons, iter->first), slot); break;
case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; case ESM::REC_LIGH: setRelativeSlot (getState (lights, iter->first), slot); break;
default: default:
std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl;

@ -84,15 +84,16 @@ namespace MWWorld
template<typename T> template<typename T>
void storeState (const LiveCellRef<T>& ref, ESM::ObjectState& state) const; void storeState (const LiveCellRef<T>& ref, ESM::ObjectState& state) const;
/// \todo make this method const once const-correct ContainerStoreIterators are available
template<typename T> template<typename T>
void storeStates (const CellRefList<T>& collection, void storeStates (CellRefList<T>& collection,
std::vector<std::pair<ESM::ObjectState, int> >& states, std::vector<std::pair<ESM::ObjectState, int> >& states,
bool equipable = false) const; bool equipable = false);
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const;
///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). ///< 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); virtual void setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot);
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
public: public:
@ -171,7 +172,8 @@ namespace MWWorld
Ptr search (const std::string& id); Ptr search (const std::string& id);
virtual void writeState (ESM::InventoryState& state) const; /// \todo make this method const once const-correct ContainerStoreIterators are available
virtual void writeState (ESM::InventoryState& state);
virtual void readState (const ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state);

@ -49,19 +49,40 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_)
slots_.push_back (end()); slots_.push_back (end());
} }
int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const int MWWorld::InventoryStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter)
{ {
for (int i = 0; i<static_cast<int> (mSlots.size()); ++i) for (int i = 0; i<static_cast<int> (mSlots.size()); ++i)
if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) if (mSlots[i].getType()!=-1 && mSlots[i] == iter)
return i; {
// linear complexity, but allowedSlots is most of the time just 1 anyway
std::vector<int> allowedSlots = iter->getClass().getEquipmentSlots(*iter).first;
std::vector<int>::iterator found = std::find(allowedSlots.begin(),allowedSlots.end(),i);
if (found == allowedSlots.end())
return -1;
else
return std::distance(allowedSlots.begin(), found);
}
return -1; return -1;
} }
void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) void MWWorld::InventoryStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot)
{ {
if (iter!=end() && slot>=0 && slot<Slots) if (relativeSlot < 0 || iter == end())
mSlots[slot] = iter; return;
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)
{
MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1);
iter->getRefData().setCount(iter->getRefData().getCount()-1);
mSlots[allowedSlots.first[relativeSlot]] = newIter;
}
else
mSlots[allowedSlots.first[relativeSlot]] = iter;
} }
MWWorld::InventoryStore::InventoryStore() MWWorld::InventoryStore::InventoryStore()
@ -703,7 +724,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item)
return false; return false;
} }
void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const void MWWorld::InventoryStore::writeState(ESM::InventoryState &state)
{ {
MWWorld::ContainerStore::writeState(state); MWWorld::ContainerStore::writeState(state);

@ -113,10 +113,10 @@ namespace MWWorld
void fireEquipmentChangedEvent(); void fireEquipmentChangedEvent();
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter);
///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). ///< 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); virtual void setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot);
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
public: public:
@ -209,7 +209,7 @@ namespace MWWorld
virtual void clear(); virtual void clear();
///< Empty container. ///< Empty container.
virtual void writeState (ESM::InventoryState& state) const; virtual void writeState (ESM::InventoryState& state);
virtual void readState (const ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state);
}; };

@ -2031,7 +2031,7 @@ namespace MWWorld
bool World::isOnGround(const MWWorld::Ptr &ptr) const bool World::isOnGround(const MWWorld::Ptr &ptr) const
{ {
RefData &refdata = ptr.getRefData(); RefData &refdata = ptr.getRefData();
const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle());
if(!physactor) if(!physactor)
return false; return false;
@ -2049,7 +2049,7 @@ namespace MWWorld
mPhysEngine); mPhysEngine);
if(tracer.mFraction < 1.0f) // collision, must be close to something below if(tracer.mFraction < 1.0f) // collision, must be close to something below
{ {
const_cast<OEngine::Physic::PhysicActor *> (physactor)->setOnGround(true); physactor->setOnGround(true);
return true; return true;
} }
else else

@ -15,6 +15,7 @@ namespace ESM
/// \brief State for inventories and containers /// \brief State for inventories and containers
struct InventoryState struct InventoryState
{ {
/// <ObjectState, relative equipment slot>
std::vector<std::pair<ObjectState, int> > mItems; std::vector<std::pair<ObjectState, int> > mItems;
std::map<std::string, int> mLevelledItemMap; std::map<std::string, int> mLevelledItemMap;

Loading…
Cancel
Save