mirror of
https://github.com/OpenMW/openmw.git
synced 2025-11-01 04:26:42 +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;
|
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 << " ID: '" << ref.mRefID << "'\n";
|
||||||
std::cout << " Owner: '" << ref.mOwner << "'\n";
|
std::cout << " Owner: '" << ref.mOwner << "'\n";
|
||||||
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,8 @@ namespace MWBase
|
||||||
virtual void update(float duration) = 0;
|
virtual void update(float duration) = 0;
|
||||||
|
|
||||||
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 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 Potion;
|
||||||
struct Spell;
|
struct Spell;
|
||||||
struct NPC;
|
struct NPC;
|
||||||
|
struct CellId;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
|
@ -105,12 +106,14 @@ namespace MWBase
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
||||||
|
|
||||||
virtual OEngine::Render::Fader* getFader() = 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 *getExterior (int x, int y) = 0;
|
||||||
|
|
||||||
virtual MWWorld::CellStore *getInterior (const std::string& name) = 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 useDeathCamera() = 0;
|
||||||
|
|
||||||
virtual void setWaterHeight(const float height) = 0;
|
virtual void setWaterHeight(const float height) = 0;
|
||||||
|
|
@ -236,6 +239,8 @@ namespace MWBase
|
||||||
virtual void changeToExteriorCell (const ESM::Position& position) = 0;
|
virtual void changeToExteriorCell (const ESM::Position& position) = 0;
|
||||||
///< Move to exterior cell.
|
///< 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;
|
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.
|
///< 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/statemanager.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwstate/character.hpp"
|
#include "../mwstate/character.hpp"
|
||||||
|
|
||||||
|
|
@ -123,6 +124,12 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisible(false);
|
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)
|
void SaveGameDialog::onCharacterSelected(MyGUI::ComboBox *sender, size_t pos)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include <extern/sdl4ogre/sdlcursormanager.hpp>
|
#include <extern/sdl4ogre/sdlcursormanager.hpp>
|
||||||
|
|
||||||
#include "../mwbase/inputmanager.hpp"
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
|
|
@ -709,6 +710,10 @@ namespace MWGui
|
||||||
|
|
||||||
mToolTips->onFrame(frameDuration);
|
mToolTips->onFrame(frameDuration);
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||||
|
MWBase::StateManager::State_NoGame)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mDragAndDrop->mIsOnDragAndDrop)
|
if (mDragAndDrop->mIsOnDragAndDrop)
|
||||||
{
|
{
|
||||||
assert(mDragAndDrop->mDraggedWidget);
|
assert(mDragAndDrop->mDraggedWidget);
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/inputmanager.hpp" // FIXME
|
#include "../mwbase/inputmanager.hpp" // FIXME
|
||||||
#include "../mwbase/windowmanager.hpp" // FIXME
|
#include "../mwbase/windowmanager.hpp" // FIXME
|
||||||
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
|
|
@ -329,6 +330,12 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr)
|
||||||
|
|
||||||
void RenderingManager::update (float duration, bool paused)
|
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();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
MWWorld::Ptr player = world->getPlayer().getPlayer();
|
MWWorld::Ptr player = world->getPlayer().getPlayer();
|
||||||
|
|
@ -365,8 +372,6 @@ void RenderingManager::update (float duration, bool paused)
|
||||||
|
|
||||||
mOcclusionQuery->update(duration);
|
mOcclusionQuery->update(duration);
|
||||||
|
|
||||||
mVideoPlayer->update ();
|
|
||||||
|
|
||||||
mRendering.update(duration);
|
mRendering.update(duration);
|
||||||
|
|
||||||
Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f);
|
Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
|
|
@ -607,8 +608,13 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
if(!mOutput->isInitialized())
|
if(!mOutput->isInitialized())
|
||||||
return;
|
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);
|
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 update(float duration);
|
||||||
|
|
||||||
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up);
|
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/esmwriter.hpp>
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/cellid.hpp>
|
||||||
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
|
@ -13,6 +15,7 @@
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/scriptmanager.hpp"
|
#include "../mwbase/scriptmanager.hpp"
|
||||||
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
@ -21,10 +24,11 @@
|
||||||
|
|
||||||
#include "../mwscript/globalscripts.hpp"
|
#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().getDialogueManager()->clear();
|
||||||
MWBase::Environment::get().getJournal()->clear();
|
MWBase::Environment::get().getJournal()->clear();
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().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)
|
void MWState::StateManager::loadGame (const Character *character, const Slot *slot)
|
||||||
{
|
{
|
||||||
cleanup();
|
try
|
||||||
|
|
||||||
mTimePlayed = slot->mProfile.mTimePlayed;
|
|
||||||
|
|
||||||
ESM::ESMReader reader;
|
|
||||||
reader.open (slot->mPath.string());
|
|
||||||
|
|
||||||
while (reader.hasMoreRecs())
|
|
||||||
{
|
{
|
||||||
ESM::NAME n = reader.getRecName();
|
cleanup();
|
||||||
reader.getRecHeader();
|
|
||||||
|
|
||||||
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
|
switch (n.val)
|
||||||
reader.skipRecord();
|
{
|
||||||
break;
|
case ESM::REC_SAVE:
|
||||||
|
|
||||||
case ESM::REC_JOUR:
|
// don't need to read that here
|
||||||
case ESM::REC_QUES:
|
reader.skipRecord();
|
||||||
|
break;
|
||||||
|
|
||||||
MWBase::Environment::get().getJournal()->readRecord (reader, n.val);
|
case ESM::REC_JOUR:
|
||||||
break;
|
case ESM::REC_QUES:
|
||||||
|
|
||||||
case ESM::REC_ALCH:
|
MWBase::Environment::get().getJournal()->readRecord (reader, n.val);
|
||||||
case ESM::REC_ARMO:
|
break;
|
||||||
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().getWorld()->readRecord (reader, n.val);
|
case ESM::REC_ALCH:
|
||||||
break;
|
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);
|
case ESM::REC_GSCR:
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val);
|
||||||
|
break;
|
||||||
|
|
||||||
// ignore invalid records
|
default:
|
||||||
/// \todo log error
|
|
||||||
reader.skipRecord();
|
// 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)
|
MWState::Character *MWState::StateManager::getCurrentCharacter (bool create)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ namespace MWState
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void cleanup();
|
void cleanup (bool force = false);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
#include "cells.hpp"
|
#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/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
|
@ -59,6 +64,30 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore&
|
||||||
return ptr;
|
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)
|
MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader)
|
||||||
: mStore (store), mReader (reader),
|
: mStore (store), mReader (reader),
|
||||||
mIdCache (40, std::pair<std::string, CellStore *> ("", (CellStore*)0)), /// \todo make cache size configurable
|
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;
|
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,
|
MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell,
|
||||||
bool searchInContainers)
|
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
|
namespace ESM
|
||||||
{
|
{
|
||||||
class ESMReader;
|
class ESMReader;
|
||||||
|
class ESMWriter;
|
||||||
|
struct CellId;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
|
@ -33,18 +35,23 @@ namespace MWWorld
|
||||||
|
|
||||||
Ptr getPtrAndCache (const std::string& name, CellStore& cellStore);
|
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:
|
public:
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader);
|
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 *getExterior (int x, int y);
|
||||||
|
|
||||||
CellStore *getInterior (const std::string& name);
|
CellStore *getInterior (const std::string& name);
|
||||||
|
|
||||||
|
CellStore *getCell (const ESM::CellId& id);
|
||||||
|
|
||||||
Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false);
|
Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false);
|
||||||
///< \param searchInContainers Only affect loaded cells.
|
///< \param searchInContainers Only affect loaded cells.
|
||||||
/// @note name must be lower case
|
/// @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 Due to the current implementation of getPtr this only supports one Ptr per cell.
|
||||||
/// @note name must be lower case
|
/// @note name must be lower case
|
||||||
void getExteriorPtrs (const std::string& name, std::vector<MWWorld::Ptr>& out);
|
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 <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/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
|
@ -29,6 +34,33 @@ namespace
|
||||||
|
|
||||||
return MWWorld::Ptr();
|
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
|
namespace MWWorld
|
||||||
|
|
@ -42,7 +74,7 @@ namespace MWWorld
|
||||||
if (const X *ptr = store.search (ref.mRefID))
|
if (const X *ptr = store.search (ref.mRefID))
|
||||||
{
|
{
|
||||||
typename std::list<LiveRef>::iterator iter =
|
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);
|
LiveRef liveCellRef (ref, ptr);
|
||||||
|
|
||||||
|
|
@ -143,13 +175,16 @@ namespace MWWorld
|
||||||
mCell->restore (esm[index], i);
|
mCell->restore (esm[index], i);
|
||||||
|
|
||||||
ESM::CellRef ref;
|
ESM::CellRef ref;
|
||||||
|
ref.mRefNum.mContentFile = -1;
|
||||||
|
|
||||||
// Get each reference in turn
|
// Get each reference in turn
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
while(mCell->getNextRef(esm[index], ref, deleted))
|
while(mCell->getNextRef(esm[index], ref, deleted))
|
||||||
{
|
{
|
||||||
// Don't load reference if it was moved to a different cell.
|
// 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()) {
|
if (iter != mCell->mMovedRefs.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -227,4 +262,46 @@ namespace MWWorld
|
||||||
<< "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
|
<< "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 "livecellref.hpp"
|
||||||
#include "esmstore.hpp"
|
#include "esmstore.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct CellState;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -133,6 +138,12 @@ namespace MWWorld
|
||||||
|
|
||||||
Ptr searchInContainer (const std::string& id);
|
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:
|
private:
|
||||||
|
|
||||||
template<class Functor, class List>
|
template<class Functor, class List>
|
||||||
|
|
@ -158,7 +169,6 @@ namespace MWWorld
|
||||||
///< Make case-adjustments to \a ref and insert it into the respective container.
|
///< Make case-adjustments to \a ref and insert it into the respective container.
|
||||||
///
|
///
|
||||||
/// Invalid \a ref objects are silently dropped.
|
/// Invalid \a ref objects are silently dropped.
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,9 +161,9 @@ void ESMStore::setUp()
|
||||||
mClasses.write (writer);
|
mClasses.write (writer);
|
||||||
mClothes.write (writer);
|
mClothes.write (writer);
|
||||||
mEnchants.write (writer);
|
mEnchants.write (writer);
|
||||||
mNpcs.write (writer);
|
|
||||||
mSpells.write (writer);
|
mSpells.write (writer);
|
||||||
mWeapons.write (writer);
|
mWeapons.write (writer);
|
||||||
|
mNpcs.write (writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type)
|
bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||||
|
|
@ -176,11 +176,25 @@ void ESMStore::setUp()
|
||||||
case ESM::REC_CLAS:
|
case ESM::REC_CLAS:
|
||||||
case ESM::REC_CLOT:
|
case ESM::REC_CLOT:
|
||||||
case ESM::REC_ENCH:
|
case ESM::REC_ENCH:
|
||||||
case ESM::REC_NPC_:
|
|
||||||
case ESM::REC_SPEL:
|
case ESM::REC_SPEL:
|
||||||
case ESM::REC_WEAP:
|
case ESM::REC_WEAP:
|
||||||
|
case ESM::REC_NPC_:
|
||||||
|
|
||||||
mStores[type]->read (reader);
|
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;
|
return true;
|
||||||
|
|
||||||
default:
|
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"
|
#include "refdata.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ObjectState;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
|
@ -29,8 +34,31 @@ namespace MWWorld
|
||||||
LiveCellRefBase(std::string type, const ESM::CellRef &cref=ESM::CellRef());
|
LiveCellRefBase(std::string type, const ESM::CellRef &cref=ESM::CellRef());
|
||||||
/* Need this for the class to be recognized as polymorphic */
|
/* Need this for the class to be recognized as polymorphic */
|
||||||
virtual ~LiveCellRefBase() { }
|
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.
|
/// A reference to one object (of any type) in a cell.
|
||||||
///
|
///
|
||||||
/// Constructing this with a CellRef instance in the constructor means that
|
/// 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.
|
// The object that this instance is based on.
|
||||||
const X* mBase;
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
LiveCellRef<T> ref;
|
LiveCellRef<T> ref;
|
||||||
ref.mBase = instance;
|
ref.mBase = instance;
|
||||||
|
ref.mRef.mRefNum.mIndex = 0;
|
||||||
|
ref.mRef.mRefNum.mContentFile = -1;
|
||||||
|
|
||||||
mRef = ref;
|
mRef = ref;
|
||||||
mPtr = Ptr (&boost::any_cast<LiveCellRef<T>&> (mRef), 0);
|
mPtr = Ptr (&boost::any_cast<LiveCellRef<T>&> (mRef), 0);
|
||||||
|
|
@ -64,8 +66,9 @@ namespace MWWorld
|
||||||
|
|
||||||
// initialise
|
// initialise
|
||||||
ESM::CellRef& cellRef = mPtr.getCellRef();
|
ESM::CellRef& cellRef = mPtr.getCellRef();
|
||||||
cellRef.mRefID = Misc::StringUtils::lowerCase(name);
|
cellRef.mRefID = Misc::StringUtils::lowerCase (name);
|
||||||
cellRef.mRefnum = -1;
|
cellRef.mRefNum.mIndex = 0;
|
||||||
|
cellRef.mRefNum.mContentFile = -1;
|
||||||
cellRef.mScale = 1;
|
cellRef.mScale = 1;
|
||||||
cellRef.mFactIndex = 0;
|
cellRef.mFactIndex = 0;
|
||||||
cellRef.mCharge = -1;
|
cellRef.mCharge = -1;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
|
||||||
#include "player.hpp"
|
#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/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
@ -34,9 +41,6 @@ namespace MWWorld
|
||||||
void Player::set(const ESM::NPC *player)
|
void Player::set(const ESM::NPC *player)
|
||||||
{
|
{
|
||||||
mPlayer.mBase = player;
|
mPlayer.mBase = player;
|
||||||
|
|
||||||
float* playerPos = mPlayer.mData.getPosition().pos;
|
|
||||||
playerPos[0] = playerPos[1] = playerPos[2] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::setCell (MWWorld::CellStore *cellStore)
|
void Player::setCell (MWWorld::CellStore *cellStore)
|
||||||
|
|
@ -171,4 +175,102 @@ namespace MWWorld
|
||||||
if (mMarkedCell)
|
if (mMarkedCell)
|
||||||
markedPosition = mMarkedPosition;
|
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
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct NPC;
|
struct NPC;
|
||||||
|
class ESMWriter;
|
||||||
|
class ESMReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWBase
|
namespace MWBase
|
||||||
|
|
@ -86,6 +88,12 @@ namespace MWWorld
|
||||||
|
|
||||||
bool wasTeleported() const;
|
bool wasTeleported() const;
|
||||||
void setTeleported(bool teleported);
|
void setTeleported(bool teleported);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void write (ESM::ESMWriter& writer) const;
|
||||||
|
|
||||||
|
bool readRecord (ESM::ESMReader& reader, int32_t type);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
|
|
||||||
|
#include <components/esm/objectstate.hpp>
|
||||||
|
|
||||||
#include "customdata.hpp"
|
#include "customdata.hpp"
|
||||||
#include "cellstore.hpp"
|
#include "cellstore.hpp"
|
||||||
|
|
||||||
|
|
@ -52,6 +54,14 @@ namespace MWWorld
|
||||||
mLocalRotation.rot[2]=0;
|
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)
|
RefData::RefData (const RefData& refData)
|
||||||
: mBaseNode(0), mCustomData (0)
|
: 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)
|
RefData& RefData::operator= (const RefData& refData)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ namespace ESM
|
||||||
{
|
{
|
||||||
class Script;
|
class Script;
|
||||||
class CellRef;
|
class CellRef;
|
||||||
|
class ObjectState;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
|
@ -55,10 +56,18 @@ namespace MWWorld
|
||||||
/// to reset the position as the orignal data is still held in the CellRef
|
/// to reset the position as the orignal data is still held in the CellRef
|
||||||
RefData (const ESM::CellRef& 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 (const RefData& 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);
|
RefData& operator= (const RefData& refData);
|
||||||
|
|
||||||
/// Return OGRE handle (may be empty).
|
/// 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.
|
// We should not need to test for duplicates, as this part of the code is pre-cell merge.
|
||||||
cell->mMovedRefs.push_back(cMRef);
|
cell->mMovedRefs.push_back(cMRef);
|
||||||
// But there may be duplicates here!
|
// 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())
|
if (iter == cellAlt->mLeasedRefs.end())
|
||||||
cellAlt->mLeasedRefs.push_back(ref);
|
cellAlt->mLeasedRefs.push_back(ref);
|
||||||
else
|
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
|
// 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) {
|
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
|
// 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()) {
|
if (itold != oldcell->mMovedRefs.end()) {
|
||||||
ESM::MovedCellRef target0 = *itold;
|
ESM::MovedCellRef target0 = *itold;
|
||||||
ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(target0.mTarget[0], target0.mTarget[1]));
|
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);
|
wipecell->mLeasedRefs.erase(it_lease);
|
||||||
*itold = *it;
|
*itold = *it;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include <components/bsa/bsa_archive.hpp>
|
#include <components/bsa/bsa_archive.hpp>
|
||||||
#include <components/files/collections.hpp>
|
#include <components/files/collections.hpp>
|
||||||
#include <components/compiler/locals.hpp>
|
#include <components/compiler/locals.hpp>
|
||||||
|
#include <components/esm/cellid.hpp>
|
||||||
|
|
||||||
#include <boost/math/special_functions/sign.hpp>
|
#include <boost/math/special_functions/sign.hpp>
|
||||||
|
|
||||||
|
|
@ -267,6 +268,7 @@ namespace MWWorld
|
||||||
void World::clear()
|
void World::clear()
|
||||||
{
|
{
|
||||||
mLocalScripts.clear();
|
mLocalScripts.clear();
|
||||||
|
mPlayer->clear();
|
||||||
|
|
||||||
// enable collision
|
// enable collision
|
||||||
if (!mPhysics->toggleCollisionMode())
|
if (!mPhysics->toggleCollisionMode())
|
||||||
|
|
@ -274,15 +276,16 @@ namespace MWWorld
|
||||||
|
|
||||||
mWorldScene->changeToVoid();
|
mWorldScene->changeToVoid();
|
||||||
|
|
||||||
|
mStore.clearDynamic();
|
||||||
|
mStore.setUp();
|
||||||
|
|
||||||
if (mPlayer)
|
if (mPlayer)
|
||||||
{
|
{
|
||||||
mPlayer->setCell (0);
|
mPlayer->setCell (0);
|
||||||
mPlayer->getPlayer().getRefData() = RefData();
|
mPlayer->getPlayer().getRefData() = RefData();
|
||||||
|
mPlayer->set (mStore.get<ESM::NPC>().find ("player"));
|
||||||
}
|
}
|
||||||
|
|
||||||
mStore.clearDynamic();
|
|
||||||
mStore.setUp();
|
|
||||||
|
|
||||||
mCells.clear();
|
mCells.clear();
|
||||||
|
|
||||||
mProjectiles.clear();
|
mProjectiles.clear();
|
||||||
|
|
@ -301,19 +304,25 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
mStore.countSavedGameRecords()
|
mStore.countSavedGameRecords()
|
||||||
+mGlobalVariables.countSavedGameRecords();
|
+mGlobalVariables.countSavedGameRecords()
|
||||||
|
+1 // player record
|
||||||
|
+mCells.countSavedGameRecords();
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::write (ESM::ESMWriter& writer) const
|
void World::write (ESM::ESMWriter& writer) const
|
||||||
{
|
{
|
||||||
mStore.write (writer);
|
mStore.write (writer);
|
||||||
mGlobalVariables.write (writer);
|
mGlobalVariables.write (writer);
|
||||||
|
mCells.write (writer);
|
||||||
|
mPlayer->write (writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::readRecord (ESM::ESMReader& reader, int32_t type)
|
void World::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||||
{
|
{
|
||||||
if (!mStore.readRecord (reader, 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");
|
throw std::runtime_error ("unknown record in saved game");
|
||||||
}
|
}
|
||||||
|
|
@ -401,6 +410,14 @@ namespace MWWorld
|
||||||
return mCells.getInterior (name);
|
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()
|
void World::useDeathCamera()
|
||||||
{
|
{
|
||||||
if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() )
|
if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() )
|
||||||
|
|
@ -801,6 +818,14 @@ namespace MWWorld
|
||||||
addContainerScripts(getPlayer().getPlayer(), getPlayer().getPlayer().getCell());
|
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()
|
void World::markCellAsUnchanged()
|
||||||
{
|
{
|
||||||
return mWorldScene->markCellAsUnchanged();
|
return mWorldScene->markCellAsUnchanged();
|
||||||
|
|
@ -1314,7 +1339,7 @@ namespace MWWorld
|
||||||
|
|
||||||
updateWindowManager ();
|
updateWindowManager ();
|
||||||
|
|
||||||
if (mPlayer->getPlayer().getCell()->isExterior())
|
if (!paused && mPlayer->getPlayer().getCell()->isExterior())
|
||||||
{
|
{
|
||||||
ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition();
|
ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition();
|
||||||
mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos));
|
mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos));
|
||||||
|
|
|
||||||
|
|
@ -181,12 +181,14 @@ namespace MWWorld
|
||||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||||
|
|
||||||
virtual OEngine::Render::Fader* getFader();
|
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 *getExterior (int x, int y);
|
||||||
|
|
||||||
virtual CellStore *getInterior (const std::string& name);
|
virtual CellStore *getInterior (const std::string& name);
|
||||||
|
|
||||||
|
virtual CellStore *getCell (const ESM::CellId& id);
|
||||||
|
|
||||||
//switch to POV before showing player's death animation
|
//switch to POV before showing player's death animation
|
||||||
virtual void useDeathCamera();
|
virtual void useDeathCamera();
|
||||||
|
|
||||||
|
|
@ -314,6 +316,8 @@ namespace MWWorld
|
||||||
virtual void changeToExteriorCell (const ESM::Position& position);
|
virtual void changeToExteriorCell (const ESM::Position& position);
|
||||||
///< Move to exterior cell.
|
///< 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;
|
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.
|
///< 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
|
loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc
|
||||||
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
||||||
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
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
|
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 "cellref.hpp"
|
||||||
|
|
||||||
|
#include "esmreader.hpp"
|
||||||
#include "esmwriter.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);
|
esm.writeHNCString("NAME", mRefID);
|
||||||
|
|
||||||
if (mScale != 1.0) {
|
if (mScale != 1.0) {
|
||||||
|
|
@ -58,7 +130,8 @@ void ESM::CellRef::save(ESMWriter &esm) const
|
||||||
|
|
||||||
void ESM::CellRef::blank()
|
void ESM::CellRef::blank()
|
||||||
{
|
{
|
||||||
mRefnum = 0;
|
mRefNum.mIndex = 0;
|
||||||
|
mRefNum.mContentFile = -1;
|
||||||
mRefID.clear();
|
mRefID.clear();
|
||||||
mScale = 1;
|
mScale = 1;
|
||||||
mOwner.clear();
|
mOwner.clear();
|
||||||
|
|
@ -84,4 +157,9 @@ void ESM::CellRef::blank()
|
||||||
mPos.pos[i] = 0;
|
mPos.pos[i] = 0;
|
||||||
mPos.rot[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
|
namespace ESM
|
||||||
{
|
{
|
||||||
class ESMWriter;
|
class ESMWriter;
|
||||||
|
class ESMReader;
|
||||||
|
|
||||||
/* Cell reference. This represents ONE object (of many) inside the
|
/* Cell reference. This represents ONE object (of many) inside the
|
||||||
cell. The cell references are not loaded as part of the normal
|
cell. The cell references are not loaded as part of the normal
|
||||||
|
|
@ -19,8 +20,14 @@ namespace ESM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int mRefnum; // Reference number
|
struct RefNum
|
||||||
std::string mRefID; // ID of object being referenced (must be lowercase)
|
{
|
||||||
|
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
|
float mScale; // Scale applied to mesh
|
||||||
|
|
||||||
|
|
@ -80,10 +87,14 @@ namespace ESM
|
||||||
// Position and rotation of this object within the cell
|
// Position and rotation of this object within the cell
|
||||||
Position mPos;
|
Position mPos;
|
||||||
|
|
||||||
void save(ESMWriter &esm) const;
|
void load (ESMReader& esm, bool wideRefNum = false);
|
||||||
|
|
||||||
|
void save(ESMWriter &esm, bool wideRefNum = false) const;
|
||||||
|
|
||||||
void blank();
|
void blank();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool operator== (const CellRef::RefNum& left, const CellRef::RefNum& right);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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_JOUR = 0x524f55a4,
|
||||||
REC_QUES = 0x53455551,
|
REC_QUES = 0x53455551,
|
||||||
REC_GSCR = 0x52435347,
|
REC_GSCR = 0x52435347,
|
||||||
|
REC_PLAY = 0x59414c50,
|
||||||
|
REC_CSTA = 0x41545343,
|
||||||
|
REC_OBJE = 0x454a424f,
|
||||||
|
|
||||||
// format 1
|
// format 1
|
||||||
REC_FILT = 0x544C4946
|
REC_FILT = 0x544C4946
|
||||||
|
|
|
||||||
|
|
@ -3,26 +3,52 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include <boost/concept_check.hpp>
|
#include <boost/concept_check.hpp>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "esmreader.hpp"
|
#include "esmreader.hpp"
|
||||||
#include "esmwriter.hpp"
|
#include "esmwriter.hpp"
|
||||||
#include "defs.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
|
namespace ESM
|
||||||
{
|
{
|
||||||
unsigned int Cell::sRecordId = REC_CELL;
|
unsigned int Cell::sRecordId = REC_CELL;
|
||||||
|
|
||||||
/// Some overloaded compare operators.
|
// Some overloaded compare operators.
|
||||||
bool operator==(const MovedCellRef& ref, int pRefnum)
|
bool operator== (const MovedCellRef& ref, const CellRef::RefNum& refNum)
|
||||||
{
|
{
|
||||||
return (ref.mRefnum == pRefnum);
|
return ref.mRefNum == refNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const CellRef& ref, int pRefnum)
|
bool operator== (const CellRef& ref, const CellRef::RefNum& refNum)
|
||||||
{
|
{
|
||||||
return (ref.mRefnum == pRefnum);
|
return ref.mRefNum == refNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cell::load(ESMReader &esm, bool saveContext)
|
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.
|
// That should be it, I haven't seen any other fields yet.
|
||||||
}
|
}
|
||||||
|
|
||||||
// NAM0 sometimes appears here, sometimes further on
|
ref.load (esm);
|
||||||
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");
|
|
||||||
|
|
||||||
// Identify references belonging to a parent file and adapt the ID accordingly.
|
// Identify references belonging to a parent file and adapt the ID accordingly.
|
||||||
int local = (ref.mRefnum & 0xff000000) >> 24;
|
adjustRefNum (ref.mRefNum, esm);
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esm.isNextSub("DELE"))
|
if (esm.isNextSub("DELE"))
|
||||||
{
|
{
|
||||||
|
|
@ -272,16 +199,10 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted)
|
||||||
|
|
||||||
bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref)
|
bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref)
|
||||||
{
|
{
|
||||||
esm.getHT(mref.mRefnum);
|
esm.getHT(mref.mRefNum.mIndex);
|
||||||
esm.getHNOT(mref.mTarget, "CNDT");
|
esm.getHNOT(mref.mTarget, "CNDT");
|
||||||
|
|
||||||
// Identify references belonging to a parent file and adapt the ID accordingly.
|
adjustRefNum (mref.mRefNum, esm);
|
||||||
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
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -304,4 +225,24 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref)
|
||||||
mAmbi.mFog = 0;
|
mAmbi.mFog = 0;
|
||||||
mAmbi.mFogDensity = 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 ESMReader;
|
||||||
class ESMWriter;
|
class ESMWriter;
|
||||||
|
class CellId;
|
||||||
|
|
||||||
/* Moved cell reference tracking object. This mainly stores the target cell
|
/* 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
|
of the reference, so we can easily know where it has been moved when another
|
||||||
|
|
@ -27,7 +28,7 @@ class ESMWriter;
|
||||||
class MovedCellRef
|
class MovedCellRef
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int mRefnum;
|
CellRef::RefNum mRefNum;
|
||||||
|
|
||||||
// Target cell (if exterior)
|
// Target cell (if exterior)
|
||||||
int mTarget[2];
|
int mTarget[2];
|
||||||
|
|
@ -37,9 +38,9 @@ public:
|
||||||
// introduces a henchman (which no one uses), so we may need this as well.
|
// 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.
|
/// Overloaded compare operator used to search inside a list of cell refs.
|
||||||
bool operator==(const MovedCellRef& ref, int pRefnum);
|
bool operator==(const MovedCellRef& ref, const CellRef::RefNum& refNum);
|
||||||
bool operator==(const CellRef& ref, int pRefnum);
|
bool operator==(const CellRef& ref, const CellRef::RefNum& refNum);
|
||||||
|
|
||||||
typedef std::list<MovedCellRef> MovedCellRefTracker;
|
typedef std::list<MovedCellRef> MovedCellRefTracker;
|
||||||
typedef std::list<CellRef> CellRefTracker;
|
typedef std::list<CellRef> CellRefTracker;
|
||||||
|
|
@ -150,6 +151,8 @@ struct Cell
|
||||||
|
|
||||||
void blank();
|
void blank();
|
||||||
///< Set record to default state (does not touch the ID/index).
|
///< Set record to default state (does not touch the ID/index).
|
||||||
|
|
||||||
|
CellId getCellId() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#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