forked from teamnwah/openmw-tes3coop
Merge branch 'savedgame'
Conflicts: apps/openmw/mwbase/mechanicsmanager.hpp apps/openmw/mwbase/soundmanager.hpp apps/openmw/mwgui/mapwindow.hpp apps/openmw/mwmechanics/actors.cpp apps/openmw/mwmechanics/mechanicsmanagerimp.hpp apps/openmw/mwsound/soundmanagerimp.hpp components/esm/loadcell.cpp
This commit is contained in:
commit
1b5301eec0
158 changed files with 4983 additions and 1260 deletions
|
@ -236,7 +236,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||
// Loop through all the references
|
||||
ESM::CellRef ref;
|
||||
if(!quiet) std::cout << " References:\n";
|
||||
while(cell.getNextRef(esm, ref))
|
||||
|
||||
bool deleted = false;
|
||||
while(cell.getNextRef(esm, ref, deleted))
|
||||
{
|
||||
if (save) {
|
||||
info.data.mCellRefs[&cell].push_back(ref);
|
||||
|
@ -244,13 +246,14 @@ 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";
|
||||
std::cout << " Uses/health: '" << ref.mCharge << "'\n";
|
||||
std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
|
||||
std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl;
|
||||
std::cout << " Deleted: " << deleted << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -133,16 +133,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::
|
|||
state==CSMWorld::RecordBase::State_ModifiedOnly ||
|
||||
infoModified)
|
||||
{
|
||||
// always write the topic record
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&topic.mModified.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (topic.mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
|
||||
topic.mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (topic.mModified.sRecordId);
|
||||
|
||||
// write modified selected info records
|
||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second;
|
||||
|
@ -178,15 +172,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::
|
|||
next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1);
|
||||
}
|
||||
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&info.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (info.sRecordId);
|
||||
mState.getWriter().writeHNCString ("INAM", info.mId);
|
||||
info.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (info.sRecordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,10 +104,10 @@ namespace CSMDoc
|
|||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&mCollection.getRecord (stage).mModified.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
|
||||
mCollection.getRecord (stage).mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId);
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
|
|
|
@ -8,6 +8,5 @@ void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string
|
|||
mId = id;
|
||||
mCell = cell.mId;
|
||||
|
||||
if (!mDeleted)
|
||||
cell.addRef (mId);
|
||||
}
|
|
@ -16,7 +16,8 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||
|
||||
CellRef ref;
|
||||
|
||||
while (cell2.getNextRef (reader, ref))
|
||||
bool deleted = false;
|
||||
while (cell2.getNextRef (reader, ref, deleted))
|
||||
{
|
||||
/// \todo handle deleted and moved references
|
||||
ref.load (reader, cell2, getNewId());
|
||||
|
|
|
@ -147,15 +147,10 @@ namespace CSMWorld
|
|||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&mContainer.at (index).mModified.sRecordId)[i];
|
||||
|
||||
writer.startRecord (type);
|
||||
writer.startRecord (mContainer.at (index).mModified.sRecordId);
|
||||
writer.writeHNCString ("NAME", getId (index));
|
||||
mContainer.at (index).mModified.save (writer);
|
||||
writer.endRecord (type);
|
||||
writer.endRecord (mContainer.at (index).mModified.sRecordId);
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
|
|
|
@ -77,9 +77,13 @@ add_openmw_dir (mwmechanics
|
|||
disease pickpocket levelledlist combat steering
|
||||
)
|
||||
|
||||
add_openmw_dir (mwstate
|
||||
statemanagerimp charactermanager character
|
||||
)
|
||||
|
||||
add_openmw_dir (mwbase
|
||||
environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager
|
||||
inputmanager windowmanager
|
||||
inputmanager windowmanager statemanager
|
||||
)
|
||||
|
||||
# Main executable
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <MyGUI_WidgetManager.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <components/compiler/extensions0.hpp>
|
||||
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
|
@ -41,8 +43,7 @@
|
|||
|
||||
#include "mwmechanics/mechanicsmanagerimp.hpp"
|
||||
|
||||
|
||||
#include <SDL.h>
|
||||
#include "mwstate/statemanagerimp.hpp"
|
||||
|
||||
void OMW::Engine::executeLocalScripts()
|
||||
{
|
||||
|
@ -88,31 +89,47 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
if (mUseSound)
|
||||
MWBase::Environment::get().getSoundManager()->update(frametime);
|
||||
|
||||
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_Running)
|
||||
{
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
|
||||
bool changed = MWBase::Environment::get().getWorld()->hasCellChanged();
|
||||
|
||||
// local scripts
|
||||
executeLocalScripts(); // This does not handle the case where a global script causes a cell
|
||||
// change, followed by a cell change in a local script during the same
|
||||
// frame.
|
||||
executeLocalScripts(); // This does not handle the case where a global script causes a
|
||||
// cell change, followed by a cell change in a local script during
|
||||
// the same frame.
|
||||
|
||||
// passing of time
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
if (changed) // keep change flag for another frame, if cell changed happened in local script
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
|
||||
if (!paused)
|
||||
MWBase::Environment::get().getWorld()->advanceTime(
|
||||
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
|
||||
|
||||
// update game state
|
||||
MWBase::Environment::get().getStateManager()->update (frametime);
|
||||
}
|
||||
|
||||
if (changed) // keep change flag for another frame, if cell changed happend in local script
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
|
||||
// update actors
|
||||
MWBase::Environment::get().getMechanicsManager()->update(frametime,
|
||||
MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
paused);
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_Running)
|
||||
{
|
||||
MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
|
||||
if(!paused && player.getClass().getCreatureStats(player).isDead())
|
||||
MWBase::Environment::get().getStateManager()->endGame();
|
||||
}
|
||||
|
||||
// update world
|
||||
MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
MWBase::Environment::get().getWorld()->update(frametime, paused);
|
||||
|
||||
// update GUI
|
||||
Ogre::RenderWindow* window = mOgre->getWindow();
|
||||
|
@ -135,7 +152,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
|||
: mOgre (0)
|
||||
, mFpsLevel(0)
|
||||
, mVerboseScripts (false)
|
||||
, mNewGame (false)
|
||||
, mSkipMenu (false)
|
||||
, mUseSound (true)
|
||||
, mCompileAll (false)
|
||||
, mScriptContext (0)
|
||||
|
@ -265,11 +282,6 @@ void OMW::Engine::setCell (const std::string& cellName)
|
|||
|
||||
void OMW::Engine::addContentFile(const std::string& file)
|
||||
{
|
||||
if (file.find_last_of(".") == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Missing extension in content file!");
|
||||
}
|
||||
|
||||
mContentFiles.push_back(file);
|
||||
}
|
||||
|
||||
|
@ -278,9 +290,9 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
|
|||
mVerboseScripts = scriptsVerbosity;
|
||||
}
|
||||
|
||||
void OMW::Engine::setNewGame(bool newGame)
|
||||
void OMW::Engine::setSkipMenu (bool skipMenu)
|
||||
{
|
||||
mNewGame = newGame;
|
||||
mSkipMenu = skipMenu;
|
||||
}
|
||||
|
||||
std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
||||
|
@ -326,6 +338,9 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
|||
|
||||
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
{
|
||||
mEnvironment.setStateManager (
|
||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
||||
|
||||
Nif::NIFFile::CacheLock cachelock;
|
||||
|
||||
std::string renderSystem = settings.getString("render system", "Video");
|
||||
|
@ -392,10 +407,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
||||
|
||||
window->initUI();
|
||||
if (mNewGame)
|
||||
// still redundant work here: recreate CharacterCreation(),
|
||||
// double update visibility etc.
|
||||
window->setNewGame(true);
|
||||
window->renderWorldMap();
|
||||
|
||||
//Load translation data
|
||||
|
@ -427,12 +438,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mechanics->buildPlayer();
|
||||
window->updatePlayer();
|
||||
|
||||
if (!mNewGame)
|
||||
{
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
if (!mCellName.empty())
|
||||
{
|
||||
if (world->findExteriorPosition(mCellName, pos)) {
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
@ -442,7 +453,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
}
|
||||
}
|
||||
else
|
||||
mEnvironment.getWorld()->startNewGame();
|
||||
{
|
||||
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
|
||||
pos.rot[0] = pos.rot[1] = pos.pos[2] = 0;
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
||||
Ogre::FrameEvent event;
|
||||
event.timeSinceLastEvent = 0;
|
||||
|
@ -468,7 +483,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
void OMW::Engine::go()
|
||||
{
|
||||
assert (!mCellName.empty());
|
||||
assert (!mContentFiles.empty());
|
||||
assert (!mOgre);
|
||||
|
||||
|
@ -489,8 +503,14 @@ void OMW::Engine::go()
|
|||
if (!mStartupScript.empty())
|
||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||
|
||||
// start in main menu
|
||||
if (!mSkipMenu)
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
else
|
||||
MWBase::Environment::get().getStateManager()->newGame (true);
|
||||
|
||||
// Start the main rendering loop
|
||||
while (!mEnvironment.getRequestExit())
|
||||
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
||||
Ogre::Root::getSingleton().renderOneFrame();
|
||||
|
||||
// Save user settings
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace OMW
|
|||
std::vector<std::string> mContentFiles;
|
||||
int mFpsLevel;
|
||||
bool mVerboseScripts;
|
||||
bool mNewGame;
|
||||
bool mSkipMenu;
|
||||
bool mUseSound;
|
||||
bool mCompileAll;
|
||||
std::string mFocusName;
|
||||
|
@ -151,8 +151,7 @@ namespace OMW
|
|||
/// Disable or enable all sounds
|
||||
void setSoundUsage(bool soundUsage);
|
||||
|
||||
/// Start as a new game.
|
||||
void setNewGame(bool newGame);
|
||||
void setSkipMenu (bool skipMenu);
|
||||
|
||||
void setGrabMouse(bool grab) { mGrab = grab; }
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("resources", bpo::value<std::string>()->default_value("resources"),
|
||||
"set resources directory")
|
||||
|
||||
("start", bpo::value<std::string>()->default_value("Beshara"),
|
||||
("start", bpo::value<std::string>()->default_value(""),
|
||||
"set initial cell")
|
||||
|
||||
("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||
|
@ -137,8 +137,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("script-run", bpo::value<std::string>()->default_value(""),
|
||||
"select a file containing a list of console commands that is executed on startup")
|
||||
|
||||
("new-game", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "activate char gen/new game mechanics")
|
||||
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "skip main menu on game startup")
|
||||
|
||||
("fs-strict", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "strict file system handling (no case folding)")
|
||||
|
@ -232,7 +232,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
|
||||
// startup-settings
|
||||
engine.setCell(variables["start"].as<std::string>());
|
||||
engine.setNewGame(variables["new-game"].as<bool>());
|
||||
engine.setSkipMenu (variables["skip-menu"].as<bool>());
|
||||
|
||||
// other settings
|
||||
engine.setSoundUsage(!variables["no-sound"].as<bool>());
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
#include "mechanicsmanager.hpp"
|
||||
#include "inputmanager.hpp"
|
||||
#include "windowmanager.hpp"
|
||||
#include "statemanager.hpp"
|
||||
|
||||
MWBase::Environment *MWBase::Environment::sThis = 0;
|
||||
bool MWBase::Environment::sExit = false;
|
||||
|
||||
MWBase::Environment::Environment()
|
||||
: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0),
|
||||
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0)
|
||||
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0),
|
||||
mStateManager (0)
|
||||
{
|
||||
assert (!sThis);
|
||||
sThis = this;
|
||||
|
@ -69,6 +70,11 @@ void MWBase::Environment::setInputManager (InputManager *inputManager)
|
|||
mInputManager = inputManager;
|
||||
}
|
||||
|
||||
void MWBase::Environment::setStateManager (StateManager *stateManager)
|
||||
{
|
||||
mStateManager = stateManager;
|
||||
}
|
||||
|
||||
void MWBase::Environment::setFrameDuration (float duration)
|
||||
{
|
||||
mFrameDuration = duration;
|
||||
|
@ -122,6 +128,12 @@ MWBase::InputManager *MWBase::Environment::getInputManager() const
|
|||
return mInputManager;
|
||||
}
|
||||
|
||||
MWBase::StateManager *MWBase::Environment::getStateManager() const
|
||||
{
|
||||
assert (mStateManager);
|
||||
return mStateManager;
|
||||
}
|
||||
|
||||
float MWBase::Environment::getFrameDuration() const
|
||||
{
|
||||
return mFrameDuration;
|
||||
|
@ -152,6 +164,9 @@ void MWBase::Environment::cleanup()
|
|||
|
||||
delete mInputManager;
|
||||
mInputManager = 0;
|
||||
|
||||
delete mStateManager;
|
||||
mStateManager = 0;
|
||||
}
|
||||
|
||||
const MWBase::Environment& MWBase::Environment::get()
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace MWBase
|
|||
class MechanicsManager;
|
||||
class InputManager;
|
||||
class WindowManager;
|
||||
class StateManager;
|
||||
|
||||
/// \brief Central hub for mw-subsystems
|
||||
///
|
||||
|
@ -30,10 +31,9 @@ namespace MWBase
|
|||
DialogueManager *mDialogueManager;
|
||||
Journal *mJournal;
|
||||
InputManager *mInputManager;
|
||||
StateManager *mStateManager;
|
||||
float mFrameDuration;
|
||||
|
||||
static bool sExit;
|
||||
|
||||
Environment (const Environment&);
|
||||
///< not implemented
|
||||
|
||||
|
@ -46,9 +46,6 @@ namespace MWBase
|
|||
|
||||
~Environment();
|
||||
|
||||
static void setRequestExit () { sExit = true; }
|
||||
static bool getRequestExit () { return sExit; }
|
||||
|
||||
void setWorld (World *world);
|
||||
|
||||
void setSoundManager (SoundManager *soundManager);
|
||||
|
@ -65,6 +62,8 @@ namespace MWBase
|
|||
|
||||
void setInputManager (InputManager *inputManager);
|
||||
|
||||
void setStateManager (StateManager *stateManager);
|
||||
|
||||
void setFrameDuration (float duration);
|
||||
///< Set length of current frame in seconds.
|
||||
|
||||
|
@ -84,6 +83,8 @@ namespace MWBase
|
|||
|
||||
InputManager *getInputManager() const;
|
||||
|
||||
StateManager *getStateManager() const;
|
||||
|
||||
float getFrameDuration() const;
|
||||
|
||||
void cleanup();
|
||||
|
|
|
@ -5,10 +5,18 @@
|
|||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
#include "../mwdialogue/topic.hpp"
|
||||
#include "../mwdialogue/quest.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
/// \brief Interface for the player's journal (implemented in MWDialogue)
|
||||
|
@ -69,6 +77,12 @@ namespace MWBase
|
|||
|
||||
virtual TTopicIter topicEnd() const = 0;
|
||||
///< Iterator pointing past the last topic.
|
||||
|
||||
virtual int countSavedGameRecords() const = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const = 0;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -163,6 +163,8 @@ namespace MWBase
|
|||
|
||||
///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor)
|
||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
virtual void playerLoaded() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@ namespace MWBase
|
|||
|
||||
virtual ~ScriptManager() {}
|
||||
|
||||
virtual void resetGlobalScripts() = 0;
|
||||
|
||||
virtual void run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
|
||||
///< Run the script with the given name (compile first, if not compiled yet)
|
||||
|
||||
|
|
|
@ -149,6 +149,8 @@ namespace MWBase
|
|||
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0;
|
||||
|
||||
virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
81
apps/openmw/mwbase/statemanager.hpp
Normal file
81
apps/openmw/mwbase/statemanager.hpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#ifndef GAME_MWSTATE_STATEMANAGER_H
|
||||
#define GAME_MWSTATE_STATEMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
struct Slot;
|
||||
class Character;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
/// \brief Interface for game state manager (implemented in MWState)
|
||||
class StateManager
|
||||
{
|
||||
public:
|
||||
|
||||
enum State
|
||||
{
|
||||
State_NoGame,
|
||||
State_Ended,
|
||||
State_Running
|
||||
};
|
||||
|
||||
typedef std::vector<MWState::Character>::const_iterator CharacterIterator;
|
||||
|
||||
private:
|
||||
|
||||
StateManager (const StateManager&);
|
||||
///< not implemented
|
||||
|
||||
StateManager& operator= (const StateManager&);
|
||||
///< not implemented
|
||||
|
||||
public:
|
||||
|
||||
StateManager() {}
|
||||
|
||||
virtual ~StateManager() {}
|
||||
|
||||
virtual void requestQuit() = 0;
|
||||
|
||||
virtual bool hasQuitRequest() const = 0;
|
||||
|
||||
virtual void askLoadRecent() = 0;
|
||||
|
||||
virtual State getState() const = 0;
|
||||
|
||||
virtual void newGame (bool bypass = false) = 0;
|
||||
///< Start a new game.
|
||||
///
|
||||
/// \param bypass Skip new game mechanics.
|
||||
|
||||
virtual void endGame() = 0;
|
||||
|
||||
virtual void saveGame (const std::string& description, const MWState::Slot *slot = 0) = 0;
|
||||
///< Write a saved game to \a slot or create a new slot if \a slot == 0.
|
||||
///
|
||||
/// \note Slot must belong to the current character.
|
||||
|
||||
virtual void loadGame (const MWState::Character *character, const MWState::Slot *slot) = 0;
|
||||
///< Load a saved game file from \a slot.
|
||||
///
|
||||
/// \note \a slot must belong to \a character.
|
||||
|
||||
virtual MWState::Character *getCurrentCharacter (bool create = true) = 0;
|
||||
///< \param create Create a new character, if there is no current character.
|
||||
|
||||
virtual CharacterIterator characterBegin() = 0;
|
||||
///< Any call to SaveGame and getCurrentCharacter can invalidate the returned
|
||||
/// iterator.
|
||||
|
||||
virtual CharacterIterator characterEnd() = 0;
|
||||
|
||||
virtual void update (float duration) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -33,6 +33,8 @@ namespace OEngine
|
|||
namespace ESM
|
||||
{
|
||||
struct Class;
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -285,6 +287,12 @@ namespace MWBase
|
|||
|
||||
/// Should the cursor be visible?
|
||||
virtual bool getCursorVisible() = 0;
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) = 0;
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define GAME_MWBASE_WORLD_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
|
@ -30,12 +31,14 @@ namespace OEngine
|
|||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
struct Position;
|
||||
struct Cell;
|
||||
struct Class;
|
||||
struct Potion;
|
||||
struct Spell;
|
||||
struct NPC;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -94,13 +97,26 @@ namespace MWBase
|
|||
|
||||
virtual void startNewGame() = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual int countSavedGameRecords() const = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const = 0;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
|
||||
const std::map<int, int>& contentFileMap) = 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;
|
||||
|
||||
virtual void toggleWater() = 0;
|
||||
|
@ -139,16 +155,26 @@ namespace MWBase
|
|||
virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0;
|
||||
///< see MWRender::LocalMap::isPositionExplored
|
||||
|
||||
virtual MWWorld::Globals::Data& getGlobalVariable (const std::string& name) = 0;
|
||||
virtual void setGlobalInt (const std::string& name, int value) = 0;
|
||||
///< Set value independently from real type.
|
||||
|
||||
virtual MWWorld::Globals::Data getGlobalVariable (const std::string& name) const = 0;
|
||||
virtual void setGlobalFloat (const std::string& name, float value) = 0;
|
||||
///< Set value independently from real type.
|
||||
|
||||
virtual int getGlobalInt (const std::string& name) const = 0;
|
||||
///< Get value independently from real type.
|
||||
|
||||
virtual float getGlobalFloat (const std::string& name) const = 0;
|
||||
///< Get value independently from real type.
|
||||
|
||||
virtual char getGlobalVariableType (const std::string& name) const = 0;
|
||||
///< Return ' ', if there is no global variable with this name.
|
||||
|
||||
virtual std::vector<std::string> getGlobals () const = 0;
|
||||
|
||||
virtual std::string getCurrentCellName() const = 0;
|
||||
virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const = 0;
|
||||
///< Return name of the cell.
|
||||
///
|
||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||
/// generate a name.
|
||||
|
||||
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
|
||||
//< Remove the script attached to ref from mLocalScripts
|
||||
|
@ -185,8 +211,12 @@ namespace MWBase
|
|||
virtual void setDay (int day) = 0;
|
||||
///< Set in-game time day.
|
||||
|
||||
virtual int getDay() = 0;
|
||||
virtual int getMonth() = 0;
|
||||
virtual int getDay() const = 0;
|
||||
virtual int getMonth() const = 0;
|
||||
virtual int getYear() const = 0;
|
||||
|
||||
virtual std::string getMonthName (int month = -1) const = 0;
|
||||
///< Return name of month (-1: current month)
|
||||
|
||||
virtual MWWorld::TimeStamp getTimeStamp() const = 0;
|
||||
///< Return current in-game time stamp.
|
||||
|
@ -215,6 +245,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.
|
||||
|
||||
|
@ -336,7 +368,7 @@ namespace MWBase
|
|||
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
|
||||
///Is the head of the creature underwater?
|
||||
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
|
||||
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||
virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
||||
|
||||
virtual void togglePOV() = 0;
|
||||
|
@ -384,6 +416,7 @@ namespace MWBase
|
|||
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
|
||||
virtual void stopVideo() = 0;
|
||||
virtual void frameStarted (float dt, bool paused) = 0;
|
||||
virtual void screenshot (Ogre::Image& image, int w, int h) = 0;
|
||||
|
||||
/// Find default position inside exterior cell specified by name
|
||||
/// \return false if exterior with given name not exists, true otherwise
|
||||
|
@ -428,6 +461,8 @@ namespace MWBase
|
|||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
||||
|
||||
virtual const std::vector<std::string>& getContentFiles() const = 0;
|
||||
|
||||
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
// Are we in an exterior or pseudo-exterior cell and it's night?
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "container.hpp"
|
||||
|
||||
#include <components/esm/loadcont.hpp>
|
||||
#include <components/esm/containerstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -258,4 +259,26 @@ namespace MWClass
|
|||
|
||||
return MWWorld::Ptr(&cell.mContainers.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::ContainerState& state2 = dynamic_cast<const ESM::ContainerState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::ContainerState& state2 = dynamic_cast<ESM::ContainerState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,14 @@ namespace MWClass
|
|||
virtual void unlock (const MWWorld::Ptr& ptr) const;
|
||||
///< Unlock object
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "creature.hpp"
|
||||
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
|
@ -758,6 +759,28 @@ namespace MWClass
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore->
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::CreatureState& state2 = dynamic_cast<ESM::CreatureState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore->
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
|
||||
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
||||
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
|
||||
const ESM::GameSetting *Creature::fEncumberedMoveEffect;
|
||||
|
|
|
@ -125,6 +125,14 @@ namespace MWClass
|
|||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
virtual int getBloodTexture (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "light.hpp"
|
||||
|
||||
#include <components/esm/loadligh.hpp>
|
||||
#include <components/esm/lightstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -269,4 +270,24 @@ namespace MWClass
|
|||
}
|
||||
return std::make_pair(1,"");
|
||||
}
|
||||
|
||||
void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::LightState& state2 = dynamic_cast<const ESM::LightState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime = state2.mTime;
|
||||
}
|
||||
|
||||
void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::LightState& state2 = dynamic_cast<ESM::LightState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
state2.mTime = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,14 @@ namespace MWClass
|
|||
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
||||
|
||||
std::pair<int, std::string> canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
#include <components/esm/npcstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -1270,6 +1271,28 @@ namespace MWClass
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore.
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::NpcState& state2 = dynamic_cast<ESM::NpcState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore.
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
|
||||
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fMaxWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
|
||||
|
|
|
@ -158,6 +158,14 @@ namespace MWClass
|
|||
virtual bool isNpc() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
|
|||
|
||||
// internally all globals are float :(
|
||||
return select.selectCompare (
|
||||
MWBase::Environment::get().getWorld()->getGlobalVariable (select.getName()).mFloat);
|
||||
MWBase::Environment::get().getWorld()->getGlobalFloat (select.getName()));
|
||||
|
||||
case SelectWrapper::Function_Local:
|
||||
{
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/journalentry.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -10,23 +12,54 @@
|
|||
|
||||
namespace MWDialogue
|
||||
{
|
||||
JournalEntry::JournalEntry() {}
|
||||
Entry::Entry() {}
|
||||
|
||||
JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId)
|
||||
: mTopic (topic), mInfoId (infoId)
|
||||
{}
|
||||
|
||||
std::string JournalEntry::getText (const MWWorld::ESMStore& store) const
|
||||
Entry::Entry (const std::string& topic, const std::string& infoId)
|
||||
: mInfoId (infoId)
|
||||
{
|
||||
const ESM::Dialogue *dialogue =
|
||||
store.get<ESM::Dialogue>().find (mTopic);
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (topic);
|
||||
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter (dialogue->mInfo.begin());
|
||||
iter!=dialogue->mInfo.end(); ++iter)
|
||||
if (iter->mId == mInfoId)
|
||||
return iter->mResponse;
|
||||
{
|
||||
/// \todo text replacement
|
||||
mText = iter->mResponse;
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + mTopic);
|
||||
throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + topic);
|
||||
}
|
||||
|
||||
Entry::Entry (const ESM::JournalEntry& record) : mInfoId (record.mInfo), mText (record.mText) {}
|
||||
|
||||
std::string Entry::getText() const
|
||||
{
|
||||
return mText;
|
||||
}
|
||||
|
||||
void Entry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
entry.mInfo = mInfoId;
|
||||
entry.mText = mText;
|
||||
}
|
||||
|
||||
|
||||
JournalEntry::JournalEntry() {}
|
||||
|
||||
JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId)
|
||||
: Entry (topic, infoId), mTopic (topic)
|
||||
{}
|
||||
|
||||
JournalEntry::JournalEntry (const ESM::JournalEntry& record)
|
||||
: Entry (record), mTopic (record.mTopic)
|
||||
{}
|
||||
|
||||
void JournalEntry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
Entry::write (entry);
|
||||
entry.mTopic = mTopic;
|
||||
}
|
||||
|
||||
JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index)
|
||||
|
@ -49,6 +82,7 @@ namespace MWDialogue
|
|||
throw std::runtime_error ("unknown journal index for topic " + topic);
|
||||
}
|
||||
|
||||
|
||||
StampedJournalEntry::StampedJournalEntry()
|
||||
: mDay (0), mMonth (0), mDayOfMonth (0)
|
||||
{}
|
||||
|
@ -58,11 +92,24 @@ namespace MWDialogue
|
|||
: JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth)
|
||||
{}
|
||||
|
||||
StampedJournalEntry::StampedJournalEntry (const ESM::JournalEntry& record)
|
||||
: JournalEntry (record), mDay (record.mDay), mMonth (record.mMonth),
|
||||
mDayOfMonth (record.mDayOfMonth)
|
||||
{}
|
||||
|
||||
void StampedJournalEntry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
JournalEntry::write (entry);
|
||||
entry.mDay = mDay;
|
||||
entry.mMonth = mMonth;
|
||||
entry.mDayOfMonth = mDayOfMonth;
|
||||
}
|
||||
|
||||
StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index)
|
||||
{
|
||||
int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong;
|
||||
int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong;
|
||||
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong;
|
||||
int day = MWBase::Environment::get().getWorld()->getGlobalInt ("dayspassed");
|
||||
int month = MWBase::Environment::get().getWorld()->getGlobalInt ("month");
|
||||
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalInt ("day");
|
||||
|
||||
return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth);
|
||||
}
|
||||
|
|
|
@ -3,24 +3,44 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
namespace MWWorld
|
||||
namespace ESM
|
||||
{
|
||||
struct ESMStore;
|
||||
struct JournalEntry;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief A quest or dialogue entry
|
||||
struct JournalEntry
|
||||
/// \brief Basic quest/dialogue/topic entry
|
||||
struct Entry
|
||||
{
|
||||
std::string mInfoId;
|
||||
std::string mText;
|
||||
|
||||
Entry();
|
||||
|
||||
Entry (const std::string& topic, const std::string& infoId);
|
||||
|
||||
Entry (const ESM::JournalEntry& record);
|
||||
|
||||
std::string getText() const;
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
};
|
||||
|
||||
/// \brief A dialogue entry
|
||||
///
|
||||
/// Same as entry, but store TopicID
|
||||
struct JournalEntry : public Entry
|
||||
{
|
||||
std::string mTopic;
|
||||
std::string mInfoId;
|
||||
|
||||
JournalEntry();
|
||||
|
||||
JournalEntry (const std::string& topic, const std::string& infoId);
|
||||
|
||||
std::string getText (const MWWorld::ESMStore& store) const;
|
||||
JournalEntry (const ESM::JournalEntry& record);
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
|
||||
static JournalEntry makeFromQuest (const std::string& topic, int index);
|
||||
|
||||
|
@ -39,6 +59,10 @@ namespace MWDialogue
|
|||
StampedJournalEntry (const std::string& topic, const std::string& infoId,
|
||||
int day, int month, int dayOfMonth);
|
||||
|
||||
StampedJournalEntry (const ESM::JournalEntry& record);
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
|
||||
static StampedJournalEntry makeFromQuest (const std::string& topic, int index);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
|
||||
#include "journalimp.hpp"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/queststate.hpp>
|
||||
#include <components/esm/journalentry.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -26,6 +33,38 @@ namespace MWDialogue
|
|||
return iter->second;
|
||||
}
|
||||
|
||||
Topic& Journal::getTopic (const std::string& id)
|
||||
{
|
||||
TTopicContainer::iterator iter = mTopics.find (id);
|
||||
|
||||
if (iter==mTopics.end())
|
||||
{
|
||||
std::pair<TTopicContainer::iterator, bool> result
|
||||
= mTopics.insert (std::make_pair (id, Topic (id)));
|
||||
|
||||
iter = result.first;
|
||||
}
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool Journal::isThere (const std::string& topicId, const std::string& infoId) const
|
||||
{
|
||||
if (const ESM::Dialogue *dialogue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().search (topicId))
|
||||
{
|
||||
if (infoId.empty())
|
||||
return true;
|
||||
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter (dialogue->mInfo.begin());
|
||||
iter!=dialogue->mInfo.end(); ++iter)
|
||||
if (iter->mId == infoId)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Journal::Journal()
|
||||
{}
|
||||
|
||||
|
@ -66,17 +105,9 @@ namespace MWDialogue
|
|||
|
||||
void Journal::addTopic (const std::string& topicId, const std::string& infoId)
|
||||
{
|
||||
TTopicContainer::iterator iter = mTopics.find (topicId);
|
||||
Topic& topic = getTopic (topicId);
|
||||
|
||||
if (iter==mTopics.end())
|
||||
{
|
||||
std::pair<TTopicContainer::iterator, bool> result
|
||||
= mTopics.insert (std::make_pair (topicId, Topic (topicId)));
|
||||
|
||||
iter = result.first;
|
||||
}
|
||||
|
||||
iter->second.addEntry (JournalEntry (topicId, infoId));
|
||||
topic.addEntry (JournalEntry (topicId, infoId));
|
||||
}
|
||||
|
||||
int Journal::getJournalIndex (const std::string& id) const
|
||||
|
@ -118,4 +149,106 @@ namespace MWDialogue
|
|||
{
|
||||
return mTopics.end();
|
||||
}
|
||||
|
||||
int Journal::countSavedGameRecords() const
|
||||
{
|
||||
int count = static_cast<int> (mQuests.size());
|
||||
|
||||
for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
|
||||
count += std::distance (iter->second.begin(), iter->second.end());
|
||||
|
||||
count += std::distance (mJournal.begin(), mJournal.end());
|
||||
|
||||
for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
|
||||
count += std::distance (iter->second.begin(), iter->second.end());
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void Journal::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
|
||||
{
|
||||
const Quest& quest = iter->second;
|
||||
|
||||
ESM::QuestState state;
|
||||
quest.write (state);
|
||||
writer.startRecord (ESM::REC_QUES);
|
||||
state.save (writer);
|
||||
writer.endRecord (ESM::REC_QUES);
|
||||
|
||||
for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Quest;
|
||||
entry.mTopic = quest.getTopic();
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
}
|
||||
|
||||
for (TEntryIter iter (mJournal.begin()); iter!=mJournal.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Journal;
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
|
||||
for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
|
||||
{
|
||||
const Topic& topic = iter->second;
|
||||
|
||||
for (Topic::TEntryIter iter (topic.begin()); iter!=topic.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Topic;
|
||||
entry.mTopic = topic.getTopic();
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||
{
|
||||
if (type==ESM::REC_JOUR)
|
||||
{
|
||||
ESM::JournalEntry record;
|
||||
record.load (reader);
|
||||
|
||||
if (isThere (record.mTopic, record.mInfo))
|
||||
switch (record.mType)
|
||||
{
|
||||
case ESM::JournalEntry::Type_Quest:
|
||||
|
||||
getQuest (record.mTopic).insertEntry (record);
|
||||
break;
|
||||
|
||||
case ESM::JournalEntry::Type_Journal:
|
||||
|
||||
mJournal.push_back (record);
|
||||
break;
|
||||
|
||||
case ESM::JournalEntry::Type_Topic:
|
||||
|
||||
getTopic (record.mTopic).insertEntry (record);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type==ESM::REC_QUES)
|
||||
{
|
||||
ESM::QuestState record;
|
||||
record.load (reader);
|
||||
|
||||
if (isThere (record.mTopic))
|
||||
mQuests.insert (std::make_pair (record.mTopic, record));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,14 @@ namespace MWDialogue
|
|||
TQuestContainer mQuests;
|
||||
TTopicContainer mTopics;
|
||||
|
||||
private:
|
||||
|
||||
Quest& getQuest (const std::string& id);
|
||||
|
||||
Topic& getTopic (const std::string& id);
|
||||
|
||||
bool isThere (const std::string& topicId, const std::string& infoId = "") const;
|
||||
|
||||
public:
|
||||
|
||||
Journal();
|
||||
|
@ -55,6 +61,12 @@ namespace MWDialogue
|
|||
|
||||
virtual TTopicIter topicEnd() const;
|
||||
///< Iterator pointing past the last topic.
|
||||
|
||||
virtual int countSavedGameRecords() const;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
#include "quest.hpp"
|
||||
|
||||
#include <components/esm/queststate.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -16,7 +18,11 @@ namespace MWDialogue
|
|||
: Topic (topic), mIndex (0), mFinished (false)
|
||||
{}
|
||||
|
||||
const std::string Quest::getName() const
|
||||
Quest::Quest (const ESM::QuestState& state)
|
||||
: Topic (state.mTopic), mIndex (state.mState), mFinished (state.mFinished!=0)
|
||||
{}
|
||||
|
||||
std::string Quest::getName() const
|
||||
{
|
||||
const ESM::Dialogue *dialogue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (mTopic);
|
||||
|
@ -86,9 +92,16 @@ namespace MWDialogue
|
|||
setIndex (index);
|
||||
|
||||
for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter)
|
||||
if (*iter==entry.mInfoId)
|
||||
if (iter->mInfoId==entry.mInfoId)
|
||||
return;
|
||||
|
||||
mEntries.push_back (entry.mInfoId);
|
||||
mEntries.push_back (entry); // we want slicing here
|
||||
}
|
||||
|
||||
void Quest::write (ESM::QuestState& state) const
|
||||
{
|
||||
state.mTopic = getTopic();
|
||||
state.mState = mIndex;
|
||||
state.mFinished = mFinished;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
|
||||
#include "topic.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct QuestState;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief A quest in progress or a compelted quest
|
||||
/// \brief A quest in progress or a completed quest
|
||||
class Quest : public Topic
|
||||
{
|
||||
int mIndex;
|
||||
|
@ -17,13 +22,15 @@ namespace MWDialogue
|
|||
|
||||
Quest (const std::string& topic);
|
||||
|
||||
const std::string getName() const;
|
||||
Quest (const ESM::QuestState& state);
|
||||
|
||||
virtual std::string getName() const;
|
||||
///< May be an empty string
|
||||
|
||||
int getIndex() const;
|
||||
|
||||
void setIndex (int index);
|
||||
///< Calling this function with a non-existant index while throw an exception.
|
||||
///< Calling this function with a non-existent index will throw an exception.
|
||||
|
||||
bool isFinished() const;
|
||||
|
||||
|
@ -31,6 +38,8 @@ namespace MWDialogue
|
|||
///< Add entry and adjust index accordingly.
|
||||
///
|
||||
/// \note Redundant entries are ignored, but the index is still adjusted.
|
||||
|
||||
void write (ESM::QuestState& state) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
|
||||
#include "topic.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
namespace MWDialogue
|
||||
|
@ -9,7 +12,8 @@ namespace MWDialogue
|
|||
{}
|
||||
|
||||
Topic::Topic (const std::string& topic)
|
||||
: mTopic (topic)
|
||||
: mTopic (topic), mName (
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (topic)->mId)
|
||||
{}
|
||||
|
||||
Topic::~Topic()
|
||||
|
@ -20,11 +24,22 @@ namespace MWDialogue
|
|||
if (entry.mTopic!=mTopic)
|
||||
throw std::runtime_error ("topic does not match: " + mTopic);
|
||||
|
||||
for (TEntryIter iter = begin(); iter!=end(); ++iter)
|
||||
if (*iter==entry.mInfoId)
|
||||
return;
|
||||
mEntries.push_back (entry); // we want slicing here
|
||||
}
|
||||
|
||||
mEntries.push_back (entry.mInfoId);
|
||||
void Topic::insertEntry (const ESM::JournalEntry& entry)
|
||||
{
|
||||
mEntries.push_back (entry);
|
||||
}
|
||||
|
||||
std::string Topic::getTopic() const
|
||||
{
|
||||
return mTopic;
|
||||
}
|
||||
|
||||
std::string Topic::getName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
Topic::TEntryIter Topic::begin() const
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
|
||||
#include "journalentry.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct JournalEntry;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief Collection of seen responses for a topic
|
||||
|
@ -13,13 +18,14 @@ namespace MWDialogue
|
|||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<std::string> TEntryContainer;
|
||||
typedef std::vector<Entry> TEntryContainer;
|
||||
typedef TEntryContainer::const_iterator TEntryIter;
|
||||
|
||||
protected:
|
||||
|
||||
std::string mTopic;
|
||||
TEntryContainer mEntries; // info-IDs
|
||||
std::string mName;
|
||||
TEntryContainer mEntries;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -34,7 +40,13 @@ namespace MWDialogue
|
|||
///
|
||||
/// \note Redundant entries are ignored.
|
||||
|
||||
std::string const & getName () const { return mTopic; }
|
||||
void insertEntry (const ESM::JournalEntry& entry);
|
||||
///< Add entry without checking for redundant entries or modifying the state of the
|
||||
/// topic otherwise
|
||||
|
||||
std::string getTopic() const;
|
||||
|
||||
virtual std::string getName() const;
|
||||
|
||||
TEntryIter begin() const;
|
||||
///< Iterator pointing to the begin of the journal for this topic.
|
||||
|
|
|
@ -196,34 +196,6 @@ book JournalBooks::createEmptyJournalBook ()
|
|||
typesetter->lineBreak ();
|
||||
typesetter->write (body, to_utf8_span ("You should have gone though the starting quest and got an initial quest."));
|
||||
|
||||
BookTypesetter::Style* big = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* test = typesetter->createStyle ("MonoFont", MyGUI::Colour::Blue);
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (body, to_utf8_span (
|
||||
"The layout engine doesn't currently support aligning fonts to "
|
||||
"their baseline within a single line so the following text looks "
|
||||
"funny. In order to properly implement it, a stupidly simple "
|
||||
"change is needed in MyGUI to report the where the baseline is for "
|
||||
"a particular font"
|
||||
));
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (big, to_utf8_span ("big text g"));
|
||||
typesetter->write (body, to_utf8_span (" проверяем только в дебаге"));
|
||||
typesetter->write (body, to_utf8_span (" normal g"));
|
||||
typesetter->write (big, to_utf8_span (" done g"));
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (test, to_utf8_span (
|
||||
"int main (int argc,\n"
|
||||
" char ** argv)\n"
|
||||
"{\n"
|
||||
" print (\"hello world!\\n\");\n"
|
||||
" return 0;\n"
|
||||
"}\n"
|
||||
));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ namespace MWGui {
|
|||
|
||||
struct JournalViewModelImpl;
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month);
|
||||
|
||||
struct JournalViewModelImpl : JournalViewModel
|
||||
{
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
@ -237,21 +235,21 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
|
||||
std::string getText () const
|
||||
{
|
||||
return itr->getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
return itr->getText();
|
||||
}
|
||||
|
||||
Utf8Span timestamp () const
|
||||
{
|
||||
if (timestamp_buffer.empty ())
|
||||
{
|
||||
std::string dayStr = MyGUI::LanguageManager::getInstance().replaceTags("#{sDay}");
|
||||
|
||||
std::ostringstream os;
|
||||
|
||||
os << itr->mDayOfMonth << ' ';
|
||||
|
||||
injectMonthName (os, itr->mMonth);
|
||||
|
||||
const std::string& dayStr = MyGUI::LanguageManager::getInstance().replaceTags("#{sDay}");
|
||||
os << " (" << dayStr << " " << (itr->mDay + 1) << ')';
|
||||
os
|
||||
<< itr->mDayOfMonth << ' '
|
||||
<< MWBase::Environment::get().getWorld()->getMonthName (itr->mMonth)
|
||||
<< " (" << dayStr << " " << (itr->mDay + 1) << ')';
|
||||
|
||||
timestamp_buffer = os.str ();
|
||||
}
|
||||
|
@ -272,7 +270,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
{
|
||||
for (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j)
|
||||
{
|
||||
if (i->mInfoId == *j)
|
||||
if (i->mInfoId == j->mInfoId)
|
||||
visitor (JournalEntryImpl <MWBase::Journal::TEntryIter> (this, i));
|
||||
}
|
||||
}
|
||||
|
@ -292,9 +290,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
void visitTopicName (TopicId topicId, boost::function <void (Utf8Span)> visitor) const
|
||||
{
|
||||
MWDialogue::Topic const & topic = * reinterpret_cast <MWDialogue::Topic const *> (topicId);
|
||||
// This is to get the correct case for the topic
|
||||
const std::string& name = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find(topic.getName())->mId;
|
||||
visitor (toUtf8Span (name));
|
||||
visitor (toUtf8Span (topic.getName()));
|
||||
}
|
||||
|
||||
void visitTopicNamesStartingWith (char character, boost::function < void (TopicId , Utf8Span) > visitor) const
|
||||
|
@ -306,10 +302,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
if (i->first [0] != std::tolower (character, mLocale))
|
||||
continue;
|
||||
|
||||
// This is to get the correct case for the topic
|
||||
const std::string& name = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find(i->first)->mId;
|
||||
|
||||
visitor (TopicId (&i->second), toUtf8Span (name));
|
||||
visitor (TopicId (&i->second), toUtf8Span (i->second.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -326,9 +319,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
|
||||
std::string getText () const
|
||||
{
|
||||
/// \todo defines are not replaced (%PCName etc). should probably be done elsewhere though since we need the actor
|
||||
return mTopic.getEntry (*itr).getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
return itr->getText();
|
||||
}
|
||||
|
||||
Utf8Span source () const
|
||||
|
@ -351,38 +342,6 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
}
|
||||
};
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month)
|
||||
{
|
||||
MyGUI::LanguageManager& lm = MyGUI::LanguageManager::getInstance();
|
||||
|
||||
if (month == 0)
|
||||
os << lm.replaceTags ("#{sMonthMorningstar}");
|
||||
else if (month == 1)
|
||||
os << lm.replaceTags ("#{sMonthSunsdawn}");
|
||||
else if (month == 2)
|
||||
os << lm.replaceTags ("#{sMonthFirstseed}");
|
||||
else if (month == 3)
|
||||
os << lm.replaceTags ("#{sMonthRainshand}");
|
||||
else if (month == 4)
|
||||
os << lm.replaceTags ("#{sMonthSecondseed}");
|
||||
else if (month == 5)
|
||||
os << lm.replaceTags ("#{sMonthMidyear}");
|
||||
else if (month == 6)
|
||||
os << lm.replaceTags ("#{sMonthSunsheight}");
|
||||
else if (month == 7)
|
||||
os << lm.replaceTags ("#{sMonthLastseed}");
|
||||
else if (month == 8)
|
||||
os << lm.replaceTags ("#{sMonthHeartfire}");
|
||||
else if (month == 9)
|
||||
os << lm.replaceTags ("#{sMonthFrostfall}");
|
||||
else if (month == 10)
|
||||
os << lm.replaceTags ("#{sMonthSunsdusk}");
|
||||
else if (month == 11)
|
||||
os << lm.replaceTags ("#{sMonthEveningstar}");
|
||||
else
|
||||
os << month;
|
||||
}
|
||||
|
||||
JournalViewModel::Ptr JournalViewModel::create ()
|
||||
{
|
||||
return boost::make_shared <JournalViewModelImpl> ();
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include "mainmenu.hpp"
|
||||
|
||||
#include <OgreRoot.h>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include "../mwstate/character.hpp"
|
||||
|
||||
#include "savegamedialog.hpp"
|
||||
|
||||
|
@ -16,90 +17,132 @@ namespace MWGui
|
|||
|
||||
MainMenu::MainMenu(int w, int h)
|
||||
: OEngine::GUI::Layout("openmw_mainmenu.layout")
|
||||
, mButtonBox(0)
|
||||
, mButtonBox(0), mWidth (w), mHeight (h)
|
||||
, mSaveGameDialog(NULL)
|
||||
{
|
||||
onResChange(w,h);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
MainMenu::~MainMenu()
|
||||
{
|
||||
delete mSaveGameDialog;
|
||||
}
|
||||
|
||||
void MainMenu::onResChange(int w, int h)
|
||||
{
|
||||
setCoord(0,0,w,h);
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
void MainMenu::setVisible (bool visible)
|
||||
{
|
||||
if (visible)
|
||||
updateMenu();
|
||||
|
||||
OEngine::GUI::Layout::setVisible (visible);
|
||||
}
|
||||
|
||||
void MainMenu::onButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
std::string name = *sender->getUserData<std::string>();
|
||||
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
|
||||
if (name == "return")
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager ()->resumeSounds (MWBase::SoundManager::Play_TypeSfx);
|
||||
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
|
||||
}
|
||||
else if (name == "options")
|
||||
MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings);
|
||||
else if (name == "exitgame")
|
||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||
else if (name == "newgame")
|
||||
{
|
||||
MWBase::Environment::get().getStateManager()->newGame();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!mSaveGameDialog)
|
||||
mSaveGameDialog = new SaveGameDialog();
|
||||
if (name == "loadgame")
|
||||
mSaveGameDialog->setLoadOrSave(true);
|
||||
else if (name == "savegame")
|
||||
mSaveGameDialog->setLoadOrSave(false);
|
||||
mSaveGameDialog->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainMenu::updateMenu()
|
||||
{
|
||||
setCoord(0,0, mWidth, mHeight);
|
||||
|
||||
|
||||
if (mButtonBox)
|
||||
MyGUI::Gui::getInstance ().destroyWidget(mButtonBox);
|
||||
|
||||
if (!mButtonBox)
|
||||
mButtonBox = mMainWidget->createWidget<MyGUI::Widget>("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default);
|
||||
|
||||
int curH = 0;
|
||||
|
||||
MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState();
|
||||
|
||||
std::vector<std::string> buttons;
|
||||
|
||||
if (state==MWBase::StateManager::State_Running)
|
||||
buttons.push_back("return");
|
||||
|
||||
buttons.push_back("newgame");
|
||||
//buttons.push_back("loadgame");
|
||||
//buttons.push_back("savegame");
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->characterBegin()!=
|
||||
MWBase::Environment::get().getStateManager()->characterEnd())
|
||||
buttons.push_back("loadgame");
|
||||
|
||||
if (state==MWBase::StateManager::State_Running &&
|
||||
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1)
|
||||
buttons.push_back("savegame");
|
||||
|
||||
buttons.push_back("options");
|
||||
//buttons.push_back("credits");
|
||||
buttons.push_back("exitgame");
|
||||
|
||||
int maxwidth = 0;
|
||||
|
||||
mButtons.clear();
|
||||
// Create new buttons if needed
|
||||
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
|
||||
{
|
||||
if (mButtons.find(*it) == mButtons.end())
|
||||
{
|
||||
MWGui::ImageButton* button = mButtonBox->createWidget<MWGui::ImageButton>
|
||||
("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default);
|
||||
button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds");
|
||||
button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds");
|
||||
button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds");
|
||||
MyGUI::IntSize requested = button->getRequestedSize();
|
||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked);
|
||||
button->setUserData(std::string(*it));
|
||||
mButtons[*it] = button;
|
||||
curH += requested.height;
|
||||
}
|
||||
}
|
||||
|
||||
// Start by hiding all buttons
|
||||
int maxwidth = 0;
|
||||
for (std::map<std::string, MWGui::ImageButton*>::iterator it = mButtons.begin(); it != mButtons.end(); ++it)
|
||||
{
|
||||
it->second->setVisible(false);
|
||||
MyGUI::IntSize requested = it->second->getRequestedSize();
|
||||
if (requested.width > maxwidth)
|
||||
maxwidth = requested.width;
|
||||
}
|
||||
for (std::map<std::string, MWGui::ImageButton*>::iterator it = mButtons.begin(); it != mButtons.end(); ++it)
|
||||
|
||||
// Now show and position the ones we want
|
||||
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
|
||||
{
|
||||
MyGUI::IntSize requested = it->second->getRequestedSize();
|
||||
it->second->setCoord((maxwidth-requested.width) / 2, it->second->getTop(), requested.width, requested.height);
|
||||
assert(mButtons.find(*it) != mButtons.end());
|
||||
MWGui::ImageButton* button = mButtons[*it];
|
||||
button->setVisible(true);
|
||||
MyGUI::IntSize requested = button->getRequestedSize();
|
||||
button->setCoord((maxwidth-requested.width) / 2, curH, requested.width, requested.height);
|
||||
curH += requested.height;
|
||||
}
|
||||
|
||||
mButtonBox->setCoord (w/2 - maxwidth/2, h/2 - curH/2, maxwidth, curH);
|
||||
}
|
||||
mButtonBox->setCoord (mWidth/2 - maxwidth/2, mHeight/2 - curH/2, maxwidth, curH);
|
||||
|
||||
void MainMenu::onButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
|
||||
if (sender == mButtons["return"])
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager ()->resumeSounds (MWBase::SoundManager::Play_TypeSfx);
|
||||
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
|
||||
}
|
||||
else if (sender == mButtons["options"])
|
||||
MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings);
|
||||
else if (sender == mButtons["exitgame"])
|
||||
MWBase::Environment::get().setRequestExit();
|
||||
else if (sender == mButtons["newgame"])
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->startNewGame();
|
||||
MWBase::Environment::get().getWindowManager()->setNewGame(true);
|
||||
MWBase::Environment::get().getDialogueManager()->clear();
|
||||
MWBase::Environment::get().getJournal()->clear();
|
||||
}
|
||||
|
||||
else if (sender == mButtons["loadgame"])
|
||||
{
|
||||
MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog();
|
||||
dialog->setLoadOrSave(true);
|
||||
dialog->setVisible(true);
|
||||
}
|
||||
else if (sender == mButtons["savegame"])
|
||||
{
|
||||
MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog();
|
||||
dialog->setLoadOrSave(false);
|
||||
dialog->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,19 +5,33 @@
|
|||
namespace MWGui
|
||||
{
|
||||
|
||||
class SaveGameDialog;
|
||||
|
||||
class MainMenu : public OEngine::GUI::Layout
|
||||
{
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
public:
|
||||
|
||||
MainMenu(int w, int h);
|
||||
~MainMenu();
|
||||
|
||||
void onResChange(int w, int h);
|
||||
|
||||
virtual void setVisible (bool visible);
|
||||
|
||||
private:
|
||||
|
||||
MyGUI::Widget* mButtonBox;
|
||||
|
||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||
|
||||
void onButtonClicked (MyGUI::Widget* sender);
|
||||
|
||||
void updateMenu();
|
||||
|
||||
SaveGameDialog* mSaveGameDialog;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -435,7 +435,7 @@ namespace MWGui
|
|||
|
||||
|
||||
static int _counter=0;
|
||||
MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage",
|
||||
MyGUI::Button* markerWidget = mGlobalMapOverlay->createWidget<MyGUI::Button>("ButtonImage",
|
||||
widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(_counter));
|
||||
markerWidget->setImageResource("DoorMarker");
|
||||
markerWidget->setUserString("ToolTipType", "Layout");
|
||||
|
@ -500,10 +500,11 @@ namespace MWGui
|
|||
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
|
||||
for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i)
|
||||
// force markers to foreground
|
||||
for (unsigned int i=0; i<mGlobalMapOverlay->getChildCount (); ++i)
|
||||
{
|
||||
if (mGlobalMapImage->getChildAt (i)->getName().substr(0,4) == "Door")
|
||||
mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
|
||||
if (mGlobalMapOverlay->getChildAt (i)->getName().substr(0,4) == "Door")
|
||||
mGlobalMapOverlay->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
|
||||
}
|
||||
|
||||
globalMapUpdatePlayer();
|
||||
|
@ -574,4 +575,31 @@ namespace MWGui
|
|||
mGlobalMap->setViewOffset(viewoffs);
|
||||
}
|
||||
|
||||
void MapWindow::clear()
|
||||
{
|
||||
mGlobalMapRender->clear();
|
||||
|
||||
while (mEventBoxGlobal->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mEventBoxGlobal->getChildAt(0));
|
||||
while (mGlobalMapOverlay->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mGlobalMapOverlay->getChildAt(0));
|
||||
}
|
||||
|
||||
void MapWindow::write(ESM::ESMWriter &writer)
|
||||
{
|
||||
mGlobalMapRender->write(writer);
|
||||
}
|
||||
|
||||
void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type)
|
||||
{
|
||||
std::vector<std::pair<int, int> > exploredCells;
|
||||
mGlobalMapRender->readRecord(reader, type, exploredCells);
|
||||
|
||||
for (std::vector<std::pair<int, int> >::iterator it = exploredCells.begin(); it != exploredCells.end(); ++it)
|
||||
{
|
||||
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Cell>().search(it->first, it->second);
|
||||
if (cell && !cell->mName.empty())
|
||||
addVisitedLocation(cell->mName, it->first, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,12 @@ namespace MWRender
|
|||
class GlobalMap;
|
||||
}
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace Loading
|
||||
{
|
||||
class Listener;
|
||||
|
@ -94,6 +100,12 @@ namespace MWGui
|
|||
|
||||
void onFrame(float dt) { NoDrop::onFrame(dt); }
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
void clear();
|
||||
|
||||
void write (ESM::ESMWriter& writer);
|
||||
void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
|
||||
private:
|
||||
void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace MWGui
|
|||
|
||||
void ReferenceInterface::checkReferenceAvailable()
|
||||
{
|
||||
MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
|
||||
// check if player has changed cell, or count of the reference has become 0
|
||||
if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL)
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
#include "savegamedialog.hpp"
|
||||
#include "widgets.hpp"
|
||||
|
||||
#include <OgreImage.h>
|
||||
#include <OgreTextureManager.h>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwstate/character.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
SaveGameDialog::SaveGameDialog()
|
||||
: WindowModal("openmw_savegame_dialog.layout")
|
||||
, mSaving(true)
|
||||
, mCurrentCharacter(NULL)
|
||||
{
|
||||
getWidget(mScreenshot, "Screenshot");
|
||||
getWidget(mCharacterSelection, "SelectCharacter");
|
||||
|
@ -18,21 +32,67 @@ namespace MWGui
|
|||
getWidget(mSpacer, "Spacer");
|
||||
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked);
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
|
||||
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
|
||||
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
|
||||
|
||||
}
|
||||
|
||||
void SaveGameDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
|
||||
mSaveNameEdit->setCaption ("");
|
||||
|
||||
center();
|
||||
|
||||
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
|
||||
if (mgr->characterBegin() == mgr->characterEnd())
|
||||
return;
|
||||
|
||||
mCurrentCharacter = mgr->getCurrentCharacter (false);
|
||||
|
||||
std::string directory =
|
||||
Misc::StringUtils::lowerCase (Settings::Manager::getString ("character", "Saves"));
|
||||
|
||||
mCharacterSelection->removeAllItems();
|
||||
|
||||
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it)
|
||||
{
|
||||
if (it->begin()!=it->end())
|
||||
{
|
||||
std::stringstream title;
|
||||
title << it->getSignature().mPlayerName;
|
||||
title << " (Level " << it->getSignature().mPlayerLevel << " " << it->getSignature().mPlayerClass << ")";
|
||||
|
||||
mCharacterSelection->addItem (title.str());
|
||||
|
||||
if (mCurrentCharacter == &*it ||
|
||||
(!mCurrentCharacter && !mSaving && directory==Misc::StringUtils::lowerCase (
|
||||
it->begin()->mPath.parent_path().filename().string())))
|
||||
{
|
||||
mCurrentCharacter = &*it;
|
||||
mCharacterSelection->setIndexSelected(mCharacterSelection->getItemCount()-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fillSaveList();
|
||||
|
||||
}
|
||||
|
||||
void SaveGameDialog::setLoadOrSave(bool load)
|
||||
{
|
||||
mSaving = !load;
|
||||
mSaveNameEdit->setVisible(!load);
|
||||
mCharacterSelection->setUserString("Hidden", load ? "false" : "true");
|
||||
mCharacterSelection->setVisible(load);
|
||||
mSpacer->setUserString("Hidden", load ? "false" : "true");
|
||||
|
||||
if (!load)
|
||||
{
|
||||
mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter (false);
|
||||
}
|
||||
|
||||
center();
|
||||
}
|
||||
|
||||
|
@ -43,7 +103,129 @@ namespace MWGui
|
|||
|
||||
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
setVisible(false);
|
||||
// Get the selected slot, if any
|
||||
unsigned int i=0;
|
||||
const MWState::Slot* slot = NULL;
|
||||
|
||||
if (mCurrentCharacter)
|
||||
{
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it,++i)
|
||||
{
|
||||
if (i == mSaveList->getIndexSelected())
|
||||
slot = &*it;
|
||||
}
|
||||
}
|
||||
|
||||
if (mSaving)
|
||||
{
|
||||
MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mCurrentCharacter && slot)
|
||||
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
|
||||
|
||||
unsigned int i=0;
|
||||
const MWState::Character* character = NULL;
|
||||
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it, ++i)
|
||||
{
|
||||
if (i == pos)
|
||||
character = &*it;
|
||||
}
|
||||
assert(character && "Can't find selected character");
|
||||
|
||||
mCurrentCharacter = character;
|
||||
fillSaveList();
|
||||
}
|
||||
|
||||
void SaveGameDialog::fillSaveList()
|
||||
{
|
||||
mSaveList->removeAllItems();
|
||||
if (!mCurrentCharacter)
|
||||
return;
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it)
|
||||
{
|
||||
mSaveList->addItem(it->mProfile.mDescription);
|
||||
}
|
||||
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos)
|
||||
{
|
||||
if (pos == MyGUI::ITEM_NONE)
|
||||
{
|
||||
mInfoText->setCaption("");
|
||||
mScreenshot->setImageTexture("");
|
||||
return;
|
||||
}
|
||||
|
||||
const MWState::Slot* slot = NULL;
|
||||
unsigned int i=0;
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it, ++i)
|
||||
{
|
||||
if (i == pos)
|
||||
slot = &*it;
|
||||
}
|
||||
assert(slot && "Can't find selected slot");
|
||||
|
||||
std::stringstream text;
|
||||
time_t time = slot->mTimeStamp;
|
||||
struct tm* timeinfo;
|
||||
timeinfo = localtime(&time);
|
||||
|
||||
text << asctime(timeinfo) << "\n";
|
||||
text << "Level " << slot->mProfile.mPlayerLevel << "\n";
|
||||
text << slot->mProfile.mPlayerCell << "\n";
|
||||
// text << "Time played: " << slot->mProfile.mTimePlayed << "\n";
|
||||
|
||||
int hour = int(slot->mProfile.mInGameTime.mGameHour);
|
||||
bool pm = hour >= 12;
|
||||
if (hour >= 13) hour -= 12;
|
||||
if (hour == 0) hour = 12;
|
||||
|
||||
text
|
||||
<< slot->mProfile.mInGameTime.mDay << " "
|
||||
<< MWBase::Environment::get().getWorld()->getMonthName(slot->mProfile.mInGameTime.mMonth)
|
||||
<< " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
|
||||
|
||||
mInfoText->setCaptionWithReplacing(text.str());
|
||||
|
||||
// Decode screenshot
|
||||
std::vector<char> data = slot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :(
|
||||
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size()));
|
||||
Ogre::Image image;
|
||||
image.load(stream, "jpg");
|
||||
|
||||
const std::string textureName = "@savegame_screenshot";
|
||||
Ogre::TexturePtr texture;
|
||||
texture = Ogre::TextureManager::getSingleton().getByName(textureName);
|
||||
mScreenshot->setImageTexture("");
|
||||
if (texture.isNull())
|
||||
{
|
||||
texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
image.getWidth(), image.getHeight(), 0, Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY);
|
||||
}
|
||||
texture->unload();
|
||||
texture->setWidth(image.getWidth());
|
||||
texture->setHeight(image.getHeight());
|
||||
texture->loadImage(image);
|
||||
|
||||
mScreenshot->setImageTexture(textureName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "windowbase.hpp"
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
class Character;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
@ -17,10 +22,15 @@ namespace MWGui
|
|||
|
||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||
void onOkButtonClicked (MyGUI::Widget* sender);
|
||||
void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos);
|
||||
void onSlotSelected (MyGUI::ListBox* sender, size_t pos);
|
||||
|
||||
void fillSaveList();
|
||||
|
||||
|
||||
private:
|
||||
MyGUI::ImageBox* mScreenshot;
|
||||
bool mSaving;
|
||||
|
||||
MyGUI::ComboBox* mCharacterSelection;
|
||||
MyGUI::EditBox* mInfoText;
|
||||
|
@ -30,6 +40,8 @@ namespace MWGui
|
|||
MyGUI::EditBox* mSaveNameEdit;
|
||||
MyGUI::Widget* mSpacer;
|
||||
|
||||
const MWState::Character* mCurrentCharacter;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -87,49 +87,7 @@ namespace MWGui
|
|||
onHourSliderChangedPosition(mHourSlider, 0);
|
||||
mHourSlider->setScrollPosition (0);
|
||||
|
||||
// http://www.uesp.net/wiki/Lore:Calendar
|
||||
std::string month;
|
||||
int m = MWBase::Environment::get().getWorld ()->getMonth ();
|
||||
switch (m) {
|
||||
case 0:
|
||||
month = "#{sMonthMorningstar}";
|
||||
break;
|
||||
case 1:
|
||||
month = "#{sMonthSunsdawn}";
|
||||
break;
|
||||
case 2:
|
||||
month = "#{sMonthFirstseed}";
|
||||
break;
|
||||
case 3:
|
||||
month = "#{sMonthRainshand}";
|
||||
break;
|
||||
case 4:
|
||||
month = "#{sMonthSecondseed}";
|
||||
break;
|
||||
case 5:
|
||||
month = "#{sMonthMidyear}";
|
||||
break;
|
||||
case 6:
|
||||
month = "#{sMonthSunsheight}";
|
||||
break;
|
||||
case 7:
|
||||
month = "#{sMonthLastseed}";
|
||||
break;
|
||||
case 8:
|
||||
month = "#{sMonthHeartfire}";
|
||||
break;
|
||||
case 9:
|
||||
month = "#{sMonthFrostfall}";
|
||||
break;
|
||||
case 10:
|
||||
month = "#{sMonthSunsdusk}";
|
||||
break;
|
||||
case 11:
|
||||
month = "#{sMonthEveningstar}";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
std::string month = MWBase::Environment::get().getWorld ()->getMonthName();
|
||||
int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour ();
|
||||
bool pm = hour >= 12;
|
||||
if (hour >= 13) hour -= 12;
|
||||
|
|
|
@ -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"
|
||||
|
@ -699,6 +700,10 @@ namespace MWGui
|
|||
|
||||
mToolTips->onFrame(frameDuration);
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_NoGame)
|
||||
return;
|
||||
|
||||
if (mDragAndDrop->mIsOnDragAndDrop)
|
||||
{
|
||||
assert(mDragAndDrop->mDraggedWidget);
|
||||
|
@ -732,31 +737,20 @@ namespace MWGui
|
|||
mCompanionWindow->onFrame();
|
||||
}
|
||||
|
||||
void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell)
|
||||
void WindowManager::changeCell(MWWorld::CellStore* cell)
|
||||
{
|
||||
if (cell->mCell->isExterior())
|
||||
{
|
||||
std::string name;
|
||||
if (cell->mCell->mName != "")
|
||||
{
|
||||
name = cell->mCell->mName;
|
||||
mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ());
|
||||
}
|
||||
else
|
||||
{
|
||||
const ESM::Region* region =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().search(cell->mCell->mRegion);
|
||||
if (region)
|
||||
name = region->mName;
|
||||
else
|
||||
name = getGameSettingString("sDefaultCellname", "Wilderness");
|
||||
}
|
||||
|
||||
mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY());
|
||||
std::string name = MWBase::Environment::get().getWorld()->getCellName (cell);
|
||||
|
||||
mMap->setCellName( name );
|
||||
mHud->setCellName( name );
|
||||
|
||||
if (cell->mCell->isExterior())
|
||||
{
|
||||
if (!cell->mCell->mName.empty())
|
||||
mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ());
|
||||
|
||||
mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY());
|
||||
|
||||
mMap->setCellPrefix("Cell");
|
||||
mHud->setCellPrefix("Cell");
|
||||
mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() );
|
||||
|
@ -764,8 +758,6 @@ namespace MWGui
|
|||
}
|
||||
else
|
||||
{
|
||||
mMap->setCellName( cell->mCell->mName );
|
||||
mHud->setCellName( cell->mCell->mName );
|
||||
mMap->setCellPrefix( cell->mCell->mName );
|
||||
mHud->setCellPrefix( cell->mCell->mName );
|
||||
|
||||
|
@ -776,7 +768,6 @@ namespace MWGui
|
|||
MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos);
|
||||
mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WindowManager::setInteriorMapTexture(const int x, const int y)
|
||||
|
@ -1239,7 +1230,7 @@ namespace MWGui
|
|||
bool WindowManager::getRestEnabled()
|
||||
{
|
||||
//Enable rest dialogue if character creation finished
|
||||
if(mRestAllowed==false && MWBase::Environment::get().getWorld()->getGlobalVariable ("chargenstate").mFloat==-1)
|
||||
if(mRestAllowed==false && MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1)
|
||||
mRestAllowed=true;
|
||||
return mRestAllowed;
|
||||
}
|
||||
|
@ -1392,4 +1383,19 @@ namespace MWGui
|
|||
Settings::Manager::setFloat(setting + " h", "Windows", h);
|
||||
}
|
||||
|
||||
void WindowManager::clear()
|
||||
{
|
||||
mMap->clear();
|
||||
}
|
||||
|
||||
void WindowManager::write(ESM::ESMWriter &writer)
|
||||
{
|
||||
mMap->write(writer);
|
||||
}
|
||||
|
||||
void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type)
|
||||
{
|
||||
mMap->readRecord(reader, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -280,6 +280,12 @@ namespace MWGui
|
|||
|
||||
virtual bool getCursorVisible();
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear();
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer);
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
|
||||
private:
|
||||
bool mConsoleOnlyScripts;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
using namespace ICS;
|
||||
|
@ -167,6 +168,8 @@ namespace MWInput
|
|||
switch (action)
|
||||
{
|
||||
case A_GameMenu:
|
||||
if(!(MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running
|
||||
&& MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_MainMenu))
|
||||
toggleMainMenu ();
|
||||
break;
|
||||
case A_Screenshot:
|
||||
|
@ -280,7 +283,9 @@ namespace MWInput
|
|||
return;
|
||||
|
||||
// Disable movement in Gui mode
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode()
|
||||
|| MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)
|
||||
return;
|
||||
|
||||
|
||||
// Configure player movement according to keyboard input. Actual movement will
|
||||
|
@ -613,7 +618,7 @@ namespace MWInput
|
|||
|
||||
void InputManager::windowClosed()
|
||||
{
|
||||
MWBase::Environment::setRequestExit();
|
||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||
}
|
||||
|
||||
void InputManager::toggleMainMenu()
|
||||
|
|
|
@ -757,7 +757,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore, const MWWorld::Ptr& ignore)
|
||||
void Actors::dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.begin();
|
||||
while(iter != mActors.end())
|
||||
|
@ -774,6 +774,24 @@ namespace MWMechanics
|
|||
|
||||
void Actors::update (float duration, bool paused)
|
||||
{
|
||||
if(!paused)
|
||||
{
|
||||
// Note: we need to do this before any of the animations are updated.
|
||||
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
|
||||
// so updating VFX immediately after that would just remove the particle effects instantly.
|
||||
// There needs to be a magic effect update in between.
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
iter->second->updateContinuousVfx();
|
||||
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
{
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
|
||||
ESM::MagicEffect::Paralyze).mMagnitude > 0)
|
||||
iter->second->skipAnim();
|
||||
iter->second->update(duration);
|
||||
}
|
||||
}
|
||||
|
||||
if (!paused)
|
||||
{
|
||||
for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
|
@ -806,22 +824,31 @@ namespace MWMechanics
|
|||
if(iter->first.getRefData().getHandle()=="player" &&
|
||||
MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
{
|
||||
MWMechanics::DynamicStat<float> stat(stats.getHealth());
|
||||
MWMechanics::DynamicStat<float> stat (stats.getHealth());
|
||||
|
||||
if(stat.getModified()<1)
|
||||
if (stat.getModified()<1)
|
||||
{
|
||||
stat.setModified(1, 0);
|
||||
stats.setHealth(stat);
|
||||
}
|
||||
|
||||
stats.resurrect();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(iter->second->isDead())
|
||||
continue;
|
||||
// Make sure spell effects with CasterLinked flag are removed
|
||||
// TODO: would be nice not to do this all the time...
|
||||
for(PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||
{
|
||||
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
||||
spells.purge(iter->first.getRefData().getHandle());
|
||||
}
|
||||
|
||||
iter->second->kill();
|
||||
// FIXME: see http://bugs.openmw.org/issues/869
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false);
|
||||
|
||||
if (iter->second->kill())
|
||||
{
|
||||
++mDeathCount[cls.getId(iter->first)];
|
||||
|
||||
// Apply soultrap
|
||||
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
|
||||
|
@ -835,37 +862,10 @@ namespace MWMechanics
|
|||
stats.setMagicEffects(MWMechanics::MagicEffects());
|
||||
calculateCreatureStatModifiers(iter->first, 0);
|
||||
|
||||
// Make sure spell effects with CasterLinked flag are removed
|
||||
for(PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||
{
|
||||
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
||||
spells.purge(iter->first.getRefData().getHandle());
|
||||
}
|
||||
|
||||
++mDeathCount[cls.getId(iter->first)];
|
||||
|
||||
if(cls.isEssential(iter->first))
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(!paused)
|
||||
{
|
||||
// Note: we need to do this before any of the animations are updated.
|
||||
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
|
||||
// so updating VFX immediately after that would just remove the particle effects instantly.
|
||||
// There needs to be a magic effect update in between.
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
iter->second->updateContinuousVfx();
|
||||
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
{
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
|
||||
ESM::MagicEffect::Paralyze).mMagnitude > 0)
|
||||
iter->second->skipAnim();
|
||||
iter->second->update(duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
void Actors::restoreDynamicStats(bool sleep)
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
@ -1135,7 +1136,6 @@ void CharacterController::update(float duration)
|
|||
}
|
||||
else if(cls.getCreatureStats(mPtr).isDead())
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(mPtr, false);
|
||||
world->queueMovement(mPtr, Ogre::Vector3(0.0f));
|
||||
}
|
||||
|
||||
|
@ -1237,10 +1237,18 @@ void CharacterController::forceStateUpdate()
|
|||
}
|
||||
}
|
||||
|
||||
void CharacterController::kill()
|
||||
bool CharacterController::kill()
|
||||
{
|
||||
if(mDeathState != CharState_None)
|
||||
return;
|
||||
if( isDead() )
|
||||
{
|
||||
//player's death animation is over
|
||||
if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) )
|
||||
{
|
||||
MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setHealth(0);
|
||||
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
playRandomDeath();
|
||||
|
||||
|
@ -1251,6 +1259,8 @@ void CharacterController::kill()
|
|||
|
||||
mIdleState = CharState_None;
|
||||
mCurrentIdle.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CharacterController::resurrect()
|
||||
|
|
|
@ -198,7 +198,7 @@ public:
|
|||
void skipAnim();
|
||||
bool isAnimPlaying(const std::string &groupName);
|
||||
|
||||
void kill();
|
||||
bool kill();
|
||||
void resurrect();
|
||||
bool isDead() const
|
||||
{ return mDeathState != CharState_None; }
|
||||
|
|
|
@ -760,6 +760,14 @@ namespace MWMechanics
|
|||
return mAI;
|
||||
}
|
||||
|
||||
void MechanicsManager::playerLoaded()
|
||||
{
|
||||
mUpdatePlayer = true;
|
||||
mClassSelected = true;
|
||||
mRaceSelected = true;
|
||||
mAI = true;
|
||||
}
|
||||
|
||||
bool MechanicsManager::sleepInBed(const MWWorld::Ptr &ptr, const MWWorld::Ptr &bed)
|
||||
{
|
||||
MWWorld::Ptr victim;
|
||||
|
|
|
@ -133,12 +133,14 @@ namespace MWMechanics
|
|||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr);
|
||||
|
||||
virtual void toggleAI();
|
||||
virtual bool isAIActive();
|
||||
|
||||
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects);
|
||||
|
||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
|
||||
|
||||
virtual void toggleAI();
|
||||
virtual bool isAIActive();
|
||||
|
||||
virtual void playerLoaded();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
|||
}
|
||||
}
|
||||
|
||||
void Objects::dropObjects (const MWWorld::Ptr::CellStore *cellStore)
|
||||
void Objects::dropObjects (const MWWorld::CellStore *cellStore)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mObjects.begin();
|
||||
while(iter != mObjects.end())
|
||||
|
|
|
@ -127,7 +127,7 @@ bool Actors::deleteObject (const MWWorld::Ptr& ptr)
|
|||
return true;
|
||||
}
|
||||
|
||||
void Actors::removeCell(MWWorld::Ptr::CellStore* store)
|
||||
void Actors::removeCell(MWWorld::CellStore* store)
|
||||
{
|
||||
for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();)
|
||||
{
|
||||
|
|
|
@ -185,14 +185,14 @@ bool Debugging::toggleRenderMode (int mode){
|
|||
return false;
|
||||
}
|
||||
|
||||
void Debugging::cellAdded(MWWorld::Ptr::CellStore *store)
|
||||
void Debugging::cellAdded(MWWorld::CellStore *store)
|
||||
{
|
||||
mActiveCells.push_back(store);
|
||||
if (mPathgridEnabled)
|
||||
enableCellPathgrid(store);
|
||||
}
|
||||
|
||||
void Debugging::cellRemoved(MWWorld::Ptr::CellStore *store)
|
||||
void Debugging::cellRemoved(MWWorld::CellStore *store)
|
||||
{
|
||||
mActiveCells.erase(std::remove(mActiveCells.begin(), mActiveCells.end(), store), mActiveCells.end());
|
||||
if (mPathgridEnabled)
|
||||
|
@ -227,7 +227,7 @@ void Debugging::togglePathgrid()
|
|||
}
|
||||
}
|
||||
|
||||
void Debugging::enableCellPathgrid(MWWorld::Ptr::CellStore *store)
|
||||
void Debugging::enableCellPathgrid(MWWorld::CellStore *store)
|
||||
{
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*store->mCell);
|
||||
|
@ -254,7 +254,7 @@ void Debugging::enableCellPathgrid(MWWorld::Ptr::CellStore *store)
|
|||
}
|
||||
}
|
||||
|
||||
void Debugging::disableCellPathgrid(MWWorld::Ptr::CellStore *store)
|
||||
void Debugging::disableCellPathgrid(MWWorld::CellStore *store)
|
||||
{
|
||||
if (store->mCell->isExterior())
|
||||
{
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <components/loadinglistener/loadinglistener.hpp>
|
||||
|
||||
#include <components/esm/globalmap.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -60,8 +62,6 @@ namespace MWRender
|
|||
loadingListener->setProgressRange((mMaxX-mMinX+1) * (mMaxY-mMinY+1));
|
||||
loadingListener->setProgress(0);
|
||||
|
||||
mExploredBuffer.resize((mMaxX-mMinX+1) * (mMaxY-mMinY+1) * 4);
|
||||
|
||||
//if (!boost::filesystem::exists(mCacheDir + "/GlobalMap.png"))
|
||||
if (1)
|
||||
{
|
||||
|
@ -170,21 +170,10 @@ namespace MWRender
|
|||
tex->load();
|
||||
|
||||
|
||||
|
||||
|
||||
mOverlayTexture = Ogre::TextureManager::getSingleton().createManual("GlobalMapOverlay", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D, mWidth, mHeight, 0, Ogre::PF_A8B8G8R8, Ogre::TU_DYNAMIC_WRITE_ONLY);
|
||||
|
||||
|
||||
std::vector<Ogre::uint32> buffer;
|
||||
buffer.resize(mWidth * mHeight);
|
||||
|
||||
// initialize to (0, 0, 0, 0)
|
||||
for (int p=0; p<mWidth * mHeight; ++p)
|
||||
buffer[p] = 0;
|
||||
|
||||
memcpy(mOverlayTexture->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mWidth*mHeight*4);
|
||||
mOverlayTexture->getBuffer()->unlock();
|
||||
clear();
|
||||
|
||||
loadingListener->loadingOff();
|
||||
}
|
||||
|
@ -227,9 +216,114 @@ namespace MWRender
|
|||
|
||||
if (!localMapTexture.isNull())
|
||||
{
|
||||
|
||||
mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,512,512),
|
||||
Ogre::Image::Box(originX,originY,originX+24,originY+24));
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalMap::clear()
|
||||
{
|
||||
std::vector<Ogre::uint32> buffer;
|
||||
// initialize to (0,0,0,0)
|
||||
buffer.resize(mWidth * mHeight, 0);
|
||||
|
||||
Ogre::PixelBox pb(mWidth, mHeight, 1, Ogre::PF_A8B8G8R8, &buffer[0]);
|
||||
|
||||
mOverlayTexture->getBuffer()->blitFromMemory(pb);
|
||||
}
|
||||
|
||||
void GlobalMap::write(ESM::ESMWriter &writer)
|
||||
{
|
||||
ESM::GlobalMap map;
|
||||
map.mBounds.mMinX = mMinX;
|
||||
map.mBounds.mMaxX = mMaxX;
|
||||
map.mBounds.mMinY = mMinY;
|
||||
map.mBounds.mMaxY = mMaxY;
|
||||
|
||||
Ogre::Image image;
|
||||
mOverlayTexture->convertToImage(image);
|
||||
Ogre::DataStreamPtr encoded = image.encode("png");
|
||||
map.mImageData.resize(encoded->size());
|
||||
encoded->read(&map.mImageData[0], encoded->size());
|
||||
|
||||
writer.startRecord(ESM::REC_GMAP);
|
||||
map.save(writer);
|
||||
writer.endRecord(ESM::REC_GMAP);
|
||||
}
|
||||
|
||||
void GlobalMap::readRecord(ESM::ESMReader &reader, int32_t type, std::vector<std::pair<int, int> >& exploredCells)
|
||||
{
|
||||
if (type == ESM::REC_GMAP)
|
||||
{
|
||||
ESM::GlobalMap map;
|
||||
map.load(reader);
|
||||
|
||||
const ESM::GlobalMap::Bounds& bounds = map.mBounds;
|
||||
|
||||
if (bounds.mMaxX-bounds.mMinX <= 0)
|
||||
return;
|
||||
if (bounds.mMaxY-bounds.mMinY <= 0)
|
||||
return;
|
||||
|
||||
Ogre::Image image;
|
||||
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size()));
|
||||
image.load(stream, "png");
|
||||
|
||||
int xLength = (bounds.mMaxX-bounds.mMinX+1);
|
||||
int yLength = (bounds.mMaxY-bounds.mMinY+1);
|
||||
|
||||
// Size of one cell in image space
|
||||
int cellImageSizeSrc = image.getWidth() / xLength;
|
||||
if (int(image.getHeight() / yLength) != cellImageSizeSrc)
|
||||
throw std::runtime_error("cell size must be quadratic");
|
||||
|
||||
// Determine which cells were explored by reading the image data
|
||||
for (int x=0; x < xLength; ++x)
|
||||
{
|
||||
for (int y=0; y < yLength; ++y)
|
||||
{
|
||||
unsigned int imageX = (x) * cellImageSizeSrc;
|
||||
// NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is
|
||||
unsigned int imageY = (yLength - (y + 1)) * cellImageSizeSrc;
|
||||
|
||||
assert(imageX < image.getWidth());
|
||||
assert(imageY < image.getWidth());
|
||||
|
||||
if (image.getColourAt(imageX, imageY, 0).a > 0)
|
||||
exploredCells.push_back(std::make_pair(x+bounds.mMinX,y+bounds.mMinY));
|
||||
}
|
||||
}
|
||||
|
||||
// If cell bounds of the currently loaded content and the loaded savegame do not match,
|
||||
// we need to resize source/dest boxes to accommodate
|
||||
// This means nonexisting cells will be dropped silently
|
||||
|
||||
int cellImageSizeDst = 24;
|
||||
|
||||
int leftDiff = (mMinX - bounds.mMinX);
|
||||
int topDiff = (bounds.mMaxY - mMaxY);
|
||||
int rightDiff = (bounds.mMaxX - mMaxX);
|
||||
int bottomDiff = (mMinY - bounds.mMinY);
|
||||
Ogre::Image::Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc),
|
||||
std::max(0, topDiff * cellImageSizeSrc),
|
||||
std::min(image.getWidth(), image.getWidth() - rightDiff * cellImageSizeSrc),
|
||||
std::min(image.getHeight(), image.getHeight() - bottomDiff * cellImageSizeSrc));
|
||||
|
||||
Ogre::Image::Box destBox ( std::max(0, -leftDiff * cellImageSizeDst),
|
||||
std::max(0, -topDiff * cellImageSizeDst),
|
||||
std::min(mOverlayTexture->getWidth(), mOverlayTexture->getWidth() + rightDiff * cellImageSizeDst),
|
||||
std::min(mOverlayTexture->getHeight(), mOverlayTexture->getHeight() + bottomDiff * cellImageSizeDst));
|
||||
|
||||
// Looks like there is no interface for blitting from memory with src/dst boxes.
|
||||
// So we create a temporary texture for blitting.
|
||||
Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().createManual("@temp",
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, image.getWidth(),
|
||||
image.getHeight(), 0, Ogre::PF_A8B8G8R8);
|
||||
tex->loadImage(image);
|
||||
|
||||
mOverlayTexture->getBuffer()->blit(tex->getBuffer(), srcBox, destBox);
|
||||
|
||||
Ogre::TextureManager::getSingleton().remove("@temp");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,12 @@ namespace Loading
|
|||
class Listener;
|
||||
}
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMWriter;
|
||||
class ESMReader;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
|
@ -31,13 +37,18 @@ namespace MWRender
|
|||
|
||||
void exploreCell (int cellX, int cellY);
|
||||
|
||||
/// Clears the overlay
|
||||
void clear();
|
||||
|
||||
void write (ESM::ESMWriter& writer);
|
||||
void readRecord (ESM::ESMReader& reader, int32_t type, std::vector<std::pair<int, int> >& exploredCells);
|
||||
|
||||
private:
|
||||
std::string mCacheDir;
|
||||
|
||||
std::vector< std::pair<int,int> > mExploredCells;
|
||||
|
||||
Ogre::TexturePtr mOverlayTexture;
|
||||
std::vector<Ogre::uchar> mExploredBuffer;
|
||||
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
|
|
@ -79,7 +79,7 @@ std::string LocalMap::coordStr(const int x, const int y)
|
|||
return StringConverter::toString(x) + "_" + StringConverter::toString(y);
|
||||
}
|
||||
|
||||
void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell)
|
||||
void LocalMap::saveFogOfWar(MWWorld::CellStore* cell)
|
||||
{
|
||||
if (!mInterior)
|
||||
{
|
||||
|
@ -108,7 +108,7 @@ void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell)
|
|||
}
|
||||
}
|
||||
|
||||
void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, float zMin, float zMax)
|
||||
void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax)
|
||||
{
|
||||
mInterior = false;
|
||||
|
||||
|
@ -125,7 +125,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, float zMin, float zMax)
|
|||
render((x+0.5)*sSize, (y+0.5)*sSize, zMin, zMax, sSize, sSize, name);
|
||||
}
|
||||
|
||||
void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell,
|
||||
void LocalMap::requestMap(MWWorld::CellStore* cell,
|
||||
AxisAlignedBox bounds)
|
||||
{
|
||||
// if we're in an empty cell, don't bother rendering anything
|
||||
|
|
|
@ -172,7 +172,7 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
|||
}
|
||||
|
||||
|
||||
void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
||||
void Objects::removeCell(MWWorld::CellStore* store)
|
||||
{
|
||||
for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();)
|
||||
{
|
||||
|
@ -212,7 +212,7 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
|||
}
|
||||
}
|
||||
|
||||
void Objects::buildStaticGeometry(MWWorld::Ptr::CellStore& cell)
|
||||
void Objects::buildStaticGeometry(MWWorld::CellStore& cell)
|
||||
{
|
||||
if(mStaticGeometry.find(&cell) != mStaticGeometry.end())
|
||||
{
|
||||
|
@ -226,7 +226,7 @@ void Objects::buildStaticGeometry(MWWorld::Ptr::CellStore& cell)
|
|||
}
|
||||
}
|
||||
|
||||
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
||||
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell)
|
||||
{
|
||||
return mBounds[cell];
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/inputmanager.hpp" // FIXME
|
||||
#include "../mwbase/windowmanager.hpp" // FIXME
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
|
@ -217,7 +218,12 @@ OEngine::Render::Fader* RenderingManager::getFader()
|
|||
return mRendering.getFader();
|
||||
}
|
||||
|
||||
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store)
|
||||
MWRender::Camera* RenderingManager::getCamera() const
|
||||
{
|
||||
return mCamera;
|
||||
}
|
||||
|
||||
void RenderingManager::removeCell (MWWorld::CellStore *store)
|
||||
{
|
||||
mObjects->removeCell(store);
|
||||
mActors->removeCell(store);
|
||||
|
@ -234,7 +240,7 @@ void RenderingManager::toggleWater()
|
|||
mWater->toggle();
|
||||
}
|
||||
|
||||
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
|
||||
void RenderingManager::cellAdded (MWWorld::CellStore *store)
|
||||
{
|
||||
mObjects->buildStaticGeometry (*store);
|
||||
sh::Factory::getInstance().unloadUnreferencedMaterials();
|
||||
|
@ -325,6 +331,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->getPlayerPtr();
|
||||
|
@ -363,8 +375,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);
|
||||
|
@ -410,7 +420,7 @@ void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt)
|
|||
mOcclusionQuery->setActive(false);
|
||||
}
|
||||
|
||||
void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store)
|
||||
void RenderingManager::waterAdded (MWWorld::CellStore *store)
|
||||
{
|
||||
if(store->mCell->mData.mFlags & ESM::Cell::HasWater)
|
||||
{
|
||||
|
@ -488,7 +498,7 @@ bool RenderingManager::toggleRenderMode(int mode)
|
|||
}
|
||||
}
|
||||
|
||||
void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell)
|
||||
void RenderingManager::configureFog(MWWorld::CellStore &mCell)
|
||||
{
|
||||
Ogre::ColourValue color;
|
||||
color.setAsABGR (mCell.mCell->mAmbi.mFog);
|
||||
|
@ -541,7 +551,7 @@ void RenderingManager::setAmbientMode()
|
|||
}
|
||||
}
|
||||
|
||||
void RenderingManager::configureAmbient(MWWorld::Ptr::CellStore &mCell)
|
||||
void RenderingManager::configureAmbient(MWWorld::CellStore &mCell)
|
||||
{
|
||||
if (mCell.mCell->mData.mFlags & ESM::Cell::Interior)
|
||||
mAmbientColor.setAsABGR (mCell.mCell->mAmbi.mAmbient);
|
||||
|
@ -638,7 +648,7 @@ void RenderingManager::setGlare(bool glare)
|
|||
mSkyManager->setGlare(glare);
|
||||
}
|
||||
|
||||
void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell)
|
||||
void RenderingManager::requestMap(MWWorld::CellStore* cell)
|
||||
{
|
||||
if (cell->mCell->isExterior())
|
||||
{
|
||||
|
@ -657,7 +667,7 @@ void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell)
|
|||
mLocalMap->requestMap(cell, mObjects->getDimensions(cell));
|
||||
}
|
||||
|
||||
void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell)
|
||||
void RenderingManager::preCellChange(MWWorld::CellStore* cell)
|
||||
{
|
||||
mLocalMap->saveFogOfWar(cell);
|
||||
}
|
||||
|
@ -949,6 +959,38 @@ Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr)
|
|||
return anim;
|
||||
}
|
||||
|
||||
void RenderingManager::screenshot(Image &image, int w, int h)
|
||||
{
|
||||
// Create a temporary render target. We do not use the RenderWindow since we want a specific size.
|
||||
// Also, the GUI should not be visible (and it is only rendered on the RenderWindow's primary viewport)
|
||||
const std::string tempName = "@temp";
|
||||
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(tempName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, w, h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
|
||||
|
||||
float oldAspect = mRendering.getCamera()->getAspectRatio();
|
||||
|
||||
mRendering.getCamera()->setAspectRatio(w / static_cast<float>(h));
|
||||
|
||||
Ogre::RenderTarget* rt = texture->getBuffer()->getRenderTarget();
|
||||
Ogre::Viewport* vp = rt->addViewport(mRendering.getCamera());
|
||||
vp->setBackgroundColour(mRendering.getViewport()->getBackgroundColour());
|
||||
vp->setOverlaysEnabled(false);
|
||||
vp->setVisibilityMask(mRendering.getViewport()->getVisibilityMask());
|
||||
rt->update();
|
||||
|
||||
Ogre::PixelFormat pf = rt->suggestPixelFormat();
|
||||
|
||||
std::vector<Ogre::uchar> data;
|
||||
data.resize(w * h * Ogre::PixelUtil::getNumElemBytes(pf));
|
||||
|
||||
Ogre::PixelBox pb(w, h, 1, pf, &data[0]);
|
||||
rt->copyContentsToMemory(pb);
|
||||
|
||||
image.loadDynamicImage(&data[0], w, h, pf);
|
||||
|
||||
Ogre::TextureManager::getSingleton().remove(tempName);
|
||||
mRendering.getCamera()->setAspectRatio(oldAspect);
|
||||
}
|
||||
|
||||
void RenderingManager::playVideo(const std::string& name, bool allowSkipping)
|
||||
{
|
||||
|
|
|
@ -94,6 +94,8 @@ public:
|
|||
|
||||
SkyManager* getSkyManager();
|
||||
|
||||
MWRender::Camera* getCamera() const;
|
||||
|
||||
void toggleLight();
|
||||
bool toggleRenderMode(int mode);
|
||||
|
||||
|
@ -206,6 +208,7 @@ public:
|
|||
void playVideo(const std::string& name, bool allowSkipping);
|
||||
void stopVideo();
|
||||
void frameStarted(float dt, bool paused);
|
||||
void screenshot(Ogre::Image& image, int w, int h);
|
||||
|
||||
void spawnEffect (const std::string& model, const std::string& texture, const Ogre::Vector3& worldPosition, float scale=1.f);
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
if (cell->mCell->hasWater())
|
||||
runtime.push (cell->mWaterLevel);
|
||||
else
|
||||
|
@ -146,7 +146,7 @@ namespace MWScript
|
|||
{
|
||||
Interpreter::Type_Float level = runtime[0].mFloat;
|
||||
|
||||
MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
|
||||
if (cell->mCell->isExterior())
|
||||
throw std::runtime_error("Can't set water level in exterior cell");
|
||||
|
@ -164,7 +164,7 @@ namespace MWScript
|
|||
{
|
||||
Interpreter::Type_Float level = runtime[0].mFloat;
|
||||
|
||||
MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
|
||||
if (cell->mCell->isExterior())
|
||||
throw std::runtime_error("Can't set water level in exterior cell");
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include <cassert>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/esm/globalscript.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -15,25 +18,16 @@ namespace MWScript
|
|||
GlobalScripts::GlobalScripts (const MWWorld::ESMStore& store)
|
||||
: mStore (store)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void GlobalScripts::reset()
|
||||
{
|
||||
mScripts.clear();
|
||||
addScript ("Main");
|
||||
|
||||
MWWorld::Store<ESM::StartScript>::iterator iter =
|
||||
mStore.get<ESM::StartScript>().begin();
|
||||
|
||||
for (; iter != mStore.get<ESM::StartScript>().end(); ++iter) {
|
||||
addScript (iter->mScript);
|
||||
}
|
||||
addStartup();
|
||||
}
|
||||
|
||||
void GlobalScripts::addScript (const std::string& name)
|
||||
{
|
||||
if (mScripts.find (name)==mScripts.end())
|
||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
||||
mScripts.find (Misc::StringUtils::lowerCase (name));
|
||||
|
||||
if (iter==mScripts.end())
|
||||
{
|
||||
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
|
||||
{
|
||||
Locals locals;
|
||||
|
@ -43,10 +37,14 @@ namespace MWScript
|
|||
mScripts.insert (std::make_pair (name, std::make_pair (true, locals)));
|
||||
}
|
||||
}
|
||||
else
|
||||
iter->second.first = true;
|
||||
}
|
||||
|
||||
void GlobalScripts::removeScript (const std::string& name)
|
||||
{
|
||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter = mScripts.find (name);
|
||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
||||
mScripts.find (Misc::StringUtils::lowerCase (name));
|
||||
|
||||
if (iter!=mScripts.end())
|
||||
iter->second.first = false;
|
||||
|
@ -55,7 +53,7 @@ namespace MWScript
|
|||
bool GlobalScripts::isRunning (const std::string& name) const
|
||||
{
|
||||
std::map<std::string, std::pair<bool, Locals> >::const_iterator iter =
|
||||
mScripts.find (name);
|
||||
mScripts.find (Misc::StringUtils::lowerCase (name));
|
||||
|
||||
if (iter==mScripts.end())
|
||||
return false;
|
||||
|
@ -76,4 +74,78 @@ namespace MWScript
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalScripts::clear()
|
||||
{
|
||||
mScripts.clear();
|
||||
}
|
||||
|
||||
void GlobalScripts::addStartup()
|
||||
{
|
||||
addScript ("main");
|
||||
|
||||
for (MWWorld::Store<ESM::StartScript>::iterator iter =
|
||||
mStore.get<ESM::StartScript>().begin();
|
||||
iter != mStore.get<ESM::StartScript>().end(); ++iter)
|
||||
{
|
||||
addScript (iter->mScript);
|
||||
}
|
||||
}
|
||||
|
||||
int GlobalScripts::countSavedGameRecords() const
|
||||
{
|
||||
return mScripts.size();
|
||||
}
|
||||
|
||||
void GlobalScripts::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
for (std::map<std::string, std::pair<bool, Locals> >::const_iterator iter (mScripts.begin());
|
||||
iter!=mScripts.end(); ++iter)
|
||||
{
|
||||
ESM::GlobalScript script;
|
||||
|
||||
script.mId = iter->first;
|
||||
|
||||
iter->second.second.write (script.mLocals, iter->first);
|
||||
|
||||
script.mRunning = iter->second.first ? 1 : 0;
|
||||
|
||||
writer.startRecord (ESM::REC_GSCR);
|
||||
script.save (writer);
|
||||
writer.endRecord (ESM::REC_GSCR);
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalScripts::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||
{
|
||||
if (type==ESM::REC_GSCR)
|
||||
{
|
||||
ESM::GlobalScript script;
|
||||
script.load (reader);
|
||||
|
||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
||||
mScripts.find (script.mId);
|
||||
|
||||
if (iter==mScripts.end())
|
||||
{
|
||||
if (const ESM::Script *scriptRecord = mStore.get<ESM::Script>().search (script.mId))
|
||||
{
|
||||
std::pair<bool, Locals> data (false, Locals());
|
||||
|
||||
data.second.configure (*scriptRecord);
|
||||
|
||||
iter = mScripts.insert (std::make_pair (script.mId, data)).first;
|
||||
}
|
||||
else // script does not exist anymore
|
||||
return true;
|
||||
}
|
||||
|
||||
iter->second.first = script.mRunning!=0;
|
||||
iter->second.second.read (script.mLocals, script.mId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,16 @@
|
|||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
#include "locals.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMWriter;
|
||||
class ESMReader;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
struct ESMStore;
|
||||
|
@ -22,8 +30,6 @@ namespace MWScript
|
|||
|
||||
GlobalScripts (const MWWorld::ESMStore& store);
|
||||
|
||||
void reset();
|
||||
|
||||
void addScript (const std::string& name);
|
||||
|
||||
void removeScript (const std::string& name);
|
||||
|
@ -32,6 +38,20 @@ namespace MWScript
|
|||
|
||||
void run();
|
||||
///< run all active global scripts
|
||||
|
||||
void clear();
|
||||
|
||||
void addStartup();
|
||||
///< Add startup script
|
||||
|
||||
int countSavedGameRecords() const;
|
||||
|
||||
void write (ESM::ESMWriter& writer) const;
|
||||
|
||||
bool readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
///< Records for variables that do not exist are dropped silently.
|
||||
///
|
||||
/// \return Known type?
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -126,61 +126,49 @@ namespace MWScript
|
|||
|
||||
int InterpreterContext::getGlobalShort (const std::string& name) const
|
||||
{
|
||||
return MWBase::Environment::get().getWorld()->getGlobalVariable (name).mShort;
|
||||
return MWBase::Environment::get().getWorld()->getGlobalInt (name);
|
||||
}
|
||||
|
||||
int InterpreterContext::getGlobalLong (const std::string& name) const
|
||||
{
|
||||
// a global long is internally a float.
|
||||
return MWBase::Environment::get().getWorld()->getGlobalVariable (name).mLong;
|
||||
return MWBase::Environment::get().getWorld()->getGlobalInt (name);
|
||||
}
|
||||
|
||||
float InterpreterContext::getGlobalFloat (const std::string& name) const
|
||||
{
|
||||
return MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat;
|
||||
return MWBase::Environment::get().getWorld()->getGlobalFloat (name);
|
||||
}
|
||||
|
||||
void InterpreterContext::setGlobalShort (const std::string& name, int value)
|
||||
{
|
||||
if (name=="gamehour")
|
||||
MWBase::Environment::get().getWorld()->setHour (value);
|
||||
else if (name=="day")
|
||||
MWBase::Environment::get().getWorld()->setDay (value);
|
||||
else if (name=="month")
|
||||
MWBase::Environment::get().getWorld()->setMonth (value);
|
||||
else
|
||||
MWBase::Environment::get().getWorld()->getGlobalVariable (name).mShort = value;
|
||||
MWBase::Environment::get().getWorld()->setGlobalInt (name, value);
|
||||
}
|
||||
|
||||
void InterpreterContext::setGlobalLong (const std::string& name, int value)
|
||||
{
|
||||
if (name=="gamehour")
|
||||
MWBase::Environment::get().getWorld()->setHour (value);
|
||||
else if (name=="day")
|
||||
MWBase::Environment::get().getWorld()->setDay (value);
|
||||
else if (name=="month")
|
||||
MWBase::Environment::get().getWorld()->setMonth (value);
|
||||
else
|
||||
MWBase::Environment::get().getWorld()->getGlobalVariable (name).mLong = value;
|
||||
MWBase::Environment::get().getWorld()->setGlobalInt (name, value);
|
||||
}
|
||||
|
||||
void InterpreterContext::setGlobalFloat (const std::string& name, float value)
|
||||
{
|
||||
if (name=="gamehour")
|
||||
MWBase::Environment::get().getWorld()->setHour (value);
|
||||
else if (name=="day")
|
||||
MWBase::Environment::get().getWorld()->setDay (value);
|
||||
else if (name=="month")
|
||||
MWBase::Environment::get().getWorld()->setMonth (value);
|
||||
else
|
||||
MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat = value;
|
||||
MWBase::Environment::get().getWorld()->setGlobalFloat (name, value);
|
||||
}
|
||||
|
||||
std::vector<std::string> InterpreterContext::getGlobals () const
|
||||
std::vector<std::string> InterpreterContext::getGlobals() const
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
return world->getGlobals();
|
||||
std::vector<std::string> ids;
|
||||
|
||||
const MWWorld::Store<ESM::Global>& globals =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Global>();
|
||||
|
||||
for (MWWorld::Store<ESM::Global>::iterator iter = globals.begin(); iter!=globals.end();
|
||||
++iter)
|
||||
{
|
||||
ids.push_back (iter->mId);
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
char InterpreterContext::getGlobalType (const std::string& name) const
|
||||
|
@ -321,8 +309,7 @@ namespace MWScript
|
|||
|
||||
std::string InterpreterContext::getCurrentCellName() const
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
return world->getCurrentCellName();
|
||||
return MWBase::Environment::get().getWorld()->getCellName();
|
||||
}
|
||||
|
||||
bool InterpreterContext::isScriptRunning (const std::string& name) const
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "locals.hpp"
|
||||
|
||||
#include <components/esm/loadscpt.hpp>
|
||||
#include <components/esm/variant.hpp>
|
||||
#include <components/esm/locals.hpp>
|
||||
|
||||
#include <components/compiler/locals.hpp>
|
||||
|
||||
|
@ -65,4 +67,68 @@ namespace MWScript
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Locals::write (ESM::Locals& locals, const std::string& script) const
|
||||
{
|
||||
const Compiler::Locals& declarations =
|
||||
MWBase::Environment::get().getScriptManager()->getLocals(script);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
char type = 0;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0: type = 's'; break;
|
||||
case 1: type = 'l'; break;
|
||||
case 2: type = 'f'; break;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& names = declarations.get (type);
|
||||
|
||||
for (int i2=0; i2<static_cast<int> (names.size()); ++i2)
|
||||
{
|
||||
ESM::Variant value;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0: value.setType (ESM::VT_Int); value.setInteger (mShorts.at (i2)); break;
|
||||
case 1: value.setType (ESM::VT_Int); value.setInteger (mLongs.at (i2)); break;
|
||||
case 2: value.setType (ESM::VT_Float); value.setFloat (mFloats.at (i2)); break;
|
||||
}
|
||||
|
||||
locals.mVariables.push_back (std::make_pair (names[i2], value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Locals::read (const ESM::Locals& locals, const std::string& script)
|
||||
{
|
||||
const Compiler::Locals& declarations =
|
||||
MWBase::Environment::get().getScriptManager()->getLocals(script);
|
||||
|
||||
for (std::vector<std::pair<std::string, ESM::Variant> >::const_iterator iter
|
||||
= locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter)
|
||||
{
|
||||
char type = declarations.getType (iter->first);
|
||||
char index = declarations.getIndex (iter->first);
|
||||
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 's': mShorts.at (index) = iter->second.getInteger(); break;
|
||||
case 'l': mLongs.at (index) = iter->second.getInteger(); break;
|
||||
case 'f': mFloats.at (index) = iter->second.getFloat(); break;
|
||||
|
||||
// silently ignore locals that don't exist anymore
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// ignore type changes
|
||||
/// \todo write to log
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace ESM
|
||||
{
|
||||
struct Script;
|
||||
struct Locals;
|
||||
}
|
||||
|
||||
namespace MWScript
|
||||
|
@ -23,6 +24,9 @@ namespace MWScript
|
|||
bool setVarByInt(const std::string& script, const std::string& var, int val);
|
||||
int getIntVar (const std::string& script, const std::string& var); ///< if var does not exist, returns 0
|
||||
|
||||
void write (ESM::Locals& locals, const std::string& script) const;
|
||||
|
||||
void read (const ESM::Locals& locals, const std::string& script);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -682,23 +682,43 @@ namespace MWScript
|
|||
|
||||
void printGlobalVars(Interpreter::Runtime &runtime)
|
||||
{
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::stringstream str;
|
||||
str<< "Global variables:";
|
||||
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
std::vector<std::string> names = world->getGlobals();
|
||||
std::vector<std::string> names = context.getGlobals();
|
||||
for(size_t i = 0;i < names.size();++i)
|
||||
{
|
||||
char type = world->getGlobalVariableType(names[i]);
|
||||
if(type == 's')
|
||||
str<<std::endl<< " "<<names[i]<<" = "<<world->getGlobalVariable(names[i]).mShort<<" (short)";
|
||||
else if(type == 'l')
|
||||
str<<std::endl<< " "<<names[i]<<" = "<<world->getGlobalVariable(names[i]).mLong<<" (long)";
|
||||
else if(type == 'f')
|
||||
str<<std::endl<< " "<<names[i]<<" = "<<world->getGlobalVariable(names[i]).mFloat<<" (float)";
|
||||
char type = world->getGlobalVariableType (names[i]);
|
||||
str << std::endl << " " << names[i] << " = ";
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 's':
|
||||
|
||||
str << context.getGlobalShort (names[i]) << " (short)";
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
str << context.getGlobalLong (names[i]) << " (long)";
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
|
||||
str << context.getGlobalFloat (names[i]) << " (float)";
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
str << "<unknown type>";
|
||||
}
|
||||
}
|
||||
|
||||
runtime.getContext().report(str.str());
|
||||
context.report (str.str());
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -220,9 +220,4 @@ namespace MWScript
|
|||
|
||||
throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId);
|
||||
}
|
||||
|
||||
void ScriptManager::resetGlobalScripts()
|
||||
{
|
||||
mGlobalScripts.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,8 +61,6 @@ namespace MWScript
|
|||
///< Compile script with the given namen
|
||||
/// \return Success?
|
||||
|
||||
virtual void resetGlobalScripts();
|
||||
|
||||
virtual std::pair<int, int> compileAll();
|
||||
///< Compile all scripts
|
||||
/// \return count, success
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
|
@ -398,7 +399,7 @@ namespace MWSound
|
|||
}
|
||||
}
|
||||
|
||||
void SoundManager::stopSound(const MWWorld::Ptr::CellStore *cell)
|
||||
void SoundManager::stopSound(const MWWorld::CellStore *cell)
|
||||
{
|
||||
SoundMap::iterator snditer = mActiveSounds.begin();
|
||||
while(snditer != mActiveSounds.end())
|
||||
|
@ -606,9 +607,14 @@ namespace MWSound
|
|||
{
|
||||
if(!mOutput->isInitialized())
|
||||
return;
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()!=
|
||||
MWBase::StateManager::State_NoGame)
|
||||
{
|
||||
updateSounds(duration);
|
||||
updateRegionSound(duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SoundManager::processChangedSettings(const Settings::CategorySettingVector& settings)
|
||||
|
@ -713,4 +719,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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,6 +150,8 @@ namespace MWSound
|
|||
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up);
|
||||
|
||||
virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated);
|
||||
|
||||
virtual void clear();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
153
apps/openmw/mwstate/character.cpp
Normal file
153
apps/openmw/mwstate/character.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
|
||||
#include "character.hpp"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/defs.hpp>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
bool MWState::operator< (const Slot& left, const Slot& right)
|
||||
{
|
||||
return left.mTimeStamp<right.mTimeStamp;
|
||||
}
|
||||
|
||||
|
||||
void MWState::Character::addSlot (const boost::filesystem::path& path, const std::string& game)
|
||||
{
|
||||
Slot slot;
|
||||
slot.mPath = path;
|
||||
slot.mTimeStamp = boost::filesystem::last_write_time (path);
|
||||
|
||||
ESM::ESMReader reader;
|
||||
reader.open (slot.mPath.string());
|
||||
|
||||
if (reader.getFormat()>ESM::Header::CurrentFormat)
|
||||
return; // format is too new -> ignore
|
||||
|
||||
if (reader.getRecName()!=ESM::REC_SAVE)
|
||||
return; // invalid save file -> ignore
|
||||
|
||||
reader.getRecHeader();
|
||||
|
||||
slot.mProfile.load (reader);
|
||||
|
||||
if (Misc::StringUtils::lowerCase (slot.mProfile.mContentFiles.at (0))!=
|
||||
Misc::StringUtils::lowerCase (game))
|
||||
return; // this file is for a different game -> ignore
|
||||
|
||||
mSlots.push_back (slot);
|
||||
}
|
||||
|
||||
void MWState::Character::addSlot (const ESM::SavedGame& profile)
|
||||
{
|
||||
Slot slot;
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << mNext++;
|
||||
|
||||
slot.mPath = mPath / stream.str();
|
||||
slot.mProfile = profile;
|
||||
slot.mTimeStamp = std::time (0);
|
||||
|
||||
mSlots.push_back (slot);
|
||||
}
|
||||
|
||||
MWState::Character::Character (const boost::filesystem::path& saves, const std::string& game)
|
||||
: mPath (saves), mNext (0)
|
||||
{
|
||||
if (!boost::filesystem::is_directory (mPath))
|
||||
{
|
||||
boost::filesystem::create_directories (mPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (boost::filesystem::directory_iterator iter (mPath);
|
||||
iter!=boost::filesystem::directory_iterator(); ++iter)
|
||||
{
|
||||
boost::filesystem::path slotPath = *iter;
|
||||
|
||||
try
|
||||
{
|
||||
addSlot (slotPath, game);
|
||||
}
|
||||
catch (...) {} // ignoring bad saved game files for now
|
||||
|
||||
std::istringstream stream (slotPath.filename().string());
|
||||
|
||||
int index = 0;
|
||||
|
||||
if ((stream >> index) && index>=mNext)
|
||||
mNext = index+1;
|
||||
}
|
||||
|
||||
std::sort (mSlots.begin(), mSlots.end());
|
||||
}
|
||||
}
|
||||
|
||||
const MWState::Slot *MWState::Character::createSlot (const ESM::SavedGame& profile)
|
||||
{
|
||||
addSlot (profile);
|
||||
|
||||
return &mSlots.back();
|
||||
}
|
||||
|
||||
const MWState::Slot *MWState::Character::updateSlot (const Slot *slot, const ESM::SavedGame& profile)
|
||||
{
|
||||
int index = slot - &mSlots[0];
|
||||
|
||||
if (index<0 || index>=static_cast<int> (mSlots.size()))
|
||||
{
|
||||
// sanity check; not entirely reliable
|
||||
throw std::logic_error ("slot not found");
|
||||
}
|
||||
|
||||
Slot newSlot = *slot;
|
||||
newSlot.mProfile = profile;
|
||||
newSlot.mTimeStamp = std::time (0);
|
||||
|
||||
mSlots.erase (mSlots.begin()+index);
|
||||
|
||||
mSlots.push_back (newSlot);
|
||||
|
||||
return &mSlots.back();
|
||||
}
|
||||
|
||||
MWState::Character::SlotIterator MWState::Character::begin() const
|
||||
{
|
||||
return mSlots.rbegin();
|
||||
}
|
||||
|
||||
MWState::Character::SlotIterator MWState::Character::end() const
|
||||
{
|
||||
return mSlots.rend();
|
||||
}
|
||||
|
||||
ESM::SavedGame MWState::Character::getSignature() const
|
||||
{
|
||||
if (mSlots.empty())
|
||||
throw std::logic_error ("character signature not available");
|
||||
|
||||
std::vector<Slot>::const_iterator iter (mSlots.begin());
|
||||
|
||||
Slot slot = *iter;
|
||||
|
||||
for (++iter; iter!=mSlots.end(); ++iter)
|
||||
if (iter->mProfile.mPlayerLevel>slot.mProfile.mPlayerLevel)
|
||||
slot = *iter;
|
||||
else if (iter->mProfile.mPlayerLevel==slot.mProfile.mPlayerLevel &&
|
||||
iter->mTimeStamp>slot.mTimeStamp)
|
||||
slot = *iter;
|
||||
|
||||
return slot.mProfile;
|
||||
}
|
63
apps/openmw/mwstate/character.hpp
Normal file
63
apps/openmw/mwstate/character.hpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef GAME_STATE_CHARACTER_H
|
||||
#define GAME_STATE_CHARACTER_H
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <components/esm/savedgame.hpp>
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
struct Slot
|
||||
{
|
||||
boost::filesystem::path mPath;
|
||||
ESM::SavedGame mProfile;
|
||||
std::time_t mTimeStamp;
|
||||
};
|
||||
|
||||
bool operator< (const Slot& left, const Slot& right);
|
||||
|
||||
class Character
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<Slot>::const_reverse_iterator SlotIterator;
|
||||
|
||||
private:
|
||||
|
||||
boost::filesystem::path mPath;
|
||||
std::vector<Slot> mSlots;
|
||||
int mNext;
|
||||
|
||||
void addSlot (const boost::filesystem::path& path, const std::string& game);
|
||||
|
||||
void addSlot (const ESM::SavedGame& profile);
|
||||
|
||||
public:
|
||||
|
||||
Character (const boost::filesystem::path& saves, const std::string& game);
|
||||
|
||||
const Slot *createSlot (const ESM::SavedGame& profile);
|
||||
///< Create new slot.
|
||||
///
|
||||
/// \attention The ownership of the slot is not transferred.
|
||||
|
||||
const Slot *updateSlot (const Slot *slot, const ESM::SavedGame& profile);
|
||||
/// \note Slot must belong to this character.
|
||||
///
|
||||
/// \attention The \a slot pointer will be invalidated by this call.
|
||||
|
||||
SlotIterator begin() const;
|
||||
///< First slot is the most recent. Other slots follow in descending order of save date.
|
||||
///
|
||||
/// Any call to createSlot and updateSlot can invalidate the returned iterator.
|
||||
|
||||
SlotIterator end() const;
|
||||
|
||||
ESM::SavedGame getSignature() const;
|
||||
///< Return signature information for this character.
|
||||
///
|
||||
/// \attention This function must not be called if there are no slots.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
85
apps/openmw/mwstate/charactermanager.cpp
Normal file
85
apps/openmw/mwstate/charactermanager.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
|
||||
#include "charactermanager.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
MWState::CharacterManager::CharacterManager (const boost::filesystem::path& saves,
|
||||
const std::string& game)
|
||||
: mPath (saves), mNext (0), mCurrent (0), mGame (game)
|
||||
{
|
||||
if (!boost::filesystem::is_directory (mPath))
|
||||
{
|
||||
boost::filesystem::create_directories (mPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (boost::filesystem::directory_iterator iter (mPath);
|
||||
iter!=boost::filesystem::directory_iterator(); ++iter)
|
||||
{
|
||||
boost::filesystem::path characterDir = *iter;
|
||||
|
||||
if (boost::filesystem::is_directory (characterDir))
|
||||
{
|
||||
Character character (characterDir, mGame);
|
||||
|
||||
if (character.begin()!=character.end())
|
||||
mCharacters.push_back (character);
|
||||
}
|
||||
|
||||
std::istringstream stream (characterDir.filename().string());
|
||||
|
||||
int index = 0;
|
||||
|
||||
if ((stream >> index) && index>=mNext)
|
||||
mNext = index+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MWState::Character *MWState::CharacterManager::getCurrentCharacter (bool create)
|
||||
{
|
||||
if (!mCurrent && create)
|
||||
createCharacter();
|
||||
|
||||
return mCurrent;
|
||||
}
|
||||
|
||||
void MWState::CharacterManager::createCharacter()
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << mNext++;
|
||||
|
||||
boost::filesystem::path path = mPath / stream.str();
|
||||
|
||||
mCharacters.push_back (Character (path, mGame));
|
||||
|
||||
mCurrent = &mCharacters.back();
|
||||
}
|
||||
|
||||
void MWState::CharacterManager::setCurrentCharacter (const Character *character)
|
||||
{
|
||||
int index = character - &mCharacters[0];
|
||||
|
||||
if (index<0 || index>=static_cast<int> (mCharacters.size()))
|
||||
throw std::logic_error ("invalid character");
|
||||
|
||||
mCurrent = &mCharacters[index];
|
||||
}
|
||||
|
||||
void MWState::CharacterManager::clearCurrentCharacter()
|
||||
{
|
||||
mCurrent = 0;
|
||||
}
|
||||
|
||||
std::vector<MWState::Character>::const_iterator MWState::CharacterManager::begin() const
|
||||
{
|
||||
return mCharacters.begin();
|
||||
}
|
||||
|
||||
std::vector<MWState::Character>::const_iterator MWState::CharacterManager::end() const
|
||||
{
|
||||
return mCharacters.end();
|
||||
}
|
46
apps/openmw/mwstate/charactermanager.hpp
Normal file
46
apps/openmw/mwstate/charactermanager.hpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef GAME_STATE_CHARACTERMANAGER_H
|
||||
#define GAME_STATE_CHARACTERMANAGER_H
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include "character.hpp"
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
class CharacterManager
|
||||
{
|
||||
boost::filesystem::path mPath;
|
||||
int mNext;
|
||||
std::vector<Character> mCharacters;
|
||||
Character *mCurrent;
|
||||
std::string mGame;
|
||||
|
||||
private:
|
||||
|
||||
CharacterManager (const CharacterManager&);
|
||||
///< Not implemented
|
||||
|
||||
CharacterManager& operator= (const CharacterManager&);
|
||||
///< Not implemented
|
||||
|
||||
public:
|
||||
|
||||
CharacterManager (const boost::filesystem::path& saves, const std::string& game);
|
||||
|
||||
Character *getCurrentCharacter (bool create = true);
|
||||
///< \param create Create a new character, if there is no current character.
|
||||
|
||||
void createCharacter();
|
||||
///< Create new character within saved game management
|
||||
|
||||
void setCurrentCharacter (const Character *character);
|
||||
|
||||
void clearCurrentCharacter();
|
||||
|
||||
std::vector<Character>::const_iterator begin() const;
|
||||
|
||||
std::vector<Character>::const_iterator end() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
343
apps/openmw/mwstate/statemanagerimp.cpp
Normal file
343
apps/openmw/mwstate/statemanagerimp.cpp
Normal file
|
@ -0,0 +1,343 @@
|
|||
|
||||
#include "statemanagerimp.hpp"
|
||||
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/cellid.hpp>
|
||||
#include <components/esm/loadcell.hpp>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include <OgreImage.h>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/scriptmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include "../mwscript/globalscripts.hpp"
|
||||
|
||||
void MWState::StateManager::cleanup (bool force)
|
||||
{
|
||||
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();
|
||||
MWBase::Environment::get().getWorld()->clear();
|
||||
MWBase::Environment::get().getWindowManager()->clear();
|
||||
|
||||
mState = State_NoGame;
|
||||
mCharacterManager.clearCurrentCharacter();
|
||||
mTimePlayed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<int, int> MWState::StateManager::buildContentFileIndexMap (const ESM::ESMReader& reader)
|
||||
const
|
||||
{
|
||||
const std::vector<std::string>& current =
|
||||
MWBase::Environment::get().getWorld()->getContentFiles();
|
||||
|
||||
const std::vector<ESM::Header::MasterData>& prev = reader.getGameFiles();
|
||||
|
||||
std::map<int, int> map;
|
||||
|
||||
for (int iPrev = 0; iPrev<static_cast<int> (prev.size()); ++iPrev)
|
||||
{
|
||||
std::string id = Misc::StringUtils::lowerCase (prev[iPrev].name);
|
||||
|
||||
for (int iCurrent = 0; iCurrent<static_cast<int> (current.size()); ++iCurrent)
|
||||
if (id==Misc::StringUtils::lowerCase (current[iCurrent]))
|
||||
{
|
||||
map.insert (std::make_pair (iPrev, iCurrent));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::string& game)
|
||||
: mQuitRequest (false), mAskLoadRecent(false), mState (State_NoGame), mCharacterManager (saves, game), mTimePlayed (0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MWState::StateManager::requestQuit()
|
||||
{
|
||||
mQuitRequest = true;
|
||||
}
|
||||
|
||||
bool MWState::StateManager::hasQuitRequest() const
|
||||
{
|
||||
return mQuitRequest;
|
||||
}
|
||||
|
||||
void MWState::StateManager::askLoadRecent()
|
||||
{
|
||||
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_MainMenu)
|
||||
return;
|
||||
|
||||
if( !mAskLoadRecent )
|
||||
{
|
||||
if(getCurrentCharacter()->begin() == getCurrentCharacter()->end() )//no saves
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
MWState::Slot lastSave = *getCurrentCharacter()->begin();
|
||||
std::vector<std::string> buttons;
|
||||
buttons.push_back("#{sYes}");
|
||||
buttons.push_back("#{sNo}");
|
||||
std::string tag("%s");
|
||||
std::string message = MWBase::Environment::get().getWindowManager()->getGameSettingString("sLoadLastSaveMsg", tag);
|
||||
size_t pos = message.find(tag);
|
||||
message.replace(pos, tag.length(), lastSave.mProfile.mDescription);
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(message, buttons);
|
||||
mAskLoadRecent = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int iButton = MWBase::Environment::get().getWindowManager()->readPressedButton();
|
||||
if(iButton==0)
|
||||
{
|
||||
mAskLoadRecent = false;
|
||||
//Load last saved game for current character
|
||||
MWState::Character *curCharacter = getCurrentCharacter();
|
||||
MWState::Slot lastSave = *curCharacter->begin();
|
||||
loadGame(curCharacter, &lastSave);
|
||||
}
|
||||
else if(iButton==1)
|
||||
{
|
||||
mAskLoadRecent = false;
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MWState::StateManager::State MWState::StateManager::getState() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void MWState::StateManager::newGame (bool bypass)
|
||||
{
|
||||
cleanup();
|
||||
|
||||
if (!bypass)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->startNewGame();
|
||||
MWBase::Environment::get().getWindowManager()->setNewGame (true);
|
||||
}
|
||||
else
|
||||
MWBase::Environment::get().getWorld()->setGlobalInt ("chargenstate", -1);
|
||||
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup();
|
||||
|
||||
mState = State_Running;
|
||||
}
|
||||
|
||||
void MWState::StateManager::endGame()
|
||||
{
|
||||
mState = State_Ended;
|
||||
MWBase::Environment::get().getWorld()->useDeathCamera();
|
||||
}
|
||||
|
||||
void MWState::StateManager::saveGame (const std::string& description, const Slot *slot)
|
||||
{
|
||||
ESM::SavedGame profile;
|
||||
|
||||
MWBase::World& world = *MWBase::Environment::get().getWorld();
|
||||
|
||||
MWWorld::Ptr player = world.getPlayer().getPlayer();
|
||||
|
||||
profile.mContentFiles = world.getContentFiles();
|
||||
|
||||
profile.mPlayerName = player.getClass().getName (player);
|
||||
profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel();
|
||||
profile.mPlayerClass = player.get<ESM::NPC>()->mBase->mClass;
|
||||
|
||||
profile.mPlayerCell = world.getCellName();
|
||||
|
||||
profile.mInGameTime.mGameHour = world.getTimeStamp().getHour();
|
||||
profile.mInGameTime.mDay = world.getDay();
|
||||
profile.mInGameTime.mMonth = world.getMonth();
|
||||
profile.mInGameTime.mYear = world.getYear();
|
||||
profile.mTimePlayed = mTimePlayed;
|
||||
profile.mDescription = description;
|
||||
|
||||
int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing
|
||||
Ogre::Image screenshot;
|
||||
world.screenshot(screenshot, screenshotW, screenshotH);
|
||||
Ogre::DataStreamPtr encoded = screenshot.encode("jpg");
|
||||
profile.mScreenshot.resize(encoded->size());
|
||||
encoded->read(&profile.mScreenshot[0], encoded->size());
|
||||
|
||||
if (!slot)
|
||||
slot = mCharacterManager.getCurrentCharacter()->createSlot (profile);
|
||||
else
|
||||
slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile);
|
||||
|
||||
std::ofstream stream (slot->mPath.string().c_str());
|
||||
|
||||
ESM::ESMWriter writer;
|
||||
|
||||
const std::vector<std::string>& current =
|
||||
MWBase::Environment::get().getWorld()->getContentFiles();
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (current.begin()); iter!=current.end();
|
||||
++iter)
|
||||
writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0
|
||||
|
||||
writer.setFormat (ESM::Header::CurrentFormat);
|
||||
writer.setRecordCount (
|
||||
1 // saved game header
|
||||
+MWBase::Environment::get().getJournal()->countSavedGameRecords()
|
||||
+MWBase::Environment::get().getWorld()->countSavedGameRecords()
|
||||
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
|
||||
+ 1 // global map
|
||||
);
|
||||
|
||||
writer.save (stream);
|
||||
|
||||
writer.startRecord (ESM::REC_SAVE);
|
||||
slot->mProfile.save (writer);
|
||||
writer.endRecord (ESM::REC_SAVE);
|
||||
|
||||
MWBase::Environment::get().getJournal()->write (writer);
|
||||
MWBase::Environment::get().getWorld()->write (writer);
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer);
|
||||
MWBase::Environment::get().getWindowManager()->write(writer);
|
||||
|
||||
writer.close();
|
||||
|
||||
Settings::Manager::setString ("character", "Saves",
|
||||
slot->mPath.parent_path().filename().string());
|
||||
}
|
||||
|
||||
void MWState::StateManager::loadGame (const Character *character, const Slot *slot)
|
||||
{
|
||||
try
|
||||
{
|
||||
cleanup();
|
||||
|
||||
mTimePlayed = slot->mProfile.mTimePlayed;
|
||||
|
||||
ESM::ESMReader reader;
|
||||
reader.open (slot->mPath.string());
|
||||
|
||||
std::map<int, int> contentFileMap = buildContentFileIndexMap (reader);
|
||||
|
||||
while (reader.hasMoreRecs())
|
||||
{
|
||||
ESM::NAME n = reader.getRecName();
|
||||
reader.getRecHeader();
|
||||
|
||||
switch (n.val)
|
||||
{
|
||||
case ESM::REC_SAVE:
|
||||
|
||||
// don't need to read that here
|
||||
reader.skipRecord();
|
||||
break;
|
||||
|
||||
case ESM::REC_JOUR:
|
||||
case ESM::REC_QUES:
|
||||
|
||||
MWBase::Environment::get().getJournal()->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:
|
||||
|
||||
MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_GSCR:
|
||||
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val);
|
||||
break;
|
||||
|
||||
case ESM::REC_GMAP:
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->readRecord(reader, n.val);
|
||||
break;
|
||||
|
||||
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().getWindowManager()->setNewGame(false);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
MWState::Character *MWState::StateManager::getCurrentCharacter (bool create)
|
||||
{
|
||||
return mCharacterManager.getCurrentCharacter (create);
|
||||
}
|
||||
|
||||
MWState::StateManager::CharacterIterator MWState::StateManager::characterBegin()
|
||||
{
|
||||
return mCharacterManager.begin();
|
||||
}
|
||||
|
||||
MWState::StateManager::CharacterIterator MWState::StateManager::characterEnd()
|
||||
{
|
||||
return mCharacterManager.end();
|
||||
}
|
||||
|
||||
void MWState::StateManager::update (float duration)
|
||||
{
|
||||
mTimePlayed += duration;
|
||||
}
|
70
apps/openmw/mwstate/statemanagerimp.hpp
Normal file
70
apps/openmw/mwstate/statemanagerimp.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#ifndef GAME_STATE_STATEMANAGER_H
|
||||
#define GAME_STATE_STATEMANAGER_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include "charactermanager.hpp"
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
class StateManager : public MWBase::StateManager
|
||||
{
|
||||
bool mQuitRequest;
|
||||
bool mAskLoadRecent;
|
||||
State mState;
|
||||
CharacterManager mCharacterManager;
|
||||
double mTimePlayed;
|
||||
|
||||
private:
|
||||
|
||||
void cleanup (bool force = false);
|
||||
|
||||
std::map<int, int> buildContentFileIndexMap (const ESM::ESMReader& reader) const;
|
||||
|
||||
public:
|
||||
|
||||
StateManager (const boost::filesystem::path& saves, const std::string& game);
|
||||
|
||||
virtual void requestQuit();
|
||||
|
||||
virtual bool hasQuitRequest() const;
|
||||
|
||||
virtual void askLoadRecent();
|
||||
|
||||
virtual State getState() const;
|
||||
|
||||
virtual void newGame (bool bypass = false);
|
||||
///< Start a new game.
|
||||
///
|
||||
/// \param bypass Skip new game mechanics.
|
||||
|
||||
virtual void endGame();
|
||||
|
||||
virtual void saveGame (const std::string& description, const Slot *slot = 0);
|
||||
///< Write a saved game to \a slot or create a new slot if \a slot == 0.
|
||||
///
|
||||
/// \note Slot must belong to the current character.
|
||||
|
||||
virtual void loadGame (const Character *character, const Slot *slot);
|
||||
///< Load a saved game file from \a slot.
|
||||
///
|
||||
/// \note \a slot must belong to \a character.
|
||||
|
||||
virtual Character *getCurrentCharacter (bool create = true);
|
||||
///< \param create Create a new character, if there is no current character.
|
||||
|
||||
virtual CharacterIterator characterBegin();
|
||||
///< Any call to SaveGame and getCurrentCharacter can invalidate the returned
|
||||
/// iterator.
|
||||
|
||||
virtual CharacterIterator characterEnd();
|
||||
|
||||
virtual void update (float duration);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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"
|
||||
|
||||
|
@ -7,29 +12,29 @@
|
|||
#include "esmstore.hpp"
|
||||
#include "containerstore.hpp"
|
||||
|
||||
MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
|
||||
MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
|
||||
{
|
||||
if (cell->mData.mFlags & ESM::Cell::Interior)
|
||||
{
|
||||
std::string lowerName(Misc::StringUtils::lowerCase(cell->mName));
|
||||
std::map<std::string, Ptr::CellStore>::iterator result = mInteriors.find (lowerName);
|
||||
std::map<std::string, CellStore>::iterator result = mInteriors.find (lowerName);
|
||||
|
||||
if (result==mInteriors.end())
|
||||
{
|
||||
result = mInteriors.insert (std::make_pair (lowerName, Ptr::CellStore (cell))).first;
|
||||
result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first;
|
||||
}
|
||||
|
||||
return &result->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<std::pair<int, int>, Ptr::CellStore>::iterator result =
|
||||
std::map<std::pair<int, int>, CellStore>::iterator result =
|
||||
mExteriors.find (std::make_pair (cell->getGridX(), cell->getGridY()));
|
||||
|
||||
if (result==mExteriors.end())
|
||||
{
|
||||
result = mExteriors.insert (std::make_pair (
|
||||
std::make_pair (cell->getGridX(), cell->getGridY()), Ptr::CellStore (cell))).first;
|
||||
std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell))).first;
|
||||
|
||||
}
|
||||
|
||||
|
@ -41,11 +46,11 @@ void MWWorld::Cells::clear()
|
|||
{
|
||||
mInteriors.clear();
|
||||
mExteriors.clear();
|
||||
std::fill(mIdCache.begin(), mIdCache.end(), std::make_pair("", (MWWorld::Ptr::CellStore*)0));
|
||||
std::fill(mIdCache.begin(), mIdCache.end(), std::make_pair("", (MWWorld::CellStore*)0));
|
||||
mIdCacheIndex = 0;
|
||||
}
|
||||
|
||||
MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellStore& cellStore)
|
||||
MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore& cellStore)
|
||||
{
|
||||
Ptr ptr = getPtr (name, cellStore);
|
||||
|
||||
|
@ -60,15 +65,39 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS
|
|||
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, Ptr::CellStore *> ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable
|
||||
mIdCache (40, std::pair<std::string, CellStore *> ("", (CellStore*)0)), /// \todo make cache size configurable
|
||||
mIdCacheIndex (0)
|
||||
{}
|
||||
|
||||
MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y)
|
||||
MWWorld::CellStore *MWWorld::Cells::getExterior (int x, int y)
|
||||
{
|
||||
std::map<std::pair<int, int>, Ptr::CellStore>::iterator result =
|
||||
std::map<std::pair<int, int>, CellStore>::iterator result =
|
||||
mExteriors.find (std::make_pair (x, y));
|
||||
|
||||
if (result==mExteriors.end())
|
||||
|
@ -93,7 +122,7 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y)
|
|||
std::make_pair (x, y), CellStore (cell))).first;
|
||||
}
|
||||
|
||||
if (result->second.mState!=Ptr::CellStore::State_Loaded)
|
||||
if (result->second.mState!=CellStore::State_Loaded)
|
||||
{
|
||||
// Multiple plugin support for landscape data is much easier than for references. The last plugin wins.
|
||||
result->second.load (mStore, mReader);
|
||||
|
@ -102,19 +131,19 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y)
|
|||
return &result->second;
|
||||
}
|
||||
|
||||
MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name)
|
||||
MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name)
|
||||
{
|
||||
std::string lowerName = Misc::StringUtils::lowerCase(name);
|
||||
std::map<std::string, Ptr::CellStore>::iterator result = mInteriors.find (lowerName);
|
||||
std::map<std::string, CellStore>::iterator result = mInteriors.find (lowerName);
|
||||
|
||||
if (result==mInteriors.end())
|
||||
{
|
||||
const ESM::Cell *cell = mStore.get<ESM::Cell>().find(lowerName);
|
||||
|
||||
result = mInteriors.insert (std::make_pair (lowerName, Ptr::CellStore (cell))).first;
|
||||
result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first;
|
||||
}
|
||||
|
||||
if (result->second.mState!=Ptr::CellStore::State_Loaded)
|
||||
if (result->second.mState!=CellStore::State_Loaded)
|
||||
{
|
||||
result->second.load (mStore, mReader);
|
||||
}
|
||||
|
@ -122,13 +151,21 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name)
|
|||
return &result->second;
|
||||
}
|
||||
|
||||
MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& cell,
|
||||
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)
|
||||
{
|
||||
if (cell.mState==Ptr::CellStore::State_Unloaded)
|
||||
if (cell.mState==CellStore::State_Unloaded)
|
||||
cell.preload (mStore, mReader);
|
||||
|
||||
if (cell.mState==Ptr::CellStore::State_Preloaded)
|
||||
if (cell.mState==CellStore::State_Preloaded)
|
||||
{
|
||||
if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), name))
|
||||
{
|
||||
|
@ -207,7 +244,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce
|
|||
MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
|
||||
{
|
||||
// First check the cache
|
||||
for (std::vector<std::pair<std::string, Ptr::CellStore *> >::iterator iter (mIdCache.begin());
|
||||
for (std::vector<std::pair<std::string, CellStore *> >::iterator iter (mIdCache.begin());
|
||||
iter!=mIdCache.end(); ++iter)
|
||||
if (iter->first==name && iter->second)
|
||||
{
|
||||
|
@ -217,7 +254,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
|
|||
}
|
||||
|
||||
// Then check cells that are already listed
|
||||
for (std::map<std::pair<int, int>, Ptr::CellStore>::iterator iter = mExteriors.begin();
|
||||
for (std::map<std::pair<int, int>, CellStore>::iterator iter = mExteriors.begin();
|
||||
iter!=mExteriors.end(); ++iter)
|
||||
{
|
||||
Ptr ptr = getPtrAndCache (name, iter->second);
|
||||
|
@ -225,7 +262,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
for (std::map<std::string, Ptr::CellStore>::iterator iter = mInteriors.begin();
|
||||
for (std::map<std::string, CellStore>::iterator iter = mInteriors.begin();
|
||||
iter!=mInteriors.end(); ++iter)
|
||||
{
|
||||
Ptr ptr = getPtrAndCache (name, iter->second);
|
||||
|
@ -239,7 +276,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
|
|||
|
||||
for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter)
|
||||
{
|
||||
Ptr::CellStore *cellStore = getCellStore (&(*iter));
|
||||
CellStore *cellStore = getCellStore (&(*iter));
|
||||
|
||||
Ptr ptr = getPtrAndCache (name, *cellStore);
|
||||
|
||||
|
@ -249,7 +286,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
|
|||
|
||||
for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter)
|
||||
{
|
||||
Ptr::CellStore *cellStore = getCellStore (&(*iter));
|
||||
CellStore *cellStore = getCellStore (&(*iter));
|
||||
|
||||
Ptr ptr = getPtrAndCache (name, *cellStore);
|
||||
|
||||
|
@ -263,7 +300,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
|
|||
|
||||
void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorld::Ptr> &out)
|
||||
{
|
||||
for (std::map<std::pair<int, int>, Ptr::CellStore>::iterator iter = mExteriors.begin();
|
||||
for (std::map<std::pair<int, int>, CellStore>::iterator iter = mExteriors.begin();
|
||||
iter!=mExteriors.end(); ++iter)
|
||||
{
|
||||
Ptr ptr = getPtrAndCache (name, iter->second);
|
||||
|
@ -275,7 +312,7 @@ void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorl
|
|||
|
||||
void MWWorld::Cells::getInteriorPtrs(const std::string &name, std::vector<MWWorld::Ptr> &out)
|
||||
{
|
||||
for (std::map<std::string, Ptr::CellStore>::iterator iter = mInteriors.begin();
|
||||
for (std::map<std::string, CellStore>::iterator iter = mInteriors.begin();
|
||||
iter!=mInteriors.end(); ++iter)
|
||||
{
|
||||
Ptr ptr = getPtrAndCache (name, iter->second);
|
||||
|
@ -284,3 +321,67 @@ void MWWorld::Cells::getInteriorPtrs(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,
|
||||
const std::map<int, int>& contentFileMap)
|
||||
{
|
||||
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);
|
||||
|
||||
if (cellStore->mState!=CellStore::State_Loaded)
|
||||
cellStore->load (mStore, mReader);
|
||||
|
||||
cellStore->readReferences (reader, contentFileMap);
|
||||
|
||||
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
|
||||
|
@ -62,6 +69,12 @@ namespace MWWorld
|
|||
/// @note name must be lower case
|
||||
void getInteriorPtrs (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,
|
||||
const std::map<int, int>& contentFileMap);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,15 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <components/esm/cellstate.hpp>
|
||||
#include <components/esm/cellid.hpp>
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/objectstate.hpp>
|
||||
#include <components/esm/lightstate.hpp>
|
||||
#include <components/esm/containerstate.hpp>
|
||||
#include <components/esm/npcstate.hpp>
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -29,38 +38,99 @@ namespace
|
|||
|
||||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
template<typename RecordType, typename T>
|
||||
void writeReferenceCollection (ESM::ESMWriter& writer,
|
||||
const MWWorld::CellRefList<T>& collection)
|
||||
{
|
||||
if (!collection.mList.empty())
|
||||
{
|
||||
// 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.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId);
|
||||
state.save (writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RecordType, typename T>
|
||||
void readReferenceCollection (ESM::ESMReader& reader,
|
||||
MWWorld::CellRefList<T>& collection, const std::map<int, int>& contentFileMap)
|
||||
{
|
||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
RecordType state;
|
||||
state.load (reader);
|
||||
|
||||
std::map<int, int>::const_iterator iter =
|
||||
contentFileMap.find (state.mRef.mRefNum.mContentFile);
|
||||
|
||||
if (iter==contentFileMap.end())
|
||||
return; // content file has been removed -> skip
|
||||
|
||||
state.mRef.mRefNum.mContentFile = iter->second;
|
||||
|
||||
if (!MWWorld::LiveCellRef<T>::checkState (state))
|
||||
return; // not valid anymore with current content files -> skip
|
||||
|
||||
const T *record = esmStore.get<T>().search (state.mRef.mRefID);
|
||||
|
||||
if (!record)
|
||||
return;
|
||||
|
||||
for (typename MWWorld::CellRefList<T>::List::iterator iter (collection.mList.begin());
|
||||
iter!=collection.mList.end(); ++iter)
|
||||
if (iter->mRef.mRefNum==state.mRef.mRefNum)
|
||||
{
|
||||
// overwrite existing reference
|
||||
iter->load (state);
|
||||
return;
|
||||
}
|
||||
|
||||
// new reference
|
||||
MWWorld::LiveCellRef<T> ref (record);
|
||||
ref.load (state);
|
||||
collection.mList.push_back (ref);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
|
||||
template <typename X>
|
||||
void CellRefList<X>::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore)
|
||||
void CellRefList<X>::load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore)
|
||||
{
|
||||
// Get existing reference, in case we need to overwrite it.
|
||||
typename std::list<LiveRef>::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefnum);
|
||||
|
||||
// Skip this when reference was deleted.
|
||||
// TODO: Support respawning references, in this case, we need to track it somehow.
|
||||
if (ref.mDeleted) {
|
||||
if (iter != mList.end())
|
||||
mList.erase(iter);
|
||||
return;
|
||||
}
|
||||
|
||||
// for throwing exception on unhandled record type
|
||||
const MWWorld::Store<X> &store = esmStore.get<X>();
|
||||
const X *ptr = store.search(ref.mRefID);
|
||||
|
||||
/// \note no longer redundant - changed to Store<X>::search(), don't throw
|
||||
/// an exception on miss, try to continue (that's how MW does it, anyway)
|
||||
if (ptr == NULL) {
|
||||
std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl;
|
||||
} else {
|
||||
if (const X *ptr = store.search (ref.mRefID))
|
||||
{
|
||||
typename std::list<LiveRef>::iterator iter =
|
||||
std::find(mList.begin(), mList.end(), ref.mRefNum);
|
||||
|
||||
LiveRef liveCellRef (ref, ptr);
|
||||
|
||||
if (deleted)
|
||||
liveCellRef.mData.setCount (0);
|
||||
|
||||
if (iter != mList.end())
|
||||
*iter = LiveRef(ref, ptr);
|
||||
*iter = liveCellRef;
|
||||
else
|
||||
mList.push_back(LiveRef(ref, ptr));
|
||||
mList.push_back (liveCellRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr
|
||||
<< "Error: could not resolve cell reference " << ref.mRefID
|
||||
<< " (dropping reference)" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,16 +187,13 @@ namespace MWWorld
|
|||
ESM::CellRef ref;
|
||||
|
||||
// Get each reference in turn
|
||||
while (mCell->getNextRef (esm[index], ref))
|
||||
bool deleted = false;
|
||||
while (mCell->getNextRef (esm[index], ref, deleted))
|
||||
{
|
||||
std::string lowerCase = Misc::StringUtils::lowerCase (ref.mRefID);
|
||||
if (ref.mDeleted) {
|
||||
// Right now, don't do anything. Where is "listRefs" actually used, anyway?
|
||||
// Skipping for now...
|
||||
if (deleted)
|
||||
continue;
|
||||
}
|
||||
|
||||
mIds.push_back (lowerCase);
|
||||
mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,98 +215,30 @@ namespace MWWorld
|
|||
mCell->restore (esm[index], i);
|
||||
|
||||
ESM::CellRef ref;
|
||||
ref.mRefNum.mContentFile = -1;
|
||||
|
||||
// Get each reference in turn
|
||||
while(mCell->getNextRef(esm[index], ref))
|
||||
bool deleted = false;
|
||||
while(mCell->getNextRef(esm[index], ref, deleted))
|
||||
{
|
||||
// Don't load reference if it was moved to a different cell.
|
||||
std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID);
|
||||
ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum);
|
||||
ESM::MovedCellRefTracker::const_iterator iter =
|
||||
std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum);
|
||||
if (iter != mCell->mMovedRefs.end()) {
|
||||
continue;
|
||||
}
|
||||
int rec = store.find(ref.mRefID);
|
||||
|
||||
ref.mRefID = lowerCase;
|
||||
|
||||
/* We can optimize this further by storing the pointer to the
|
||||
record itself in store.all, so that we don't need to look it
|
||||
up again here. However, never optimize. There are infinite
|
||||
opportunities to do that later.
|
||||
*/
|
||||
switch(rec)
|
||||
{
|
||||
case ESM::REC_ACTI: mActivators.load(ref, store); break;
|
||||
case ESM::REC_ALCH: mPotions.load(ref, store); break;
|
||||
case ESM::REC_APPA: mAppas.load(ref, store); break;
|
||||
case ESM::REC_ARMO: mArmors.load(ref, store); break;
|
||||
case ESM::REC_BOOK: mBooks.load(ref, store); break;
|
||||
case ESM::REC_CLOT: mClothes.load(ref, store); break;
|
||||
case ESM::REC_CONT: mContainers.load(ref, store); break;
|
||||
case ESM::REC_CREA: mCreatures.load(ref, store); break;
|
||||
case ESM::REC_DOOR: mDoors.load(ref, store); break;
|
||||
case ESM::REC_INGR: mIngreds.load(ref, store); break;
|
||||
case ESM::REC_LEVC: mCreatureLists.load(ref, store); break;
|
||||
case ESM::REC_LEVI: mItemLists.load(ref, store); break;
|
||||
case ESM::REC_LIGH: mLights.load(ref, store); break;
|
||||
case ESM::REC_LOCK: mLockpicks.load(ref, store); break;
|
||||
case ESM::REC_MISC: mMiscItems.load(ref, store); break;
|
||||
case ESM::REC_NPC_: mNpcs.load(ref, store); break;
|
||||
case ESM::REC_PROB: mProbes.load(ref, store); break;
|
||||
case ESM::REC_REPA: mRepairs.load(ref, store); break;
|
||||
case ESM::REC_STAT: mStatics.load(ref, store); break;
|
||||
case ESM::REC_WEAP: mWeapons.load(ref, store); break;
|
||||
|
||||
case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break;
|
||||
default:
|
||||
std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
|
||||
}
|
||||
loadRef (ref, deleted, store);
|
||||
}
|
||||
}
|
||||
|
||||
// Load moved references, from separately tracked list.
|
||||
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
|
||||
{
|
||||
// Doesn't seem to work in one line... huh? Too sleepy to check...
|
||||
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
|
||||
//ESM::CellRef &ref = const_cast<ESM::CellRef&>(it->second);
|
||||
|
||||
int rec = store.find(ref.mRefID);
|
||||
Misc::StringUtils::toLower(ref.mRefID);
|
||||
|
||||
/* We can optimize this further by storing the pointer to the
|
||||
record itself in store.all, so that we don't need to look it
|
||||
up again here. However, never optimize. There are infinite
|
||||
opportunities to do that later.
|
||||
*/
|
||||
switch(rec)
|
||||
{
|
||||
case ESM::REC_ACTI: mActivators.load(ref, store); break;
|
||||
case ESM::REC_ALCH: mPotions.load(ref, store); break;
|
||||
case ESM::REC_APPA: mAppas.load(ref, store); break;
|
||||
case ESM::REC_ARMO: mArmors.load(ref, store); break;
|
||||
case ESM::REC_BOOK: mBooks.load(ref, store); break;
|
||||
case ESM::REC_CLOT: mClothes.load(ref, store); break;
|
||||
case ESM::REC_CONT: mContainers.load(ref, store); break;
|
||||
case ESM::REC_CREA: mCreatures.load(ref, store); break;
|
||||
case ESM::REC_DOOR: mDoors.load(ref, store); break;
|
||||
case ESM::REC_INGR: mIngreds.load(ref, store); break;
|
||||
case ESM::REC_LEVC: mCreatureLists.load(ref, store); break;
|
||||
case ESM::REC_LEVI: mItemLists.load(ref, store); break;
|
||||
case ESM::REC_LIGH: mLights.load(ref, store); break;
|
||||
case ESM::REC_LOCK: mLockpicks.load(ref, store); break;
|
||||
case ESM::REC_MISC: mMiscItems.load(ref, store); break;
|
||||
case ESM::REC_NPC_: mNpcs.load(ref, store); break;
|
||||
case ESM::REC_PROB: mProbes.load(ref, store); break;
|
||||
case ESM::REC_REPA: mRepairs.load(ref, store); break;
|
||||
case ESM::REC_STAT: mStatics.load(ref, store); break;
|
||||
case ESM::REC_WEAP: mWeapons.load(ref, store); break;
|
||||
|
||||
case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break;
|
||||
default:
|
||||
std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
|
||||
}
|
||||
|
||||
loadRef (ref, false, store);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,4 +267,198 @@ namespace MWWorld
|
|||
|
||||
return Ptr();
|
||||
}
|
||||
|
||||
void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store)
|
||||
{
|
||||
Misc::StringUtils::toLower (ref.mRefID);
|
||||
|
||||
switch (store.find (ref.mRefID))
|
||||
{
|
||||
case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break;
|
||||
case ESM::REC_ALCH: mPotions.load(ref, deleted, store); break;
|
||||
case ESM::REC_APPA: mAppas.load(ref, deleted, store); break;
|
||||
case ESM::REC_ARMO: mArmors.load(ref, deleted, store); break;
|
||||
case ESM::REC_BOOK: mBooks.load(ref, deleted, store); break;
|
||||
case ESM::REC_CLOT: mClothes.load(ref, deleted, store); break;
|
||||
case ESM::REC_CONT: mContainers.load(ref, deleted, store); break;
|
||||
case ESM::REC_CREA: mCreatures.load(ref, deleted, store); break;
|
||||
case ESM::REC_DOOR: mDoors.load(ref, deleted, store); break;
|
||||
case ESM::REC_INGR: mIngreds.load(ref, deleted, store); break;
|
||||
case ESM::REC_LEVC: mCreatureLists.load(ref, deleted, store); break;
|
||||
case ESM::REC_LEVI: mItemLists.load(ref, deleted, store); break;
|
||||
case ESM::REC_LIGH: mLights.load(ref, deleted, store); break;
|
||||
case ESM::REC_LOCK: mLockpicks.load(ref, deleted, store); break;
|
||||
case ESM::REC_MISC: mMiscItems.load(ref, deleted, store); break;
|
||||
case ESM::REC_NPC_: mNpcs.load(ref, deleted, store); break;
|
||||
case ESM::REC_PROB: mProbes.load(ref, deleted, store); break;
|
||||
case ESM::REC_REPA: mRepairs.load(ref, deleted, store); break;
|
||||
case ESM::REC_STAT: mStatics.load(ref, deleted, store); break;
|
||||
case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break;
|
||||
|
||||
case 0: std::cerr << "Cell reference " + ref.mRefID + " not found!\n"; break;
|
||||
|
||||
default:
|
||||
std::cerr
|
||||
<< "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::ContainerState> (writer, mContainers);
|
||||
writeReferenceCollection<ESM::CreatureState> (writer, mCreatures);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mDoors);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mIngreds);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mCreatureLists);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mItemLists);
|
||||
writeReferenceCollection<ESM::LightState> (writer, mLights);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mLockpicks);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mMiscItems);
|
||||
writeReferenceCollection<ESM::NpcState> (writer, mNpcs);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mProbes);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mRepairs);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mStatics);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mWeapons);
|
||||
}
|
||||
|
||||
void CellStore::readReferences (ESM::ESMReader& reader,
|
||||
const std::map<int, int>& contentFileMap)
|
||||
{
|
||||
while (reader.isNextSub ("OBJE"))
|
||||
{
|
||||
unsigned int id = 0;
|
||||
reader.getHT (id);
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case ESM::REC_ACTI:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mActivators, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_ALCH:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mPotions, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_APPA:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mAppas, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_ARMO:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mArmors, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_BOOK:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mBooks, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_CLOT:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mClothes, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_CONT:
|
||||
|
||||
readReferenceCollection<ESM::ContainerState> (reader, mContainers, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_CREA:
|
||||
|
||||
readReferenceCollection<ESM::CreatureState> (reader, mCreatures, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_DOOR:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mDoors, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_INGR:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mIngreds, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LEVC:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mCreatureLists, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LEVI:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mItemLists, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LIGH:
|
||||
|
||||
readReferenceCollection<ESM::LightState> (reader, mLights, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LOCK:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_MISC:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_NPC_:
|
||||
|
||||
readReferenceCollection<ESM::NpcState> (reader, mNpcs, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_PROB:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mProbes, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_REPA:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mRepairs, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_STAT:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mStatics, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_WEAP:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mWeapons, contentFileMap);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown type in cell reference section");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
#include "livecellref.hpp"
|
||||
#include "esmstore.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct CellState;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
|
||||
|
@ -25,7 +30,7 @@ namespace MWWorld
|
|||
// and the build will fail with an ugly three-way cyclic header dependence
|
||||
// so we need to pass the instantiation of the method to the lnker, when
|
||||
// all methods are known.
|
||||
void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore);
|
||||
void load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore);
|
||||
|
||||
LiveRef *find (const std::string& name)
|
||||
{
|
||||
|
@ -133,6 +138,14 @@ 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;
|
||||
|
||||
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap);
|
||||
|
||||
private:
|
||||
|
||||
template<class Functor, class List>
|
||||
|
@ -154,6 +167,10 @@ namespace MWWorld
|
|||
|
||||
void loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
|
||||
|
||||
void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store);
|
||||
///< Make case-adjustments to \a ref and insert it into the respective container.
|
||||
///
|
||||
/// Invalid \a ref objects are silently dropped.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -377,4 +377,8 @@ namespace MWWorld
|
|||
{
|
||||
throw std::runtime_error("class does not support gore");
|
||||
}
|
||||
|
||||
void Class::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const {}
|
||||
|
||||
void Class::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const {}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
|
||||
#include "ptr.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct ObjectState;
|
||||
}
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
class Vector3;
|
||||
|
@ -306,6 +311,14 @@ namespace MWWorld
|
|||
|
||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
|
||||
static const Class& get (const std::string& key);
|
||||
///< If there is no class for this \a key, an exception is thrown.
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <typeinfo>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/inventorystate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -57,6 +59,54 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState (CellRefList<T>& collection,
|
||||
const ESM::ObjectState& state)
|
||||
{
|
||||
if (!LiveCellRef<T>::checkState (state))
|
||||
return ContainerStoreIterator (this); // not valid anymore with current content files -> skip
|
||||
|
||||
const T *record = MWBase::Environment::get().getWorld()->getStore().
|
||||
get<T>().search (state.mRef.mRefID);
|
||||
|
||||
if (!record)
|
||||
return ContainerStoreIterator (this);
|
||||
|
||||
LiveCellRef<T> ref (record);
|
||||
ref.load (state);
|
||||
ref.mRef.mRefNum.mContentFile = -1;
|
||||
collection.mList.push_back (ref);
|
||||
|
||||
return ContainerStoreIterator (this, --collection.mList.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MWWorld::ContainerStore::storeState (const LiveCellRef<T>& ref, ESM::ObjectState& state) const
|
||||
{
|
||||
ref.save (state);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
|
||||
std::vector<std::pair<ESM::ObjectState, std::pair<unsigned int, int> > >& states, bool equipable) const
|
||||
{
|
||||
for (typename CellRefList<T>::List::const_iterator iter (collection.mList.begin());
|
||||
iter!=collection.mList.end(); ++iter)
|
||||
{
|
||||
ESM::ObjectState state;
|
||||
storeState (*iter, state);
|
||||
int slot = equipable ? getSlot (*iter) : -1;
|
||||
states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, slot)));
|
||||
}
|
||||
}
|
||||
|
||||
int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {}
|
||||
|
||||
const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
|
||||
|
||||
MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {}
|
||||
|
@ -493,6 +543,69 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id)
|
|||
return Ptr();
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const
|
||||
{
|
||||
state.mItems.clear();
|
||||
|
||||
storeStates (potions, state.mItems);
|
||||
storeStates (appas, state.mItems);
|
||||
storeStates (armors, state.mItems, true);
|
||||
storeStates (books, state.mItems);
|
||||
storeStates (clothes, state.mItems, true);
|
||||
storeStates (ingreds, state.mItems);
|
||||
storeStates (lockpicks, state.mItems, true);
|
||||
storeStates (miscItems, state.mItems);
|
||||
storeStates (probes, state.mItems, true);
|
||||
storeStates (repairs, state.mItems);
|
||||
storeStates (weapons, state.mItems, true);
|
||||
|
||||
state.mLights.clear();
|
||||
|
||||
for (MWWorld::CellRefList<ESM::Light>::List::const_iterator iter (lights.mList.begin());
|
||||
iter!=lights.mList.end(); ++iter)
|
||||
{
|
||||
ESM::LightState objectState;
|
||||
storeState (*iter, objectState);
|
||||
state.mLights.push_back (std::make_pair (objectState, getSlot (*iter)));
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::readState (const ESM::InventoryState& state)
|
||||
{
|
||||
clear();
|
||||
|
||||
for (std::vector<std::pair<ESM::ObjectState, std::pair<unsigned int, int> > >::const_iterator
|
||||
iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter)
|
||||
{
|
||||
int slot = iter->second.second;
|
||||
|
||||
switch (iter->second.first)
|
||||
{
|
||||
case ESM::REC_ALCH: getState (potions, iter->first); break;
|
||||
case ESM::REC_APPA: getState (appas, iter->first); break;
|
||||
case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break;
|
||||
case ESM::REC_BOOK: getState (books, iter->first); break;
|
||||
case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break;
|
||||
case ESM::REC_INGR: getState (ingreds, iter->first); break;
|
||||
case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break;
|
||||
case ESM::REC_MISC: getState (miscItems, iter->first); break;
|
||||
case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break;
|
||||
case ESM::REC_REPA: getState (repairs, iter->first); break;
|
||||
case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break;
|
||||
|
||||
default:
|
||||
|
||||
std::cerr << "invalid item type in inventory state" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<std::pair<ESM::LightState, int> >::const_iterator iter (state.mLights.begin());
|
||||
iter!=state.mLights.end(); ++iter)
|
||||
{
|
||||
getState (lights, iter->first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container)
|
||||
: mType (-1), mMask (0), mContainer (container)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace ESM
|
||||
{
|
||||
struct InventoryList;
|
||||
struct InventoryState;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -56,6 +57,24 @@ namespace MWWorld
|
|||
ContainerStoreIterator addImp (const Ptr& ptr, int count);
|
||||
void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true);
|
||||
|
||||
template<typename T>
|
||||
ContainerStoreIterator getState (CellRefList<T>& collection,
|
||||
const ESM::ObjectState& state);
|
||||
|
||||
template<typename T>
|
||||
void storeState (const LiveCellRef<T>& ref, ESM::ObjectState& state) const;
|
||||
|
||||
template<typename T>
|
||||
void storeStates (const CellRefList<T>& collection,
|
||||
std::vector<std::pair<ESM::ObjectState, std::pair<unsigned int, int> > >& states,
|
||||
bool equipable = false) const;
|
||||
|
||||
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const;
|
||||
///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot).
|
||||
|
||||
virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot);
|
||||
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
|
||||
|
||||
public:
|
||||
|
||||
ContainerStore();
|
||||
|
@ -113,7 +132,7 @@ namespace MWWorld
|
|||
void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, const MWWorld::ESMStore& store);
|
||||
///< Insert items into *this.
|
||||
|
||||
void clear();
|
||||
virtual void clear();
|
||||
///< Empty container.
|
||||
|
||||
float getWeight() const;
|
||||
|
@ -125,6 +144,10 @@ namespace MWWorld
|
|||
|
||||
Ptr search (const std::string& id);
|
||||
|
||||
void writeState (ESM::InventoryState& state) const;
|
||||
|
||||
void readState (const ESM::InventoryState& state);
|
||||
|
||||
friend class ContainerStoreIterator;
|
||||
};
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
|
|||
if (index == (int)~0) {
|
||||
// Tried to load a parent file that has not been loaded yet. This is bad,
|
||||
// the launcher should have taken care of this.
|
||||
std::string fstring = "File " + fname + " asks for parent file " + masters[j].name
|
||||
std::string fstring = "File " + esm.getName() + " asks for parent file " + masters[j].name
|
||||
+ ", but it has not been loaded yet. Please check your load order.";
|
||||
esm.fail(fstring);
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
|
|||
}
|
||||
// Insert the reference into the global lookup
|
||||
if (!id.empty() && isCacheableRecord(n.val)) {
|
||||
mIds[id] = n.val;
|
||||
mIds[Misc::StringUtils::lowerCase (id)] = n.val;
|
||||
}
|
||||
}
|
||||
listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000);
|
||||
|
@ -139,4 +139,68 @@ void ESMStore::setUp()
|
|||
mAttributes.setUp();
|
||||
}
|
||||
|
||||
int ESMStore::countSavedGameRecords() const
|
||||
{
|
||||
return
|
||||
mPotions.getDynamicSize()
|
||||
+mArmors.getDynamicSize()
|
||||
+mBooks.getDynamicSize()
|
||||
+mClasses.getDynamicSize()
|
||||
+mClothes.getDynamicSize()
|
||||
+mEnchants.getDynamicSize()
|
||||
+mNpcs.getDynamicSize()
|
||||
+mSpells.getDynamicSize()
|
||||
+mWeapons.getDynamicSize();
|
||||
}
|
||||
|
||||
void ESMStore::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
mPotions.write (writer);
|
||||
mArmors.write (writer);
|
||||
mBooks.write (writer);
|
||||
mClasses.write (writer);
|
||||
mClothes.write (writer);
|
||||
mEnchants.write (writer);
|
||||
mSpells.write (writer);
|
||||
mWeapons.write (writer);
|
||||
mNpcs.write (writer);
|
||||
}
|
||||
|
||||
bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
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_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:
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
|
|
@ -24,10 +24,8 @@ namespace MWWorld
|
|||
Store<ESM::BirthSign> mBirthSigns;
|
||||
Store<ESM::Class> mClasses;
|
||||
Store<ESM::Clothing> mClothes;
|
||||
Store<ESM::LoadCNTC> mContChange;
|
||||
Store<ESM::Container> mContainers;
|
||||
Store<ESM::Creature> mCreatures;
|
||||
Store<ESM::LoadCREC> mCreaChange;
|
||||
Store<ESM::Dialogue> mDialogs;
|
||||
Store<ESM::Door> mDoors;
|
||||
Store<ESM::Enchantment> mEnchants;
|
||||
|
@ -40,7 +38,6 @@ namespace MWWorld
|
|||
Store<ESM::Lockpick> mLockpicks;
|
||||
Store<ESM::Miscellaneous> mMiscItems;
|
||||
Store<ESM::NPC> mNpcs;
|
||||
Store<ESM::LoadNPCC> mNpcChange;
|
||||
Store<ESM::Probe> mProbes;
|
||||
Store<ESM::Race> mRaces;
|
||||
Store<ESM::Region> mRegions;
|
||||
|
@ -114,10 +111,8 @@ namespace MWWorld
|
|||
mStores[ESM::REC_CELL] = &mCells;
|
||||
mStores[ESM::REC_CLAS] = &mClasses;
|
||||
mStores[ESM::REC_CLOT] = &mClothes;
|
||||
mStores[ESM::REC_CNTC] = &mContChange;
|
||||
mStores[ESM::REC_CONT] = &mContainers;
|
||||
mStores[ESM::REC_CREA] = &mCreatures;
|
||||
mStores[ESM::REC_CREC] = &mCreaChange;
|
||||
mStores[ESM::REC_DIAL] = &mDialogs;
|
||||
mStores[ESM::REC_DOOR] = &mDoors;
|
||||
mStores[ESM::REC_ENCH] = &mEnchants;
|
||||
|
@ -133,7 +128,6 @@ namespace MWWorld
|
|||
mStores[ESM::REC_LTEX] = &mLandTextures;
|
||||
mStores[ESM::REC_MISC] = &mMiscItems;
|
||||
mStores[ESM::REC_NPC_] = &mNpcs;
|
||||
mStores[ESM::REC_NPCC] = &mNpcChange;
|
||||
mStores[ESM::REC_PGRD] = &mPathgrids;
|
||||
mStores[ESM::REC_PROB] = &mProbes;
|
||||
mStores[ESM::REC_RACE] = &mRaces;
|
||||
|
@ -215,6 +209,13 @@ namespace MWWorld
|
|||
// This method must be called once, after loading all master/plugin files. This can only be done
|
||||
// from the outside, so it must be public.
|
||||
void setUp();
|
||||
|
||||
int countSavedGameRecords() const;
|
||||
|
||||
void write (ESM::ESMWriter& writer) const;
|
||||
|
||||
bool readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
///< \return Known type?
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -287,11 +288,6 @@ namespace MWWorld
|
|||
return mClothes;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const Store<ESM::LoadCNTC> &ESMStore::get<ESM::LoadCNTC>() const {
|
||||
return mContChange;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const Store<ESM::Container> &ESMStore::get<ESM::Container>() const {
|
||||
return mContainers;
|
||||
|
@ -302,11 +298,6 @@ namespace MWWorld
|
|||
return mCreatures;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const Store<ESM::LoadCREC> &ESMStore::get<ESM::LoadCREC>() const {
|
||||
return mCreaChange;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const Store<ESM::Dialogue> &ESMStore::get<ESM::Dialogue>() const {
|
||||
return mDialogs;
|
||||
|
@ -367,11 +358,6 @@ namespace MWWorld
|
|||
return mNpcs;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const Store<ESM::LoadNPCC> &ESMStore::get<ESM::LoadNPCC>() const {
|
||||
return mNpcChange;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const Store<ESM::Probe> &ESMStore::get<ESM::Probe>() const {
|
||||
return mProbes;
|
||||
|
|
|
@ -3,21 +3,15 @@
|
|||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
#include "esmstore.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
std::vector<std::string> Globals::getGlobals () const
|
||||
{
|
||||
std::vector<std::string> retval;
|
||||
Collection::const_iterator it;
|
||||
for(it = mVariables.begin(); it != mVariables.end(); ++it){
|
||||
retval.push_back(it->first);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
Globals::Collection::const_iterator Globals::find (const std::string& name) const
|
||||
{
|
||||
Collection::const_iterator iter = mVariables.find (name);
|
||||
|
@ -38,112 +32,27 @@ namespace MWWorld
|
|||
return iter;
|
||||
}
|
||||
|
||||
Globals::Globals (const MWWorld::ESMStore& store)
|
||||
void Globals::fill (const MWWorld::ESMStore& store)
|
||||
{
|
||||
const MWWorld::Store<ESM::Global> &globals = store.get<ESM::Global>();
|
||||
MWWorld::Store<ESM::Global>::iterator iter = globals.begin();
|
||||
for (; iter != globals.end(); ++iter)
|
||||
mVariables.clear();
|
||||
|
||||
const MWWorld::Store<ESM::Global>& globals = store.get<ESM::Global>();
|
||||
|
||||
for (MWWorld::Store<ESM::Global>::iterator iter = globals.begin(); iter!=globals.end();
|
||||
++iter)
|
||||
{
|
||||
char type = ' ';
|
||||
Data value;
|
||||
|
||||
switch (iter->mValue.getType())
|
||||
{
|
||||
case ESM::VT_Short:
|
||||
|
||||
type = 's';
|
||||
value.mShort = iter->mValue.getInteger();
|
||||
break;
|
||||
|
||||
case ESM::VT_Long:
|
||||
|
||||
type = 'l';
|
||||
value.mLong = iter->mValue.getInteger();
|
||||
break;
|
||||
|
||||
case ESM::VT_Float:
|
||||
|
||||
type = 'f';
|
||||
value.mFloat = iter->mValue.getFloat();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unsupported global variable type");
|
||||
}
|
||||
|
||||
mVariables.insert (std::make_pair (iter->mId, std::make_pair (type, value)));
|
||||
mVariables.insert (std::make_pair (iter->mId, iter->mValue));
|
||||
}
|
||||
}
|
||||
|
||||
const Globals::Data& Globals::operator[] (const std::string& name) const
|
||||
const ESM::Variant& Globals::operator[] (const std::string& name) const
|
||||
{
|
||||
Collection::const_iterator iter = find (name);
|
||||
|
||||
return iter->second.second;
|
||||
return find (name)->second;
|
||||
}
|
||||
|
||||
Globals::Data& Globals::operator[] (const std::string& name)
|
||||
ESM::Variant& Globals::operator[] (const std::string& name)
|
||||
{
|
||||
Collection::iterator iter = find (name);
|
||||
|
||||
return iter->second.second;
|
||||
}
|
||||
|
||||
void Globals::setInt (const std::string& name, int value)
|
||||
{
|
||||
Collection::iterator iter = find (name);
|
||||
|
||||
switch (iter->second.first)
|
||||
{
|
||||
case 's': iter->second.second.mShort = value; break;
|
||||
case 'l': iter->second.second.mLong = value; break;
|
||||
case 'f': iter->second.second.mFloat = value; break;
|
||||
|
||||
default: throw std::runtime_error ("unsupported global variable type");
|
||||
}
|
||||
}
|
||||
|
||||
void Globals::setFloat (const std::string& name, float value)
|
||||
{
|
||||
Collection::iterator iter = find (name);
|
||||
|
||||
switch (iter->second.first)
|
||||
{
|
||||
case 's': iter->second.second.mShort = value; break;
|
||||
case 'l': iter->second.second.mLong = value; break;
|
||||
case 'f': iter->second.second.mFloat = value; break;
|
||||
|
||||
default: throw std::runtime_error ("unsupported global variable type");
|
||||
}
|
||||
}
|
||||
|
||||
int Globals::getInt (const std::string& name) const
|
||||
{
|
||||
Collection::const_iterator iter = find (name);
|
||||
|
||||
switch (iter->second.first)
|
||||
{
|
||||
case 's': return iter->second.second.mShort;
|
||||
case 'l': return iter->second.second.mLong;
|
||||
case 'f': return iter->second.second.mFloat;
|
||||
|
||||
default: throw std::runtime_error ("unsupported global variable type");
|
||||
}
|
||||
}
|
||||
|
||||
float Globals::getFloat (const std::string& name) const
|
||||
{
|
||||
Collection::const_iterator iter = find (name);
|
||||
|
||||
switch (iter->second.first)
|
||||
{
|
||||
case 's': return iter->second.second.mShort;
|
||||
case 'l': return iter->second.second.mLong;
|
||||
case 'f': return iter->second.second.mFloat;
|
||||
|
||||
default: throw std::runtime_error ("unsupported global variable type");
|
||||
}
|
||||
return find (name)->second;
|
||||
}
|
||||
|
||||
char Globals::getType (const std::string& name) const
|
||||
|
@ -153,7 +62,48 @@ namespace MWWorld
|
|||
if (iter==mVariables.end())
|
||||
return ' ';
|
||||
|
||||
return iter->second.first;
|
||||
switch (iter->second.getType())
|
||||
{
|
||||
case ESM::VT_Short: return 's';
|
||||
case ESM::VT_Long: return 'l';
|
||||
case ESM::VT_Float: return 'f';
|
||||
|
||||
default: return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
int Globals::countSavedGameRecords() const
|
||||
{
|
||||
return mVariables.size();
|
||||
}
|
||||
|
||||
void Globals::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
for (Collection::const_iterator iter (mVariables.begin()); iter!=mVariables.end(); ++iter)
|
||||
{
|
||||
writer.startRecord (ESM::REC_GLOB);
|
||||
writer.writeHNString ("NAME", iter->first);
|
||||
iter->second.write (writer, ESM::Variant::Format_Global);
|
||||
writer.endRecord (ESM::REC_GLOB);
|
||||
}
|
||||
}
|
||||
|
||||
bool Globals::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||
{
|
||||
if (type==ESM::REC_GLOB)
|
||||
{
|
||||
std::string id = reader.getHNString ("NAME");
|
||||
|
||||
Collection::iterator iter = mVariables.find (Misc::StringUtils::lowerCase (id));
|
||||
|
||||
if (iter!=mVariables.end())
|
||||
iter->second.read (reader, ESM::Variant::Format_Global);
|
||||
else
|
||||
reader.skipHRecord();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,16 @@
|
|||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
#include <components/esm/variant.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMWriter;
|
||||
class ESMReader;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
|
@ -13,19 +22,10 @@ namespace MWWorld
|
|||
|
||||
class Globals
|
||||
{
|
||||
public:
|
||||
|
||||
union Data
|
||||
{
|
||||
Interpreter::Type_Float mFloat;
|
||||
Interpreter::Type_Float mLong; // Why Morrowind, why? :(
|
||||
Interpreter::Type_Float mShort;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, std::pair<char, Data> > Collection;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<std::string, ESM::Variant> Collection;
|
||||
|
||||
Collection mVariables; // type, value
|
||||
|
||||
Collection::const_iterator find (const std::string& name) const;
|
||||
|
@ -34,28 +34,25 @@ namespace MWWorld
|
|||
|
||||
public:
|
||||
|
||||
Globals (const MWWorld::ESMStore& store);
|
||||
const ESM::Variant& operator[] (const std::string& name) const;
|
||||
|
||||
const Data& operator[] (const std::string& name) const;
|
||||
|
||||
Data& operator[] (const std::string& name);
|
||||
|
||||
void setInt (const std::string& name, int value);
|
||||
///< Set value independently from real type.
|
||||
|
||||
void setFloat (const std::string& name, float value);
|
||||
///< Set value independently from real type.
|
||||
|
||||
int getInt (const std::string& name) const;
|
||||
///< Get value independently from real type.
|
||||
|
||||
float getFloat (const std::string& name) const;
|
||||
///< Get value independently from real type.
|
||||
ESM::Variant& operator[] (const std::string& name);
|
||||
|
||||
char getType (const std::string& name) const;
|
||||
///< If there is no global variable with this name, ' ' is returned.
|
||||
|
||||
std::vector<std::string> getGlobals () const;
|
||||
void fill (const MWWorld::ESMStore& store);
|
||||
///< Replace variables with variables from \a store with default values.
|
||||
|
||||
int countSavedGameRecords() const;
|
||||
|
||||
void write (ESM::ESMWriter& writer) const;
|
||||
|
||||
bool readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
///< Records for variables that do not exist are dropped silently.
|
||||
///
|
||||
/// \return Known type?
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,21 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_)
|
|||
slots_.push_back (end());
|
||||
}
|
||||
|
||||
int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const
|
||||
{
|
||||
for (int i = 0; i<static_cast<int> (mSlots.size()); ++i)
|
||||
if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot)
|
||||
{
|
||||
if (iter!=end() && slot>=0 && slot<Slots)
|
||||
mSlots[slot] = iter;
|
||||
}
|
||||
|
||||
MWWorld::InventoryStore::InventoryStore()
|
||||
: mSelectedEnchantItem(end())
|
||||
, mUpdatesEnabled (true)
|
||||
|
@ -637,3 +652,10 @@ void MWWorld::InventoryStore::purgeEffect(short effectId)
|
|||
{
|
||||
mMagicEffects.add(MWMechanics::EffectKey(effectId), -mMagicEffects.get(MWMechanics::EffectKey(effectId)).mMagnitude);
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::clear()
|
||||
{
|
||||
mSlots.clear();
|
||||
initSlots (mSlots);
|
||||
ContainerStore::clear();
|
||||
}
|
||||
|
|
|
@ -105,6 +105,12 @@ namespace MWWorld
|
|||
|
||||
void fireEquipmentChangedEvent();
|
||||
|
||||
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const;
|
||||
///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot).
|
||||
|
||||
virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot);
|
||||
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
|
||||
|
||||
public:
|
||||
|
||||
InventoryStore();
|
||||
|
@ -187,6 +193,9 @@ namespace MWWorld
|
|||
|
||||
void purgeEffect (short effectId);
|
||||
///< Remove a magic effect
|
||||
|
||||
virtual void clear();
|
||||
///< Empty container.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
29
apps/openmw/mwworld/livecellref.cpp
Normal file
29
apps/openmw/mwworld/livecellref.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
|
||||
#include "livecellref.hpp"
|
||||
|
||||
#include <components/esm/objectstate.hpp>
|
||||
|
||||
#include "ptr.hpp"
|
||||
#include "class.hpp"
|
||||
|
||||
void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state)
|
||||
{
|
||||
mRef = state.mRef;
|
||||
mData = RefData (state);
|
||||
Ptr ptr (this);
|
||||
mClass->readAdditionalState (ptr, state);
|
||||
}
|
||||
|
||||
void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const
|
||||
{
|
||||
state.mRef = mRef;
|
||||
mData.write (state);
|
||||
/// \todo get rid of this cast once const-correct Ptr are available
|
||||
Ptr ptr (const_cast<LiveCellRefBase *> (this));
|
||||
mClass->writeAdditionalState (ptr, 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,39 @@ namespace MWWorld
|
|||
LiveCellRefBase(std::string type, const ESM::CellRef &cref=ESM::CellRef());
|
||||
/* Need this for the class to be recognized as polymorphic */
|
||||
virtual ~LiveCellRefBase() { }
|
||||
|
||||
virtual void load (const ESM::ObjectState& state) = 0;
|
||||
///< Load state into a LiveCellRef, that has already been initialised with base and class.
|
||||
///
|
||||
/// \attention Must not be called with an invalid \a state.
|
||||
|
||||
virtual void save (ESM::ObjectState& state) const = 0;
|
||||
///< Save LiveCellRef state into \a state.
|
||||
|
||||
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 +86,41 @@ namespace MWWorld
|
|||
|
||||
// The object that this instance is based on.
|
||||
const X* mBase;
|
||||
|
||||
virtual 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.
|
||||
|
||||
virtual 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
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace
|
|||
{
|
||||
template<typename T>
|
||||
void listCellScripts (MWWorld::LocalScripts& localScripts,
|
||||
MWWorld::CellRefList<T>& cellRefList, MWWorld::Ptr::CellStore *cell)
|
||||
MWWorld::CellRefList<T>& cellRefList, MWWorld::CellStore *cell)
|
||||
{
|
||||
for (typename MWWorld::CellRefList<T>::List::iterator iter (
|
||||
cellRefList.mList.begin());
|
||||
|
@ -27,7 +27,7 @@ namespace
|
|||
// Adds scripts for items in containers (containers/npcs/creatures)
|
||||
template<typename T>
|
||||
void listCellScriptsCont (MWWorld::LocalScripts& localScripts,
|
||||
MWWorld::CellRefList<T>& cellRefList, MWWorld::Ptr::CellStore *cell)
|
||||
MWWorld::CellRefList<T>& cellRefList, MWWorld::CellStore *cell)
|
||||
{
|
||||
for (typename MWWorld::CellRefList<T>::List::iterator iter (
|
||||
cellRefList.mList.begin());
|
||||
|
@ -99,7 +99,7 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr)
|
|||
}
|
||||
}
|
||||
|
||||
void MWWorld::LocalScripts::addCell (Ptr::CellStore *cell)
|
||||
void MWWorld::LocalScripts::addCell (CellStore *cell)
|
||||
{
|
||||
listCellScripts (*this, cell->mActivators, cell);
|
||||
listCellScripts (*this, cell->mPotions, cell);
|
||||
|
@ -128,7 +128,7 @@ void MWWorld::LocalScripts::clear()
|
|||
mScripts.clear();
|
||||
}
|
||||
|
||||
void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell)
|
||||
void MWWorld::LocalScripts::clearCell (CellStore *cell)
|
||||
{
|
||||
std::list<std::pair<std::string, Ptr> >::iterator iter = mScripts.begin();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue