From 89d9649b50b2b6e102b90517a5b136cc74415ba0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 23:55:26 +0100 Subject: [PATCH] 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. --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 27 ++++++++++---------- apps/openmw/mwworld/containerstore.hpp | 12 +++++---- apps/openmw/mwworld/inventorystore.cpp | 35 ++++++++++++++++++++------ apps/openmw/mwworld/inventorystore.hpp | 6 ++--- apps/openmw/mwworld/worldimp.cpp | 4 +-- components/esm/inventorystate.hpp | 1 + 7 files changed, 56 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 605c8f9d2..545bbd4b3 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -466,7 +466,7 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - ESM::CellRef &ref = const_cast(*it); + const ESM::CellRef &ref = *it; mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bd14720f7..5911b45f7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -85,28 +85,29 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object ref.save (state); } +/// \todo make this method const once const-correct ContainerStoreIterators are available template -void MWWorld::ContainerStore::storeStates (const CellRefList& collection, - std::vector >& states, bool equipable) const +void MWWorld::ContainerStore::storeStates (CellRefList& collection, + std::vector >& states, bool equipable) { - for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); + for (typename CellRefList::List::iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { if (iter->mData.getCount() == 0) continue; ESM::ObjectState 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)); } } -int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const +int MWWorld::ContainerStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const { 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"; @@ -641,7 +642,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { 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_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_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_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_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_WEAP: setSlot (getState (weapons, iter->first), slot); break; - case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case ESM::REC_WEAP: setRelativeSlot (getState (weapons, iter->first), slot); break; + case ESM::REC_LIGH: setRelativeSlot (getState (lights, iter->first), slot); break; default: std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 68ee41a1d..4a95606f7 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -84,15 +84,16 @@ namespace MWWorld template void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; + /// \todo make this method const once const-correct ContainerStoreIterators are available template - void storeStates (const CellRefList& collection, + void storeStates (CellRefList& collection, std::vector >& 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). - 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. public: @@ -171,7 +172,8 @@ namespace MWWorld 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); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 445b42d8d..8f272ca49 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -49,19 +49,40 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_) 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 (mSlots.size()); ++i) - if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) - return i; + if (mSlots[i].getType()!=-1 && mSlots[i] == iter) + { + // linear complexity, but allowedSlots is most of the time just 1 anyway + std::vector allowedSlots = iter->getClass().getEquipmentSlots(*iter).first; + std::vector::iterator found = std::find(allowedSlots.begin(),allowedSlots.end(),i); + if (found == allowedSlots.end()) + return -1; + else + return std::distance(allowedSlots.begin(), found); + } 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, 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() @@ -703,7 +724,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) return false; } -void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) { MWWorld::ContainerStore::writeState(state); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9fd18c54b..ae2ced2b8 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -113,10 +113,10 @@ namespace MWWorld 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). - 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. public: @@ -209,7 +209,7 @@ namespace MWWorld virtual void clear(); ///< Empty container. - virtual void writeState (ESM::InventoryState& state) const; + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 104605e65..f7d5d9616 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2031,7 +2031,7 @@ namespace MWWorld bool World::isOnGround(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2049,7 +2049,7 @@ namespace MWWorld mPhysEngine); if(tracer.mFraction < 1.0f) // collision, must be close to something below { - const_cast (physactor)->setOnGround(true); + physactor->setOnGround(true); return true; } else diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 3d4407e7b..13af28e30 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,6 +15,7 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { + /// std::vector > mItems; std::map mLevelledItemMap;