mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 19:56:38 +00:00 
			
		
		
		
	Merge branch 'savedgame' of https://github.com/zinnschlag/openmw into savedgame
This commit is contained in:
		
						commit
						ac1859fb77
					
				
					 39 changed files with 1029 additions and 217 deletions
				
			
		|  | @ -246,7 +246,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) | |||
| 
 | ||||
|         if(quiet) continue; | ||||
| 
 | ||||
|         std::cout << "    Refnum: " << ref.mRefnum << std::endl; | ||||
|         std::cout << "    Refnum: " << ref.mRefNum.mIndex << std::endl; | ||||
|         std::cout << "    ID: '" << ref.mRefID << "'\n"; | ||||
|         std::cout << "    Owner: '" << ref.mOwner << "'\n"; | ||||
|         std::cout << "    Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; | ||||
|  |  | |||
|  | @ -147,6 +147,8 @@ namespace MWBase | |||
|             virtual void update(float duration) = 0; | ||||
| 
 | ||||
|             virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0; | ||||
| 
 | ||||
|             virtual void clear() = 0; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ namespace ESM | |||
|     struct Potion; | ||||
|     struct Spell; | ||||
|     struct NPC; | ||||
|     struct CellId; | ||||
| } | ||||
| 
 | ||||
| namespace MWRender | ||||
|  | @ -105,12 +106,14 @@ namespace MWBase | |||
|             virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; | ||||
| 
 | ||||
|             virtual OEngine::Render::Fader* getFader() = 0; | ||||
|             ///< \ŧodo remove this function. Rendering details should not be exposed.
 | ||||
|             ///< \todo remove this function. Rendering details should not be exposed.
 | ||||
| 
 | ||||
|             virtual MWWorld::CellStore *getExterior (int x, int y) = 0; | ||||
| 
 | ||||
|             virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; | ||||
| 
 | ||||
|             virtual MWWorld::CellStore *getCell (const ESM::CellId& id) = 0; | ||||
| 
 | ||||
|             virtual void useDeathCamera() = 0; | ||||
| 
 | ||||
|             virtual void setWaterHeight(const float height) = 0; | ||||
|  | @ -236,6 +239,8 @@ namespace MWBase | |||
|             virtual void changeToExteriorCell (const ESM::Position& position) = 0; | ||||
|             ///< Move to exterior cell.
 | ||||
| 
 | ||||
|             virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position) = 0; | ||||
| 
 | ||||
|             virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0; | ||||
|             ///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| #include "../mwbase/statemanager.hpp" | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwbase/windowmanager.hpp" | ||||
| 
 | ||||
| #include "../mwstate/character.hpp" | ||||
| 
 | ||||
|  | @ -123,6 +124,12 @@ namespace MWGui | |||
|         } | ||||
| 
 | ||||
|         setVisible(false); | ||||
| 
 | ||||
|         if (MWBase::Environment::get().getStateManager()->getState()== | ||||
|             MWBase::StateManager::State_NoGame) | ||||
|         { | ||||
|             MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void SaveGameDialog::onCharacterSelected(MyGUI::ComboBox *sender, size_t pos) | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| #include <extern/sdl4ogre/sdlcursormanager.hpp> | ||||
| 
 | ||||
| #include "../mwbase/inputmanager.hpp" | ||||
| #include "../mwbase/statemanager.hpp" | ||||
| 
 | ||||
| #include "../mwworld/class.hpp" | ||||
| #include "../mwworld/player.hpp" | ||||
|  | @ -709,6 +710,10 @@ namespace MWGui | |||
| 
 | ||||
|         mToolTips->onFrame(frameDuration); | ||||
| 
 | ||||
|         if (MWBase::Environment::get().getStateManager()->getState()== | ||||
|             MWBase::StateManager::State_NoGame) | ||||
|             return; | ||||
| 
 | ||||
|         if (mDragAndDrop->mIsOnDragAndDrop) | ||||
|         { | ||||
|             assert(mDragAndDrop->mDraggedWidget); | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ | |||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/inputmanager.hpp" // FIXME
 | ||||
| #include "../mwbase/windowmanager.hpp" // FIXME
 | ||||
| #include "../mwbase/statemanager.hpp" | ||||
| 
 | ||||
| #include "../mwmechanics/creaturestats.hpp" | ||||
| 
 | ||||
|  | @ -329,6 +330,12 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) | |||
| 
 | ||||
| void RenderingManager::update (float duration, bool paused) | ||||
| { | ||||
|     mVideoPlayer->update (); | ||||
| 
 | ||||
|     if (MWBase::Environment::get().getStateManager()->getState()== | ||||
|         MWBase::StateManager::State_NoGame) | ||||
|         return; | ||||
| 
 | ||||
|     MWBase::World *world = MWBase::Environment::get().getWorld(); | ||||
| 
 | ||||
|     MWWorld::Ptr player = world->getPlayer().getPlayer(); | ||||
|  | @ -365,8 +372,6 @@ void RenderingManager::update (float duration, bool paused) | |||
| 
 | ||||
|     mOcclusionQuery->update(duration); | ||||
| 
 | ||||
|     mVideoPlayer->update (); | ||||
| 
 | ||||
|     mRendering.update(duration); | ||||
| 
 | ||||
|     Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwbase/statemanager.hpp" | ||||
| 
 | ||||
| #include "../mwworld/esmstore.hpp" | ||||
| #include "../mwworld/player.hpp" | ||||
|  | @ -607,8 +608,13 @@ namespace MWSound | |||
|     { | ||||
|         if(!mOutput->isInitialized()) | ||||
|             return; | ||||
|         updateSounds(duration); | ||||
|         updateRegionSound(duration); | ||||
| 
 | ||||
|         if (MWBase::Environment::get().getStateManager()->getState()!= | ||||
|             MWBase::StateManager::State_NoGame) | ||||
|         { | ||||
|             updateSounds(duration); | ||||
|             updateRegionSound(duration); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -705,4 +711,13 @@ namespace MWSound | |||
|     { | ||||
|         return bytes / framesToBytes(1, config, type); | ||||
|     } | ||||
| 
 | ||||
|     void SoundManager::clear() | ||||
|     { | ||||
|         for (SoundMap::iterator iter (mActiveSounds.begin()); iter!=mActiveSounds.end(); ++iter) | ||||
|             iter->first->stop(); | ||||
| 
 | ||||
|         mActiveSounds.clear(); | ||||
|         stopMusic(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -148,6 +148,8 @@ namespace MWSound | |||
|         virtual void update(float duration); | ||||
| 
 | ||||
|         virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up); | ||||
| 
 | ||||
|         virtual void clear(); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ | |||
| 
 | ||||
| #include <components/esm/esmwriter.hpp> | ||||
| #include <components/esm/esmreader.hpp> | ||||
| #include <components/esm/cellid.hpp> | ||||
| #include <components/esm/loadcell.hpp> | ||||
| 
 | ||||
| #include <components/settings/settings.hpp> | ||||
| 
 | ||||
|  | @ -13,6 +15,7 @@ | |||
| #include "../mwbase/windowmanager.hpp" | ||||
| #include "../mwbase/mechanicsmanager.hpp" | ||||
| #include "../mwbase/scriptmanager.hpp" | ||||
| #include "../mwbase/soundmanager.hpp" | ||||
| 
 | ||||
| #include "../mwworld/player.hpp" | ||||
| #include "../mwworld/class.hpp" | ||||
|  | @ -21,10 +24,11 @@ | |||
| 
 | ||||
| #include "../mwscript/globalscripts.hpp" | ||||
| 
 | ||||
| void MWState::StateManager::cleanup() | ||||
| void MWState::StateManager::cleanup (bool force) | ||||
| { | ||||
|     if (mState!=State_NoGame) | ||||
|     if (mState!=State_NoGame || force) | ||||
|     { | ||||
|         MWBase::Environment::get().getSoundManager()->clear(); | ||||
|         MWBase::Environment::get().getDialogueManager()->clear(); | ||||
|         MWBase::Environment::get().getJournal()->clear(); | ||||
|         MWBase::Environment::get().getScriptManager()->getGlobalScripts().clear(); | ||||
|  | @ -180,76 +184,86 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot | |||
| 
 | ||||
| void MWState::StateManager::loadGame (const Character *character, const Slot *slot) | ||||
| { | ||||
|     cleanup(); | ||||
| 
 | ||||
|     mTimePlayed = slot->mProfile.mTimePlayed; | ||||
| 
 | ||||
|     ESM::ESMReader reader; | ||||
|     reader.open (slot->mPath.string()); | ||||
| 
 | ||||
|     while (reader.hasMoreRecs()) | ||||
|     try | ||||
|     { | ||||
|         ESM::NAME n = reader.getRecName(); | ||||
|         reader.getRecHeader(); | ||||
|         cleanup(); | ||||
| 
 | ||||
|         switch (n.val) | ||||
|         mTimePlayed = slot->mProfile.mTimePlayed; | ||||
| 
 | ||||
|         ESM::ESMReader reader; | ||||
|         reader.open (slot->mPath.string()); | ||||
| 
 | ||||
|         while (reader.hasMoreRecs()) | ||||
|         { | ||||
|             case ESM::REC_SAVE: | ||||
|             ESM::NAME n = reader.getRecName(); | ||||
|             reader.getRecHeader(); | ||||
| 
 | ||||
|                 // don't need to read that here
 | ||||
|                 reader.skipRecord(); | ||||
|                 break; | ||||
|             switch (n.val) | ||||
|             { | ||||
|                 case ESM::REC_SAVE: | ||||
| 
 | ||||
|             case ESM::REC_JOUR: | ||||
|             case ESM::REC_QUES: | ||||
|                     // don't need to read that here
 | ||||
|                     reader.skipRecord(); | ||||
|                     break; | ||||
| 
 | ||||
|                 MWBase::Environment::get().getJournal()->readRecord (reader, n.val); | ||||
|                 break; | ||||
|                 case ESM::REC_JOUR: | ||||
|                 case ESM::REC_QUES: | ||||
| 
 | ||||
|             case ESM::REC_ALCH: | ||||
|             case ESM::REC_ARMO: | ||||
|             case ESM::REC_BOOK: | ||||
|             case ESM::REC_CLAS: | ||||
|             case ESM::REC_CLOT: | ||||
|             case ESM::REC_ENCH: | ||||
|             case ESM::REC_NPC_: | ||||
|             case ESM::REC_SPEL: | ||||
|             case ESM::REC_WEAP: | ||||
|             case ESM::REC_GLOB: | ||||
|                     MWBase::Environment::get().getJournal()->readRecord (reader, n.val); | ||||
|                     break; | ||||
| 
 | ||||
|                 MWBase::Environment::get().getWorld()->readRecord (reader, n.val); | ||||
|                 break; | ||||
|                 case ESM::REC_ALCH: | ||||
|                 case ESM::REC_ARMO: | ||||
|                 case ESM::REC_BOOK: | ||||
|                 case ESM::REC_CLAS: | ||||
|                 case ESM::REC_CLOT: | ||||
|                 case ESM::REC_ENCH: | ||||
|                 case ESM::REC_NPC_: | ||||
|                 case ESM::REC_SPEL: | ||||
|                 case ESM::REC_WEAP: | ||||
|                 case ESM::REC_GLOB: | ||||
|                 case ESM::REC_PLAY: | ||||
|                 case ESM::REC_CSTA: | ||||
| 
 | ||||
|             case ESM::REC_GSCR: | ||||
|                     MWBase::Environment::get().getWorld()->readRecord (reader, n.val); | ||||
|                     break; | ||||
| 
 | ||||
|                 MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val); | ||||
|                 break; | ||||
|                 case ESM::REC_GSCR: | ||||
| 
 | ||||
|             default: | ||||
|                     MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val); | ||||
|                     break; | ||||
| 
 | ||||
|                 // ignore invalid records
 | ||||
|                 /// \todo log error
 | ||||
|                 reader.skipRecord(); | ||||
|                 default: | ||||
| 
 | ||||
|                     // ignore invalid records
 | ||||
|                     /// \todo log error
 | ||||
|                     reader.skipRecord(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         mCharacterManager.setCurrentCharacter(character); | ||||
| 
 | ||||
|         mState = State_Running; | ||||
| 
 | ||||
|         Settings::Manager::setString ("character", "Saves", | ||||
|             slot->mPath.parent_path().filename().string()); | ||||
| 
 | ||||
|         MWBase::Environment::get().getWorld()->setupPlayer(); | ||||
|         MWBase::Environment::get().getWorld()->renderPlayer(); | ||||
|         MWBase::Environment::get().getWindowManager()->updatePlayer(); | ||||
|         MWBase::Environment::get().getMechanicsManager()->playerLoaded(); | ||||
| 
 | ||||
|         MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); | ||||
| 
 | ||||
|         ESM::CellId cellId = ptr.getCell()->mCell->getCellId(); | ||||
| 
 | ||||
|         MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition()); | ||||
|     } | ||||
|     catch (const std::exception& e) | ||||
|     { | ||||
|         std::cerr << "failed to load saved game: " << e.what() << std::endl; | ||||
|         cleanup (true); | ||||
|     } | ||||
| 
 | ||||
|     mCharacterManager.setCurrentCharacter(character); | ||||
| 
 | ||||
|     mState = State_Running; | ||||
| 
 | ||||
|     Settings::Manager::setString ("character", "Saves", | ||||
|         slot->mPath.parent_path().filename().string()); | ||||
| 
 | ||||
|     MWBase::Environment::get().getWorld()->setupPlayer(); | ||||
|     MWBase::Environment::get().getWorld()->renderPlayer(); | ||||
|     MWBase::Environment::get().getWindowManager()->updatePlayer(); | ||||
|     MWBase::Environment::get().getMechanicsManager()->playerLoaded(); | ||||
| 
 | ||||
|     // for testing purpose only
 | ||||
|     ESM::Position pos; | ||||
|     pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; | ||||
|     pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; | ||||
|     MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); | ||||
| } | ||||
| 
 | ||||
| MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ namespace MWState | |||
| 
 | ||||
|         private: | ||||
| 
 | ||||
|             void cleanup(); | ||||
|             void cleanup (bool force = false); | ||||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,10 @@ | |||
| #include "cells.hpp" | ||||
| 
 | ||||
| #include <components/esm/esmreader.hpp> | ||||
| #include <components/esm/esmwriter.hpp> | ||||
| #include <components/esm/defs.hpp> | ||||
| #include <components/esm/cellstate.hpp> | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| 
 | ||||
|  | @ -59,6 +64,30 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore& | |||
|     return ptr; | ||||
| } | ||||
| 
 | ||||
| void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, const CellStore& cell) const | ||||
| { | ||||
|     ESM::CellState cellState; | ||||
| 
 | ||||
|     cell.saveState (cellState); | ||||
| 
 | ||||
|     writer.startRecord (ESM::REC_CSTA); | ||||
|     cellState.mId.save (writer); | ||||
|     cellState.save (writer); | ||||
|     cell.writeReferences (writer); | ||||
|     writer.endRecord (ESM::REC_CSTA); | ||||
| } | ||||
| 
 | ||||
| bool MWWorld::Cells::hasState (const CellStore& cellStore) const | ||||
| { | ||||
|     if (cellStore.mState==CellStore::State_Loaded) | ||||
|         return true; | ||||
| 
 | ||||
|     if (cellStore.mCell->mData.mFlags & ESM::Cell::Interior) | ||||
|         return cellStore.mCell->mData.mFlags & ESM::Cell::HasWater; | ||||
|     else | ||||
|         return false; | ||||
| } | ||||
| 
 | ||||
| MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader) | ||||
| : mStore (store), mReader (reader), | ||||
|   mIdCache (40, std::pair<std::string, CellStore *> ("", (CellStore*)0)), /// \todo make cache size configurable
 | ||||
|  | @ -121,6 +150,14 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name) | |||
|     return &result->second; | ||||
| } | ||||
| 
 | ||||
| MWWorld::CellStore *MWWorld::Cells::getCell (const ESM::CellId& id) | ||||
| { | ||||
|     if (id.mPaged) | ||||
|         return getExterior (id.mIndex.mX, id.mIndex.mY); | ||||
| 
 | ||||
|     return getInterior (id.mWorldspace); | ||||
| } | ||||
| 
 | ||||
| MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell, | ||||
|     bool searchInContainers) | ||||
| { | ||||
|  | @ -271,3 +308,62 @@ void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorl | |||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| int MWWorld::Cells::countSavedGameRecords() const | ||||
| { | ||||
|     int count = 0; | ||||
| 
 | ||||
|     for (std::map<std::string, CellStore>::const_iterator iter (mInteriors.begin()); | ||||
|         iter!=mInteriors.end(); ++iter) | ||||
|         if (hasState (iter->second)) | ||||
|             ++count; | ||||
| 
 | ||||
|     for (std::map<std::pair<int, int>, CellStore>::const_iterator iter (mExteriors.begin()); | ||||
|         iter!=mExteriors.end(); ++iter) | ||||
|         if (hasState (iter->second)) | ||||
|             ++count; | ||||
| 
 | ||||
|     return count; | ||||
| } | ||||
| 
 | ||||
| void MWWorld::Cells::write (ESM::ESMWriter& writer) const | ||||
| { | ||||
|     for (std::map<std::pair<int, int>, CellStore>::const_iterator iter (mExteriors.begin()); | ||||
|         iter!=mExteriors.end(); ++iter) | ||||
|         if (hasState (iter->second)) | ||||
|             writeCell (writer, iter->second); | ||||
| 
 | ||||
|     for (std::map<std::string, CellStore>::const_iterator iter (mInteriors.begin()); | ||||
|         iter!=mInteriors.end(); ++iter) | ||||
|         if (hasState (iter->second)) | ||||
|             writeCell (writer, iter->second); | ||||
| } | ||||
| 
 | ||||
| bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type) | ||||
| { | ||||
|     if (type==ESM::REC_CSTA) | ||||
|     { | ||||
|         ESM::CellState state; | ||||
|         state.mId.load (reader); | ||||
| 
 | ||||
|         CellStore *cellStore = 0; | ||||
| 
 | ||||
|         try | ||||
|         { | ||||
|             cellStore = getCell (state.mId); | ||||
|         } | ||||
|         catch (...) | ||||
|         { | ||||
|             // silently drop cells that don't exist anymore
 | ||||
|             /// \todo log
 | ||||
|         } | ||||
| 
 | ||||
|         state.load (reader); | ||||
|         cellStore->loadState (state); | ||||
|         reader.skipRecord(); | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
|  | @ -10,6 +10,8 @@ | |||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
|     class ESMWriter; | ||||
|     struct CellId; | ||||
| } | ||||
| 
 | ||||
| namespace MWWorld | ||||
|  | @ -33,18 +35,23 @@ namespace MWWorld | |||
| 
 | ||||
|             Ptr getPtrAndCache (const std::string& name, CellStore& cellStore); | ||||
| 
 | ||||
|             void writeCell (ESM::ESMWriter& writer, const CellStore& cell) const; | ||||
| 
 | ||||
|             bool hasState (const CellStore& cellStore) const; | ||||
|             ///< Check if cell has state that needs to be included in a saved game file.
 | ||||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|             void clear(); | ||||
| 
 | ||||
|             Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader); | ||||
|             ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole
 | ||||
|             /// world
 | ||||
| 
 | ||||
|             CellStore *getExterior (int x, int y); | ||||
| 
 | ||||
|             CellStore *getInterior (const std::string& name); | ||||
| 
 | ||||
|             CellStore *getCell (const ESM::CellId& id); | ||||
| 
 | ||||
|             Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false); | ||||
|             ///< \param searchInContainers Only affect loaded cells.
 | ||||
|             /// @note name must be lower case
 | ||||
|  | @ -56,6 +63,12 @@ namespace MWWorld | |||
|             /// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
 | ||||
|             /// @note name must be lower case
 | ||||
|             void getExteriorPtrs (const std::string& name, std::vector<MWWorld::Ptr>& out); | ||||
| 
 | ||||
|             int countSavedGameRecords() const; | ||||
| 
 | ||||
|             void write (ESM::ESMWriter& writer) const; | ||||
| 
 | ||||
|             bool readRecord (ESM::ESMReader& reader, int32_t type); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,11 @@ | |||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include <components/esm/cellstate.hpp> | ||||
| #include <components/esm/cellid.hpp> | ||||
| #include <components/esm/esmwriter.hpp> | ||||
| #include <components/esm/objectstate.hpp> | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| 
 | ||||
|  | @ -29,6 +34,33 @@ namespace | |||
| 
 | ||||
|         return MWWorld::Ptr(); | ||||
|     } | ||||
| 
 | ||||
|     template<typename RecordType, typename T> | ||||
|     void writeReferenceCollection (ESM::ESMWriter& writer, | ||||
|         const MWWorld::CellRefList<T>& collection) | ||||
|     { | ||||
|         if (!collection.mList.empty()) | ||||
|         { | ||||
|             // section header
 | ||||
|             writer.writeHNT ("CSEC", collection.mList.front().mBase->sRecordId); | ||||
| 
 | ||||
|             // references
 | ||||
|             for (typename MWWorld::CellRefList<T>::List::const_iterator | ||||
|                 iter (collection.mList.begin()); | ||||
|                 iter!=collection.mList.end(); ++iter) | ||||
|             { | ||||
|                 if (iter->mData.getCount()==0 && iter->mRef.mRefNum.mContentFile==-1) | ||||
|                     continue; // deleted file that did not came from a content file -> ignore
 | ||||
| 
 | ||||
|                 RecordType state; | ||||
|                 iter->save (state); | ||||
| 
 | ||||
|                 writer.startRecord (ESM::REC_OBJE); | ||||
|                 state.save (writer); | ||||
|                 writer.endRecord (ESM::REC_OBJE); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| namespace MWWorld | ||||
|  | @ -42,7 +74,7 @@ namespace MWWorld | |||
|         if (const X *ptr = store.search (ref.mRefID)) | ||||
|         { | ||||
|             typename std::list<LiveRef>::iterator iter = | ||||
|                 std::find(mList.begin(), mList.end(), ref.mRefnum); | ||||
|                 std::find(mList.begin(), mList.end(), ref.mRefNum); | ||||
| 
 | ||||
|             LiveRef liveCellRef (ref, ptr); | ||||
| 
 | ||||
|  | @ -143,13 +175,16 @@ namespace MWWorld | |||
|             mCell->restore (esm[index], i); | ||||
| 
 | ||||
|             ESM::CellRef ref; | ||||
|             ref.mRefNum.mContentFile = -1; | ||||
| 
 | ||||
|             // Get each reference in turn
 | ||||
|             bool deleted = false; | ||||
|             while(mCell->getNextRef(esm[index], ref, deleted)) | ||||
|             { | ||||
|                 // Don't load reference if it was moved to a different cell.
 | ||||
|                 ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum); | ||||
|                 std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID); | ||||
|                 ESM::MovedCellRefTracker::const_iterator iter = | ||||
|                     std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum); | ||||
|                 if (iter != mCell->mMovedRefs.end()) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | @ -227,4 +262,46 @@ namespace MWWorld | |||
|                     << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void CellStore::loadState (const ESM::CellState& state) | ||||
|     { | ||||
|         if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater) | ||||
|             mWaterLevel = state.mWaterLevel; | ||||
| 
 | ||||
|         mWaterLevel = state.mWaterLevel; | ||||
|     } | ||||
| 
 | ||||
|     void CellStore::saveState (ESM::CellState& state) const | ||||
|     { | ||||
|         state.mId = mCell->getCellId(); | ||||
| 
 | ||||
|         if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater) | ||||
|             state.mWaterLevel = mWaterLevel; | ||||
| 
 | ||||
|         state.mWaterLevel = mWaterLevel; | ||||
|     } | ||||
| 
 | ||||
|     void CellStore::writeReferences (ESM::ESMWriter& writer) const | ||||
|     { | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mActivators); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mPotions); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mAppas); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mArmors); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mBooks); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mClothes); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mContainers); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mCreatures); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mDoors); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mIngreds); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mCreatureLists); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mItemLists); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mLights); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mLockpicks); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mMiscItems); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mNpcs); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mProbes); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mRepairs); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mStatics); | ||||
|         writeReferenceCollection<ESM::ObjectState> (writer, mWeapons); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -7,6 +7,11 @@ | |||
| #include "livecellref.hpp" | ||||
| #include "esmstore.hpp" | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     struct CellState; | ||||
| } | ||||
| 
 | ||||
| namespace MWWorld | ||||
| { | ||||
| 
 | ||||
|  | @ -133,6 +138,12 @@ namespace MWWorld | |||
| 
 | ||||
|     Ptr searchInContainer (const std::string& id); | ||||
| 
 | ||||
|         void loadState (const ESM::CellState& state); | ||||
| 
 | ||||
|         void saveState (ESM::CellState& state) const; | ||||
| 
 | ||||
|         void writeReferences (ESM::ESMWriter& writer) const; | ||||
| 
 | ||||
|   private: | ||||
| 
 | ||||
|     template<class Functor, class List> | ||||
|  | @ -158,7 +169,6 @@ namespace MWWorld | |||
|         ///< Make case-adjustments to \a ref and insert it into the respective container.
 | ||||
|         ///
 | ||||
|         /// Invalid \a ref objects are silently dropped.
 | ||||
| 
 | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -161,9 +161,9 @@ void ESMStore::setUp() | |||
|         mClasses.write (writer); | ||||
|         mClothes.write (writer); | ||||
|         mEnchants.write (writer); | ||||
|         mNpcs.write (writer); | ||||
|         mSpells.write (writer); | ||||
|         mWeapons.write (writer); | ||||
|         mNpcs.write (writer); | ||||
|     } | ||||
| 
 | ||||
|     bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type) | ||||
|  | @ -176,11 +176,25 @@ void ESMStore::setUp() | |||
|             case ESM::REC_CLAS: | ||||
|             case ESM::REC_CLOT: | ||||
|             case ESM::REC_ENCH: | ||||
|             case ESM::REC_NPC_: | ||||
|             case ESM::REC_SPEL: | ||||
|             case ESM::REC_WEAP: | ||||
|             case ESM::REC_NPC_: | ||||
| 
 | ||||
|                 mStores[type]->read (reader); | ||||
| 
 | ||||
|                 if (type==ESM::REC_NPC_) | ||||
|                 { | ||||
|                     // NPC record will always be last and we know that there can be only one
 | ||||
|                     // dynamic NPC record (player) -> We are done here with dynamic record laoding
 | ||||
|                     setUp(); | ||||
| 
 | ||||
|                     const ESM::NPC *player = mNpcs.find ("player"); | ||||
| 
 | ||||
|                     if (!mRaces.find (player->mRace) || | ||||
|                         !mClasses.find (player->mClass)) | ||||
|                         throw std::runtime_error ("Invalid player record (race or class unavilable"); | ||||
|                 } | ||||
| 
 | ||||
|                 return true; | ||||
| 
 | ||||
|             default: | ||||
|  |  | |||
							
								
								
									
										21
									
								
								apps/openmw/mwworld/livecellref.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								apps/openmw/mwworld/livecellref.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| 
 | ||||
| #include "livecellref.hpp" | ||||
| 
 | ||||
| #include <components/esm/objectstate.hpp> | ||||
| 
 | ||||
| void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state) | ||||
| { | ||||
|     mRef = state.mRef; | ||||
|     mData = RefData (state); | ||||
| } | ||||
| 
 | ||||
| void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const | ||||
| { | ||||
|     state.mRef = mRef; | ||||
|     mData.write (state); | ||||
| } | ||||
| 
 | ||||
| bool MWWorld::LiveCellRefBase::checkStateImp (const ESM::ObjectState& state) | ||||
| { | ||||
|     return true; | ||||
| } | ||||
|  | @ -7,6 +7,11 @@ | |||
| 
 | ||||
| #include "refdata.hpp" | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ObjectState; | ||||
| } | ||||
| 
 | ||||
| namespace MWWorld | ||||
| { | ||||
|     class Ptr; | ||||
|  | @ -29,8 +34,31 @@ namespace MWWorld | |||
|         LiveCellRefBase(std::string type, const ESM::CellRef &cref=ESM::CellRef()); | ||||
|         /* Need this for the class to be recognized as polymorphic */ | ||||
|         virtual ~LiveCellRefBase() { } | ||||
| 
 | ||||
|         protected: | ||||
| 
 | ||||
|             void loadImp (const ESM::ObjectState& state); | ||||
|             ///< Load state into a LiveCellRef, that has already been initialised with base and
 | ||||
|             /// class.
 | ||||
|             ///
 | ||||
|             /// \attention Must not be called with an invalid \a state.
 | ||||
| 
 | ||||
|             void saveImp (ESM::ObjectState& state) const; | ||||
|             ///< Save LiveCellRef state into \a state.
 | ||||
| 
 | ||||
|             static bool checkStateImp (const ESM::ObjectState& state); | ||||
|             ///< Check if state is valid and report errors.
 | ||||
|             ///
 | ||||
|             /// \return Valid?
 | ||||
|             ///
 | ||||
|             /// \note Does not check if the RefId exists.
 | ||||
|     }; | ||||
| 
 | ||||
|     inline bool operator== (const LiveCellRefBase& cellRef, const ESM::CellRef::RefNum refNum) | ||||
|     { | ||||
|         return cellRef.mRef.mRefNum==refNum; | ||||
|     } | ||||
| 
 | ||||
|     /// A reference to one object (of any type) in a cell.
 | ||||
|     ///
 | ||||
|     /// Constructing this with a CellRef instance in the constructor means that
 | ||||
|  | @ -50,9 +78,41 @@ namespace MWWorld | |||
| 
 | ||||
|         // The object that this instance is based on.
 | ||||
|         const X* mBase; | ||||
| 
 | ||||
|         void load (const ESM::ObjectState& state); | ||||
|         ///< Load state into a LiveCellRef, that has already been initialised with base and class.
 | ||||
|         ///
 | ||||
|         /// \attention Must not be called with an invalid \a state.
 | ||||
| 
 | ||||
|         void save (ESM::ObjectState& state) const; | ||||
|         ///< Save LiveCellRef state into \a state.
 | ||||
| 
 | ||||
|         static bool checkState (const ESM::ObjectState& state); | ||||
|         ///< Check if state is valid and report errors.
 | ||||
|         ///
 | ||||
|         /// \return Valid?
 | ||||
|         ///
 | ||||
|         /// \note Does not check if the RefId exists.
 | ||||
|     }; | ||||
| 
 | ||||
| //    template<typename X> bool operator==(const LiveCellRef<X>& ref, int pRefnum);
 | ||||
|     template <typename X> | ||||
|     void LiveCellRef<X>::load (const ESM::ObjectState& state) | ||||
|     { | ||||
|         loadImp (state); | ||||
|     } | ||||
| 
 | ||||
|     template <typename X> | ||||
|     void LiveCellRef<X>::save (ESM::ObjectState& state) const | ||||
|     { | ||||
|         saveImp (state); | ||||
|     } | ||||
| 
 | ||||
|     template <typename X> | ||||
|     bool LiveCellRef<X>::checkState (const ESM::ObjectState& state) | ||||
|     { | ||||
|         return checkStateImp (state); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -25,6 +25,8 @@ namespace MWWorld | |||
|                 { | ||||
|                     LiveCellRef<T> ref; | ||||
|                     ref.mBase = instance; | ||||
|                     ref.mRef.mRefNum.mIndex = 0; | ||||
|                     ref.mRef.mRefNum.mContentFile = -1; | ||||
| 
 | ||||
|                     mRef = ref; | ||||
|                     mPtr = Ptr (&boost::any_cast<LiveCellRef<T>&> (mRef), 0); | ||||
|  | @ -64,8 +66,9 @@ namespace MWWorld | |||
| 
 | ||||
|                 // initialise
 | ||||
|                 ESM::CellRef& cellRef = mPtr.getCellRef(); | ||||
|                 cellRef.mRefID = Misc::StringUtils::lowerCase(name); | ||||
|                 cellRef.mRefnum = -1; | ||||
|                 cellRef.mRefID = Misc::StringUtils::lowerCase (name); | ||||
|                 cellRef.mRefNum.mIndex = 0; | ||||
|                 cellRef.mRefNum.mContentFile = -1; | ||||
|                 cellRef.mScale = 1; | ||||
|                 cellRef.mFactIndex = 0; | ||||
|                 cellRef.mCharge = -1; | ||||
|  |  | |||
|  | @ -1,6 +1,13 @@ | |||
| 
 | ||||
| #include "player.hpp" | ||||
| 
 | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| #include <components/esm/esmreader.hpp> | ||||
| #include <components/esm/esmwriter.hpp> | ||||
| #include <components/esm/player.hpp> | ||||
| #include <components/esm/defs.hpp> | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwbase/windowmanager.hpp" | ||||
|  | @ -34,9 +41,6 @@ namespace MWWorld | |||
|     void Player::set(const ESM::NPC *player) | ||||
|     { | ||||
|         mPlayer.mBase = player; | ||||
| 
 | ||||
|         float* playerPos = mPlayer.mData.getPosition().pos; | ||||
|         playerPos[0] = playerPos[1] = playerPos[2] = 0; | ||||
|     } | ||||
| 
 | ||||
|     void Player::setCell (MWWorld::CellStore *cellStore) | ||||
|  | @ -171,4 +175,102 @@ namespace MWWorld | |||
|         if (mMarkedCell) | ||||
|             markedPosition = mMarkedPosition; | ||||
|     } | ||||
| 
 | ||||
|     void Player::clear() | ||||
|     { | ||||
|         mCellStore = 0; | ||||
|         mSign.clear(); | ||||
|         mMarkedCell = 0; | ||||
|         mAutoMove = false; | ||||
|         mForwardBackward = 0; | ||||
|         mTeleported = false; | ||||
|     } | ||||
| 
 | ||||
|     void Player::write (ESM::ESMWriter& writer) const | ||||
|     { | ||||
|         ESM::Player player; | ||||
| 
 | ||||
|         mPlayer.save (player.mObject); | ||||
|         player.mCellId = mCellStore->mCell->getCellId(); | ||||
| 
 | ||||
|         player.mBirthsign = mSign; | ||||
| 
 | ||||
|         player.mLastKnownExteriorPosition[0] = mLastKnownExteriorPosition.x; | ||||
|         player.mLastKnownExteriorPosition[1] = mLastKnownExteriorPosition.y; | ||||
|         player.mLastKnownExteriorPosition[2] = mLastKnownExteriorPosition.z; | ||||
| 
 | ||||
|         if (mMarkedCell) | ||||
|         { | ||||
|             player.mHasMark = true; | ||||
|             player.mMarkedPosition = mMarkedPosition; | ||||
|             player.mMarkedCell = mMarkedCell->mCell->getCellId(); | ||||
|         } | ||||
|         else | ||||
|             player.mHasMark = false; | ||||
| 
 | ||||
|         player.mAutoMove = mAutoMove ? 1 : 0; | ||||
| 
 | ||||
|         writer.startRecord (ESM::REC_PLAY); | ||||
|         player.save (writer); | ||||
|         writer.endRecord (ESM::REC_PLAY); | ||||
|     } | ||||
| 
 | ||||
|     bool Player::readRecord (ESM::ESMReader& reader, int32_t type) | ||||
|     { | ||||
|         if (type==ESM::REC_PLAY) | ||||
|         { | ||||
|             ESM::Player player; | ||||
|             player.load (reader); | ||||
| 
 | ||||
|             if (!mPlayer.checkState (player.mObject)) | ||||
|             { | ||||
|                 // this is the one object we can not silently drop.
 | ||||
|                 throw std::runtime_error ("invalid player state record (object state)"); | ||||
|             } | ||||
| 
 | ||||
|             mPlayer.load (player.mObject); | ||||
| 
 | ||||
|             MWBase::World& world = *MWBase::Environment::get().getWorld(); | ||||
| 
 | ||||
|             mCellStore = world.getCell (player.mCellId); | ||||
| 
 | ||||
|             if (!player.mBirthsign.empty() && | ||||
|                 !world.getStore().get<ESM::BirthSign>().search (player.mBirthsign)) | ||||
|                 throw std::runtime_error ("invalid player state record (birthsign)"); | ||||
| 
 | ||||
|             mSign = player.mBirthsign; | ||||
| 
 | ||||
|             mLastKnownExteriorPosition.x = player.mLastKnownExteriorPosition[0]; | ||||
|             mLastKnownExteriorPosition.y = player.mLastKnownExteriorPosition[1]; | ||||
|             mLastKnownExteriorPosition.z = player.mLastKnownExteriorPosition[2]; | ||||
| 
 | ||||
|             if (player.mHasMark && !player.mMarkedCell.mPaged) | ||||
|             { | ||||
|                 // interior cell -> need to check if it exists (exterior cell will be
 | ||||
|                 // generated on the fly)
 | ||||
| 
 | ||||
|                 if (!world.getStore().get<ESM::Cell>().search (player.mMarkedCell.mWorldspace)) | ||||
|                     player.mHasMark = false; // drop mark silently
 | ||||
|             } | ||||
| 
 | ||||
|             if (player.mHasMark) | ||||
|             { | ||||
|                 mMarkedPosition = player.mMarkedPosition; | ||||
|                 mMarkedCell = world.getCell (player.mMarkedCell); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 mMarkedCell = 0; | ||||
|             } | ||||
| 
 | ||||
|             mAutoMove = player.mAutoMove!=0; | ||||
| 
 | ||||
|             mForwardBackward = 0; | ||||
|             mTeleported = false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -11,6 +11,8 @@ | |||
| namespace ESM | ||||
| { | ||||
|     struct NPC; | ||||
|     class ESMWriter; | ||||
|     class ESMReader; | ||||
| } | ||||
| 
 | ||||
| namespace MWBase | ||||
|  | @ -86,6 +88,12 @@ namespace MWWorld | |||
| 
 | ||||
|         bool wasTeleported() const; | ||||
|         void setTeleported(bool teleported); | ||||
| 
 | ||||
|         void clear(); | ||||
| 
 | ||||
|         void write (ESM::ESMWriter& writer) const; | ||||
| 
 | ||||
|         bool readRecord (ESM::ESMReader& reader, int32_t type); | ||||
|     }; | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ | |||
| 
 | ||||
| #include <OgreSceneNode.h> | ||||
| 
 | ||||
| #include <components/esm/objectstate.hpp> | ||||
| 
 | ||||
| #include "customdata.hpp" | ||||
| #include "cellstore.hpp" | ||||
| 
 | ||||
|  | @ -52,6 +54,14 @@ namespace MWWorld | |||
|         mLocalRotation.rot[2]=0; | ||||
|     } | ||||
| 
 | ||||
|     RefData::RefData (const ESM::ObjectState& objectState) | ||||
|     : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled), | ||||
|       mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0) | ||||
|     { | ||||
|         for (int i=0; i<3; ++i) | ||||
|             mLocalRotation.rot[i] = objectState.mLocalRotation[i]; | ||||
|     } | ||||
| 
 | ||||
|     RefData::RefData (const RefData& refData) | ||||
|     : mBaseNode(0), mCustomData (0) | ||||
|     { | ||||
|  | @ -66,6 +76,17 @@ namespace MWWorld | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void RefData::write (ESM::ObjectState& objectState) const | ||||
|     { | ||||
|         objectState.mHasLocals = false; | ||||
|         objectState.mEnabled = mEnabled; | ||||
|         objectState.mCount = mCount; | ||||
|         objectState.mPosition = mPosition; | ||||
| 
 | ||||
|         for (int i=0; i<3; ++i) | ||||
|             objectState.mLocalRotation[i] = mLocalRotation.rot[i]; | ||||
|     } | ||||
| 
 | ||||
|     RefData& RefData::operator= (const RefData& refData) | ||||
|     { | ||||
|         try | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ namespace ESM | |||
| { | ||||
|     class Script; | ||||
|     class CellRef; | ||||
|     class ObjectState; | ||||
| } | ||||
| 
 | ||||
| namespace MWWorld | ||||
|  | @ -55,10 +56,18 @@ namespace MWWorld | |||
|             /// to reset the position as the orignal data is still held in the CellRef
 | ||||
|             RefData (const ESM::CellRef& cellRef); | ||||
| 
 | ||||
|             RefData (const ESM::ObjectState& objectState); | ||||
|             ///< Ignores local variables and custom data (not enough context available here to
 | ||||
|             /// perform these operations).
 | ||||
| 
 | ||||
|             RefData (const RefData& refData); | ||||
| 
 | ||||
|             ~RefData(); | ||||
| 
 | ||||
|             void write (ESM::ObjectState& objectState) const; | ||||
|             ///< Ignores local variables and custom data (not enough context available here to
 | ||||
|             /// perform these operations).
 | ||||
| 
 | ||||
|             RefData& operator= (const RefData& refData); | ||||
| 
 | ||||
|             /// Return OGRE handle (may be empty).
 | ||||
|  |  | |||
|  | @ -39,7 +39,7 @@ void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id) | |||
|         // We should not need to test for duplicates, as this part of the code is pre-cell merge.
 | ||||
|         cell->mMovedRefs.push_back(cMRef); | ||||
|         // But there may be duplicates here!
 | ||||
|         ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); | ||||
|         ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); | ||||
|         if (iter == cellAlt->mLeasedRefs.end()) | ||||
|           cellAlt->mLeasedRefs.push_back(ref); | ||||
|         else | ||||
|  | @ -75,11 +75,11 @@ void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id) | |||
|             // merge lists of leased references, use newer data in case of conflict
 | ||||
|             for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); ++it) { | ||||
|                 // remove reference from current leased ref tracker and add it to new cell
 | ||||
|                 ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefnum); | ||||
|                 ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); | ||||
|                 if (itold != oldcell->mMovedRefs.end()) { | ||||
|                     ESM::MovedCellRef target0 = *itold; | ||||
|                     ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(target0.mTarget[0], target0.mTarget[1])); | ||||
|                     ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefnum); | ||||
|                     ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); | ||||
|                     wipecell->mLeasedRefs.erase(it_lease); | ||||
|                     *itold = *it; | ||||
|                 } | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| #include <components/bsa/bsa_archive.hpp> | ||||
| #include <components/files/collections.hpp> | ||||
| #include <components/compiler/locals.hpp> | ||||
| #include <components/esm/cellid.hpp> | ||||
| 
 | ||||
| #include <boost/math/special_functions/sign.hpp> | ||||
| 
 | ||||
|  | @ -267,6 +268,7 @@ namespace MWWorld | |||
|     void World::clear() | ||||
|     { | ||||
|         mLocalScripts.clear(); | ||||
|         mPlayer->clear(); | ||||
| 
 | ||||
|         // enable collision
 | ||||
|         if (!mPhysics->toggleCollisionMode()) | ||||
|  | @ -274,15 +276,16 @@ namespace MWWorld | |||
| 
 | ||||
|         mWorldScene->changeToVoid(); | ||||
| 
 | ||||
|         mStore.clearDynamic(); | ||||
|         mStore.setUp(); | ||||
| 
 | ||||
|         if (mPlayer) | ||||
|         { | ||||
|             mPlayer->setCell (0); | ||||
|             mPlayer->getPlayer().getRefData() = RefData(); | ||||
|             mPlayer->set (mStore.get<ESM::NPC>().find ("player")); | ||||
|         } | ||||
| 
 | ||||
|         mStore.clearDynamic(); | ||||
|         mStore.setUp(); | ||||
| 
 | ||||
|         mCells.clear(); | ||||
| 
 | ||||
|         mProjectiles.clear(); | ||||
|  | @ -301,19 +304,25 @@ namespace MWWorld | |||
|     { | ||||
|         return | ||||
|             mStore.countSavedGameRecords() | ||||
|             +mGlobalVariables.countSavedGameRecords(); | ||||
|             +mGlobalVariables.countSavedGameRecords() | ||||
|             +1 // player record
 | ||||
|             +mCells.countSavedGameRecords(); | ||||
|     } | ||||
| 
 | ||||
|     void World::write (ESM::ESMWriter& writer) const | ||||
|     { | ||||
|         mStore.write (writer); | ||||
|         mGlobalVariables.write (writer); | ||||
|         mCells.write (writer); | ||||
|         mPlayer->write (writer); | ||||
|     } | ||||
| 
 | ||||
|     void World::readRecord (ESM::ESMReader& reader, int32_t type) | ||||
|     { | ||||
|         if (!mStore.readRecord (reader, type) && | ||||
|             !mGlobalVariables.readRecord (reader, type)) | ||||
|             !mGlobalVariables.readRecord (reader, type) && | ||||
|             !mPlayer->readRecord (reader, type) && | ||||
|             !mCells.readRecord (reader, type)) | ||||
|         { | ||||
|             throw std::runtime_error ("unknown record in saved game"); | ||||
|         } | ||||
|  | @ -401,6 +410,14 @@ namespace MWWorld | |||
|         return mCells.getInterior (name); | ||||
|     } | ||||
| 
 | ||||
|     CellStore *World::getCell (const ESM::CellId& id) | ||||
|     { | ||||
|         if (id.mPaged) | ||||
|             return getExterior (id.mIndex.mX, id.mIndex.mY); | ||||
|         else | ||||
|             return getInterior (id.mWorldspace); | ||||
|     } | ||||
| 
 | ||||
|     void World::useDeathCamera() | ||||
|     { | ||||
|         if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() ) | ||||
|  | @ -801,6 +818,14 @@ namespace MWWorld | |||
|         addContainerScripts(getPlayer().getPlayer(), getPlayer().getPlayer().getCell()); | ||||
|     } | ||||
| 
 | ||||
|     void World::changeToCell (const ESM::CellId& cellId, const ESM::Position& position) | ||||
|     { | ||||
|         if (cellId.mPaged) | ||||
|             changeToExteriorCell (position); | ||||
|         else | ||||
|             changeToInteriorCell (cellId.mWorldspace, position); | ||||
|     } | ||||
| 
 | ||||
|     void World::markCellAsUnchanged() | ||||
|     { | ||||
|         return mWorldScene->markCellAsUnchanged(); | ||||
|  | @ -1314,7 +1339,7 @@ namespace MWWorld | |||
| 
 | ||||
|         updateWindowManager (); | ||||
| 
 | ||||
|         if (mPlayer->getPlayer().getCell()->isExterior()) | ||||
|         if (!paused && mPlayer->getPlayer().getCell()->isExterior()) | ||||
|         { | ||||
|             ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); | ||||
|             mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); | ||||
|  |  | |||
|  | @ -181,12 +181,14 @@ namespace MWWorld | |||
|             virtual void readRecord (ESM::ESMReader& reader, int32_t type); | ||||
| 
 | ||||
|             virtual OEngine::Render::Fader* getFader(); | ||||
|             ///< \ŧodo remove this function. Rendering details should not be exposed.
 | ||||
|             ///< \todo remove this function. Rendering details should not be exposed.
 | ||||
| 
 | ||||
|             virtual CellStore *getExterior (int x, int y); | ||||
| 
 | ||||
|             virtual CellStore *getInterior (const std::string& name); | ||||
| 
 | ||||
|             virtual CellStore *getCell (const ESM::CellId& id); | ||||
| 
 | ||||
|             //switch to POV before showing player's death animation
 | ||||
|             virtual void useDeathCamera(); | ||||
| 
 | ||||
|  | @ -314,6 +316,8 @@ namespace MWWorld | |||
|             virtual void changeToExteriorCell (const ESM::Position& position); | ||||
|             ///< Move to exterior cell.
 | ||||
| 
 | ||||
|             virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position); | ||||
| 
 | ||||
|             virtual const ESM::Cell *getExterior (const std::string& cellName) const; | ||||
|             ///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ add_component_dir (esm | |||
|     loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc | ||||
|     loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat | ||||
|     loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter | ||||
|     savedgame journalentry queststate locals globalscript | ||||
|     savedgame journalentry queststate locals globalscript player objectstate cellid cellstate | ||||
|     ) | ||||
| 
 | ||||
| add_component_dir (misc | ||||
|  |  | |||
							
								
								
									
										26
									
								
								components/esm/cellid.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								components/esm/cellid.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| 
 | ||||
| #include "cellid.hpp" | ||||
| 
 | ||||
| #include "esmreader.hpp" | ||||
| #include "esmwriter.hpp" | ||||
| 
 | ||||
| void ESM::CellId::load (ESMReader &esm) | ||||
| { | ||||
|     mWorldspace = esm.getHNString ("SPAC"); | ||||
| 
 | ||||
|     if (esm.isNextSub ("CIDX")) | ||||
|     { | ||||
|         esm.getHT (mIndex, 8); | ||||
|         mPaged = true; | ||||
|     } | ||||
|     else | ||||
|         mPaged = false; | ||||
| } | ||||
| 
 | ||||
| void ESM::CellId::save (ESMWriter &esm) const | ||||
| { | ||||
|     esm.writeHNString ("SPAC", mWorldspace); | ||||
| 
 | ||||
|     if (mPaged) | ||||
|         esm.writeHNT ("CIDX", mIndex, 8); | ||||
| } | ||||
							
								
								
									
										28
									
								
								components/esm/cellid.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								components/esm/cellid.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| #ifndef OPENMW_ESM_CELLID_H | ||||
| #define OPENMW_ESM_CELLID_H | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
|     class ESMWriter; | ||||
| 
 | ||||
|     struct CellId | ||||
|     { | ||||
|         struct CellIndex | ||||
|         { | ||||
|             int mX; | ||||
|             int mY; | ||||
|         }; | ||||
| 
 | ||||
|         std::string mWorldspace; | ||||
|         CellIndex mIndex; | ||||
|         bool mPaged; | ||||
| 
 | ||||
|         void load (ESMReader &esm); | ||||
|         void save (ESMWriter &esm) const; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,11 +1,83 @@ | |||
| 
 | ||||
| #include "cellref.hpp" | ||||
| 
 | ||||
| #include "esmreader.hpp" | ||||
| #include "esmwriter.hpp" | ||||
| 
 | ||||
| void ESM::CellRef::save(ESMWriter &esm) const | ||||
| void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) | ||||
| { | ||||
|     esm.writeHNT("FRMR", mRefnum); | ||||
|     // NAM0 sometimes appears here, sometimes further on
 | ||||
|     mNam0 = 0; | ||||
|     if (esm.isNextSub ("NAM0")) | ||||
|         esm.getHT (mNam0); | ||||
| 
 | ||||
|     if (wideRefNum) | ||||
|         esm.getHNT (mRefNum, "FRMR", 8); | ||||
|     else | ||||
|         esm.getHNT (mRefNum.mIndex, "FRMR"); | ||||
| 
 | ||||
|     mRefID = esm.getHNString ("NAME"); | ||||
| 
 | ||||
|     mScale = 1.0; | ||||
|     esm.getHNOT (mScale, "XSCL"); | ||||
| 
 | ||||
|     mOwner = esm.getHNOString ("ANAM"); | ||||
|     mGlob = esm.getHNOString ("BNAM"); | ||||
|     mSoul = esm.getHNOString ("XSOL"); | ||||
| 
 | ||||
|     mFaction = esm.getHNOString ("CNAM"); | ||||
|     mFactIndex = -2; | ||||
|     esm.getHNOT (mFactIndex, "INDX"); | ||||
| 
 | ||||
|     mGoldValue = 1; | ||||
|     mCharge = -1; | ||||
|     mEnchantmentCharge = -1; | ||||
| 
 | ||||
|     esm.getHNOT (mEnchantmentCharge, "XCHG"); | ||||
| 
 | ||||
|     esm.getHNOT (mCharge, "INTV"); | ||||
| 
 | ||||
|     esm.getHNOT (mGoldValue, "NAM9"); | ||||
| 
 | ||||
|     // Present for doors that teleport you to another cell.
 | ||||
|     if (esm.isNextSub ("DODT")) | ||||
|     { | ||||
|         mTeleport = true; | ||||
|         esm.getHT (mDoorDest); | ||||
|         mDestCell = esm.getHNOString ("DNAM"); | ||||
|     } | ||||
|     else | ||||
|         mTeleport = false; | ||||
| 
 | ||||
|     mLockLevel = -1; | ||||
|     esm.getHNOT (mLockLevel, "FLTV"); | ||||
|     mKey = esm.getHNOString ("KNAM"); | ||||
|     mTrap = esm.getHNOString ("TNAM"); | ||||
| 
 | ||||
|     mReferenceBlocked = -1; | ||||
|     mFltv = 0; | ||||
|     esm.getHNOT (mReferenceBlocked, "UNAM"); | ||||
|     esm.getHNOT (mFltv, "FLTV"); | ||||
| 
 | ||||
|     esm.getHNOT(mPos, "DATA", 24); | ||||
| 
 | ||||
|     // Number of references in the cell? Maximum once in each cell,
 | ||||
|     // but not always at the beginning, and not always right. In other
 | ||||
|     // words, completely useless.
 | ||||
|     // Update: Well, maybe not completely useless. This might actually be
 | ||||
|     //  number_of_references + number_of_references_moved_here_Across_boundaries,
 | ||||
|     //  and could be helpful for collecting these weird moved references.
 | ||||
|     if (esm.isNextSub ("NAM0")) | ||||
|         esm.getHT (mNam0); | ||||
| } | ||||
| 
 | ||||
| void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum) const | ||||
| { | ||||
|     if (wideRefNum) | ||||
|         esm.writeHNT ("FRMR", mRefNum, 8); | ||||
|     else | ||||
|         esm.writeHNT ("FRMR", mRefNum.mIndex, 4); | ||||
| 
 | ||||
|     esm.writeHNCString("NAME", mRefID); | ||||
| 
 | ||||
|     if (mScale != 1.0) { | ||||
|  | @ -58,7 +130,8 @@ void ESM::CellRef::save(ESMWriter &esm) const | |||
| 
 | ||||
| void ESM::CellRef::blank() | ||||
| { | ||||
|     mRefnum = 0; | ||||
|     mRefNum.mIndex = 0; | ||||
|     mRefNum.mContentFile = -1; | ||||
|     mRefID.clear(); | ||||
|     mScale = 1; | ||||
|     mOwner.clear(); | ||||
|  | @ -84,4 +157,9 @@ void ESM::CellRef::blank() | |||
|         mPos.pos[i] = 0; | ||||
|         mPos.rot[i] = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool ESM::operator== (const CellRef::RefNum& left, const CellRef::RefNum& right) | ||||
| { | ||||
|     return left.mIndex==right.mIndex && left.mContentFile==right.mContentFile; | ||||
| } | ||||
|  | @ -8,6 +8,7 @@ | |||
| namespace ESM | ||||
| { | ||||
|     class ESMWriter; | ||||
|     class ESMReader; | ||||
| 
 | ||||
|     /* Cell reference. This represents ONE object (of many) inside the
 | ||||
|     cell. The cell references are not loaded as part of the normal | ||||
|  | @ -19,8 +20,14 @@ namespace ESM | |||
|     { | ||||
|         public: | ||||
| 
 | ||||
|             int mRefnum;           // Reference number
 | ||||
|             std::string mRefID;    // ID of object being referenced (must be lowercase)
 | ||||
|             struct RefNum | ||||
|             { | ||||
|                 int mIndex; | ||||
|                 int mContentFile; // -1 no content file
 | ||||
|             }; | ||||
| 
 | ||||
|             RefNum mRefNum;        // Reference number
 | ||||
|             std::string mRefID;    // ID of object being referenced
 | ||||
| 
 | ||||
|             float mScale;          // Scale applied to mesh
 | ||||
| 
 | ||||
|  | @ -80,10 +87,14 @@ namespace ESM | |||
|             // Position and rotation of this object within the cell
 | ||||
|             Position mPos; | ||||
| 
 | ||||
|             void save(ESMWriter &esm) const; | ||||
|             void load (ESMReader& esm, bool wideRefNum = false); | ||||
| 
 | ||||
|             void save(ESMWriter &esm, bool wideRefNum = false) const; | ||||
| 
 | ||||
|             void blank(); | ||||
|     }; | ||||
| 
 | ||||
|     bool operator== (const CellRef::RefNum& left, const CellRef::RefNum& right); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										17
									
								
								components/esm/cellstate.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								components/esm/cellstate.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| 
 | ||||
| #include "cellstate.hpp" | ||||
| 
 | ||||
| #include "esmreader.hpp" | ||||
| #include "esmwriter.hpp" | ||||
| 
 | ||||
| void ESM::CellState::load (ESMReader &esm) | ||||
| { | ||||
|     mWaterLevel = 0; | ||||
|     esm.getHNOT (mWaterLevel, "WLVL"); | ||||
| } | ||||
| 
 | ||||
| void ESM::CellState::save (ESMWriter &esm) const | ||||
| { | ||||
|     if (!mId.mPaged) | ||||
|         esm.writeHNT ("WLVL", mWaterLevel); | ||||
| } | ||||
							
								
								
									
										25
									
								
								components/esm/cellstate.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								components/esm/cellstate.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| #ifndef OPENMW_ESM_CELLSTATE_H | ||||
| #define OPENMW_ESM_CELLSTATE_H | ||||
| 
 | ||||
| #include "cellid.hpp" | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
|     class ESMWriter; | ||||
| 
 | ||||
|     // format 0, saved games only
 | ||||
| 
 | ||||
|     /// \note Does not include references
 | ||||
|     struct CellState | ||||
|     { | ||||
|         CellId mId; | ||||
| 
 | ||||
|         float mWaterLevel; | ||||
| 
 | ||||
|         void load (ESMReader &esm); | ||||
|         void save (ESMWriter &esm) const; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -88,6 +88,9 @@ enum RecNameInts | |||
|     REC_JOUR = 0x524f55a4, | ||||
|     REC_QUES = 0x53455551, | ||||
|     REC_GSCR = 0x52435347, | ||||
|     REC_PLAY = 0x59414c50, | ||||
|     REC_CSTA = 0x41545343, | ||||
|     REC_OBJE = 0x454a424f, | ||||
| 
 | ||||
|     // format 1
 | ||||
|     REC_FILT = 0x544C4946 | ||||
|  |  | |||
|  | @ -3,26 +3,52 @@ | |||
| #include <string> | ||||
| #include <sstream> | ||||
| #include <list> | ||||
| 
 | ||||
| #include <boost/concept_check.hpp> | ||||
| 
 | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include "esmreader.hpp" | ||||
| #include "esmwriter.hpp" | ||||
| #include "defs.hpp" | ||||
| #include "cellid.hpp" | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|     ///< Translate 8bit/24bit code (stored in refNum.mIndex) into a proper refNum
 | ||||
|     void adjustRefNum (ESM::CellRef::RefNum& refNum, ESM::ESMReader& reader) | ||||
|     { | ||||
|         int local = (refNum.mIndex & 0xff000000) >> 24; | ||||
| 
 | ||||
|         if (local) | ||||
|         { | ||||
|             // If the most significant 8 bits are used, then this reference already exists.
 | ||||
|             // In this case, do not spawn a new reference, but overwrite the old one.
 | ||||
|             refNum.mIndex &= 0x00ffffff; // delete old plugin ID
 | ||||
|             refNum.mContentFile = reader.getGameFiles()[local-1].index; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // This is an addition by the present plugin. Set the corresponding plugin index.
 | ||||
|             refNum.mContentFile = reader.getIndex(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     unsigned int Cell::sRecordId = REC_CELL; | ||||
| 
 | ||||
| /// Some overloaded compare operators.
 | ||||
| bool operator==(const MovedCellRef& ref, int pRefnum) | ||||
| { | ||||
|   return (ref.mRefnum == pRefnum); | ||||
| } | ||||
|     // Some overloaded compare operators.
 | ||||
|     bool operator== (const MovedCellRef& ref, const CellRef::RefNum& refNum) | ||||
|     { | ||||
|         return ref.mRefNum == refNum; | ||||
|     } | ||||
| 
 | ||||
| bool operator==(const CellRef& ref, int pRefnum) | ||||
| { | ||||
|   return (ref.mRefnum == pRefnum); | ||||
| } | ||||
|     bool operator== (const CellRef& ref, const CellRef::RefNum& refNum) | ||||
|     { | ||||
|         return ref.mRefNum == refNum; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| void Cell::load(ESMReader &esm, bool saveContext) | ||||
|  | @ -155,109 +181,10 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) | |||
|         // That should be it, I haven't seen any other fields yet.
 | ||||
|     } | ||||
| 
 | ||||
|     // NAM0 sometimes appears here, sometimes further on
 | ||||
|     ref.mNam0 = 0; | ||||
|     if (esm.isNextSub("NAM0")) | ||||
|     { | ||||
|         esm.getHT(ref.mNam0); | ||||
|         //esm.getHNOT(NAM0, "NAM0");
 | ||||
|     } | ||||
| 
 | ||||
|     esm.getHNT(ref.mRefnum, "FRMR"); | ||||
|     ref.mRefID = esm.getHNString("NAME"); | ||||
|     ref.load (esm); | ||||
| 
 | ||||
|     // Identify references belonging to a parent file and adapt the ID accordingly.
 | ||||
|     int local = (ref.mRefnum & 0xff000000) >> 24; | ||||
|     size_t global = esm.getIndex() + 1; | ||||
|     if (local) | ||||
|     { | ||||
|         // If the most significant 8 bits are used, then this reference already exists.
 | ||||
|         // In this case, do not spawn a new reference, but overwrite the old one.
 | ||||
|         ref.mRefnum &= 0x00ffffff; // delete old plugin ID
 | ||||
|         const std::vector<Header::MasterData> &masters = esm.getGameFiles(); | ||||
|         global = masters[local-1].index + 1; | ||||
|         ref.mRefnum |= global << 24; // insert global plugin ID
 | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // This is an addition by the present plugin. Set the corresponding plugin index.
 | ||||
|         ref.mRefnum |= global << 24; // insert global plugin ID
 | ||||
|     } | ||||
| 
 | ||||
|     // getHNOT will not change the existing value if the subrecord is
 | ||||
|     // missing
 | ||||
|     ref.mScale = 1.0; | ||||
|     esm.getHNOT(ref.mScale, "XSCL"); | ||||
| 
 | ||||
|     // TODO: support loading references from saves, there are tons of keys not recognized yet.
 | ||||
|     // The following is just an incomplete list.
 | ||||
|     if (esm.isNextSub("ACTN")) | ||||
|         esm.skipHSub(); | ||||
|     if (esm.isNextSub("STPR")) | ||||
|         esm.skipHSub(); | ||||
|     if (esm.isNextSub("ACDT")) | ||||
|         esm.skipHSub(); | ||||
|     if (esm.isNextSub("ACSC")) | ||||
|         esm.skipHSub(); | ||||
|     if (esm.isNextSub("ACSL")) | ||||
|         esm.skipHSub(); | ||||
|     if (esm.isNextSub("CHRD")) | ||||
|         esm.skipHSub(); | ||||
|     else if (esm.isNextSub("CRED")) // ???
 | ||||
|         esm.skipHSub(); | ||||
| 
 | ||||
|     ref.mOwner = esm.getHNOString("ANAM"); | ||||
|     ref.mGlob = esm.getHNOString("BNAM"); | ||||
|     ref.mSoul = esm.getHNOString("XSOL"); | ||||
| 
 | ||||
|     ref.mFaction = esm.getHNOString("CNAM"); | ||||
|     ref.mFactIndex = -2; | ||||
|     esm.getHNOT(ref.mFactIndex, "INDX"); | ||||
| 
 | ||||
|     ref.mGoldValue = 1; | ||||
|     ref.mCharge = -1; | ||||
|     ref.mEnchantmentCharge = -1; | ||||
| 
 | ||||
|     esm.getHNOT(ref.mEnchantmentCharge, "XCHG"); | ||||
| 
 | ||||
|     esm.getHNOT(ref.mCharge, "INTV"); | ||||
| 
 | ||||
|     esm.getHNOT(ref.mGoldValue, "NAM9"); | ||||
| 
 | ||||
|     // Present for doors that teleport you to another cell.
 | ||||
|     if (esm.isNextSub("DODT")) | ||||
|     { | ||||
|         ref.mTeleport = true; | ||||
|         esm.getHT(ref.mDoorDest); | ||||
|         ref.mDestCell = esm.getHNOString("DNAM"); | ||||
|     } else { | ||||
|         ref.mTeleport = false; | ||||
|     } | ||||
| 
 | ||||
|     // Integer, despite the name suggesting otherwise
 | ||||
|     ref.mLockLevel = -1; | ||||
|     esm.getHNOT(ref.mLockLevel, "FLTV"); | ||||
|     ref.mKey = esm.getHNOString("KNAM"); | ||||
|     ref.mTrap = esm.getHNOString("TNAM"); | ||||
| 
 | ||||
|     ref.mReferenceBlocked = -1; | ||||
|     ref.mFltv = 0; | ||||
|     esm.getHNOT(ref.mReferenceBlocked, "UNAM"); | ||||
|     esm.getHNOT(ref.mFltv, "FLTV"); | ||||
| 
 | ||||
|     esm.getHNOT(ref.mPos, "DATA", 24); | ||||
| 
 | ||||
|     // Number of references in the cell? Maximum once in each cell,
 | ||||
|     // but not always at the beginning, and not always right. In other
 | ||||
|     // words, completely useless.
 | ||||
|     // Update: Well, maybe not completely useless. This might actually be
 | ||||
|     //  number_of_references + number_of_references_moved_here_Across_boundaries,
 | ||||
|     //  and could be helpful for collecting these weird moved references.
 | ||||
|     if (esm.isNextSub("NAM0")) | ||||
|     { | ||||
|         esm.getHT(ref.mNam0); | ||||
|         //esm.getHNOT(NAM0, "NAM0");
 | ||||
|     } | ||||
|     adjustRefNum (ref.mRefNum, esm); | ||||
| 
 | ||||
|     if (esm.isNextSub("DELE")) | ||||
|     { | ||||
|  | @ -272,16 +199,10 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) | |||
| 
 | ||||
| bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) | ||||
| { | ||||
|     esm.getHT(mref.mRefnum); | ||||
|     esm.getHT(mref.mRefNum.mIndex); | ||||
|     esm.getHNOT(mref.mTarget, "CNDT"); | ||||
| 
 | ||||
|     // Identify references belonging to a parent file and adapt the ID accordingly.
 | ||||
|     int local = (mref.mRefnum & 0xff000000) >> 24; | ||||
|     size_t global = esm.getIndex() + 1; | ||||
|     mref.mRefnum &= 0x00ffffff; // delete old plugin ID
 | ||||
|     const std::vector<Header::MasterData> &masters = esm.getGameFiles(); | ||||
|     global = masters[local-1].index + 1; | ||||
|     mref.mRefnum |= global << 24; // insert global plugin ID
 | ||||
|     adjustRefNum (mref.mRefNum, esm); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
|  | @ -304,4 +225,24 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) | |||
|         mAmbi.mFog = 0; | ||||
|         mAmbi.mFogDensity = 0; | ||||
|     } | ||||
| 
 | ||||
|     CellId Cell::getCellId() const | ||||
|     { | ||||
|         CellId id; | ||||
| 
 | ||||
|         id.mPaged = !(mData.mFlags & Interior); | ||||
| 
 | ||||
|         if (id.mPaged) | ||||
|         { | ||||
|             id.mWorldspace = "default"; | ||||
|             id.mIndex.mX = mData.mX; | ||||
|             id.mIndex.mY = mData.mY; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             id.mWorldspace = Misc::StringUtils::lowerCase (mName); | ||||
|         } | ||||
| 
 | ||||
|         return id; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ namespace ESM | |||
| { | ||||
| class ESMReader; | ||||
| class ESMWriter; | ||||
|     class CellId; | ||||
| 
 | ||||
| /* Moved cell reference tracking object. This mainly stores the target cell
 | ||||
|         of the reference, so we can easily know where it has been moved when another | ||||
|  | @ -27,7 +28,7 @@ class ESMWriter; | |||
| class MovedCellRef | ||||
| { | ||||
| public: | ||||
|     int mRefnum; | ||||
|     CellRef::RefNum mRefNum; | ||||
| 
 | ||||
|     // Target cell (if exterior)
 | ||||
|     int mTarget[2]; | ||||
|  | @ -37,9 +38,9 @@ public: | |||
|     //  introduces a henchman (which no one uses), so we may need this as well.
 | ||||
| }; | ||||
| 
 | ||||
| /// Overloaded copare operator used to search inside a list of cell refs.
 | ||||
| bool operator==(const MovedCellRef& ref, int pRefnum); | ||||
| bool operator==(const CellRef& ref, int pRefnum); | ||||
| /// Overloaded compare operator used to search inside a list of cell refs.
 | ||||
| bool operator==(const MovedCellRef& ref, const CellRef::RefNum& refNum); | ||||
| bool operator==(const CellRef& ref, const CellRef::RefNum& refNum); | ||||
| 
 | ||||
| typedef std::list<MovedCellRef> MovedCellRefTracker; | ||||
| typedef std::list<CellRef> CellRefTracker; | ||||
|  | @ -150,6 +151,8 @@ struct Cell | |||
| 
 | ||||
|     void blank(); | ||||
|     ///< Set record to default state (does not touch the ID/index).
 | ||||
| 
 | ||||
|     CellId getCellId() const; | ||||
| }; | ||||
| } | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										47
									
								
								components/esm/objectstate.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								components/esm/objectstate.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| 
 | ||||
| #include "objectstate.hpp" | ||||
| 
 | ||||
| #include "esmreader.hpp" | ||||
| #include "esmwriter.hpp" | ||||
| 
 | ||||
| void ESM::ObjectState::load (ESMReader &esm) | ||||
| { | ||||
|     mRef.load (esm, true); | ||||
| 
 | ||||
|     mHasLocals = 0; | ||||
|     esm.getHNOT (mHasLocals, "HLOC"); | ||||
| 
 | ||||
|     if (mHasLocals) | ||||
|         mLocals.load (esm); | ||||
| 
 | ||||
|     mEnabled = 1; | ||||
|     esm.getHNOT (mEnabled, "ENAB"); | ||||
| 
 | ||||
|     mCount = 1; | ||||
|     esm.getHNOT (mCount, "COUN"); | ||||
| 
 | ||||
|     esm.getHNT (mPosition, "POS_", 24); | ||||
| 
 | ||||
|     esm.getHNT (mLocalRotation, "LROT", 12); | ||||
| } | ||||
| 
 | ||||
| void ESM::ObjectState::save (ESMWriter &esm) const | ||||
| { | ||||
|     mRef.save (esm, true); | ||||
| 
 | ||||
|     if (mHasLocals) | ||||
|     { | ||||
|         esm.writeHNT ("HLOC", mHasLocals); | ||||
|         mLocals.save (esm); | ||||
|     } | ||||
| 
 | ||||
|     if (!mEnabled) | ||||
|         esm.writeHNT ("ENAB", mEnabled); | ||||
| 
 | ||||
|     if (mCount!=1) | ||||
|         esm.writeHNT ("COUN", mCount); | ||||
| 
 | ||||
|     esm.writeHNT ("POS_", mPosition, 24); | ||||
| 
 | ||||
|     esm.writeHNT ("LROT", mLocalRotation, 12); | ||||
| } | ||||
							
								
								
									
										34
									
								
								components/esm/objectstate.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								components/esm/objectstate.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| #ifndef OPENMW_ESM_OBJECTSTATE_H | ||||
| #define OPENMW_ESM_OBJECTSTATE_H | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "cellref.hpp" | ||||
| #include "locals.hpp" | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
|     class ESMWriter; | ||||
| 
 | ||||
|     // format 0, saved games only
 | ||||
| 
 | ||||
|     ///< \brief Save state for objects, that do not use custom data
 | ||||
|     struct ObjectState | ||||
|     { | ||||
|         CellRef mRef; | ||||
| 
 | ||||
|         unsigned char mHasLocals; | ||||
|         Locals mLocals; | ||||
|         unsigned char mEnabled; | ||||
|         int mCount; | ||||
|         ESM::Position mPosition; | ||||
|         float mLocalRotation[3]; | ||||
| 
 | ||||
|         void load (ESMReader &esm); | ||||
|         void save (ESMWriter &esm) const; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										48
									
								
								components/esm/player.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								components/esm/player.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| 
 | ||||
| #include "player.hpp" | ||||
| 
 | ||||
| #include "esmreader.hpp" | ||||
| #include "esmwriter.hpp" | ||||
| 
 | ||||
| void ESM::Player::load (ESMReader &esm) | ||||
| { | ||||
|     mObject.load (esm); | ||||
| 
 | ||||
|     mCellId.load (esm); | ||||
| 
 | ||||
|     esm.getHNT (mLastKnownExteriorPosition, "LKEP", 12); | ||||
| 
 | ||||
|     if (esm.isNextSub ("MARK")) | ||||
|     { | ||||
|         mHasMark = true; | ||||
|         esm.getHT (mMarkedPosition, 24); | ||||
|         mMarkedCell.load (esm); | ||||
|     } | ||||
|     else | ||||
|         mHasMark = false; | ||||
| 
 | ||||
|     mAutoMove = 0; | ||||
|     esm.getHNOT (mAutoMove, "AMOV"); | ||||
| 
 | ||||
|     mBirthsign = esm.getHNString ("SIGN"); | ||||
| } | ||||
| 
 | ||||
| void ESM::Player::save (ESMWriter &esm) const | ||||
| { | ||||
|     mObject.save (esm); | ||||
| 
 | ||||
|     mCellId.save (esm); | ||||
| 
 | ||||
|     esm.writeHNT ("LKEP", mLastKnownExteriorPosition, 12); | ||||
| 
 | ||||
|     if (mHasMark) | ||||
|     { | ||||
|         esm.writeHNT ("MARK", mMarkedPosition, 24); | ||||
|         mMarkedCell.save (esm); | ||||
|     } | ||||
| 
 | ||||
|     if (mAutoMove) | ||||
|         esm.writeHNT ("AMOV", mAutoMove); | ||||
| 
 | ||||
|     esm.writeHNString ("SIGN", mBirthsign); | ||||
| } | ||||
							
								
								
									
										33
									
								
								components/esm/player.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								components/esm/player.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| #ifndef OPENMW_ESM_PLAYER_H | ||||
| #define OPENMW_ESM_PLAYER_H | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include "objectstate.hpp" | ||||
| #include "cellid.hpp" | ||||
| #include "defs.hpp" | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
|     class ESMWriter; | ||||
| 
 | ||||
|     // format 0, saved games only
 | ||||
| 
 | ||||
|     struct Player | ||||
|     { | ||||
|         ObjectState mObject; | ||||
|         CellId mCellId; | ||||
|         float mLastKnownExteriorPosition[3]; | ||||
|         unsigned char mHasMark; | ||||
|         ESM::Position mMarkedPosition; | ||||
|         CellId mMarkedCell; | ||||
|         unsigned char mAutoMove; | ||||
|         std::string mBirthsign; | ||||
| 
 | ||||
|         void load (ESMReader &esm); | ||||
|         void save (ESMWriter &esm) const; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
		Loading…
	
		Reference in a new issue