#ifndef OPENMW_MWWORLD_ESMSTORE_H #define OPENMW_MWWORLD_ESMSTORE_H #include #include #include #include "store.hpp" namespace Loading { class Listener; } namespace MWWorld { class ESMStore { Store mActivators; Store mPotions; Store mAppas; Store mArmors; Store mBodyParts; Store mBooks; Store mBirthSigns; Store mClasses; Store mClothes; Store mContainers; Store mCreatures; Store mDialogs; Store mDoors; Store mEnchants; Store mFactions; Store mGlobals; Store mIngreds; Store mCreatureLists; Store mItemLists; Store mLights; Store mLockpicks; Store mMiscItems; Store mNpcs; Store mProbes; Store mRaces; Store mRegions; Store mRepairs; Store mSoundGens; Store mSounds; Store mSpells; Store mStartScripts; Store mStatics; Store mWeapons; Store mGameSettings; Store mScripts; // Lists that need special rules Store mCells; Store mLands; Store mLandTextures; Store mPathgrids; Store mMagicEffects; Store mSkills; // Special entry which is hardcoded and not loaded from an ESM Store mAttributes; // Lookup of all IDs. Makes looking up references faster. Just // maps the id name to the record type. std::map mIds; std::map mStores; ESM::NPC mPlayerTemplate; unsigned int mDynamicCount; public: /// \todo replace with SharedIterator typedef std::map::const_iterator iterator; iterator begin() const { return mStores.begin(); } iterator end() const { return mStores.end(); } /// Look up the given ID in 'all'. Returns 0 if not found. /// \note id must be in lower case. int find(const std::string &id) const { std::map::const_iterator it = mIds.find(id); if (it == mIds.end()) { return 0; } return it->second; } ESMStore() : mDynamicCount(0) { mStores[ESM::REC_ACTI] = &mActivators; mStores[ESM::REC_ALCH] = &mPotions; mStores[ESM::REC_APPA] = &mAppas; mStores[ESM::REC_ARMO] = &mArmors; mStores[ESM::REC_BODY] = &mBodyParts; mStores[ESM::REC_BOOK] = &mBooks; mStores[ESM::REC_BSGN] = &mBirthSigns; mStores[ESM::REC_CELL] = &mCells; mStores[ESM::REC_CLAS] = &mClasses; mStores[ESM::REC_CLOT] = &mClothes; mStores[ESM::REC_CONT] = &mContainers; mStores[ESM::REC_CREA] = &mCreatures; mStores[ESM::REC_DIAL] = &mDialogs; mStores[ESM::REC_DOOR] = &mDoors; mStores[ESM::REC_ENCH] = &mEnchants; mStores[ESM::REC_FACT] = &mFactions; mStores[ESM::REC_GLOB] = &mGlobals; mStores[ESM::REC_GMST] = &mGameSettings; mStores[ESM::REC_INGR] = &mIngreds; mStores[ESM::REC_LAND] = &mLands; mStores[ESM::REC_LEVC] = &mCreatureLists; mStores[ESM::REC_LEVI] = &mItemLists; mStores[ESM::REC_LIGH] = &mLights; mStores[ESM::REC_LOCK] = &mLockpicks; mStores[ESM::REC_LTEX] = &mLandTextures; mStores[ESM::REC_MISC] = &mMiscItems; mStores[ESM::REC_NPC_] = &mNpcs; mStores[ESM::REC_PGRD] = &mPathgrids; mStores[ESM::REC_PROB] = &mProbes; mStores[ESM::REC_RACE] = &mRaces; mStores[ESM::REC_REGN] = &mRegions; mStores[ESM::REC_REPA] = &mRepairs; mStores[ESM::REC_SCPT] = &mScripts; mStores[ESM::REC_SNDG] = &mSoundGens; mStores[ESM::REC_SOUN] = &mSounds; mStores[ESM::REC_SPEL] = &mSpells; mStores[ESM::REC_SSCR] = &mStartScripts; mStores[ESM::REC_STAT] = &mStatics; mStores[ESM::REC_WEAP] = &mWeapons; mPathgrids.setCells(mCells); } void clearDynamic () { for (std::map::iterator it = mStores.begin(); it != mStores.end(); ++it) it->second->clearDynamic(); mNpcs.insert(mPlayerTemplate); } void movePlayerRecord () { mPlayerTemplate = *mNpcs.find("player"); mNpcs.eraseStatic(mPlayerTemplate.mId); mNpcs.insert(mPlayerTemplate); } void load(ESM::ESMReader &esm, Loading::Listener* listener); template const Store &get() const { throw std::runtime_error("Storage for this type not exist"); } /// Insert a custom record (i.e. with a generated ID that will not clash will pre-existing records) template const T *insert(const T &x) { std::ostringstream id; id << "$dynamic" << mDynamicCount++; Store &store = const_cast &>(get()); if (store.search(id.str()) != 0) { std::ostringstream msg; msg << "Try to override existing record '" << id.str() << "'"; throw std::runtime_error(msg.str()); } T record = x; record.mId = id.str(); T *ptr = store.insert(record); for (iterator it = mStores.begin(); it != mStores.end(); ++it) { if (it->second == &store) { mIds[ptr->mId] = it->first; } } return ptr; } /// Insert a record with set ID, and allow it to override a pre-existing static record. template const T *overrideRecord(const T &x) { Store &store = const_cast &>(get()); T *ptr = store.insert(x); for (iterator it = mStores.begin(); it != mStores.end(); ++it) { if (it->second == &store) { mIds[ptr->mId] = it->first; } } return ptr; } template const T *insertStatic(const T &x) { std::ostringstream id; id << "$dynamic" << mDynamicCount++; Store &store = const_cast &>(get()); if (store.search(id.str()) != 0) { std::ostringstream msg; msg << "Try to override existing record '" << id.str() << "'"; throw std::runtime_error(msg.str()); } T record = x; T *ptr = store.insertStatic(record); for (iterator it = mStores.begin(); it != mStores.end(); ++it) { if (it->second == &store) { mIds[ptr->mId] = it->first; } } return ptr; } // This method must be called once, after loading all master/plugin files. This can only be done // from the outside, so it must be public. void setUp(); int countSavedGameRecords() const; void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< \return Known type? }; template <> inline const ESM::Cell *ESMStore::insert(const ESM::Cell &cell) { return mCells.insert(cell); } template <> inline const ESM::NPC *ESMStore::insert(const ESM::NPC &npc) { std::ostringstream id; id << "$dynamic" << mDynamicCount++; if (Misc::StringUtils::ciEqual(npc.mId, "player")) { return mNpcs.insert(npc); } else if (mNpcs.search(id.str()) != 0) { std::ostringstream msg; msg << "Try to override existing record '" << id.str() << "'"; throw std::runtime_error(msg.str()); } ESM::NPC record = npc; record.mId = id.str(); ESM::NPC *ptr = mNpcs.insert(record); mIds[ptr->mId] = ESM::REC_NPC_; return ptr; } template <> inline const Store &ESMStore::get() const { return mActivators; } template <> inline const Store &ESMStore::get() const { return mPotions; } template <> inline const Store &ESMStore::get() const { return mAppas; } template <> inline const Store &ESMStore::get() const { return mArmors; } template <> inline const Store &ESMStore::get() const { return mBodyParts; } template <> inline const Store &ESMStore::get() const { return mBooks; } template <> inline const Store &ESMStore::get() const { return mBirthSigns; } template <> inline const Store &ESMStore::get() const { return mClasses; } template <> inline const Store &ESMStore::get() const { return mClothes; } template <> inline const Store &ESMStore::get() const { return mContainers; } template <> inline const Store &ESMStore::get() const { return mCreatures; } template <> inline const Store &ESMStore::get() const { return mDialogs; } template <> inline const Store &ESMStore::get() const { return mDoors; } template <> inline const Store &ESMStore::get() const { return mEnchants; } template <> inline const Store &ESMStore::get() const { return mFactions; } template <> inline const Store &ESMStore::get() const { return mGlobals; } template <> inline const Store &ESMStore::get() const { return mIngreds; } template <> inline const Store &ESMStore::get() const { return mCreatureLists; } template <> inline const Store &ESMStore::get() const { return mItemLists; } template <> inline const Store &ESMStore::get() const { return mLights; } template <> inline const Store &ESMStore::get() const { return mLockpicks; } template <> inline const Store &ESMStore::get() const { return mMiscItems; } template <> inline const Store &ESMStore::get() const { return mNpcs; } template <> inline const Store &ESMStore::get() const { return mProbes; } template <> inline const Store &ESMStore::get() const { return mRaces; } template <> inline const Store &ESMStore::get() const { return mRegions; } template <> inline const Store &ESMStore::get() const { return mRepairs; } template <> inline const Store &ESMStore::get() const { return mSoundGens; } template <> inline const Store &ESMStore::get() const { return mSounds; } template <> inline const Store &ESMStore::get() const { return mSpells; } template <> inline const Store &ESMStore::get() const { return mStartScripts; } template <> inline const Store &ESMStore::get() const { return mStatics; } template <> inline const Store &ESMStore::get() const { return mWeapons; } template <> inline const Store &ESMStore::get() const { return mGameSettings; } template <> inline const Store &ESMStore::get() const { return mScripts; } template <> inline const Store &ESMStore::get() const { return mCells; } template <> inline const Store &ESMStore::get() const { return mLands; } template <> inline const Store &ESMStore::get() const { return mLandTextures; } template <> inline const Store &ESMStore::get() const { return mPathgrids; } template <> inline const Store &ESMStore::get() const { return mMagicEffects; } template <> inline const Store &ESMStore::get() const { return mSkills; } template <> inline const Store &ESMStore::get() const { return mAttributes; } } #endif