mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-02 01:15:32 +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