From eddd6bf48dca2986c592342dfefa8b7627d0a998 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 15 Nov 2013 10:29:53 +0100 Subject: [PATCH 001/120] enabled load and save items in main menu --- apps/openmw/mwgui/mainmenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index fa7ed2ace..95753f540 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -35,8 +35,8 @@ namespace MWGui std::vector buttons; buttons.push_back("return"); buttons.push_back("newgame"); - //buttons.push_back("loadgame"); - //buttons.push_back("savegame"); + buttons.push_back("loadgame"); + buttons.push_back("savegame"); buttons.push_back("options"); //buttons.push_back("credits"); buttons.push_back("exitgame"); From 79b7fa258bfdb8b3a955fd9052e645d6fb49d819 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Nov 2013 10:31:46 +0100 Subject: [PATCH 002/120] added new mwstate subsystem --- apps/openmw/CMakeLists.txt | 4 ++++ apps/openmw/engine.cpp | 9 ++++++--- apps/openmw/mwbase/environment.cpp | 18 +++++++++++++++++- apps/openmw/mwbase/environment.hpp | 6 ++++++ apps/openmw/mwbase/statemanager.hpp | 25 +++++++++++++++++++++++++ apps/openmw/mwstate/statemanagerimp.cpp | 7 +++++++ apps/openmw/mwstate/statemanagerimp.hpp | 17 +++++++++++++++++ 7 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 apps/openmw/mwbase/statemanager.hpp create mode 100644 apps/openmw/mwstate/statemanagerimp.cpp create mode 100644 apps/openmw/mwstate/statemanagerimp.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 04bd89f95..0358b96d1 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -72,6 +72,10 @@ add_openmw_dir (mwmechanics aiescort aiactivate repair enchanting pathfinding security spellsuccess ) +add_openmw_dir (mwstate + statemanagerimp + ) + add_openmw_dir (mwbase environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager inputmanager windowmanager diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4a3c418f6..f900e6cb4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -7,6 +7,8 @@ #include +#include + #include #include @@ -39,8 +41,7 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" - -#include +#include "mwstate/statemanagerimp.hpp" void OMW::Engine::executeLocalScripts() { @@ -320,6 +321,8 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) void OMW::Engine::prepareEngine (Settings::Manager & settings) { + mEnvironment.setStateManager (new MWState::StateManager); + Nif::NIFFile::CacheLock cachelock; std::string renderSystem = settings.getString("render system", "Video"); @@ -397,7 +400,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) for (size_t i = 0; i < mContentFiles.size(); i++) mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]); - Compiler::registerExtensions (mExtensions); + Compiler::registerExtensions (mExtensions); // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 6b309025c..4a629743f 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -11,13 +11,15 @@ #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 +71,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 +129,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 +165,9 @@ void MWBase::Environment::cleanup() delete mInputManager; mInputManager = 0; + + delete mStateManager; + mStateManager = 0; } const MWBase::Environment& MWBase::Environment::get() diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index 466302907..d7c63601f 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -11,6 +11,7 @@ namespace MWBase class MechanicsManager; class InputManager; class WindowManager; + class StateManager; /// \brief Central hub for mw-subsystems /// @@ -30,6 +31,7 @@ namespace MWBase DialogueManager *mDialogueManager; Journal *mJournal; InputManager *mInputManager; + StateManager *mStateManager; float mFrameDuration; static bool sExit; @@ -65,6 +67,8 @@ namespace MWBase void setInputManager (InputManager *inputManager); + void setStateManager (StateManager *stateManager); + void setFrameDuration (float duration); ///< Set length of current frame in seconds. @@ -84,6 +88,8 @@ namespace MWBase InputManager *getInputManager() const; + StateManager *getStateManager() const; + float getFrameDuration() const; void cleanup(); diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp new file mode 100644 index 000000000..42b1dcc81 --- /dev/null +++ b/apps/openmw/mwbase/statemanager.hpp @@ -0,0 +1,25 @@ +#ifndef GAME_MWSTATE_STATEMANAGER_H +#define GAME_MWSTATE_STATEMANAGER_H + +namespace MWBase +{ + /// \brief Interface for game state manager (implemented in MWState) + class StateManager + { + private: + + StateManager (const StateManager&); + ///< not implemented + + StateManager& operator= (const StateManager&); + ///< not implemented + + public: + + StateManager() {} + + virtual ~StateManager() {} + }; +} + +#endif diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp new file mode 100644 index 000000000..fa8289419 --- /dev/null +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -0,0 +1,7 @@ + +#include "statemanagerimp.hpp" + +MWState::StateManager::StateManager() +{ + +} \ No newline at end of file diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp new file mode 100644 index 000000000..73cb0a86f --- /dev/null +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -0,0 +1,17 @@ +#ifndef GAME_STATE_STATEMANAGER_H +#define GAME_STATE_STATEMANAGER_H + +#include "../mwbase/statemanager.hpp" + +namespace MWState +{ + class StateManager : public MWBase::StateManager + { + public: + + StateManager(); + + }; +} + +#endif From f19973450f4ed6fddece051a11522d8ac1f7bad4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Nov 2013 11:07:23 +0100 Subject: [PATCH 003/120] moved exit game flag from Environment to StateManager --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/environment.cpp | 1 - apps/openmw/mwbase/environment.hpp | 5 ----- apps/openmw/mwbase/statemanager.hpp | 4 ++++ apps/openmw/mwgui/mainmenu.cpp | 5 ++--- apps/openmw/mwinput/inputmanagerimp.cpp | 3 ++- apps/openmw/mwstate/statemanagerimp.cpp | 11 +++++++++++ apps/openmw/mwstate/statemanagerimp.hpp | 5 +++++ 8 files changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f900e6cb4..d11e72f75 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -487,7 +487,7 @@ void OMW::Engine::go() MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript); // Start the main rendering loop - while (!mEnvironment.getRequestExit()) + while (!mEnvironment.get().getStateManager()->hasQuitRequest()) Ogre::Root::getSingleton().renderOneFrame(); // Save user settings diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 4a629743f..052bba9ab 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -14,7 +14,6 @@ #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), diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index d7c63601f..eb636ea2f 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -34,8 +34,6 @@ namespace MWBase StateManager *mStateManager; float mFrameDuration; - static bool sExit; - Environment (const Environment&); ///< not implemented @@ -48,9 +46,6 @@ namespace MWBase ~Environment(); - static void setRequestExit () { sExit = true; } - static bool getRequestExit () { return sExit; } - void setWorld (World *world); void setSoundManager (SoundManager *soundManager); diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 42b1dcc81..e90687293 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -19,6 +19,10 @@ namespace MWBase StateManager() {} virtual ~StateManager() {} + + virtual void requestQuit() = 0; + + virtual bool hasQuitRequest() const = 0; }; } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 95753f540..a58a3d0eb 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -1,13 +1,12 @@ #include "mainmenu.hpp" -#include - #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 "savegamedialog.hpp" @@ -79,7 +78,7 @@ namespace MWGui else if (sender == mButtons["options"]) MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings); else if (sender == mButtons["exitgame"]) - MWBase::Environment::get().setRequestExit(); + MWBase::Environment::get().getStateManager()->requestQuit(); else if (sender == mButtons["newgame"]) { MWBase::Environment::get().getWorld()->startNewGame(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 35487e339..c25e9ce52 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -19,6 +19,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/statemanager.hpp" #include "../mwgui/bookwindow.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -644,7 +645,7 @@ namespace MWInput void InputManager::windowClosed() { - MWBase::Environment::setRequestExit(); + MWBase::Environment::get().getStateManager()->requestQuit(); } void InputManager::toggleMainMenu() diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index fa8289419..f5e71d0ce 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -2,6 +2,17 @@ #include "statemanagerimp.hpp" MWState::StateManager::StateManager() +: mQuitRequest (false) { +} + +void MWState::StateManager::requestQuit() +{ + mQuitRequest = true; +} + +bool MWState::StateManager::hasQuitRequest() const +{ + return mQuitRequest; } \ No newline at end of file diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 73cb0a86f..271403ce5 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -7,10 +7,15 @@ namespace MWState { class StateManager : public MWBase::StateManager { + bool mQuitRequest; + public: StateManager(); + virtual void requestQuit(); + + virtual bool hasQuitRequest() const; }; } From 7a4b6043763598b8dc25d7b3e33555f792c6dc9e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Nov 2013 11:33:20 +0100 Subject: [PATCH 004/120] added --skip-menu switch --- apps/openmw/engine.cpp | 10 ++++++++++ apps/openmw/engine.hpp | 3 +++ apps/openmw/main.cpp | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d11e72f75..47cd01a80 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -139,6 +139,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mFpsLevel(0) , mVerboseScripts (false) , mNewGame (false) + , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) , mScriptContext (0) @@ -282,6 +283,11 @@ void OMW::Engine::setNewGame(bool newGame) mNewGame = newGame; } +void OMW::Engine::setSkipMenu (bool skipMenu) +{ + mSkipMenu = skipMenu; +} + std::string OMW::Engine::loadSettings (Settings::Manager & settings) { // Create the settings manager and load default settings file @@ -486,6 +492,10 @@ 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); + // Start the main rendering loop while (!mEnvironment.get().getStateManager()->hasQuitRequest()) Ogre::Root::getSingleton().renderOneFrame(); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 553d29068..72d2041b8 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -72,6 +72,7 @@ namespace OMW int mFpsLevel; bool mVerboseScripts; bool mNewGame; + bool mSkipMenu; bool mUseSound; bool mCompileAll; std::string mFocusName; @@ -152,6 +153,8 @@ namespace OMW /// Start as a new game. void setNewGame(bool newGame); + void setSkipMenu (bool skipMenu); + /// Initialise and enter main loop. void go(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 33f740b31..8c6bdf8a6 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -134,6 +134,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("new-game", bpo::value()->implicit_value(true) ->default_value(false), "activate char gen/new game mechanics") + ("skip-menu", bpo::value()->implicit_value(true) + ->default_value(false), "skip main menu on game startup") + ("fs-strict", bpo::value()->implicit_value(true) ->default_value(false), "strict file system handling (no case folding)") @@ -223,6 +226,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // startup-settings engine.setCell(variables["start"].as()); engine.setNewGame(variables["new-game"].as()); + engine.setSkipMenu (variables["skip-menu"].as()); // other settings engine.setSoundUsage(!variables["nosound"].as()); From b3a7c8c0980d23a3614f1b557d8a81241b1eff4a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Nov 2013 11:36:32 +0100 Subject: [PATCH 005/120] removed --new-game switch --- apps/openmw/engine.cpp | 33 +++++++++------------------------ apps/openmw/engine.hpp | 4 ---- apps/openmw/main.cpp | 4 ---- 3 files changed, 9 insertions(+), 32 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 47cd01a80..8a02c855a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -138,7 +138,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) , mFpsLevel(0) , mVerboseScripts (false) - , mNewGame (false) , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) @@ -278,11 +277,6 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) mVerboseScripts = scriptsVerbosity; } -void OMW::Engine::setNewGame(bool newGame) -{ - mNewGame = newGame; -} - void OMW::Engine::setSkipMenu (bool skipMenu) { mSkipMenu = skipMenu; @@ -395,10 +389,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 @@ -430,22 +420,17 @@ 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(); + // load cell + ESM::Position pos; + MWBase::World *world = MWBase::Environment::get().getWorld(); - if (world->findExteriorPosition(mCellName, pos)) { - world->changeToExteriorCell (pos); - } - else { - world->findInteriorPosition(mCellName, pos); - world->changeToInteriorCell (mCellName, pos); - } + if (world->findExteriorPosition(mCellName, pos)) { + world->changeToExteriorCell (pos); + } + else { + world->findInteriorPosition(mCellName, pos); + world->changeToInteriorCell (mCellName, pos); } - else - mEnvironment.getWorld()->startNewGame(); Ogre::FrameEvent event; event.timeSinceLastEvent = 0; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 72d2041b8..02fb73705 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -71,7 +71,6 @@ namespace OMW std::vector mContentFiles; int mFpsLevel; bool mVerboseScripts; - bool mNewGame; bool mSkipMenu; bool mUseSound; bool mCompileAll; @@ -150,9 +149,6 @@ namespace OMW /// Disable or enable all sounds void setSoundUsage(bool soundUsage); - /// Start as a new game. - void setNewGame(bool newGame); - void setSkipMenu (bool skipMenu); /// Initialise and enter main loop. diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 8c6bdf8a6..2bdfb91c3 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -131,9 +131,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-run", bpo::value()->default_value(""), "select a file containing a list of console commands that is executed on startup") - ("new-game", bpo::value()->implicit_value(true) - ->default_value(false), "activate char gen/new game mechanics") - ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") @@ -225,7 +222,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // startup-settings engine.setCell(variables["start"].as()); - engine.setNewGame(variables["new-game"].as()); engine.setSkipMenu (variables["skip-menu"].as()); // other settings From 31ec973c9c07ac54e5f57962d6597ddcee050e3f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Nov 2013 12:08:00 +0100 Subject: [PATCH 006/120] removed default value for --start --- apps/openmw/engine.cpp | 20 ++++++++++++++------ apps/openmw/main.cpp | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8a02c855a..cfb5522f1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -424,12 +424,21 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) ESM::Position pos; MWBase::World *world = MWBase::Environment::get().getWorld(); - if (world->findExteriorPosition(mCellName, pos)) { - world->changeToExteriorCell (pos); + if (!mCellName.empty()) + { + if (world->findExteriorPosition(mCellName, pos)) { + world->changeToExteriorCell (pos); + } + else { + world->findInteriorPosition(mCellName, pos); + world->changeToInteriorCell (mCellName, pos); + } } - else { - world->findInteriorPosition(mCellName, pos); - world->changeToInteriorCell (mCellName, pos); + else + { + 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; @@ -456,7 +465,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) void OMW::Engine::go() { - assert (!mCellName.empty()); assert (!mContentFiles.empty()); assert (!mOgre); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 2bdfb91c3..89613fda4 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -107,7 +107,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("resources", bpo::value()->default_value("resources"), "set resources directory") - ("start", bpo::value()->default_value("Beshara"), + ("start", bpo::value()->default_value(""), "set initial cell") ("content", bpo::value()->default_value(StringsVector(), "") From ec5b2e9a7e90f3e9c3eb8ebb59f3d50995845dad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Nov 2013 12:22:28 +0100 Subject: [PATCH 007/120] added running flag; moved new game code to MWState --- apps/openmw/engine.cpp | 2 ++ apps/openmw/mwbase/statemanager.hpp | 7 +++++ apps/openmw/mwgui/mainmenu.cpp | 5 +--- apps/openmw/mwstate/statemanagerimp.cpp | 34 +++++++++++++++++++++++-- apps/openmw/mwstate/statemanagerimp.hpp | 8 ++++++ 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index cfb5522f1..c013cdaae 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -488,6 +488,8 @@ void OMW::Engine::go() // 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.get().getStateManager()->hasQuitRequest()) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index e90687293..076e66b8c 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -23,6 +23,13 @@ namespace MWBase virtual void requestQuit() = 0; virtual bool hasQuitRequest() const = 0; + + virtual bool isGameRunning() const = 0; + + virtual void newGame (bool bypass = false) = 0; + ///< Start a new game. + /// + /// \param bypass Skip new game mechanics. }; } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index a58a3d0eb..cb3436715 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -81,10 +81,7 @@ namespace MWGui MWBase::Environment::get().getStateManager()->requestQuit(); 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(); + MWBase::Environment::get().getStateManager()->newGame(); } else if (sender == mButtons["loadgame"]) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f5e71d0ce..a226b166d 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -1,8 +1,14 @@ #include "statemanagerimp.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/journal.hpp" +#include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/windowmanager.hpp" + MWState::StateManager::StateManager() -: mQuitRequest (false) +: mQuitRequest (false), mRunning (false) { } @@ -15,4 +21,28 @@ void MWState::StateManager::requestQuit() bool MWState::StateManager::hasQuitRequest() const { return mQuitRequest; -} \ No newline at end of file +} + +bool MWState::StateManager::isGameRunning() const +{ + return mRunning; +} + +void MWState::StateManager::newGame (bool bypass) +{ + if (mRunning) + { + MWBase::Environment::get().getDialogueManager()->clear(); + MWBase::Environment::get().getJournal()->clear(); + mRunning = false; + } + + if (!bypass) + { + /// \todo extract cleanup code + MWBase::Environment::get().getWorld()->startNewGame(); + MWBase::Environment::get().getWindowManager()->setNewGame (true); + } + + mRunning = true; +} diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 271403ce5..9f8096a4a 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -8,6 +8,7 @@ namespace MWState class StateManager : public MWBase::StateManager { bool mQuitRequest; + bool mRunning; public: @@ -16,6 +17,13 @@ namespace MWState virtual void requestQuit(); virtual bool hasQuitRequest() const; + + virtual bool isGameRunning() const; + + virtual void newGame (bool bypass = false); + ///< Start a new game. + /// + /// \param bypass Skip new game mechanics. }; } From c5f81e3508e37ac7055728cb2cb197a84ba1dd0c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Nov 2013 17:46:48 +0100 Subject: [PATCH 008/120] don't run udpates if no game is running --- apps/openmw/engine.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index c013cdaae..741f7564f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -92,30 +92,31 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getSoundManager()->update(frametime); // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + if (MWBase::Environment::get().getStateManager()->isGameRunning()) + { + MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); - bool changed = MWBase::Environment::get().getWorld()->hasCellChanged(); + 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. + // 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. - // passing of time - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->advanceTime( - frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + if (changed) // keep change flag for another frame, if cell changed happened in local script + MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWorld()->advanceTime( + frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); - 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()); - // update actors - MWBase::Environment::get().getMechanicsManager()->update(frametime, - MWBase::Environment::get().getWindowManager()->isGuiMode()); - - // update world - MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); + // update world + MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); + } // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); From 82c84953383aad3dbf2f8466f93a594b87318495 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Nov 2013 15:15:47 +0100 Subject: [PATCH 009/120] removed boolean running flag with state enum --- apps/openmw/engine.cpp | 3 ++- apps/openmw/mwbase/statemanager.hpp | 11 ++++++++++- apps/openmw/mwstate/statemanagerimp.cpp | 12 ++++++------ apps/openmw/mwstate/statemanagerimp.hpp | 4 ++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 741f7564f..4de198b64 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -92,7 +92,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getSoundManager()->update(frametime); // global scripts - if (MWBase::Environment::get().getStateManager()->isGameRunning()) + if (MWBase::Environment::get().getStateManager()->getState()== + MWBase::StateManager::State_Running) { MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 076e66b8c..4fd1a297d 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -6,6 +6,15 @@ namespace MWBase /// \brief Interface for game state manager (implemented in MWState) class StateManager { + public: + + enum State + { + State_NoGame, + State_Ended, + State_Running + }; + private: StateManager (const StateManager&); @@ -24,7 +33,7 @@ namespace MWBase virtual bool hasQuitRequest() const = 0; - virtual bool isGameRunning() const = 0; + virtual State getState() const = 0; virtual void newGame (bool bypass = false) = 0; ///< Start a new game. diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a226b166d..c4cd45c8e 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -8,7 +8,7 @@ #include "../mwbase/windowmanager.hpp" MWState::StateManager::StateManager() -: mQuitRequest (false), mRunning (false) +: mQuitRequest (false), mState (State_NoGame) { } @@ -23,18 +23,18 @@ bool MWState::StateManager::hasQuitRequest() const return mQuitRequest; } -bool MWState::StateManager::isGameRunning() const +MWState::StateManager::State MWState::StateManager::getState() const { - return mRunning; + return mState; } void MWState::StateManager::newGame (bool bypass) { - if (mRunning) + if (mState!=State_NoGame) { MWBase::Environment::get().getDialogueManager()->clear(); MWBase::Environment::get().getJournal()->clear(); - mRunning = false; + mState = State_NoGame; } if (!bypass) @@ -44,5 +44,5 @@ void MWState::StateManager::newGame (bool bypass) MWBase::Environment::get().getWindowManager()->setNewGame (true); } - mRunning = true; + mState = State_Running; } diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 9f8096a4a..078a899b2 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -8,7 +8,7 @@ namespace MWState class StateManager : public MWBase::StateManager { bool mQuitRequest; - bool mRunning; + State mState; public: @@ -18,7 +18,7 @@ namespace MWState virtual bool hasQuitRequest() const; - virtual bool isGameRunning() const; + virtual State getState() const; virtual void newGame (bool bypass = false); ///< Start a new game. From f45cff8aff4d8bf29fd0a3200f78bb565cda0cb5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Nov 2013 15:38:08 +0100 Subject: [PATCH 010/120] flag game as ended when player dies --- apps/openmw/mwbase/statemanager.hpp | 2 ++ apps/openmw/mwmechanics/actors.cpp | 25 +++++++++++++++---------- apps/openmw/mwstate/statemanagerimp.cpp | 5 +++++ apps/openmw/mwstate/statemanagerimp.hpp | 2 ++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 4fd1a297d..74fcc3f7a 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -39,6 +39,8 @@ namespace MWBase ///< Start a new game. /// /// \param bypass Skip new game mechanics. + + virtual void endGame() = 0; }; } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 3d52ce8e6..cc431a7b0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -17,6 +17,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" + #include "../mwbase/statemanager.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" @@ -344,20 +345,24 @@ namespace MWMechanics continue; } - // If it's the player and God Mode is turned on, keep it alive - if(iter->first.getRefData().getHandle()=="player" && - MWBase::Environment::get().getWorld()->getGodModeState()) + if (iter->first.getRefData().getHandle()=="player") { - MWMechanics::DynamicStat stat(stats.getHealth()); - - if(stat.getModified()<1) + // If it's the player and God Mode is turned on, keep it alive + if (MWBase::Environment::get().getWorld()->getGodModeState()) { - stat.setModified(1, 0); - stats.setHealth(stat); + MWMechanics::DynamicStat stat (stats.getHealth()); + + if (stat.getModified()<1) + { + stat.setModified(1, 0); + stats.setHealth(stat); + } + + stats.resurrect(); + continue; } - stats.resurrect(); - continue; + MWBase::Environment::get().getStateManager()->endGame(); } if(iter->second->isDead()) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index c4cd45c8e..66a44872c 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -46,3 +46,8 @@ void MWState::StateManager::newGame (bool bypass) mState = State_Running; } + +void MWState::StateManager::endGame() +{ + mState = State_Ended; +} diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 078a899b2..007a9b136 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -24,6 +24,8 @@ namespace MWState ///< Start a new game. /// /// \param bypass Skip new game mechanics. + + virtual void endGame(); }; } From 1c7a4d4b3a2556c3064f622355e0200c91759a11 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Nov 2013 15:52:25 +0100 Subject: [PATCH 011/120] adjust availability of main menu items based on game state --- apps/openmw/mwgui/mainmenu.cpp | 110 ++++++++++++++++++++------------- apps/openmw/mwgui/mainmenu.hpp | 23 ++++--- 2 files changed, 84 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index cb3436715..d4a4e74ba 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -15,56 +15,25 @@ namespace MWGui MainMenu::MainMenu(int w, int h) : OEngine::GUI::Layout("openmw_mainmenu.layout") - , mButtonBox(0) + , mButtonBox(0), mWidth (w), mHeight (h) { - onResChange(w,h); + updateMenu(); } void MainMenu::onResChange(int w, int h) { - setCoord(0,0,w,h); + mWidth = w; + mHeight = h; + updateMenu(); + } - if (mButtonBox) - MyGUI::Gui::getInstance ().destroyWidget(mButtonBox); + void MainMenu::setVisible (bool visible) + { + if (visible) + updateMenu(); - mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default); - int curH = 0; - - std::vector buttons; - buttons.push_back("return"); - buttons.push_back("newgame"); - buttons.push_back("loadgame"); - buttons.push_back("savegame"); - buttons.push_back("options"); - //buttons.push_back("credits"); - buttons.push_back("exitgame"); - - int maxwidth = 0; - - mButtons.clear(); - for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) - { - MWGui::ImageButton* button = mButtonBox->createWidget - ("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); - mButtons[*it] = button; - curH += requested.height; - - if (requested.width > maxwidth) - maxwidth = requested.width; - } - for (std::map::iterator it = mButtons.begin(); it != mButtons.end(); ++it) - { - MyGUI::IntSize requested = it->second->getRequestedSize(); - it->second->setCoord((maxwidth-requested.width) / 2, it->second->getTop(), requested.width, requested.height); - } - - mButtonBox->setCoord (w/2 - maxwidth/2, h/2 - curH/2, maxwidth, curH); + OEngine::GUI::Layout::setVisible (visible); } void MainMenu::onButtonClicked(MyGUI::Widget *sender) @@ -98,4 +67,61 @@ namespace MWGui } } + void MainMenu::updateMenu() + { + setCoord(0,0, mWidth, mHeight); + + + if (mButtonBox) + MyGUI::Gui::getInstance ().destroyWidget(mButtonBox); + + mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default); + int curH = 0; + + MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState(); + + std::vector buttons; + + if (state==MWBase::StateManager::State_Running) + buttons.push_back("return"); + + buttons.push_back("newgame"); + + /// \todo hide, if no saved game is available + buttons.push_back("loadgame"); + + if (state==MWBase::StateManager::State_Running) + buttons.push_back("savegame"); + + buttons.push_back("options"); + //buttons.push_back("credits"); + buttons.push_back("exitgame"); + + int maxwidth = 0; + + mButtons.clear(); + for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) + { + MWGui::ImageButton* button = mButtonBox->createWidget + ("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); + mButtons[*it] = button; + curH += requested.height; + + if (requested.width > maxwidth) + maxwidth = requested.width; + } + for (std::map::iterator it = mButtons.begin(); it != mButtons.end(); ++it) + { + MyGUI::IntSize requested = it->second->getRequestedSize(); + it->second->setCoord((maxwidth-requested.width) / 2, it->second->getTop(), requested.width, requested.height); + } + + mButtonBox->setCoord (mWidth/2 - maxwidth/2, mHeight/2 - curH/2, maxwidth, curH); + + } } diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 4e76a64df..511f72672 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -7,17 +7,26 @@ namespace MWGui class MainMenu : public OEngine::GUI::Layout { - public: - MainMenu(int w, int h); + int mWidth; + int mHeight; - void onResChange(int w, int h); + public: - private: - MyGUI::Widget* mButtonBox; + MainMenu(int w, int h); - std::map mButtons; + void onResChange(int w, int h); - void onButtonClicked (MyGUI::Widget* sender); + virtual void setVisible (bool visible); + + private: + + MyGUI::Widget* mButtonBox; + + std::map mButtons; + + void onButtonClicked (MyGUI::Widget* sender); + + void updateMenu(); }; } From dc75627d53b3404458276cb84db822db4c23f8bd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Nov 2013 10:51:30 +0100 Subject: [PATCH 012/120] added secondary saved game header record --- components/CMakeLists.txt | 1 + components/esm/defs.hpp | 3 +++ components/esm/savedgame.cpp | 36 +++++++++++++++++++++++++++++++ components/esm/savedgame.hpp | 41 ++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 components/esm/savedgame.cpp create mode 100644 components/esm/savedgame.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 59fb084a8..ce5965be1 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,6 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter + savedgame ) add_component_dir (misc diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index dd7ebfe93..5a5ef9f1c 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -83,6 +83,9 @@ enum RecNameInts REC_STAT = 0x54415453, REC_WEAP = 0x50414557, + // format 0 - saved games + REC_SAVE = 0x45564153, + // format 1 REC_FILT = 0x544C4946 }; diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp new file mode 100644 index 000000000..a717c6469 --- /dev/null +++ b/components/esm/savedgame.cpp @@ -0,0 +1,36 @@ + +#include "savedgame.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" +#include "defs.hpp" + +unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; + +void ESM::SavedGame::load (ESMReader &esm) +{ + mPlayerName = esm.getHNString("PNAM"); + esm.getHNOT (mPlayerLevel, "PLEV"); + mPlayerClass = esm.getHNString("PCLA"); + mPlayerCell = esm.getHNString("PCEL"); + esm.getHNT (mInGameTime, "TSTM", 16); + esm.getHNT (mTimePlayed, "TIME"); + + while (esm.isNextSub ("DEPE")) + mContentFiles.push_back (esm.getHString()); +} + +void ESM::SavedGame::save (ESMWriter &esm) const +{ + esm.writeHNCString (mPlayerName, "PNAM"); + esm.writeHNT ("PLEV", mPlayerLevel); + esm.writeHNCString (mPlayerClass, "PCLA"); + esm.writeHNCString (mPlayerCell, "PCEL"); + esm.writeHNT ("TSTM", mInGameTime, 16); + esm.writeHNT ("TIME", mTimePlayed); + + for (std::vector::const_iterator iter (mContentFiles.begin()); + iter!=mContentFiles.end(); ++iter) + esm.writeHNCString (*iter, "DEPE"); + +} diff --git a/components/esm/savedgame.hpp b/components/esm/savedgame.hpp new file mode 100644 index 000000000..ae8f79263 --- /dev/null +++ b/components/esm/savedgame.hpp @@ -0,0 +1,41 @@ +#ifndef OPENMW_ESM_SAVEDGAME_H +#define OPENMW_ESM_SAVEDGAME_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct SavedGame + { + static unsigned int sRecordId; + + struct TimeStamp + { + float mGameHour; + int mDay; + int mMonth; + int mYear; + }; + + std::vector mContentFiles; + std::string mPlayerName; + int mPlayerLevel; + std::string mPlayerClass; + std::string mPlayerCell; + TimeStamp mInGameTime; + float mTimePlayed; + + /// \todo add field for screenshot + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif From 903e867c24559740c9e16fc193e9e09d8cca6ea4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Nov 2013 13:44:18 +0100 Subject: [PATCH 013/120] change to TES3 record (moved format field to the top) --- components/esm/loadtes3.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index 87a8d1d57..e5d6ec837 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -19,8 +19,6 @@ void ESM::Header::blank() void ESM::Header::load (ESMReader &esm) { - esm.getHNT (mData, "HEDR", 300); - if (esm.isNextSub ("FORM")) { esm.getHT (mFormat); @@ -30,6 +28,8 @@ void ESM::Header::load (ESMReader &esm) else mFormat = 0; + esm.getHNT (mData, "HEDR", 300); + while (esm.isNextSub ("MAST")) { MasterData m; @@ -41,11 +41,11 @@ void ESM::Header::load (ESMReader &esm) void ESM::Header::save (ESMWriter &esm) { - esm.writeHNT ("HEDR", mData, 300); - if (mFormat>0) esm.writeHNT ("FORM", mFormat); + esm.writeHNT ("HEDR", mData, 300); + for (std::vector::iterator iter = mMaster.begin(); iter != mMaster.end(); ++iter) { From 35bf98a940aeb95fee28529869388a409c5a8611 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Nov 2013 13:46:24 +0100 Subject: [PATCH 014/120] modified esm reader/writer to use UTF8 when no encoder is given --- components/esm/esmreader.cpp | 5 ++++- components/esm/esmwriter.cpp | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 51d86a2ee..f02ed2d6e 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -303,7 +303,10 @@ std::string ESMReader::getString(int size) getExact(ptr, size); // Convert to UTF8 and return - return mEncoder->getUtf8(ptr, size); + if (mEncoder) + return mEncoder->getUtf8(ptr, size); + + return std::string (ptr, size); } void ESMReader::fail(const std::string &msg) diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index f39aa2b89..c9ef61b63 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -6,7 +6,7 @@ namespace ESM { - ESMWriter::ESMWriter() : mRecordCount (0), mCounting (true) {} + ESMWriter::ESMWriter() : mEncoder (0), mRecordCount (0), mCounting (true) {} unsigned int ESMWriter::getVersion() const { @@ -152,9 +152,9 @@ namespace ESM else { // Convert to UTF8 and return - std::string ascii = mEncoder->getLegacyEnc(data); + std::string string = mEncoder ? mEncoder->getLegacyEnc(data) : data; - write(ascii.c_str(), ascii.size()); + write(string.c_str(), string.size()); } } From 4c61deca8df2ea4167091a4598a525f61e5d49b6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Nov 2013 15:31:39 +0100 Subject: [PATCH 015/120] fixed save code for SavedGame record --- components/esm/savedgame.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index a717c6469..5a5fc9fa8 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -22,10 +22,10 @@ void ESM::SavedGame::load (ESMReader &esm) void ESM::SavedGame::save (ESMWriter &esm) const { - esm.writeHNCString (mPlayerName, "PNAM"); + esm.writeHNCString ("PNAM", mPlayerName); esm.writeHNT ("PLEV", mPlayerLevel); - esm.writeHNCString (mPlayerClass, "PCLA"); - esm.writeHNCString (mPlayerCell, "PCEL"); + esm.writeHNCString ("PCLA", mPlayerClass); + esm.writeHNCString ("PCEL", mPlayerCell); esm.writeHNT ("TSTM", mInGameTime, 16); esm.writeHNT ("TIME", mTimePlayed); From 5e64888227f3f8e6a7796cf74ce70ac268bed5ae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Nov 2013 15:38:26 +0100 Subject: [PATCH 016/120] added basic save slot management and connected main menu save to save function (bypassing the save GUI for now) --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/statemanager.hpp | 14 ++++ apps/openmw/mwgui/mainmenu.cpp | 7 +- apps/openmw/mwstate/character.cpp | 101 +++++++++++++++++++++++ apps/openmw/mwstate/character.hpp | 45 ++++++++++ apps/openmw/mwstate/charactermanager.cpp | 57 +++++++++++++ apps/openmw/mwstate/charactermanager.hpp | 37 +++++++++ apps/openmw/mwstate/statemanagerimp.cpp | 31 ++++++- apps/openmw/mwstate/statemanagerimp.hpp | 15 +++- 10 files changed, 304 insertions(+), 9 deletions(-) create mode 100644 apps/openmw/mwstate/character.cpp create mode 100644 apps/openmw/mwstate/character.hpp create mode 100644 apps/openmw/mwstate/charactermanager.cpp create mode 100644 apps/openmw/mwstate/charactermanager.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0358b96d1..2b078a7ff 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -73,12 +73,12 @@ add_openmw_dir (mwmechanics ) add_openmw_dir (mwstate - statemanagerimp + statemanagerimp charactermanager character ) add_openmw_dir (mwbase environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager - inputmanager windowmanager + inputmanager windowmanager statemanager ) # Main executable diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4de198b64..cda068347 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -323,7 +323,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) void OMW::Engine::prepareEngine (Settings::Manager & settings) { - mEnvironment.setStateManager (new MWState::StateManager); + mEnvironment.setStateManager (new MWState::StateManager (mCfgMgr.getUserPath() / "saves")); Nif::NIFFile::CacheLock cachelock; diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 74fcc3f7a..b341fbb03 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -1,6 +1,12 @@ #ifndef GAME_MWSTATE_STATEMANAGER_H #define GAME_MWSTATE_STATEMANAGER_H +namespace MWState +{ + struct Slot; + class Character; +} + namespace MWBase { /// \brief Interface for game state manager (implemented in MWState) @@ -41,6 +47,14 @@ namespace MWBase /// \param bypass Skip new game mechanics. virtual void endGame() = 0; + + virtual void saveGame (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 MWState::Character *getCurrentCharacter() = 0; + ///< Must not be called, if there is no current character. }; } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index d4a4e74ba..f25b72d37 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -61,9 +61,10 @@ namespace MWGui } else if (sender == mButtons["savegame"]) { - MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); - dialog->setLoadOrSave(false); - dialog->setVisible(true); + MWBase::Environment::get().getStateManager()->saveGame (0); +// MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); +// dialog->setLoadOrSave(false); +// dialog->setVisible(true); } } diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp new file mode 100644 index 000000000..dc16085d8 --- /dev/null +++ b/apps/openmw/mwstate/character.cpp @@ -0,0 +1,101 @@ + +#include "character.hpp" + +#include + +#include +#include +#include + +#include + +bool MWState::operator< (const Slot& left, const Slot& right) +{ + return left.mTimeStamp> 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 (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(); +} \ No newline at end of file diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp new file mode 100644 index 000000000..30182e404 --- /dev/null +++ b/apps/openmw/mwstate/character.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_STATE_CHARACTER_H +#define GAME_STATE_CHARACTER_H + +#include + +#include + +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 + { + boost::filesystem::path mPath; + std::vector mSlots; + int mNext; + + void addSlot (const boost::filesystem::path& path); + + void addSlot (const ESM::SavedGame& profile); + + public: + + Character (const boost::filesystem::path& saves); + + 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 \æ slot pointer will be invalidated by this call. + }; +} + +#endif diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp new file mode 100644 index 000000000..c73adb5bb --- /dev/null +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -0,0 +1,57 @@ + +#include "charactermanager.hpp" + +#include +#include + +#include + +MWState::CharacterManager::CharacterManager (const boost::filesystem::path& saves) +: mPath (saves), mNext (0), mCurrent (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 characterDir = *iter; + + if (boost::filesystem::is_directory (characterDir)) + { + Character character (characterDir); + 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() +{ + if (!mCurrent) + throw std::logic_error ("no character selected"); + + return mCurrent; +} + +void MWState::CharacterManager::createCharacter() +{ + std::ostringstream stream; + stream << mNext++; + + boost::filesystem::path path = mPath / stream.str(); + + mCharacters.push_back (Character (path)); + + mCurrent = &mCharacters.back(); +} \ No newline at end of file diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp new file mode 100644 index 000000000..a3fe17131 --- /dev/null +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -0,0 +1,37 @@ +#ifndef GAME_STATE_CHARACTERMANAGER_H +#define GAME_STATE_CHARACTERMANAGER_H + +#include + +#include "character.hpp" + +namespace MWState +{ + class CharacterManager + { + boost::filesystem::path mPath; + int mNext; + std::vector mCharacters; + Character *mCurrent; + + private: + + CharacterManager (const CharacterManager&); + ///< Not implemented + + CharacterManager& operator= (const CharacterManager&); + ///< Not implemented + + public: + + CharacterManager (const boost::filesystem::path& saves); + + Character *getCurrentCharacter(); + ///< Must not be called, if there is no current character. + + void createCharacter(); + ///< Create new character within saved game management + }; +} + +#endif diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 66a44872c..f068093a0 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -1,14 +1,16 @@ #include "statemanagerimp.hpp" +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" -MWState::StateManager::StateManager() -: mQuitRequest (false), mState (State_NoGame) +MWState::StateManager::StateManager (const boost::filesystem::path& saves) +: mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves) { } @@ -44,6 +46,8 @@ void MWState::StateManager::newGame (bool bypass) MWBase::Environment::get().getWindowManager()->setNewGame (true); } + mCharacterManager.createCharacter(); + mState = State_Running; } @@ -51,3 +55,26 @@ void MWState::StateManager::endGame() { mState = State_Ended; } + +void MWState::StateManager::saveGame (const Slot *slot) +{ + ESM::SavedGame profile; + + /// \todo configure profile + + if (!slot) + slot = mCharacterManager.getCurrentCharacter()->createSlot (profile); + else + slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); + + ESM::ESMWriter writer; +// writer.setFormat (); + writer.save (slot->mPath.string()); + slot->mProfile.save (writer); + writer.close(); +} + +MWState::Character *MWState::StateManager::getCurrentCharacter() +{ + return mCharacterManager.getCurrentCharacter(); +} \ No newline at end of file diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 007a9b136..9dfcc4d8f 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -3,16 +3,21 @@ #include "../mwbase/statemanager.hpp" +#include + +#include "charactermanager.hpp" + namespace MWState { class StateManager : public MWBase::StateManager { bool mQuitRequest; State mState; + CharacterManager mCharacterManager; public: - StateManager(); + StateManager (const boost::filesystem::path& saves); virtual void requestQuit(); @@ -26,6 +31,14 @@ namespace MWState /// \param bypass Skip new game mechanics. virtual void endGame(); + + virtual void saveGame (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 Character *getCurrentCharacter(); + ///< Must not be called, if there is no current character. }; } From 9487bd33c3057f5d3f55e2b23ee108fa62778995 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Nov 2013 16:07:36 +0100 Subject: [PATCH 017/120] removed broken save function from ESMWriter --- apps/openmw/mwstate/statemanagerimp.cpp | 5 ++++- components/esm/esmwriter.cpp | 6 ------ components/esm/esmwriter.hpp | 3 --- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f068093a0..4b1d9e0f6 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -67,10 +67,13 @@ void MWState::StateManager::saveGame (const Slot *slot) else slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); + std::ofstream stream (slot->mPath.string().c_str()); ESM::ESMWriter writer; // writer.setFormat (); - writer.save (slot->mPath.string()); + writer.save (stream); + writer.startRecord ("SAVE"); slot->mProfile.save (writer); + writer.endRecord ("SAVE"); writer.close(); } diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index c9ef61b63..069d75c7b 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -51,12 +51,6 @@ namespace ESM mHeader.mMaster.push_back(d); } - void ESMWriter::save(const std::string& file) - { - std::ofstream fs(file.c_str(), std::ios_base::out | std::ios_base::trunc); - save(fs); - } - void ESMWriter::save(std::ostream& file) { mRecordCount = 0; diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index 104f97f90..d6646471b 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -36,9 +36,6 @@ class ESMWriter void addMaster(const std::string& name, uint64_t size); - void save(const std::string& file); - ///< Start saving a file by writing the TES3 header. - void save(std::ostream& file); ///< Start saving a file by writing the TES3 header. From d6e2701dd605fb0c8a4972e92ba35fd391101be1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Nov 2013 10:10:41 +0100 Subject: [PATCH 018/120] changed played time data type from float to double --- components/esm/savedgame.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/savedgame.hpp b/components/esm/savedgame.hpp index ae8f79263..c0e6f1aeb 100644 --- a/components/esm/savedgame.hpp +++ b/components/esm/savedgame.hpp @@ -29,7 +29,7 @@ namespace ESM std::string mPlayerClass; std::string mPlayerCell; TimeStamp mInGameTime; - float mTimePlayed; + double mTimePlayed; /// \todo add field for screenshot From e938c5a0eec1c10929c177415af086d8e4906e93 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Nov 2013 10:20:50 +0100 Subject: [PATCH 019/120] changed character creation logic (create on save instead of on new game) --- apps/openmw/mwbase/statemanager.hpp | 1 - apps/openmw/mwstate/charactermanager.cpp | 7 ++++++- apps/openmw/mwstate/charactermanager.hpp | 4 +++- apps/openmw/mwstate/statemanagerimp.cpp | 3 +-- apps/openmw/mwstate/statemanagerimp.hpp | 1 - 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index b341fbb03..3aa464ebe 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -54,7 +54,6 @@ namespace MWBase /// \note Slot must belong to the current character. virtual MWState::Character *getCurrentCharacter() = 0; - ///< Must not be called, if there is no current character. }; } diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index c73adb5bb..6eccb63dc 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -39,7 +39,7 @@ MWState::CharacterManager::CharacterManager (const boost::filesystem::path& save MWState::Character *MWState::CharacterManager::getCurrentCharacter() { if (!mCurrent) - throw std::logic_error ("no character selected"); + createCharacter(); return mCurrent; } @@ -54,4 +54,9 @@ void MWState::CharacterManager::createCharacter() mCharacters.push_back (Character (path)); mCurrent = &mCharacters.back(); +} + +void MWState::CharacterManager::clearCurrentCharacter() +{ + mCurrent = 0; } \ No newline at end of file diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index a3fe17131..543e0c94a 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -27,10 +27,12 @@ namespace MWState CharacterManager (const boost::filesystem::path& saves); Character *getCurrentCharacter(); - ///< Must not be called, if there is no current character. + ///< A character is implicitly created, if there is none. void createCharacter(); ///< Create new character within saved game management + + void clearCurrentCharacter(); }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 4b1d9e0f6..8f22408fe 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -37,6 +37,7 @@ void MWState::StateManager::newGame (bool bypass) MWBase::Environment::get().getDialogueManager()->clear(); MWBase::Environment::get().getJournal()->clear(); mState = State_NoGame; + mCharacterManager.clearCurrentCharacter(); } if (!bypass) @@ -46,8 +47,6 @@ void MWState::StateManager::newGame (bool bypass) MWBase::Environment::get().getWindowManager()->setNewGame (true); } - mCharacterManager.createCharacter(); - mState = State_Running; } diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 9dfcc4d8f..8d1ff0641 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -38,7 +38,6 @@ namespace MWState /// \note Slot must belong to the current character. virtual Character *getCurrentCharacter(); - ///< Must not be called, if there is no current character. }; } From fc1501a5109a93316674afe2e29b5ae90f0b849a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Nov 2013 10:53:42 +0100 Subject: [PATCH 020/120] store character profile information in saved game file --- apps/openmw/mwstate/statemanagerimp.cpp | 20 +++++++++++++++++++- components/esm/savedgame.hpp | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 8f22408fe..0f4e1e020 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -9,6 +9,11 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/npcstats.hpp" + MWState::StateManager::StateManager (const boost::filesystem::path& saves) : mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves) { @@ -59,7 +64,20 @@ void MWState::StateManager::saveGame (const Slot *slot) { ESM::SavedGame profile; - /// \todo configure profile + MWBase::World& world = *MWBase::Environment::get().getWorld(); + + MWWorld::Ptr player = world.getPlayer().getPlayer(); + + /// \todo store content file list + profile.mPlayerName = player.getClass().getName (player); + profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel(); + profile.mPlayerClass = player.get()->mBase->mId; + /// \todo player cell + /// \todo gamehour + profile.mInGameTime.mDay = world.getDay(); + profile.mInGameTime.mMonth = world.getMonth(); + /// \todo year + /// \todo time played if (!slot) slot = mCharacterManager.getCurrentCharacter()->createSlot (profile); diff --git a/components/esm/savedgame.hpp b/components/esm/savedgame.hpp index c0e6f1aeb..e712e8f1f 100644 --- a/components/esm/savedgame.hpp +++ b/components/esm/savedgame.hpp @@ -26,7 +26,7 @@ namespace ESM std::vector mContentFiles; std::string mPlayerName; int mPlayerLevel; - std::string mPlayerClass; + std::string mPlayerClass; // this is the ID and not the name of the class std::string mPlayerCell; TimeStamp mInGameTime; double mTimePlayed; From cbbdf390ad9902fc4d55e74e43f829e34c8ae45b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Nov 2013 11:10:18 +0100 Subject: [PATCH 021/120] added function for inspection of saved characters and character slots --- apps/openmw/mwbase/statemanager.hpp | 8 ++++++++ apps/openmw/mwstate/character.cpp | 10 ++++++++++ apps/openmw/mwstate/character.hpp | 11 +++++++++++ apps/openmw/mwstate/charactermanager.cpp | 12 +++++++++++- apps/openmw/mwstate/charactermanager.hpp | 4 ++++ apps/openmw/mwstate/statemanagerimp.cpp | 12 +++++++++++- apps/openmw/mwstate/statemanagerimp.hpp | 4 ++++ 7 files changed, 59 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 3aa464ebe..ce8094632 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWSTATE_STATEMANAGER_H #define GAME_MWSTATE_STATEMANAGER_H +#include + namespace MWState { struct Slot; @@ -21,6 +23,8 @@ namespace MWBase State_Running }; + typedef std::vector::const_iterator CharacterIterator; + private: StateManager (const StateManager&); @@ -54,6 +58,10 @@ namespace MWBase /// \note Slot must belong to the current character. virtual MWState::Character *getCurrentCharacter() = 0; + + virtual CharacterIterator characterBegin() = 0; + + virtual CharacterIterator characterEnd() = 0; }; } diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index dc16085d8..660af7d89 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -98,4 +98,14 @@ const MWState::Slot *MWState::Character::updateSlot (const Slot *slot, const ESM 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(); } \ No newline at end of file diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index 30182e404..a6cb6fa6d 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -18,6 +18,12 @@ namespace MWState class Character { + public: + + typedef std::vector::const_reverse_iterator SlotIterator; + + private: + boost::filesystem::path mPath; std::vector mSlots; int mNext; @@ -39,6 +45,11 @@ namespace MWState /// \note Slot must belong to this character. /// /// \attention The \æ 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. + + SlotIterator end() const; }; } diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 6eccb63dc..6b67d0d04 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -59,4 +59,14 @@ void MWState::CharacterManager::createCharacter() void MWState::CharacterManager::clearCurrentCharacter() { mCurrent = 0; -} \ No newline at end of file +} + +std::vector::const_iterator MWState::CharacterManager::begin() const +{ + return mCharacters.begin(); +} + +std::vector::const_iterator MWState::CharacterManager::end() const +{ + return mCharacters.end(); +} diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index 543e0c94a..ce82ccc46 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -33,6 +33,10 @@ namespace MWState ///< Create new character within saved game management void clearCurrentCharacter(); + + std::vector::const_iterator begin() const; + + std::vector::const_iterator end() const; }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 0f4e1e020..9d8fcafb0 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -97,4 +97,14 @@ void MWState::StateManager::saveGame (const Slot *slot) MWState::Character *MWState::StateManager::getCurrentCharacter() { return mCharacterManager.getCurrentCharacter(); -} \ No newline at end of file +} + +MWState::StateManager::CharacterIterator MWState::StateManager::characterBegin() +{ + return mCharacterManager.begin(); +} + +MWState::StateManager::CharacterIterator MWState::StateManager::characterEnd() +{ + return mCharacterManager.end(); +} diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 8d1ff0641..764a09a7e 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -38,6 +38,10 @@ namespace MWState /// \note Slot must belong to the current character. virtual Character *getCurrentCharacter(); + + virtual CharacterIterator characterBegin(); + + virtual CharacterIterator characterEnd(); }; } From 5ba56a5ea5f50c2469b780ebe4d8a1abf10311e9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Nov 2013 11:18:56 +0100 Subject: [PATCH 022/120] character signatures --- apps/openmw/mwstate/character.cpp | 19 +++++++++++++++++++ apps/openmw/mwstate/character.hpp | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 660af7d89..54d2b9dd8 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -108,4 +108,23 @@ MWState::Character::SlotIterator MWState::Character::begin() const 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::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; } \ No newline at end of file diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index a6cb6fa6d..676c04680 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -50,6 +50,11 @@ namespace MWState ///< First slot is the most recent. Other slots follow in descending order of save date. SlotIterator end() const; + + ESM::SavedGame getSignature() const; + ///< Return signature information for this character. + /// + /// \todo attention This function must not be called if there are no slots. }; } From c165894869e227cfe8e3f541e3abdd2166ac60d0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Nov 2013 12:24:24 +0100 Subject: [PATCH 023/120] load saved game record --- apps/openmw/mwbase/statemanager.hpp | 5 +++++ apps/openmw/mwgui/mainmenu.cpp | 22 +++++++++++++++++----- apps/openmw/mwstate/character.cpp | 13 ++++++++++++- apps/openmw/mwstate/charactermanager.cpp | 10 ++++++++++ apps/openmw/mwstate/charactermanager.hpp | 2 ++ apps/openmw/mwstate/statemanagerimp.cpp | 22 ++++++++++++++++++++++ apps/openmw/mwstate/statemanagerimp.hpp | 5 +++++ 7 files changed, 73 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index ce8094632..3369fd3bc 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -57,6 +57,11 @@ namespace MWBase /// /// \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() = 0; virtual CharacterIterator characterBegin() = 0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index f25b72d37..ac272d1c4 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -8,6 +8,8 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwstate/character.hpp" + #include "savegamedialog.hpp" namespace MWGui @@ -55,13 +57,22 @@ namespace MWGui else if (sender == mButtons["loadgame"]) { - MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); - dialog->setLoadOrSave(true); - dialog->setVisible(true); + // for testing purpose, pick the first slot of the first character: + const MWState::Character& character = + *MWBase::Environment::get().getStateManager()->characterBegin(); + const MWState::Slot& slot = *character.begin(); + + MWBase::Environment::get().getStateManager()->loadGame (&character, &slot); + +// MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); +// dialog->setLoadOrSave(true); +// dialog->setVisible(true); } else if (sender == mButtons["savegame"]) { + // for testing purpose, save into a new slot: MWBase::Environment::get().getStateManager()->saveGame (0); + // MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); // dialog->setLoadOrSave(false); // dialog->setVisible(true); @@ -88,8 +99,9 @@ namespace MWGui buttons.push_back("newgame"); - /// \todo hide, if no saved game is available - buttons.push_back("loadgame"); + if (MWBase::Environment::get().getStateManager()->characterBegin()!= + MWBase::Environment::get().getStateManager()->characterEnd()) + buttons.push_back("loadgame"); if (state==MWBase::StateManager::State_Running) buttons.push_back("savegame"); diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 54d2b9dd8..7185ce89d 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -9,6 +9,9 @@ #include +#include +#include + bool MWState::operator< (const Slot& left, const Slot& right) { return left.mTimeStamp ignore + + reader.getRecHeader(); + + slot.mProfile.load (reader); mSlots.push_back (slot); } diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 6b67d0d04..c632f61e4 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -56,6 +56,16 @@ void MWState::CharacterManager::createCharacter() mCurrent = &mCharacters.back(); } +void MWState::CharacterManager::setCurrentCharacter (const Character *character) +{ + int index = character - &mCharacters[0]; + + if (index<0 || index>=static_cast (mCharacters.size())) + throw std::logic_error ("invalid character"); + + mCurrent = &mCharacters[index]; +} + void MWState::CharacterManager::clearCurrentCharacter() { mCurrent = 0; diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index ce82ccc46..9995393aa 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -32,6 +32,8 @@ namespace MWState void createCharacter(); ///< Create new character within saved game management + void setCurrentCharacter (const Character *character); + void clearCurrentCharacter(); std::vector::const_iterator begin() const; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9d8fcafb0..12bd29596 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -2,6 +2,7 @@ #include "statemanagerimp.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -94,6 +95,27 @@ void MWState::StateManager::saveGame (const Slot *slot) writer.close(); } +void MWState::StateManager::loadGame (const Character *character, const Slot *slot) +{ + if (mState!=State_NoGame) + { + MWBase::Environment::get().getDialogueManager()->clear(); + MWBase::Environment::get().getJournal()->clear(); + mState = State_NoGame; + mCharacterManager.clearCurrentCharacter(); + } + + ESM::ESMReader reader; + reader.open (slot->mPath.string()); + + reader.getRecName(); // don't need to read that here + reader.getRecHeader(); + + /// \todo read saved game data + + mState = State_Running; +} + MWState::Character *MWState::StateManager::getCurrentCharacter() { return mCharacterManager.getCurrentCharacter(); diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 764a09a7e..d387404cb 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -37,6 +37,11 @@ namespace MWState /// /// \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(); virtual CharacterIterator characterBegin(); From b5f99522c72759149ddb1888815abc3739db84e6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Nov 2013 12:29:24 +0100 Subject: [PATCH 024/120] added a few comments --- apps/openmw/mwbase/statemanager.hpp | 4 ++++ apps/openmw/mwstate/statemanagerimp.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 3369fd3bc..3bd99c315 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -63,8 +63,12 @@ namespace MWBase /// \note \a slot must belong to \a character. virtual MWState::Character *getCurrentCharacter() = 0; + ///< \attention Do not call this function to check if there is a current character. Use + /// characterBegin()!=characterEnd() instead. virtual CharacterIterator characterBegin() = 0; + ///< Any call to SaveGame and getCurrentCharacter can invalidate the returned + /// iterator. virtual CharacterIterator characterEnd() = 0; }; diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index d387404cb..08b0776c1 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -43,8 +43,12 @@ namespace MWState /// \note \a slot must belong to \a character. virtual Character *getCurrentCharacter(); + ///< \attention Do not call this function to check if there is a current character. Use + /// characterBegin()!=characterEnd() instead. virtual CharacterIterator characterBegin(); + ///< Any call to SaveGame and getCurrentCharacter can invalidate the returned + /// iterator. virtual CharacterIterator characterEnd(); }; From 2702d10911a3a2a82da21b9bae95d8a3215521e9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Nov 2013 12:31:04 +0100 Subject: [PATCH 025/120] more comments --- apps/openmw/mwstate/character.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index 676c04680..d678c165b 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -44,17 +44,19 @@ namespace MWState const Slot *updateSlot (const Slot *slot, const ESM::SavedGame& profile); /// \note Slot must belong to this character. /// - /// \attention The \æ slot pointer will be invalidated by this call. + /// \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. /// - /// \todo attention This function must not be called if there are no slots. + /// \attention This function must not be called if there are no slots. }; } From cf79a83d4fcc06a4893176fb9f1ba51bf6269b6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 Nov 2013 19:07:54 +0100 Subject: [PATCH 026/120] Avoid recreating widgets in MainMenu::updateMenu. Fix crash when pressing new game due to the button being destroyed from within it's own delegate. --- apps/openmw/mwgui/mainmenu.cpp | 61 +++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index ac272d1c4..962b5dd31 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -40,22 +40,23 @@ namespace MWGui void MainMenu::onButtonClicked(MyGUI::Widget *sender) { + std::string name = *sender->getUserData(); MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); - if (sender == mButtons["return"]) + if (name == "return") { MWBase::Environment::get().getSoundManager ()->resumeSounds (MWBase::SoundManager::Play_TypeSfx); MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); } - else if (sender == mButtons["options"]) + else if (name == "options") MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings); - else if (sender == mButtons["exitgame"]) + else if (name == "exitgame") MWBase::Environment::get().getStateManager()->requestQuit(); - else if (sender == mButtons["newgame"]) + else if (name == "newgame") { MWBase::Environment::get().getStateManager()->newGame(); } - else if (sender == mButtons["loadgame"]) + else if (name == "loadgame") { // for testing purpose, pick the first slot of the first character: const MWState::Character& character = @@ -68,7 +69,7 @@ namespace MWGui // dialog->setLoadOrSave(true); // dialog->setVisible(true); } - else if (sender == mButtons["savegame"]) + else if (name == "savegame") { // for testing purpose, save into a new slot: MWBase::Environment::get().getStateManager()->saveGame (0); @@ -84,10 +85,9 @@ namespace MWGui setCoord(0,0, mWidth, mHeight); - if (mButtonBox) - MyGUI::Gui::getInstance ().destroyWidget(mButtonBox); + if (!mButtonBox) + mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default); - mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default); int curH = 0; MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState(); @@ -110,28 +110,41 @@ namespace MWGui //buttons.push_back("credits"); buttons.push_back("exitgame"); - int maxwidth = 0; - - mButtons.clear(); + // Create new buttons if needed for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) { - MWGui::ImageButton* button = mButtonBox->createWidget - ("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); - mButtons[*it] = button; - curH += requested.height; + if (mButtons.find(*it) == mButtons.end()) + { + MWGui::ImageButton* button = mButtonBox->createWidget + ("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"); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked); + button->setUserData(std::string(*it)); + mButtons[*it] = button; + } + } + // Start by hiding all buttons + int maxwidth = 0; + for (std::map::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::iterator it = mButtons.begin(); it != mButtons.end(); ++it) + + // Now show and position the ones we want + for (std::vector::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 (mWidth/2 - maxwidth/2, mHeight/2 - curH/2, maxwidth, curH); From 2e87cbc2313c568510de3b70cca4cd52c5f9016a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 Nov 2013 20:24:58 +0100 Subject: [PATCH 027/120] Add basic functionality to SaveGameDialog --- apps/openmw/mwbase/statemanager.hpp | 4 +- apps/openmw/mwgui/mainmenu.cpp | 34 ++-- apps/openmw/mwgui/mainmenu.hpp | 5 + apps/openmw/mwgui/savegamedialog.cpp | 179 ++++++++++++++++++++++ apps/openmw/mwgui/savegamedialog.hpp | 12 ++ apps/openmw/mwstate/statemanagerimp.cpp | 27 +++- files/mygui/openmw_savegame_dialog.layout | 9 -- 7 files changed, 236 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 3bd99c315..e9d10a796 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -63,8 +63,8 @@ namespace MWBase /// \note \a slot must belong to \a character. virtual MWState::Character *getCurrentCharacter() = 0; - ///< \attention Do not call this function to check if there is a current character. Use - /// characterBegin()!=characterEnd() instead. + ///< \attention Do not call this function to check if there is a current character. + /// Instead, assume there is a character if getState() == Running. virtual CharacterIterator characterBegin() = 0; ///< Any call to SaveGame and getCurrentCharacter can invalidate the returned diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 962b5dd31..ff8ab8c93 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -18,10 +18,16 @@ namespace MWGui MainMenu::MainMenu(int w, int h) : OEngine::GUI::Layout("openmw_mainmenu.layout") , mButtonBox(0), mWidth (w), mHeight (h) + , mSaveGameDialog(NULL) { updateMenu(); } + MainMenu::~MainMenu() + { + delete mSaveGameDialog; + } + void MainMenu::onResChange(int w, int h) { mWidth = w; @@ -56,27 +62,15 @@ namespace MWGui MWBase::Environment::get().getStateManager()->newGame(); } - else if (name == "loadgame") + else { - // for testing purpose, pick the first slot of the first character: - const MWState::Character& character = - *MWBase::Environment::get().getStateManager()->characterBegin(); - const MWState::Slot& slot = *character.begin(); - - MWBase::Environment::get().getStateManager()->loadGame (&character, &slot); - -// MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); -// dialog->setLoadOrSave(true); -// dialog->setVisible(true); - } - else if (name == "savegame") - { - // for testing purpose, save into a new slot: - MWBase::Environment::get().getStateManager()->saveGame (0); - -// MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog(); -// dialog->setLoadOrSave(false); -// dialog->setVisible(true); + if (!mSaveGameDialog) + mSaveGameDialog = new SaveGameDialog(); + if (name == "loadgame") + mSaveGameDialog->setLoadOrSave(true); + else if (name == "savegame") + mSaveGameDialog->setLoadOrSave(false); + mSaveGameDialog->setVisible(true); } } diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 511f72672..6d52f26d5 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -5,6 +5,8 @@ namespace MWGui { + class SaveGameDialog; + class MainMenu : public OEngine::GUI::Layout { int mWidth; @@ -13,6 +15,7 @@ namespace MWGui public: MainMenu(int w, int h); + ~MainMenu(); void onResChange(int w, int h); @@ -27,6 +30,8 @@ namespace MWGui void onButtonClicked (MyGUI::Widget* sender); void updateMenu(); + + SaveGameDialog* mSaveGameDialog; }; } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index a1acd3588..648dd4683 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,12 +1,68 @@ #include "savegamedialog.hpp" #include "widgets.hpp" +#include "../mwbase/statemanager.hpp" +#include "../mwbase/environment.hpp" + + +#include "../mwstate/character.hpp" + +namespace +{ +std::string getMonth(int m) +{ + std::string month; + 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; + } + return month; +} +} namespace MWGui { SaveGameDialog::SaveGameDialog() : WindowModal("openmw_savegame_dialog.layout") + , mSaving(true) + , mCurrentCharacter(NULL) { getWidget(mScreenshot, "Screenshot"); getWidget(mCharacterSelection, "SelectCharacter"); @@ -18,21 +74,57 @@ 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(); + center(); + + MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager(); + if (mgr->characterBegin() == mgr->characterEnd()) + return; + + // If we are running, there must be a current character + if (mgr->getState() == MWBase::StateManager::State_Running) + { + mCurrentCharacter = mgr->getCurrentCharacter(); + } + + mCharacterSelection->removeAllItems(); + for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it) + { + std::stringstream title; + title << it->getSignature().mPlayerName; + title << " (Level " << it->getSignature().mPlayerLevel << " " << it->getSignature().mPlayerClass << ")"; + + mCharacterSelection->addItem (title.str()); + + if (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(); + } + center(); } @@ -43,7 +135,94 @@ namespace MWGui void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender) { + // Get the selected slot, if any + unsigned int i=0; + const MWState::Slot* slot = NULL; + 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 (slot); + } + else + { + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); + } + setVisible(false); } + 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->mPath.string()); + } + onSlotSelected(mSaveList, MyGUI::ITEM_NONE); + } + + void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos) + { + if (pos == MyGUI::ITEM_NONE) + { + mInfoText->setCaption(""); + 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 << " " + << getMonth(slot->mProfile.mInGameTime.mMonth) + << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); + + mInfoText->setCaptionWithReplacing(text.str()); + + } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 1a3178ef3..2a188061c 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -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; + }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 12bd29596..6aba93dc8 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -72,9 +72,28 @@ void MWState::StateManager::saveGame (const Slot *slot) /// \todo store content file list profile.mPlayerName = player.getClass().getName (player); profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel(); - profile.mPlayerClass = player.get()->mBase->mId; - /// \todo player cell - /// \todo gamehour + profile.mPlayerClass = player.get()->mBase->mClass; + + std::string cellName; + if (player.getCell()->mCell->isExterior()) + { + if (player.getCell()->mCell->mName != "") + cellName = player.getCell()->mCell->mName; + else + { + const ESM::Region* region = + MWBase::Environment::get().getWorld()->getStore().get().search(player.getCell()->mCell->mRegion); + if (region) + cellName = region->mName; + else + cellName = MWBase::Environment::get().getWindowManager()->getGameSettingString("sDefaultCellname", "Wilderness"); + } + } + else + cellName = player.getCell()->mCell->mName; + profile.mPlayerCell = cellName; + + profile.mInGameTime.mGameHour = world.getTimeStamp().getHour(); profile.mInGameTime.mDay = world.getDay(); profile.mInGameTime.mMonth = world.getMonth(); /// \todo year @@ -113,6 +132,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl /// \todo read saved game data + mCharacterManager.setCurrentCharacter(character); + mState = State_Running; } diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index 18de6a239..ceb1a8428 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -17,8 +17,6 @@ - - @@ -26,11 +24,6 @@ - - - - - @@ -51,8 +44,6 @@ - - From 18a3b38fb49e42d410fe2729fd26d9db99ee7abb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Nov 2013 14:42:58 +0100 Subject: [PATCH 028/120] when scanning saved game directory, reject characters without a valid saved game --- apps/openmw/mwstate/charactermanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index c632f61e4..2b9c49fcc 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -23,7 +23,9 @@ MWState::CharacterManager::CharacterManager (const boost::filesystem::path& save if (boost::filesystem::is_directory (characterDir)) { Character character (characterDir); - mCharacters.push_back (character); + + if (character.begin()!=character.end()) + mCharacters.push_back (character); } std::istringstream stream (characterDir.filename().string()); From 7efac4c9a52127c806979182d40d36501dc7174f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Nov 2013 15:05:00 +0100 Subject: [PATCH 029/120] fixed handling of characters without a valid slot --- apps/openmw/mwbase/statemanager.hpp | 2 -- apps/openmw/mwgui/savegamedialog.cpp | 21 ++++++++++----------- apps/openmw/mwstate/statemanagerimp.hpp | 2 -- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index e9d10a796..7101be25d 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -63,8 +63,6 @@ namespace MWBase /// \note \a slot must belong to \a character. virtual MWState::Character *getCurrentCharacter() = 0; - ///< \attention Do not call this function to check if there is a current character. - /// Instead, assume there is a character if getState() == Running. virtual CharacterIterator characterBegin() = 0; ///< Any call to SaveGame and getCurrentCharacter can invalidate the returned diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 648dd4683..2ea83cfa3 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -89,23 +89,22 @@ namespace MWGui if (mgr->characterBegin() == mgr->characterEnd()) return; - // If we are running, there must be a current character - if (mgr->getState() == MWBase::StateManager::State_Running) - { - mCurrentCharacter = mgr->getCurrentCharacter(); - } + mCurrentCharacter = mgr->getCurrentCharacter(); mCharacterSelection->removeAllItems(); for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it) { - std::stringstream title; - title << it->getSignature().mPlayerName; - title << " (Level " << it->getSignature().mPlayerLevel << " " << it->getSignature().mPlayerClass << ")"; + if (it->begin()!=it->end()) + { + std::stringstream title; + title << it->getSignature().mPlayerName; + title << " (Level " << it->getSignature().mPlayerLevel << " " << it->getSignature().mPlayerClass << ")"; - mCharacterSelection->addItem (title.str()); + mCharacterSelection->addItem (title.str()); - if (mCurrentCharacter == &*it) - mCharacterSelection->setIndexSelected(mCharacterSelection->getItemCount()-1); + if (mgr->getCurrentCharacter() == &*it) + mCharacterSelection->setIndexSelected(mCharacterSelection->getItemCount()-1); + } } fillSaveList(); diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 08b0776c1..a380c9fee 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -43,8 +43,6 @@ namespace MWState /// \note \a slot must belong to \a character. virtual Character *getCurrentCharacter(); - ///< \attention Do not call this function to check if there is a current character. Use - /// characterBegin()!=characterEnd() instead. virtual CharacterIterator characterBegin(); ///< Any call to SaveGame and getCurrentCharacter can invalidate the returned From 67cd0887e64afa88ec5139fcb4b8a60e74bd8a3f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Nov 2013 15:19:56 +0100 Subject: [PATCH 030/120] added description field to saved game record; make use of description in GUI --- apps/openmw/mwbase/statemanager.hpp | 3 ++- apps/openmw/mwgui/savegamedialog.cpp | 6 ++++-- apps/openmw/mwstate/statemanagerimp.cpp | 3 ++- apps/openmw/mwstate/statemanagerimp.hpp | 2 +- components/esm/savedgame.cpp | 2 ++ components/esm/savedgame.hpp | 1 + 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 7101be25d..f1f130824 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -2,6 +2,7 @@ #define GAME_MWSTATE_STATEMANAGER_H #include +#include namespace MWState { @@ -52,7 +53,7 @@ namespace MWBase virtual void endGame() = 0; - virtual void saveGame (const MWState::Slot *slot = 0) = 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. diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 2ea83cfa3..38574e2fd 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -83,6 +83,8 @@ namespace MWGui { WindowModal::open(); + mSaveNameEdit->setCaption (""); + center(); MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager(); @@ -145,7 +147,7 @@ namespace MWGui if (mSaving) { - MWBase::Environment::get().getStateManager()->saveGame (slot); + MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), slot); } else { @@ -179,7 +181,7 @@ namespace MWGui return; for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) { - mSaveList->addItem(it->mPath.string()); + mSaveList->addItem(it->mProfile.mDescription); } onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 6aba93dc8..9d8cf2a81 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -61,7 +61,7 @@ void MWState::StateManager::endGame() mState = State_Ended; } -void MWState::StateManager::saveGame (const Slot *slot) +void MWState::StateManager::saveGame (const std::string& description, const Slot *slot) { ESM::SavedGame profile; @@ -98,6 +98,7 @@ void MWState::StateManager::saveGame (const Slot *slot) profile.mInGameTime.mMonth = world.getMonth(); /// \todo year /// \todo time played + profile.mDescription = description; if (!slot) slot = mCharacterManager.getCurrentCharacter()->createSlot (profile); diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index a380c9fee..abf7e123b 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -32,7 +32,7 @@ namespace MWState virtual void endGame(); - virtual void saveGame (const Slot *slot = 0); + 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. diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 5a5fc9fa8..8169b01a1 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -15,6 +15,7 @@ void ESM::SavedGame::load (ESMReader &esm) mPlayerCell = esm.getHNString("PCEL"); esm.getHNT (mInGameTime, "TSTM", 16); esm.getHNT (mTimePlayed, "TIME"); + mDescription = esm.getHNString ("DESC"); while (esm.isNextSub ("DEPE")) mContentFiles.push_back (esm.getHString()); @@ -28,6 +29,7 @@ void ESM::SavedGame::save (ESMWriter &esm) const esm.writeHNCString ("PCEL", mPlayerCell); esm.writeHNT ("TSTM", mInGameTime, 16); esm.writeHNT ("TIME", mTimePlayed); + esm.writeHNCString ("DESC", mDescription); for (std::vector::const_iterator iter (mContentFiles.begin()); iter!=mContentFiles.end(); ++iter) diff --git a/components/esm/savedgame.hpp b/components/esm/savedgame.hpp index e712e8f1f..6c11d318f 100644 --- a/components/esm/savedgame.hpp +++ b/components/esm/savedgame.hpp @@ -30,6 +30,7 @@ namespace ESM std::string mPlayerCell; TimeStamp mInGameTime; double mTimePlayed; + std::string mDescription; /// \todo add field for screenshot From e3670cff8a14bc6d028e0116d5bf500064660358 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Nov 2013 16:58:41 +0100 Subject: [PATCH 031/120] improved character selection logic --- apps/openmw/mwbase/statemanager.hpp | 3 ++- apps/openmw/mwgui/savegamedialog.cpp | 20 +++++++++++++------- apps/openmw/mwstate/charactermanager.cpp | 4 ++-- apps/openmw/mwstate/charactermanager.hpp | 4 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 4 ++-- apps/openmw/mwstate/statemanagerimp.hpp | 3 ++- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index f1f130824..f376d72c1 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -63,7 +63,8 @@ namespace MWBase /// /// \note \a slot must belong to \a character. - virtual MWState::Character *getCurrentCharacter() = 0; + 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 diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 38574e2fd..2ce0f0fbf 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -91,9 +91,10 @@ namespace MWGui if (mgr->characterBegin() == mgr->characterEnd()) return; - mCurrentCharacter = mgr->getCurrentCharacter(); + mCurrentCharacter = mgr->getCurrentCharacter (false); mCharacterSelection->removeAllItems(); + for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it) { if (it->begin()!=it->end()) @@ -104,7 +105,7 @@ namespace MWGui mCharacterSelection->addItem (title.str()); - if (mgr->getCurrentCharacter() == &*it) + if (mCurrentCharacter == &*it) mCharacterSelection->setIndexSelected(mCharacterSelection->getItemCount()-1); } } @@ -123,7 +124,7 @@ namespace MWGui if (!load) { - mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(); + mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter (false); } center(); @@ -139,10 +140,14 @@ namespace MWGui // Get the selected slot, if any unsigned int i=0; const MWState::Slot* slot = NULL; - for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it,++i) + + if (mCurrentCharacter) { - if (i == mSaveList->getIndexSelected()) - slot = &*it; + for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it,++i) + { + if (i == mSaveList->getIndexSelected()) + slot = &*it; + } } if (mSaving) @@ -151,7 +156,8 @@ namespace MWGui } else { - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); + if (mCurrentCharacter && slot) + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); } setVisible(false); diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 2b9c49fcc..cb64da2c2 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -38,9 +38,9 @@ MWState::CharacterManager::CharacterManager (const boost::filesystem::path& save } } -MWState::Character *MWState::CharacterManager::getCurrentCharacter() +MWState::Character *MWState::CharacterManager::getCurrentCharacter (bool create) { - if (!mCurrent) + if (!mCurrent && create) createCharacter(); return mCurrent; diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index 9995393aa..a02927d58 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -26,8 +26,8 @@ namespace MWState CharacterManager (const boost::filesystem::path& saves); - Character *getCurrentCharacter(); - ///< A character is implicitly created, if there is none. + 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 diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9d8cf2a81..9a7e3d158 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -138,9 +138,9 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl mState = State_Running; } -MWState::Character *MWState::StateManager::getCurrentCharacter() +MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { - return mCharacterManager.getCurrentCharacter(); + return mCharacterManager.getCurrentCharacter (create); } MWState::StateManager::CharacterIterator MWState::StateManager::characterBegin() diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index abf7e123b..8bf1fab20 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -42,7 +42,8 @@ namespace MWState /// /// \note \a slot must belong to \a character. - virtual Character *getCurrentCharacter(); + 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 From 55544e931cee0b55ad8550958f64f493ba9fa8ec Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Nov 2013 10:21:49 +0100 Subject: [PATCH 032/120] reject newer formats when scanning saved games --- apps/openmw/mwstate/character.cpp | 3 +++ apps/openmw/mwstate/statemanagerimp.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 7185ce89d..2bd2af139 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -27,6 +27,9 @@ void MWState::Character::addSlot (const boost::filesystem::path& 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 diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9a7e3d158..46239f5a2 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -107,7 +107,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot std::ofstream stream (slot->mPath.string().c_str()); ESM::ESMWriter writer; -// writer.setFormat (); + writer.setFormat (ESM::Header::CurrentFormat); writer.save (stream); writer.startRecord ("SAVE"); slot->mProfile.save (writer); From 1ecadccb280545474cadeb1389e3d1ece4f48cc0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Nov 2013 12:59:40 +0100 Subject: [PATCH 033/120] fixed save function of SavedGame record --- components/esm/savedgame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 8169b01a1..a37043da6 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -33,6 +33,6 @@ void ESM::SavedGame::save (ESMWriter &esm) const for (std::vector::const_iterator iter (mContentFiles.begin()); iter!=mContentFiles.end(); ++iter) - esm.writeHNCString (*iter, "DEPE"); + esm.writeHNCString ("DEPE", *iter); } From 616e3aa32ffcfa36ed594a8b049e439d2c9288f6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Nov 2013 13:00:05 +0100 Subject: [PATCH 034/120] store content file list in saved games and reject saved games not matching the current game --- apps/openmw/engine.cpp | 3 ++- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwstate/character.cpp | 14 +++++++++++--- apps/openmw/mwstate/character.hpp | 4 ++-- apps/openmw/mwstate/charactermanager.cpp | 9 +++++---- apps/openmw/mwstate/charactermanager.hpp | 3 ++- apps/openmw/mwstate/statemanagerimp.cpp | 7 ++++--- apps/openmw/mwstate/statemanagerimp.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 7 ++++++- apps/openmw/mwworld/worldimp.hpp | 3 +++ 10 files changed, 38 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index cda068347..bee7fa8fd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -323,7 +323,8 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) void OMW::Engine::prepareEngine (Settings::Manager & settings) { - mEnvironment.setStateManager (new MWState::StateManager (mCfgMgr.getUserPath() / "saves")); + mEnvironment.setStateManager ( + new MWState::StateManager (mCfgMgr.getUserPath() / "saves", mContentFiles.at (0))); Nif::NIFFile::CacheLock cachelock; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index e1adfbec4..fe7d8f7ac 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -416,6 +416,8 @@ namespace MWBase virtual void launchProjectile (const std::string& id, const ESM::EffectList& effects, const MWWorld::Ptr& actor, const std::string& sourceName) = 0; + + virtual const std::vector& getContentFiles() const = 0; }; } diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 2bd2af139..0766753ca 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -12,13 +12,18 @@ #include #include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + bool MWState::operator< (const Slot& left, const Slot& right) { return left.mTimeStamp ignore + mSlots.push_back (slot); } @@ -54,7 +62,7 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) mSlots.push_back (slot); } -MWState::Character::Character (const boost::filesystem::path& saves) +MWState::Character::Character (const boost::filesystem::path& saves, const std::string& game) : mPath (saves), mNext (0) { if (!boost::filesystem::is_directory (mPath)) @@ -70,7 +78,7 @@ MWState::Character::Character (const boost::filesystem::path& saves) try { - addSlot (slotPath); + addSlot (slotPath, game); } catch (...) {} // ignoring bad saved game files for now diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index d678c165b..61e4e5b25 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -28,13 +28,13 @@ namespace MWState std::vector mSlots; int mNext; - void addSlot (const boost::filesystem::path& path); + void addSlot (const boost::filesystem::path& path, const std::string& game); void addSlot (const ESM::SavedGame& profile); public: - Character (const boost::filesystem::path& saves); + Character (const boost::filesystem::path& saves, const std::string& game); const Slot *createSlot (const ESM::SavedGame& profile); ///< Create new slot. diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index cb64da2c2..2a40fb1cc 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -6,8 +6,9 @@ #include -MWState::CharacterManager::CharacterManager (const boost::filesystem::path& saves) -: mPath (saves), mNext (0), mCurrent (0) +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)) { @@ -22,7 +23,7 @@ MWState::CharacterManager::CharacterManager (const boost::filesystem::path& save if (boost::filesystem::is_directory (characterDir)) { - Character character (characterDir); + Character character (characterDir, mGame); if (character.begin()!=character.end()) mCharacters.push_back (character); @@ -53,7 +54,7 @@ void MWState::CharacterManager::createCharacter() boost::filesystem::path path = mPath / stream.str(); - mCharacters.push_back (Character (path)); + mCharacters.push_back (Character (path, mGame)); mCurrent = &mCharacters.back(); } diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index a02927d58..bc2e23f89 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -13,6 +13,7 @@ namespace MWState int mNext; std::vector mCharacters; Character *mCurrent; + std::string mGame; private: @@ -24,7 +25,7 @@ namespace MWState public: - CharacterManager (const boost::filesystem::path& saves); + 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. diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 46239f5a2..4cb97ed50 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -15,8 +15,8 @@ #include "../mwmechanics/npcstats.hpp" -MWState::StateManager::StateManager (const boost::filesystem::path& saves) -: mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves) +MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::string& game) +: mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves, game) { } @@ -69,7 +69,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot MWWorld::Ptr player = world.getPlayer().getPlayer(); - /// \todo store content file list + profile.mContentFiles = world.getContentFiles(); + profile.mPlayerName = player.getClass().getName (player); profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel(); profile.mPlayerClass = player.get()->mBase->mClass; diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 8bf1fab20..3965632cc 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -17,7 +17,7 @@ namespace MWState public: - StateManager (const boost::filesystem::path& saves); + StateManager (const boost::filesystem::path& saves, const std::string& game); virtual void requestQuit(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index eca2ebb79..5a4192529 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -215,7 +215,7 @@ namespace MWWorld mSky (true), mCells (mStore, mEsm), mActivationDistanceOverride (mActivationDistanceOverride), mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true), - mFacedDistance(FLT_MAX), mGodMode(false) + mFacedDistance(FLT_MAX), mGodMode(false), mContentFiles (contentFiles) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -2246,4 +2246,9 @@ namespace MWWorld ++it; } } + + const std::vector& World::getContentFiles() const + { + return mContentFiles; + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 19890b831..32ad84865 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -73,6 +73,7 @@ namespace MWWorld OEngine::Physic::PhysicEngine* mPhysEngine; bool mGodMode; + std::vector mContentFiles; // not implemented World (const World&); @@ -492,6 +493,8 @@ namespace MWWorld virtual void launchProjectile (const std::string& id, const ESM::EffectList& effects, const MWWorld::Ptr& actor, const std::string& sourceName); + + virtual const std::vector& getContentFiles() const; }; } From ad143e0524278e6af70c37417a5545a47ed9449c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Nov 2013 14:56:05 +0100 Subject: [PATCH 035/120] case fix (content file names) --- apps/openmw/mwstate/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 0766753ca..304eaddd3 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -42,7 +42,8 @@ void MWState::Character::addSlot (const boost::filesystem::path& path, const std slot.mProfile.load (reader); - if (Misc::StringUtils::lowerCase (slot.mProfile.mContentFiles.at (0))!=game) + 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); From b40c0f2a07eb592c695ef3c2a188374a7112969f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Nov 2013 09:56:08 +0100 Subject: [PATCH 036/120] one more fix to SavedGame record saving --- components/esm/savedgame.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index a37043da6..e98608fe6 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -23,13 +23,13 @@ void ESM::SavedGame::load (ESMReader &esm) void ESM::SavedGame::save (ESMWriter &esm) const { - esm.writeHNCString ("PNAM", mPlayerName); + esm.writeHNString ("PNAM", mPlayerName); esm.writeHNT ("PLEV", mPlayerLevel); - esm.writeHNCString ("PCLA", mPlayerClass); - esm.writeHNCString ("PCEL", mPlayerCell); + esm.writeHNString ("PCLA", mPlayerClass); + esm.writeHNString ("PCEL", mPlayerCell); esm.writeHNT ("TSTM", mInGameTime, 16); esm.writeHNT ("TIME", mTimePlayed); - esm.writeHNCString ("DESC", mDescription); + esm.writeHNString ("DESC", mDescription); for (std::vector::const_iterator iter (mContentFiles.begin()); iter!=mContentFiles.end(); ++iter) From eea433f14192e2d36a84494a85762b06787dfcf5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Nov 2013 10:37:58 +0100 Subject: [PATCH 037/120] restore last played character selection across sessions --- apps/openmw/mwgui/savegamedialog.cpp | 12 ++++++++++-- apps/openmw/mwstate/statemanagerimp.cpp | 8 ++++++++ files/settings-default.cfg | 7 +++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 2ce0f0fbf..8ec6dbfcf 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,10 +1,13 @@ #include "savegamedialog.hpp" #include "widgets.hpp" +#include + +#include + #include "../mwbase/statemanager.hpp" #include "../mwbase/environment.hpp" - #include "../mwstate/character.hpp" namespace @@ -93,6 +96,9 @@ namespace MWGui 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) @@ -105,7 +111,9 @@ namespace MWGui mCharacterSelection->addItem (title.str()); - if (mCurrentCharacter == &*it) + if (mCurrentCharacter == &*it || + (!mCurrentCharacter && directory==Misc::StringUtils::lowerCase ( + it->begin()->mPath.parent_path().filename().string()))) mCharacterSelection->setIndexSelected(mCharacterSelection->getItemCount()-1); } } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 4cb97ed50..97f8b8e55 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" @@ -114,6 +116,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot slot->mProfile.save (writer); writer.endRecord ("SAVE"); writer.close(); + + Settings::Manager::setString ("character", "Saves", + slot->mPath.parent_path().filename().string()); } void MWState::StateManager::loadGame (const Character *character, const Slot *slot) @@ -137,6 +142,9 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl mCharacterManager.setCurrentCharacter(character); mState = State_Running; + + Settings::Manager::setString ("character", "Saves", + slot->mPath.parent_path().filename().string()); } MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f191430df..b3b186142 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,4 +1,4 @@ -# WARNING: Editing this file might have no effect, as these +# WARNING: Editing this file might have no effect, as these # settings are overwritten by your user settings file. [Video] @@ -13,7 +13,7 @@ screen = 0 # Valid values: # OpenGL Rendering Subsystem # Direct3D9 Rendering Subsystem -render system = +render system = # Valid values: # none @@ -169,3 +169,6 @@ ui y multiplier = 1.0 [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false + +[Saves] +character = \ No newline at end of file From bc6fe682c91c81ab0080ca85041f34c90e4c7eb4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Nov 2013 11:39:58 +0100 Subject: [PATCH 038/120] replaced getCurrentCellName function with a more general getCellName function --- apps/openmw/mwbase/world.hpp | 6 +++- apps/openmw/mwscript/interpretercontext.cpp | 3 +- apps/openmw/mwworld/worldimp.cpp | 38 +++++---------------- apps/openmw/mwworld/worldimp.hpp | 6 +++- 4 files changed, 20 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index fe7d8f7ac..37d3c10da 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -149,7 +149,11 @@ namespace MWBase virtual std::vector 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 diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index b8fc9ed47..5639ea208 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -322,8 +322,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 diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5a4192529..7d2da389c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -442,40 +442,20 @@ namespace MWWorld return mGlobalVariables->getGlobals(); } - std::string World::getCurrentCellName () const + std::string World::getCellName (const MWWorld::CellStore *cell) const { - std::string name; + if (!cell) + cell = mWorldScene->getCurrentCell(); - Ptr::CellStore *cell = mWorldScene->getCurrentCell(); - if (cell->mCell->isExterior()) - { - if (cell->mCell->mName != "") - { - name = cell->mCell->mName; - } - else - { - const ESM::Region* region = - MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); - if (region) - name = region->mName; - else - { - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().search("sDefaultCellname"); + if (!cell->mCell->isExterior() || !cell->mCell->mName.empty()) + return cell->mCell->mName; - if (setting && setting->mValue.getType()==ESM::VT_String) - name = setting->mValue.getString(); - } + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - } - } - else - { - name = cell->mCell->mName; - } + if (const ESM::Region* region = store.get().search (cell->mCell->mRegion)) + return region->mName; - return name; + return store.get().find ("sDefaultCellname")->mValue.getString(); } void World::removeRefScript (MWWorld::RefData *ref) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 32ad84865..33f6f1c2f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -213,7 +213,11 @@ namespace MWWorld virtual std::vector getGlobals () const; - virtual std::string getCurrentCellName () const; + virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const; + ///< 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); //< Remove the script attached to ref from mLocalScripts From e6dc927f1163d3933533afaf7797a864830153ee Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Nov 2013 11:49:07 +0100 Subject: [PATCH 039/120] removed duplicates of the cell name function --- apps/openmw/mwgui/windowmanagerimp.cpp | 26 ++++++------------------- apps/openmw/mwstate/statemanagerimp.cpp | 19 +----------------- 2 files changed, 7 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 83325de23..3524c6d70 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -752,29 +752,18 @@ namespace MWGui void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) { + std::string name = MWBase::Environment::get().getWorld()->getCellName (cell); + + mMap->setCellName( name ); + mHud->setCellName( name ); + if (cell->mCell->isExterior()) { - std::string name; - if (cell->mCell->mName != "") - { - name = cell->mCell->mName; + if (!cell->mCell->mName.empty()) mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); - } - else - { - const ESM::Region* region = - MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); - if (region) - name = region->mName; - else - name = getGameSettingString("sDefaultCellname", "Wilderness"); - } mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY()); - mMap->setCellName( name ); - mHud->setCellName( name ); - mMap->setCellPrefix("Cell"); mHud->setCellPrefix("Cell"); mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); @@ -782,12 +771,9 @@ namespace MWGui } else { - mMap->setCellName( cell->mCell->mName ); - mHud->setCellName( cell->mCell->mName ); mMap->setCellPrefix( cell->mCell->mName ); mHud->setCellPrefix( cell->mCell->mName ); } - } void WindowManager::setInteriorMapTexture(const int x, const int y) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 97f8b8e55..8faab1609 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -77,24 +77,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel(); profile.mPlayerClass = player.get()->mBase->mClass; - std::string cellName; - if (player.getCell()->mCell->isExterior()) - { - if (player.getCell()->mCell->mName != "") - cellName = player.getCell()->mCell->mName; - else - { - const ESM::Region* region = - MWBase::Environment::get().getWorld()->getStore().get().search(player.getCell()->mCell->mRegion); - if (region) - cellName = region->mName; - else - cellName = MWBase::Environment::get().getWindowManager()->getGameSettingString("sDefaultCellname", "Wilderness"); - } - } - else - cellName = player.getCell()->mCell->mName; - profile.mPlayerCell = cellName; + profile.mPlayerCell = world.getCellName(); profile.mInGameTime.mGameHour = world.getTimeStamp().getHour(); profile.mInGameTime.mDay = world.getDay(); From 99ea63dc4ab648063e332cb08cb1383c4d043c67 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Nov 2013 12:47:30 +0100 Subject: [PATCH 040/120] factored out code for generating month names --- apps/openmw/mwbase/world.hpp | 7 ++- apps/openmw/mwgui/journalviewmodel.cpp | 46 +++---------------- apps/openmw/mwgui/savegamedialog.cpp | 62 +++----------------------- apps/openmw/mwgui/waitdialog.cpp | 44 +----------------- apps/openmw/mwworld/worldimp.cpp | 30 ++++++++++--- apps/openmw/mwworld/worldimp.hpp | 7 ++- 6 files changed, 47 insertions(+), 149 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 37d3c10da..dd9e20de1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -186,8 +186,11 @@ 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 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. diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 79a77070a..89885d303 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -20,8 +20,6 @@ namespace MWGui { struct JournalViewModelImpl; -static void injectMonthName (std::ostream & os, int month); - struct JournalViewModelImpl : JournalViewModel { typedef KeywordSearch KeywordSearchT; @@ -242,14 +240,14 @@ struct JournalViewModelImpl : JournalViewModel { 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 (); } @@ -349,38 +347,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 (); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 8ec6dbfcf..5f9b6a3c1 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -7,61 +7,12 @@ #include "../mwbase/statemanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwstate/character.hpp" -namespace -{ -std::string getMonth(int m) -{ - std::string month; - 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; - } - return month; -} -} - namespace MWGui { - SaveGameDialog::SaveGameDialog() : WindowModal("openmw_savegame_dialog.layout") , mSaving(true) @@ -225,19 +176,18 @@ namespace MWGui text << asctime(timeinfo) << "\n"; text << "Level " << slot->mProfile.mPlayerLevel << "\n"; text << slot->mProfile.mPlayerCell << "\n"; - //text << "Time played: " << slot->mProfile.mTimePlayed << "\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 << " " - << getMonth(slot->mProfile.mInGameTime.mMonth) - << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); + text + << slot->mProfile.mInGameTime.mDay << " " + << MWBase::Environment::get().getWorld()->getMonthName(slot->mProfile.mInGameTime.mMonth) + << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mInfoText->setCaptionWithReplacing(text.str()); - } } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 2467f6c40..071bb8804 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -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; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7d2da389c..3d64585f9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -450,12 +450,10 @@ namespace MWWorld if (!cell->mCell->isExterior() || !cell->mCell->mName.empty()) return cell->mCell->mName; - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - - if (const ESM::Region* region = store.get().search (cell->mCell->mRegion)) + if (const ESM::Region* region = getStore().get().search (cell->mCell->mRegion)) return region->mName; - return store.get().find ("sDefaultCellname")->mValue.getString(); + return getStore().get().find ("sDefaultCellname")->mValue.getString(); } void World::removeRefScript (MWWorld::RefData *ref) @@ -673,16 +671,36 @@ namespace MWWorld mRendering->skySetDate (mGlobalVariables->getInt ("day"), month); } - int World::getDay() + int World::getDay() const { return mGlobalVariables->getInt("day"); } - int World::getMonth() + int World::getMonth() const { return mGlobalVariables->getInt("month"); } + std::string World::getMonthName (int month) const + { + if (month==-1) + month = getMonth(); + + const int months = 12; + + if (month<0 || month>=months) + return ""; + + static const char *monthNames[months] = + { + "sMonthMorningstar", "sMonthSunsdawn", "sMonthFirstseed", "sMonthRainshand", + "sMonthSecondseed", "sMonthMidyear", "sMonthSunsheight", "sMonthLastseed", + "sMonthHeartfire", "sMonthFrostfall", "sMonthSunsdusk", "sMonthEveningstar" + }; + + return getStore().get().find (monthNames[month])->mValue.getString(); + } + TimeStamp World::getTimeStamp() const { return TimeStamp (mGlobalVariables->getFloat ("gamehour"), diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 33f6f1c2f..08a3182e9 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -251,8 +251,11 @@ namespace MWWorld virtual void setDay (int day); ///< Set in-game time day. - virtual int getDay(); - virtual int getMonth(); + virtual int getDay() const; + virtual int getMonth() const; + + virtual std::string getMonthName (int month = -1) const; + ///< Return name of month (-1: current month) virtual TimeStamp getTimeStamp() const; ///< Return current in-game time stamp. From 71436b11609525d9e9dd6a0ddf7a8db91f60f5ad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Nov 2013 09:10:38 +0100 Subject: [PATCH 041/120] changed interface for global variable access --- apps/openmw/mwbase/world.hpp | 12 +++++-- apps/openmw/mwdialogue/filter.cpp | 2 +- apps/openmw/mwdialogue/journalentry.cpp | 6 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwscript/interpretercontext.cpp | 12 +++---- apps/openmw/mwscript/miscextensions.cpp | 35 ++++++++++++++++----- apps/openmw/mwworld/worldimp.cpp | 18 ++++++++--- apps/openmw/mwworld/worldimp.hpp | 12 +++++-- 8 files changed, 72 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index dd9e20de1..41cacd365 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -140,9 +140,17 @@ 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. diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 11dccde42..c6089c9e4 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -170,7 +170,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: { diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 5ffde5499..dd1ad3f66 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -60,9 +60,9 @@ namespace MWDialogue 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); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3524c6d70..2be88b7f0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1238,7 +1238,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; } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 5639ea208..bbfa77e18 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -127,18 +127,18 @@ 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) @@ -150,7 +150,7 @@ namespace MWScript 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) @@ -162,7 +162,7 @@ namespace MWScript 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) @@ -174,7 +174,7 @@ namespace MWScript 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 InterpreterContext::getGlobals () const diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 35f7a4044..c9d27b09a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -657,6 +657,8 @@ namespace MWScript void printGlobalVars(Interpreter::Runtime &runtime) { + Interpreter::Context& context = runtime.getContext(); + std::stringstream str; str<< "Global variables:"; @@ -664,16 +666,33 @@ namespace MWScript std::vector names = world->getGlobals(); for(size_t i = 0;i < names.size();++i) { - char type = world->getGlobalVariableType(names[i]); - if(type == 's') - str<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 << ""; + } } - runtime.getContext().report(str.str()); + context.report (str.str()); } public: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3d64585f9..afa434cd2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -422,14 +422,24 @@ namespace MWWorld return mWorldScene->hasCellChanged(); } - Globals::Data& World::getGlobalVariable (const std::string& name) + void World::setGlobalInt (const std::string& name, int value) { - return (*mGlobalVariables)[name]; + mGlobalVariables->setInt (name, value); } - Globals::Data World::getGlobalVariable (const std::string& name) const + void World::setGlobalFloat (const std::string& name, float value) { - return (*mGlobalVariables)[name]; + mGlobalVariables->setFloat (name, value); + } + + int World::getGlobalInt (const std::string& name) const + { + return mGlobalVariables->getInt (name); + } + + float World::getGlobalFloat (const std::string& name) const + { + return mGlobalVariables->getFloat (name); } char World::getGlobalVariableType (const std::string& name) const diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 08a3182e9..eda79b433 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -204,9 +204,17 @@ namespace MWWorld virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior); ///< see MWRender::LocalMap::isPositionExplored - virtual Globals::Data& getGlobalVariable (const std::string& name); + virtual void setGlobalInt (const std::string& name, int value); + ///< Set value independently from real type. - virtual Globals::Data getGlobalVariable (const std::string& name) const; + virtual void setGlobalFloat (const std::string& name, float value); + ///< Set value independently from real type. + + virtual int getGlobalInt (const std::string& name) const; + ///< Get value independently from real type. + + virtual float getGlobalFloat (const std::string& name) const; + ///< Get value independently from real type. virtual char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name. From b0eb5938bfdd7ff3a24f219e6722bb2b5b790042 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Nov 2013 09:13:54 +0100 Subject: [PATCH 042/120] removed some redundant code --- apps/openmw/mwscript/interpretercontext.cpp | 28 +++------------------ apps/openmw/mwworld/worldimp.cpp | 18 +++++++++++-- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index bbfa77e18..a977d3440 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -143,45 +143,23 @@ namespace MWScript 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()->setGlobalInt (name, 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()->setGlobalInt (name, 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()->setGlobalFloat (name, value); + MWBase::Environment::get().getWorld()->setGlobalFloat (name, value); } std::vector InterpreterContext::getGlobals () const { MWBase::World *world = MWBase::Environment::get().getWorld(); return world->getGlobals(); - } char InterpreterContext::getGlobalType (const std::string& name) const diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index afa434cd2..0767718b8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -424,12 +424,26 @@ namespace MWWorld void World::setGlobalInt (const std::string& name, int value) { - mGlobalVariables->setInt (name, value); + if (name=="gamehour") + setHour (value); + else if (name=="day") + setDay (value); + else if (name=="month") + setMonth (value); + else + mGlobalVariables->setInt (name, value); } void World::setGlobalFloat (const std::string& name, float value) { - mGlobalVariables->setFloat (name, value); + if (name=="gamehour") + setHour (value); + else if (name=="day") + setDay (value); + else if (name=="month") + setMonth (value); + else + mGlobalVariables->setFloat (name, value); } int World::getGlobalInt (const std::string& name) const From 7e2819c62e8721020ba5459d8a8177e44a36a560 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Nov 2013 09:27:10 +0100 Subject: [PATCH 043/120] store year in saved game profile --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 41cacd365..87a9b5bbc 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -196,6 +196,7 @@ namespace MWBase 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) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 8faab1609..60b19fd46 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -82,7 +82,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot profile.mInGameTime.mGameHour = world.getTimeStamp().getHour(); profile.mInGameTime.mDay = world.getDay(); profile.mInGameTime.mMonth = world.getMonth(); - /// \todo year + profile.mInGameTime.mYear = world.getYear(); /// \todo time played profile.mDescription = description; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0767718b8..1e7b8122f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -705,6 +705,11 @@ namespace MWWorld return mGlobalVariables->getInt("month"); } + int World::getYear() const + { + return mGlobalVariables->getInt("year"); + } + std::string World::getMonthName (int month) const { if (month==-1) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index eda79b433..2b7d157ff 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -261,6 +261,7 @@ namespace MWWorld virtual int getDay() const; virtual int getMonth() const; + virtual int getYear() const; virtual std::string getMonthName (int month = -1) const; ///< Return name of month (-1: current month) From 35e8e2303745dc38ff4180ca5bfdcbfb62ce7456 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Nov 2013 09:33:50 +0100 Subject: [PATCH 044/120] keep track of total play time per character --- apps/openmw/engine.cpp | 3 +++ apps/openmw/mwbase/statemanager.hpp | 2 ++ apps/openmw/mwstate/statemanagerimp.cpp | 12 ++++++++++-- apps/openmw/mwstate/statemanagerimp.hpp | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index bee7fa8fd..7dd3214eb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -117,6 +117,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // update world MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); + + // update game state + MWBase::Environment::get().getStateManager()->update (frametime); } // update GUI diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index f376d72c1..8548a74f7 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -71,6 +71,8 @@ namespace MWBase /// iterator. virtual CharacterIterator characterEnd() = 0; + + virtual void update (float duration) = 0; }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 60b19fd46..a273aced7 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -18,7 +18,7 @@ #include "../mwmechanics/npcstats.hpp" MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::string& game) -: mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves, game) +: mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves, game), mTimePlayed (0) { } @@ -46,6 +46,7 @@ void MWState::StateManager::newGame (bool bypass) MWBase::Environment::get().getJournal()->clear(); mState = State_NoGame; mCharacterManager.clearCurrentCharacter(); + mTimePlayed = 0; } if (!bypass) @@ -83,7 +84,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot profile.mInGameTime.mDay = world.getDay(); profile.mInGameTime.mMonth = world.getMonth(); profile.mInGameTime.mYear = world.getYear(); - /// \todo time played + profile.mTimePlayed = mTimePlayed; profile.mDescription = description; if (!slot) @@ -114,6 +115,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl mCharacterManager.clearCurrentCharacter(); } + mTimePlayed = slot->mProfile.mTimePlayed; + ESM::ESMReader reader; reader.open (slot->mPath.string()); @@ -144,3 +147,8 @@ MWState::StateManager::CharacterIterator MWState::StateManager::characterEnd() { return mCharacterManager.end(); } + +void MWState::StateManager::update (float duration) +{ + mTimePlayed += duration; +} diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 3965632cc..720b1b6b0 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -14,6 +14,7 @@ namespace MWState bool mQuitRequest; State mState; CharacterManager mCharacterManager; + double mTimePlayed; public: @@ -50,6 +51,8 @@ namespace MWState /// iterator. virtual CharacterIterator characterEnd(); + + virtual void update (float duration); }; } From 5aea6ef80f6bce0718b8987afc9c414e9fea59b6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Nov 2013 11:22:34 +0100 Subject: [PATCH 045/120] some clean up for the cleanup code --- apps/openmw/mwstate/statemanagerimp.cpp | 33 +++++++++++++------------ apps/openmw/mwstate/statemanagerimp.hpp | 4 +++ apps/openmw/mwworld/worldimp.cpp | 3 ++- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a273aced7..b750f56fe 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -17,6 +17,18 @@ #include "../mwmechanics/npcstats.hpp" +void MWState::StateManager::cleanup() +{ + if (mState!=State_NoGame) + { + MWBase::Environment::get().getDialogueManager()->clear(); + MWBase::Environment::get().getJournal()->clear(); + mState = State_NoGame; + mCharacterManager.clearCurrentCharacter(); + mTimePlayed = 0; + } +} + MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::string& game) : mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves, game), mTimePlayed (0) { @@ -40,18 +52,10 @@ MWState::StateManager::State MWState::StateManager::getState() const void MWState::StateManager::newGame (bool bypass) { - if (mState!=State_NoGame) - { - MWBase::Environment::get().getDialogueManager()->clear(); - MWBase::Environment::get().getJournal()->clear(); - mState = State_NoGame; - mCharacterManager.clearCurrentCharacter(); - mTimePlayed = 0; - } + cleanup(); if (!bypass) { - /// \todo extract cleanup code MWBase::Environment::get().getWorld()->startNewGame(); MWBase::Environment::get().getWindowManager()->setNewGame (true); } @@ -99,6 +103,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.startRecord ("SAVE"); slot->mProfile.save (writer); writer.endRecord ("SAVE"); + + /// \todo write saved game data + writer.close(); Settings::Manager::setString ("character", "Saves", @@ -107,13 +114,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot void MWState::StateManager::loadGame (const Character *character, const Slot *slot) { - if (mState!=State_NoGame) - { - MWBase::Environment::get().getDialogueManager()->clear(); - MWBase::Environment::get().getJournal()->clear(); - mState = State_NoGame; - mCharacterManager.clearCurrentCharacter(); - } + cleanup(); mTimePlayed = slot->mProfile.mTimePlayed; diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 720b1b6b0..78b578766 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -16,6 +16,10 @@ namespace MWState CharacterManager mCharacterManager; double mTimePlayed; + private: + + void cleanup(); + public: StateManager (const boost::filesystem::path& saves, const std::string& game); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1e7b8122f..d7fdc3bc1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -290,7 +290,6 @@ namespace MWWorld pos.rot[2] = 0; mWorldScene->changeToExteriorCell(pos); - // enable collision if(!mPhysics->toggleCollisionMode()) mPhysics->toggleCollisionMode(); @@ -300,6 +299,7 @@ namespace MWWorld // global variables delete mGlobalVariables; + mGlobalVariables = 0; mGlobalVariables = new Globals (mStore); // set new game mark @@ -308,6 +308,7 @@ namespace MWWorld // we don't want old weather to persist on a new game delete mWeatherManager; + mWeatherManager = 0; mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); MWBase::Environment::get().getScriptManager()->resetGlobalScripts(); From e432ab5e8ace6e4a7e7f03e9635c244e6d66bffc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Nov 2013 11:51:21 +0100 Subject: [PATCH 046/120] fixed static problem in Land recrod save function --- components/esm/loadland.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index ede200d79..bc16c65d3 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -14,7 +14,7 @@ void Land::LandData::save(ESMWriter &esm) esm.writeHNT("VNML", mNormals, sizeof(VNML)); } if (mDataTypes & Land::DATA_VHGT) { - static VHGT offsets; + VHGT offsets; offsets.mHeightOffset = mHeights[0] / HEIGHT_SCALE; offsets.mUnk1 = mUnk1; offsets.mUnk2 = mUnk2; From 750133c0dd18c39c795402ff7148740bb09a7b5e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 30 Nov 2013 11:05:07 +0100 Subject: [PATCH 047/120] one more fix to SavedGame record saving --- components/esm/savedgame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index e98608fe6..7c76f4000 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -33,6 +33,6 @@ void ESM::SavedGame::save (ESMWriter &esm) const for (std::vector::const_iterator iter (mContentFiles.begin()); iter!=mContentFiles.end(); ++iter) - esm.writeHNCString ("DEPE", *iter); + esm.writeHNString ("DEPE", *iter); } From aebc2791a50f09d518a0cc40f35286f90d813c38 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 30 Nov 2013 11:08:41 +0100 Subject: [PATCH 048/120] fixed selecting current character based on value stored in settings --- apps/openmw/mwgui/savegamedialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 5f9b6a3c1..d1e047c09 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -65,7 +65,10 @@ namespace MWGui if (mCurrentCharacter == &*it || (!mCurrentCharacter && directory==Misc::StringUtils::lowerCase ( it->begin()->mPath.parent_path().filename().string()))) + { + mCurrentCharacter = &*it; mCharacterSelection->setIndexSelected(mCharacterSelection->getItemCount()-1); + } } } From 9d64c92d33efb3aac740e3cbe5f8afa8607434f9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 30 Nov 2013 11:57:33 +0100 Subject: [PATCH 049/120] store text in journal entries --- apps/openmw/mwdialogue/journalentry.cpp | 16 +++++++++++----- apps/openmw/mwdialogue/journalentry.hpp | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index dd1ad3f66..20963eb79 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -14,21 +14,27 @@ namespace MWDialogue JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId) : mTopic (topic), mInfoId (infoId) - {} - - std::string JournalEntry::getText (const MWWorld::ESMStore& store) const { const ESM::Dialogue *dialogue = - store.get().find (mTopic); + MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); for (std::vector::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); } + std::string JournalEntry::getText (const MWWorld::ESMStore& store) const + { + return mText; + } + JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index) { return JournalEntry (topic, idFromIndex (topic, index)); diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index 9d009b48b..ab4adece9 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -15,6 +15,7 @@ namespace MWDialogue { std::string mTopic; std::string mInfoId; + std::string mText; JournalEntry(); From eed46960fe7a769b979f91a1fafa3ba7e0af13d7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 30 Nov 2013 12:02:56 +0100 Subject: [PATCH 050/120] some spelling fixes --- apps/openmw/mwdialogue/quest.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/quest.hpp b/apps/openmw/mwdialogue/quest.hpp index 3afa81fac..566eef6bf 100644 --- a/apps/openmw/mwdialogue/quest.hpp +++ b/apps/openmw/mwdialogue/quest.hpp @@ -5,7 +5,7 @@ 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; @@ -23,7 +23,7 @@ namespace MWDialogue 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; From 177aab536dff53175b01241984296fca386e669b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 30 Nov 2013 12:41:18 +0100 Subject: [PATCH 051/120] storing topic name in MWDialogue::Topic (avoids a lookup in the GUI and also serves as preparation for better localisation support in OpenMW 1.1) --- apps/openmw/mwdialogue/quest.cpp | 2 +- apps/openmw/mwdialogue/quest.hpp | 2 +- apps/openmw/mwdialogue/topic.cpp | 11 ++++++++++- apps/openmw/mwdialogue/topic.hpp | 3 ++- apps/openmw/mwgui/journalviewmodel.cpp | 9 ++------- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index 5e2739be1..75dcaa028 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -16,7 +16,7 @@ namespace MWDialogue : Topic (topic), mIndex (0), mFinished (false) {} - const std::string Quest::getName() const + std::string Quest::getName() const { const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); diff --git a/apps/openmw/mwdialogue/quest.hpp b/apps/openmw/mwdialogue/quest.hpp index 566eef6bf..c6f0d0bec 100644 --- a/apps/openmw/mwdialogue/quest.hpp +++ b/apps/openmw/mwdialogue/quest.hpp @@ -17,7 +17,7 @@ namespace MWDialogue Quest (const std::string& topic); - const std::string getName() const; + virtual std::string getName() const; ///< May be an empty string int getIndex() const; diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index 3253b20d6..fc8545b5e 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -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().find (topic)->mId) {} Topic::~Topic() @@ -27,6 +31,11 @@ namespace MWDialogue mEntries.push_back (entry.mInfoId); } + std::string Topic::getName() const + { + return mName; + } + Topic::TEntryIter Topic::begin() const { return mEntries.begin(); diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp index c3f0baabc..17601977a 100644 --- a/apps/openmw/mwdialogue/topic.hpp +++ b/apps/openmw/mwdialogue/topic.hpp @@ -19,6 +19,7 @@ namespace MWDialogue protected: std::string mTopic; + std::string mName; TEntryContainer mEntries; // info-IDs public: @@ -34,7 +35,7 @@ namespace MWDialogue /// /// \note Redundant entries are ignored. - std::string const & getName () const { return mTopic; } + virtual std::string getName () const; TEntryIter begin() const; ///< Iterator pointing to the begin of the journal for this topic. diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 89885d303..e35d35013 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -288,9 +288,7 @@ struct JournalViewModelImpl : JournalViewModel void visitTopicName (TopicId topicId, boost::function visitor) const { MWDialogue::Topic const & topic = * reinterpret_cast (topicId); - // This is to get the correct case for the topic - const std::string& name = MWBase::Environment::get().getWorld()->getStore().get().find(topic.getName())->mId; - visitor (toUtf8Span (name)); + visitor (toUtf8Span (topic.getName())); } void visitTopicNamesStartingWith (char character, boost::function < void (TopicId , Utf8Span) > visitor) const @@ -302,10 +300,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().find(i->first)->mId; - - visitor (TopicId (&i->second), toUtf8Span (name)); + visitor (TopicId (&i->second), toUtf8Span (i->second.getName())); } } From 43f5f16731cb195497f4832426222930213b7185 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 30 Nov 2013 12:54:44 +0100 Subject: [PATCH 052/120] removed a todo comment --- apps/openmw/mwgui/journalviewmodel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index e35d35013..049515ac0 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -317,7 +317,6 @@ 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()); } From eec9821cd8345235e95479a46819e9b0a06ea2f9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 30 Nov 2013 14:41:12 +0100 Subject: [PATCH 053/120] added records for storing journals in saved game files --- components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 2 ++ components/esm/journalentry.cpp | 35 +++++++++++++++++++++++++++++++++ components/esm/journalentry.hpp | 35 +++++++++++++++++++++++++++++++++ components/esm/queststate.cpp | 19 ++++++++++++++++++ components/esm/queststate.hpp | 24 ++++++++++++++++++++++ 6 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 components/esm/journalentry.cpp create mode 100644 components/esm/journalentry.hpp create mode 100644 components/esm/queststate.cpp create mode 100644 components/esm/queststate.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ce5965be1..3223ab1a7 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame + savedgame journalentry queststate ) add_component_dir (misc diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 5a5ef9f1c..03091d9d8 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -85,6 +85,8 @@ enum RecNameInts // format 0 - saved games REC_SAVE = 0x45564153, + REC_JOUR = 0x524f55a4, + REC_QUES = 0x53455551, // format 1 REC_FILT = 0x544C4946 diff --git a/components/esm/journalentry.cpp b/components/esm/journalentry.cpp new file mode 100644 index 000000000..514bf3597 --- /dev/null +++ b/components/esm/journalentry.cpp @@ -0,0 +1,35 @@ + +#include "journalentry.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::JournalEntry::load (ESMReader &esm) +{ + esm.getHNOT (mType, "JETY"); + mTopic = esm.getHNString ("YETO"); + mInfo = esm.getHNString ("YEIN"); + mText = esm.getHNString ("TEXT"); + + if (mType==Type_Journal) + { + esm.getHNT (mDay, "JEDA"); + esm.getHNT (mMonth, "JEMO"); + esm.getHNT (mDayOfMonth, "JEDM"); + } +} + +void ESM::JournalEntry::save (ESMWriter &esm) const +{ + esm.writeHNT ("JETY", mType); + esm.writeHNString ("YETO", mTopic); + esm.writeHNString ("YEIN", mInfo); + esm.writeHNString ("TEXT", mText); + + if (mType==Type_Journal) + { + esm.writeHNT ("JEDA", mDay); + esm.writeHNT ("JEMO", mMonth); + esm.writeHNT ("JEDM", mDayOfMonth); + } +} \ No newline at end of file diff --git a/components/esm/journalentry.hpp b/components/esm/journalentry.hpp new file mode 100644 index 000000000..94808dde6 --- /dev/null +++ b/components/esm/journalentry.hpp @@ -0,0 +1,35 @@ +#ifndef OPENMW_ESM_JOURNALENTRY_H +#define OPENMW_ESM_JOURNALENTRY_H + +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct JournalEntry + { + enum Type + { + Type_Journal = 0, + Type_Topic = 1, + Type_Quest = 2 + }; + + int mType; + std::string mTopic; + std::string mInfo; + std::string mText; + int mDay; // time stamp + int mMonth; + int mDayOfMonth; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif diff --git a/components/esm/queststate.cpp b/components/esm/queststate.cpp new file mode 100644 index 000000000..5931e8b90 --- /dev/null +++ b/components/esm/queststate.cpp @@ -0,0 +1,19 @@ + +#include "queststate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::QuestState::load (ESMReader &esm) +{ + mTopic = esm.getHNString ("YETO"); + esm.getHNOT (mState, "QSTAT"); + esm.getHNOT (mFinished, "QFIN"); +} + +void ESM::QuestState::save (ESMWriter &esm) const +{ + esm.writeHNString ("YETO", mTopic); + esm.writeHNT ("QSTAT", mState); + esm.writeHNT ("QFIN", mFinished); +} \ No newline at end of file diff --git a/components/esm/queststate.hpp b/components/esm/queststate.hpp new file mode 100644 index 000000000..1769336f2 --- /dev/null +++ b/components/esm/queststate.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_ESM_QUESTSTATE_H +#define OPENMW_ESM_QUESTSTATE_H + +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct QuestState + { + std::string mTopic; + int mState; + unsigned char mFinished; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif \ No newline at end of file From 16e2d67b1f6fb47fe0336b23e0b064a940949b23 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 1 Dec 2013 13:32:11 +0100 Subject: [PATCH 054/120] added overloaded start/endRecord functions to ESMWriter --- apps/opencs/model/doc/savingstages.cpp | 19 ++++--------------- apps/opencs/model/doc/savingstages.hpp | 4 ++-- apps/opencs/model/world/refiddata.hpp | 9 ++------- components/esm/esmwriter.cpp | 20 ++++++++++++++++++++ components/esm/esmwriter.hpp | 2 ++ 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 8e9bcfc0d..d7df2117d 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -133,16 +133,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector (&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::vectormModified.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 (&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); } } } diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index ca5586511..b8eb0a3b3 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -104,10 +104,10 @@ namespace CSMDoc /// \todo make endianess agnostic (change ESMWriter interface?) type += reinterpret_cast (&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) { diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 9595ab23b..761c7feaa 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -136,15 +136,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 (&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) { diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index 069d75c7b..f38591b7b 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -88,6 +88,16 @@ namespace ESM assert(mRecords.back().size == 0); } + void ESMWriter::startRecord (uint32_t name, uint32_t flags) + { + std::string type; + for (int i=0; i<4; ++i) + /// \todo make endianess agnostic + type += reinterpret_cast (&name)[i]; + + startRecord (type, flags); + } + void ESMWriter::startSubRecord(const std::string& name) { writeName(name); @@ -117,6 +127,16 @@ namespace ESM } + void ESMWriter::endRecord (uint32_t name) + { + std::string type; + for (int i=0; i<4; ++i) + /// \todo make endianess agnostic + type += reinterpret_cast (&name)[i]; + + endRecord (type); + } + void ESMWriter::writeHNString(const std::string& name, const std::string& data) { startSubRecord(name); diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index d6646471b..94f0a1004 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -90,8 +90,10 @@ class ESMWriter } void startRecord(const std::string& name, uint32_t flags = 0); + void startRecord(uint32_t name, uint32_t flags = 0); void startSubRecord(const std::string& name); void endRecord(const std::string& name); + void endRecord(uint32_t name); void writeHString(const std::string& data); void writeHCString(const std::string& data); void writeName(const std::string& data); From b273f9e3874e5f52cc8025e76f47559bdb91e93a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 1 Dec 2013 14:44:27 +0100 Subject: [PATCH 055/120] splitting JournalEntry into Entry and JournalEntry --- apps/openmw/mwdialogue/journalentry.cpp | 20 +++++++++++++------ apps/openmw/mwdialogue/journalentry.hpp | 26 +++++++++++++++---------- apps/openmw/mwgui/journalviewmodel.cpp | 5 ++--- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 20963eb79..b83d19f8c 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -10,13 +10,13 @@ namespace MWDialogue { - JournalEntry::JournalEntry() {} + Entry::Entry() {} - JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId) - : mTopic (topic), mInfoId (infoId) + Entry::Entry (const std::string& topic, const std::string& infoId) + : mInfoId (infoId) { const ESM::Dialogue *dialogue = - MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); + MWBase::Environment::get().getWorld()->getStore().get().find (topic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) @@ -27,14 +27,21 @@ namespace MWDialogue return; } - throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + mTopic); + throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + topic); } - std::string JournalEntry::getText (const MWWorld::ESMStore& store) const + std::string Entry::getText() const { return mText; } + + JournalEntry::JournalEntry() {} + + JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId) + : Entry (topic, infoId), mTopic (topic) + {} + JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index) { return JournalEntry (topic, idFromIndex (topic, index)); @@ -55,6 +62,7 @@ namespace MWDialogue throw std::runtime_error ("unknown journal index for topic " + topic); } + StampedJournalEntry::StampedJournalEntry() : mDay (0), mMonth (0), mDayOfMonth (0) {} diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index ab4adece9..b51c2d2d4 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -3,26 +3,32 @@ #include -namespace MWWorld -{ - struct ESMStore; -} - namespace MWDialogue { - /// \brief A quest or dialogue entry - struct JournalEntry + /// \brief Basic quest/dialogue/topic entry + struct Entry { - std::string mTopic; std::string mInfoId; std::string mText; + Entry(); + + Entry (const std::string& topic, const std::string& infoId); + + std::string getText() const; + }; + + /// \brief A dialogue entry + /// + /// Same as entry, but store TopicID + struct JournalEntry : public Entry + { + std::string mTopic; + JournalEntry(); JournalEntry (const std::string& topic, const std::string& infoId); - std::string getText (const MWWorld::ESMStore& store) const; - static JournalEntry makeFromQuest (const std::string& topic, int index); static std::string idFromIndex (const std::string& topic, int index); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 049515ac0..7ee24a288 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -233,7 +233,7 @@ struct JournalViewModelImpl : JournalViewModel std::string getText () const { - return itr->getText(MWBase::Environment::get().getWorld()->getStore()); + return itr->getText(); } Utf8Span timestamp () const @@ -317,8 +317,7 @@ struct JournalViewModelImpl : JournalViewModel std::string getText () const { - return mTopic.getEntry (*itr).getText(MWBase::Environment::get().getWorld()->getStore()); - + return mTopic.getEntry (*itr).getText(); } Utf8Span source () const From 0f971163f709e31f98810b8ecf205faea19f96e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 1 Dec 2013 14:50:25 +0100 Subject: [PATCH 056/120] use Entry instead of plain string for topic and quest entries --- apps/openmw/mwdialogue/quest.cpp | 4 ++-- apps/openmw/mwdialogue/topic.cpp | 6 +----- apps/openmw/mwdialogue/topic.hpp | 4 ++-- apps/openmw/mwgui/journalviewmodel.cpp | 4 ++-- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index 75dcaa028..12763effd 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -82,9 +82,9 @@ 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 } } diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index fc8545b5e..f40e585dc 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -24,11 +24,7 @@ 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.mInfoId); + mEntries.push_back (entry); // we want slicing here } std::string Topic::getName() const diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp index 17601977a..ffc5e9470 100644 --- a/apps/openmw/mwdialogue/topic.hpp +++ b/apps/openmw/mwdialogue/topic.hpp @@ -13,14 +13,14 @@ namespace MWDialogue { public: - typedef std::vector TEntryContainer; + typedef std::vector TEntryContainer; typedef TEntryContainer::const_iterator TEntryIter; protected: std::string mTopic; std::string mName; - TEntryContainer mEntries; // info-IDs + TEntryContainer mEntries; public: diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 7ee24a288..ad0af3f05 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -268,7 +268,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 (this, i)); } } @@ -317,7 +317,7 @@ struct JournalViewModelImpl : JournalViewModel std::string getText () const { - return mTopic.getEntry (*itr).getText(); + return itr->getText(); } Utf8Span source () const From 7d8e3ac6518e4bf3449a58dce83c6ee1abcf0f00 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Dec 2013 13:51:44 +0100 Subject: [PATCH 057/120] fixed QuestState::load/save --- components/esm/queststate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/queststate.cpp b/components/esm/queststate.cpp index 5931e8b90..e93826725 100644 --- a/components/esm/queststate.cpp +++ b/components/esm/queststate.cpp @@ -7,13 +7,13 @@ void ESM::QuestState::load (ESMReader &esm) { mTopic = esm.getHNString ("YETO"); - esm.getHNOT (mState, "QSTAT"); + esm.getHNOT (mState, "QSTA"); esm.getHNOT (mFinished, "QFIN"); } void ESM::QuestState::save (ESMWriter &esm) const { esm.writeHNString ("YETO", mTopic); - esm.writeHNT ("QSTAT", mState); + esm.writeHNT ("QSTA", mState); esm.writeHNT ("QFIN", mFinished); } \ No newline at end of file From 2293b92efe5534b97c021683d444a18584b6212c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Dec 2013 14:28:46 +0100 Subject: [PATCH 058/120] storing and loading the journal --- apps/openmw/mwbase/journal.hpp | 14 +++ apps/openmw/mwdialogue/journalentry.cpp | 33 ++++++ apps/openmw/mwdialogue/journalentry.hpp | 17 +++ apps/openmw/mwdialogue/journalimp.cpp | 135 ++++++++++++++++++++++-- apps/openmw/mwdialogue/journalimp.hpp | 10 ++ apps/openmw/mwdialogue/quest.cpp | 13 +++ apps/openmw/mwdialogue/quest.hpp | 9 ++ apps/openmw/mwdialogue/topic.cpp | 10 ++ apps/openmw/mwdialogue/topic.hpp | 13 ++- apps/openmw/mwstate/statemanagerimp.cpp | 42 ++++++-- 10 files changed, 278 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index 51e51edda..81b4ba0b4 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -5,10 +5,18 @@ #include #include +#include + #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; }; } diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index b83d19f8c..7828d18ad 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -30,11 +32,19 @@ namespace MWDialogue 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() {} @@ -42,6 +52,16 @@ namespace MWDialogue : 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) { return JournalEntry (topic, idFromIndex (topic, index)); @@ -72,6 +92,19 @@ 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()->getGlobalInt ("dayspassed"); diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index b51c2d2d4..18d022aab 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -3,6 +3,11 @@ #include +namespace ESM +{ + struct JournalEntry; +} + namespace MWDialogue { /// \brief Basic quest/dialogue/topic entry @@ -15,7 +20,11 @@ namespace MWDialogue 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 @@ -29,6 +38,10 @@ namespace MWDialogue JournalEntry (const std::string& topic, const std::string& infoId); + JournalEntry (const ESM::JournalEntry& record); + + void write (ESM::JournalEntry& entry) const; + static JournalEntry makeFromQuest (const std::string& topic, int index); static std::string idFromIndex (const std::string& topic, int index); @@ -46,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); }; } diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 23cfb5fdd..b9359aae6 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -1,6 +1,13 @@ #include "journalimp.hpp" +#include + +#include +#include +#include +#include + #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" @@ -26,6 +33,22 @@ namespace MWDialogue return iter->second; } + Topic& Journal::getTopic (const std::string& id) + { + TTopicContainer::iterator iter = mTopics.find (id); + + if (iter==mTopics.end()) + { + std::pair result + = mTopics.insert (std::make_pair (id, Topic (id))); + + iter = result.first; + } + + return iter->second; + } + + Journal::Journal() {} @@ -66,17 +89,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 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 +133,104 @@ namespace MWDialogue { return mTopics.end(); } + + int Journal::countSavedGameRecords() const + { + int count = static_cast (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); + + 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); + + mQuests.insert (std::make_pair (record.mTopic, record)); + } + } } diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index f4f8eb1c2..54c49df01 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -15,8 +15,12 @@ namespace MWDialogue TQuestContainer mQuests; TTopicContainer mTopics; + private: + Quest& getQuest (const std::string& id); + Topic& getTopic (const std::string& id); + public: Journal(); @@ -55,6 +59,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); }; } diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index 12763effd..14c5c1da9 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -1,6 +1,8 @@ #include "quest.hpp" +#include + #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" @@ -16,6 +18,10 @@ namespace MWDialogue : Topic (topic), mIndex (0), mFinished (false) {} + 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 = @@ -87,4 +93,11 @@ namespace MWDialogue mEntries.push_back (entry); // we want slicing here } + + void Quest::write (ESM::QuestState& state) const + { + state.mTopic = getTopic(); + state.mState = mIndex; + state.mFinished = mFinished; + } } diff --git a/apps/openmw/mwdialogue/quest.hpp b/apps/openmw/mwdialogue/quest.hpp index c6f0d0bec..40824f398 100644 --- a/apps/openmw/mwdialogue/quest.hpp +++ b/apps/openmw/mwdialogue/quest.hpp @@ -3,6 +3,11 @@ #include "topic.hpp" +namespace ESM +{ + struct QuestState; +} + namespace MWDialogue { /// \brief A quest in progress or a completed quest @@ -17,6 +22,8 @@ namespace MWDialogue Quest (const std::string& topic); + Quest (const ESM::QuestState& state); + virtual std::string getName() const; ///< May be an empty string @@ -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; }; } diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index f40e585dc..0e546f43b 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -27,6 +27,16 @@ namespace MWDialogue mEntries.push_back (entry); // we want slicing here } + 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; diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp index ffc5e9470..02fa6d524 100644 --- a/apps/openmw/mwdialogue/topic.hpp +++ b/apps/openmw/mwdialogue/topic.hpp @@ -6,6 +6,11 @@ #include "journalentry.hpp" +namespace ESM +{ + struct JournalEntry; +} + namespace MWDialogue { /// \brief Collection of seen responses for a topic @@ -35,7 +40,13 @@ namespace MWDialogue /// /// \note Redundant entries are ignored. - virtual std::string getName () const; + 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. diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index b750f56fe..5bc313f37 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -99,11 +99,17 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot std::ofstream stream (slot->mPath.string().c_str()); ESM::ESMWriter writer; writer.setFormat (ESM::Header::CurrentFormat); - writer.save (stream); - writer.startRecord ("SAVE"); - slot->mProfile.save (writer); - writer.endRecord ("SAVE"); + writer.setRecordCount ( + 1+ // saved game header + MWBase::Environment::get().getJournal()->countSavedGameRecords()); + writer.save (stream); + + writer.startRecord (ESM::REC_SAVE); + slot->mProfile.save (writer); + writer.endRecord (ESM::REC_SAVE); + + MWBase::Environment::get().getJournal()->write (writer); /// \todo write saved game data writer.close(); @@ -121,10 +127,32 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl ESM::ESMReader reader; reader.open (slot->mPath.string()); - reader.getRecName(); // don't need to read that here - reader.getRecHeader(); + while (reader.hasMoreRecs()) + { + ESM::NAME n = reader.getRecName(); + reader.getRecHeader(); - /// \todo read saved game data + 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; + + default: + + // ignore invalid records + /// \todo log error + reader.skipRecord(); + } + } mCharacterManager.setCurrentCharacter(character); From e269c9e6898314f7c6201b30f3f439f7b7321d64 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Dec 2013 14:30:18 +0100 Subject: [PATCH 059/120] changed a few sub record names to make them more unique --- components/esm/savedgame.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 7c76f4000..55b17289c 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -9,10 +9,10 @@ unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; void ESM::SavedGame::load (ESMReader &esm) { - mPlayerName = esm.getHNString("PNAM"); - esm.getHNOT (mPlayerLevel, "PLEV"); - mPlayerClass = esm.getHNString("PCLA"); - mPlayerCell = esm.getHNString("PCEL"); + mPlayerName = esm.getHNString("PLNA"); + esm.getHNOT (mPlayerLevel, "PLLE"); + mPlayerClass = esm.getHNString("PLCL"); + mPlayerCell = esm.getHNString("PLCE"); esm.getHNT (mInGameTime, "TSTM", 16); esm.getHNT (mTimePlayed, "TIME"); mDescription = esm.getHNString ("DESC"); @@ -23,10 +23,10 @@ void ESM::SavedGame::load (ESMReader &esm) void ESM::SavedGame::save (ESMWriter &esm) const { - esm.writeHNString ("PNAM", mPlayerName); - esm.writeHNT ("PLEV", mPlayerLevel); - esm.writeHNString ("PCLA", mPlayerClass); - esm.writeHNString ("PCEL", mPlayerCell); + esm.writeHNString ("PLNA", mPlayerName); + esm.writeHNT ("PLLE", mPlayerLevel); + esm.writeHNString ("PLCL", mPlayerClass); + esm.writeHNString ("PLCE", mPlayerCell); esm.writeHNT ("TSTM", mInGameTime, 16); esm.writeHNT ("TIME", mTimePlayed); esm.writeHNString ("DESC", mDescription); From 34cdd2bb1f63a38dbe4741c817259f6cd986eea2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Dec 2013 14:39:54 +0100 Subject: [PATCH 060/120] deal with dialogue/info records that don't exist anymore --- apps/openmw/mwdialogue/journalimp.cpp | 44 +++++++++++++++++++-------- apps/openmw/mwdialogue/journalimp.hpp | 2 ++ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index b9359aae6..f24a93356 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -48,6 +48,22 @@ namespace MWDialogue 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().search (topicId)) + { + if (infoId.empty()) + return true; + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->mId == infoId) + return true; + } + + return false; + } Journal::Journal() {} @@ -207,30 +223,32 @@ namespace MWDialogue ESM::JournalEntry record; record.load (reader); - switch (record.mType) - { - case ESM::JournalEntry::Type_Quest: + if (isThere (record.mTopic, record.mInfo)) + switch (record.mType) + { + case ESM::JournalEntry::Type_Quest: - getQuest (record.mTopic).insertEntry (record); - break; + getQuest (record.mTopic).insertEntry (record); + break; - case ESM::JournalEntry::Type_Journal: + case ESM::JournalEntry::Type_Journal: - mJournal.push_back (record); - break; + mJournal.push_back (record); + break; - case ESM::JournalEntry::Type_Topic: + case ESM::JournalEntry::Type_Topic: - getTopic (record.mTopic).insertEntry (record); - break; - } + getTopic (record.mTopic).insertEntry (record); + break; + } } else if (type==ESM::REC_QUES) { ESM::QuestState record; record.load (reader); - mQuests.insert (std::make_pair (record.mTopic, record)); + if (isThere (record.mTopic)) + mQuests.insert (std::make_pair (record.mTopic, record)); } } } diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index 54c49df01..86091a12d 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -21,6 +21,8 @@ namespace MWDialogue Topic& getTopic (const std::string& id); + bool isThere (const std::string& topicId, const std::string& infoId = "") const; + public: Journal(); From 63721682f6724c84de992f15d301ff4e47a66a80 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Dec 2013 15:19:13 +0100 Subject: [PATCH 061/120] GUI fix: previous character was selected when saving new character --- apps/openmw/mwgui/savegamedialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index d1e047c09..04461fef9 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -63,7 +63,7 @@ namespace MWGui mCharacterSelection->addItem (title.str()); if (mCurrentCharacter == &*it || - (!mCurrentCharacter && directory==Misc::StringUtils::lowerCase ( + (!mCurrentCharacter && !mSaving && directory==Misc::StringUtils::lowerCase ( it->begin()->mPath.parent_path().filename().string()))) { mCurrentCharacter = &*it; From 537b2efe8ebb3d4b3ee29aee5cee69cbdcd007a7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Dec 2013 12:49:25 +0100 Subject: [PATCH 062/120] first round of cleaning up world cleanup --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/refdata.cpp | 15 +++++++++-- apps/openmw/mwworld/refdata.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 36 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 2 ++ 6 files changed, 38 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 87a9b5bbc..837b4c23e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -96,6 +96,8 @@ namespace MWBase virtual void startNewGame() = 0; + virtual void clear() = 0; + virtual OEngine::Render::Fader* getFader() = 0; ///< \ŧodo remove this function. Rendering details should not be exposed. diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 5bc313f37..09e574e84 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -23,6 +23,7 @@ void MWState::StateManager::cleanup() { MWBase::Environment::get().getDialogueManager()->clear(); MWBase::Environment::get().getJournal()->clear(); + MWBase::Environment::get().getWorld()->clear(); mState = State_NoGame; mCharacterManager.clearCurrentCharacter(); mTimePlayed = 0; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index c1a3ae785..87d0efe19 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -32,6 +32,17 @@ namespace MWWorld mCustomData = 0; } + RefData::RefData() + : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0) + { + for (int i=0; i<3; ++i) + { + mLocalRotation.rot[i] = 0; + mPosition.pos[i] = 0; + mPosition.rot[i] = 0; + } + } + RefData::RefData (const ESM::CellRef& cellRef) : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0) @@ -88,7 +99,7 @@ namespace MWWorld static const std::string empty; return empty; } - + return mBaseNode->getName(); } @@ -120,7 +131,7 @@ namespace MWWorld { if(count == 0) MWBase::Environment::get().getWorld()->removeRefScript(this); - + mCount = count; } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index d5701efc5..07841e470 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -48,6 +48,8 @@ namespace MWWorld public: + RefData(); + /// @param cellRef Used to copy constant data such as position into this class where it can /// be altered without effecting the original data. This makes it possible /// to reset the position as the orignal data is still held in the CellRef diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d7fdc3bc1..509aee983 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -258,26 +258,12 @@ namespace MWWorld void World::startNewGame() { - mWorldScene->changeToVoid(); - - mStore.clearDynamic(); - mStore.setUp(); - - mCells.clear(); - // Rebuild player setupPlayer(); - MWWorld::Ptr player = mPlayer->getPlayer(); - - // removes NpcStats, ContainerStore etc - player.getRefData().setCustomData(NULL); renderPlayer(); mRendering->resetCamera(); - // make sure to do this so that local scripts from items that were in the players inventory are removed - mLocalScripts.clear(); - MWBase::Environment::get().getWindowManager()->updatePlayer(); ESM::Position pos; @@ -290,10 +276,6 @@ namespace MWWorld pos.rot[2] = 0; mWorldScene->changeToExteriorCell(pos); - // enable collision - if(!mPhysics->toggleCollisionMode()) - mPhysics->toggleCollisionMode(); - // FIXME: should be set to 1, but the sound manager won't pause newly started sounds mPlayIntro = 2; @@ -314,6 +296,24 @@ namespace MWWorld MWBase::Environment::get().getScriptManager()->resetGlobalScripts(); } + void World::clear() + { + mLocalScripts.clear(); + + // enable collision + if (!mPhysics->toggleCollisionMode()) + mPhysics->toggleCollisionMode(); + + mWorldScene->changeToVoid(); + + if (mPlayer) + mPlayer->getPlayer().getRefData() = RefData(); + + mStore.clearDynamic(); + mStore.setUp(); + + mCells.clear(); + } void World::ensureNeededRecords() { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 2b7d157ff..1cee7d50f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -160,6 +160,8 @@ namespace MWWorld virtual void startNewGame(); + virtual void clear(); + virtual OEngine::Render::Fader* getFader(); ///< \ŧodo remove this function. Rendering details should not be exposed. From e818d43bc3d541b1d253e3db9800850c1dba6f98 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Dec 2013 13:21:26 +0100 Subject: [PATCH 063/120] removed an outdated typedef and some dead code --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwgui/referenceinterface.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/objects.cpp | 2 +- apps/openmw/mwrender/actors.cpp | 2 +- apps/openmw/mwrender/debugging.cpp | 8 ++-- apps/openmw/mwrender/localmap.cpp | 6 +-- apps/openmw/mwrender/objects.cpp | 6 +-- apps/openmw/mwrender/renderingmanager.cpp | 14 +++---- apps/openmw/mwscript/cellextensions.cpp | 6 +-- apps/openmw/mwsound/soundmanagerimp.cpp | 4 +- apps/openmw/mwworld/cells.cpp | 46 ++++++++++----------- apps/openmw/mwworld/localscripts.cpp | 14 +++---- apps/openmw/mwworld/ptr.hpp | 5 +-- apps/openmw/mwworld/scene.cpp | 10 ++--- apps/openmw/mwworld/scene.hpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 50 ++++++----------------- apps/openmw/mwworld/worldimp.hpp | 6 +-- 19 files changed, 82 insertions(+), 109 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 837b4c23e..36c970839 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -351,7 +351,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; diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 86a85be18..9ba7154c2 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -18,7 +18,7 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2be88b7f0..887bf2c68 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -750,7 +750,7 @@ namespace MWGui mCompanionWindow->onFrame(); } - void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) + void WindowManager::changeCell(MWWorld::CellStore* cell) { std::string name = MWBase::Environment::get().getWorld()->getCellName (cell); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cc431a7b0..66d8de6f8 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -302,7 +302,7 @@ namespace MWMechanics } } - void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) + void Actors::dropActors (const MWWorld::CellStore *cellStore) { PtrControllerMap::iterator iter = mActors.begin(); while(iter != mActors.end()) diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index 694987855..8a1e6ee6b 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -45,7 +45,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()) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 1bdec6e19..5eecfaf35 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -126,7 +126,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();) { diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index b318c2d56..2b61e109b 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -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().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()) { diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 5f4128978..f70533d22 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -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 diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index fd81baf6e..852c25044 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -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]; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 57e00d76c..cd309df47 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -221,7 +221,7 @@ OEngine::Render::Fader* RenderingManager::getFader() return mRendering.getFader(); } -void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) +void RenderingManager::removeCell (MWWorld::CellStore *store) { mObjects.removeCell(store); mActors.removeCell(store); @@ -238,7 +238,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(); @@ -410,7 +410,7 @@ void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt) mOcclusionQuery->setActive(false); } -void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) +void RenderingManager::waterAdded (MWWorld::CellStore *store) { const MWWorld::Store &lands = MWBase::Environment::get().getWorld()->getStore().get(); @@ -501,7 +501,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); @@ -554,7 +554,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); @@ -651,7 +651,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()) { @@ -670,7 +670,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); } diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 316f912da..ce39cfa65 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -125,7 +125,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); runtime.push (cell->mWaterLevel); } }; @@ -138,7 +138,7 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; - MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); if (cell->mCell->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); @@ -156,7 +156,7 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; - MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); if (cell->mCell->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 372be8393..c1c891ab4 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -399,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()) @@ -595,7 +595,7 @@ namespace MWSound soundDuration=snditer->first->mFadeOutTime; snditer->first->setVolume(snditer->first->mVolume - soundDuration / snditer->first->mFadeOutTime * snditer->first->mVolume); - snditer->first->mFadeOutTime -= soundDuration; + snditer->first->mFadeOutTime -= soundDuration; } snditer->first->update(); ++snditer; diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 37c4b6a3f..2cb22cf59 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -7,28 +7,28 @@ #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::map::iterator result = mInteriors.find (Misc::StringUtils::lowerCase(cell->mName)); + std::map::iterator result = mInteriors.find (Misc::StringUtils::lowerCase(cell->mName)); if (result==mInteriors.end()) { - result = mInteriors.insert (std::make_pair (Misc::StringUtils::lowerCase(cell->mName), Ptr::CellStore (cell))).first; + result = mInteriors.insert (std::make_pair (Misc::StringUtils::lowerCase(cell->mName), CellStore (cell))).first; } return &result->second; } else { - std::map, Ptr::CellStore>::iterator result = + std::map, 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; } @@ -40,11 +40,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); @@ -61,13 +61,13 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector& reader) : mStore (store), mReader (reader), - mIdCache (40, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable + mIdCache (40, std::pair ("", (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, Ptr::CellStore>::iterator result = + std::map, CellStore>::iterator result = mExteriors.find (std::make_pair (x, y)); if (result==mExteriors.end()) @@ -92,7 +92,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); @@ -101,19 +101,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::iterator result = mInteriors.find (lowerName); + std::map::iterator result = mInteriors.find (lowerName); if (result==mInteriors.end()) { const ESM::Cell *cell = mStore.get().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); } @@ -121,13 +121,13 @@ 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::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) { std::string lowerCase = Misc::StringUtils::lowerCase(name); @@ -208,7 +208,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 >::iterator iter (mIdCache.begin()); + for (std::vector >::iterator iter (mIdCache.begin()); iter!=mIdCache.end(); ++iter) if (iter->first==name && iter->second) { @@ -218,7 +218,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) } // Then check cells that are already listed - for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); + for (std::map, CellStore>::iterator iter = mExteriors.begin(); iter!=mExteriors.end(); ++iter) { Ptr ptr = getPtrAndCache (name, iter->second); @@ -226,7 +226,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) return ptr; } - for (std::map::iterator iter = mInteriors.begin(); + for (std::map::iterator iter = mInteriors.begin(); iter!=mInteriors.end(); ++iter) { Ptr ptr = getPtrAndCache (name, iter->second); @@ -240,7 +240,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); @@ -250,7 +250,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); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 5ec5ca9b5..997e9e32c 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -11,7 +11,7 @@ namespace { template void listCellScripts (MWWorld::LocalScripts& localScripts, - MWWorld::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) + MWWorld::CellRefList& cellRefList, MWWorld::CellStore *cell) { for (typename MWWorld::CellRefList::List::iterator iter ( cellRefList.mList.begin()); @@ -27,15 +27,15 @@ namespace // Adds scripts for items in containers (containers/npcs/creatures) template void listCellScriptsCont (MWWorld::LocalScripts& localScripts, - MWWorld::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) + MWWorld::CellRefList& cellRefList, MWWorld::CellStore *cell) { for (typename MWWorld::CellRefList::List::iterator iter ( cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) { - - MWWorld::Ptr containerPtr (&*iter, cell); - + + MWWorld::Ptr containerPtr (&*iter, cell); + MWWorld::ContainerStore& container = MWWorld::Class::get(containerPtr).getContainerStore(containerPtr); for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) { @@ -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 >::iterator iter = mScripts.begin(); diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index e5352da28..8b70382d0 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -14,9 +14,6 @@ namespace MWWorld { public: - typedef MWWorld::CellStore CellStore; - ///< \deprecated - MWWorld::LiveCellRefBase *mRef; CellStore *mCell; ContainerStore *mContainerStore; @@ -59,7 +56,7 @@ namespace MWWorld RefData& getRefData() const; - Ptr::CellStore *getCell() const + CellStore *getCell() const { assert(mCell); return mCell; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 254ad98cf..348f01dc5 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -116,7 +116,7 @@ namespace MWWorld mActiveCells.erase(*iter); } - void Scene::loadCell (Ptr::CellStore *cell, Loading::Listener* loadingListener) + void Scene::loadCell (CellStore *cell, Loading::Listener* loadingListener) { std::pair result = mActiveCells.insert(cell); @@ -161,7 +161,7 @@ namespace MWWorld MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell); } - void Scene::playerCellChange(MWWorld::CellStore *cell, const ESM::Position& pos, bool adjustPlayerPos) + void Scene::playerCellChange(CellStore *cell, const ESM::Position& pos, bool adjustPlayerPos) { MWBase::World *world = MWBase::Environment::get().getWorld(); world->getPlayer().setCell(cell); @@ -441,7 +441,7 @@ namespace MWWorld changeCell (x, y, position, true); } - Ptr::CellStore* Scene::getCurrentCell () + CellStore* Scene::getCurrentCell () { return mCurrentCell; } @@ -451,7 +451,7 @@ namespace MWWorld mCellChanged = false; } - int Scene::countRefs (const Ptr::CellStore& cell) + int Scene::countRefs (const CellStore& cell) { return cell.mActivators.mList.size() + cell.mPotions.mList.size() @@ -475,7 +475,7 @@ namespace MWWorld + cell.mNpcs.mList.size(); } - void Scene::insertCell (Ptr::CellStore &cell, bool rescale, Loading::Listener* loadingListener) + void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) { // Loop through all references in the cell insertCellRefList(mRendering, cell.mActivators, cell, *mPhysics, rescale, loadingListener); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index e3edad352..b7bb944ed 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -56,9 +56,9 @@ namespace MWWorld void playerCellChange (CellStore *cell, const ESM::Position& position, bool adjustPlayerPos = true); - void insertCell (Ptr::CellStore &cell, bool rescale, Loading::Listener* loadingListener); + void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); - int countRefs (const Ptr::CellStore& cell); + int countRefs (const CellStore& cell); public: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 509aee983..b2d18a27f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -48,30 +48,6 @@ using namespace Ogre; namespace { -/* // NOTE this code is never instantiated (proper copy in localscripts.cpp), - // so this commented out to not produce syntactic errors - - template - void listCellScripts (const MWWorld::ESMStore& store, - MWWorld::CellRefList& cellRefList, MWWorld::LocalScripts& localScripts, - MWWorld::Ptr::CellStore *cell) - { - for (typename MWWorld::CellRefList::List::iterator iter ( - cellRefList.mList.begin()); - iter!=cellRefList.mList.end(); ++iter) - { - if (!iter->mBase->mScript.empty() && iter->mData.getCount()) - { - if (const ESM::Script *script = store.get().find (iter->mBase->mScript)) - { - iter->mData.setLocals (*script); - - localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); - } - } - } - } -*/ template MWWorld::LiveCellRef *searchViaHandle (const std::string& handle, MWWorld::CellRefList& refList) @@ -125,7 +101,7 @@ namespace MWWorld LoadersContainer mLoaders; }; - Ptr World::getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell) + Ptr World::getPtrViaHandle (const std::string& handle, CellStore& cell) { if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mActivators)) @@ -388,12 +364,12 @@ namespace MWWorld return &mFallback; } - Ptr::CellStore *World::getExterior (int x, int y) + CellStore *World::getExterior (int x, int y) { return mCells.getExterior (x, y); } - Ptr::CellStore *World::getInterior (const std::string& name) + CellStore *World::getInterior (const std::string& name) { return mCells.getInterior (name); } @@ -504,7 +480,7 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); iter!=mWorldScene->getActiveCells().end(); ++iter) { - Ptr::CellStore* cellstore = *iter; + CellStore* cellstore = *iter; Ptr ptr = mCells.getPtr (name, *cellstore, true); if (!ptr.isEmpty()) @@ -537,7 +513,7 @@ namespace MWWorld for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); iter!=mWorldScene->getActiveCells().end(); ++iter) { - Ptr::CellStore* cellstore = *iter; + CellStore* cellstore = *iter; Ptr ptr = getPtrViaHandle (handle, *cellstore); if (!ptr.isEmpty()) @@ -547,7 +523,7 @@ namespace MWWorld return MWWorld::Ptr(); } - void World::addContainerScripts(const Ptr& reference, Ptr::CellStore * cell) + void World::addContainerScripts(const Ptr& reference, CellStore * cell) { if( reference.getTypeName()==typeid (ESM::Container).name() || reference.getTypeName()==typeid (ESM::NPC).name() || @@ -1400,7 +1376,7 @@ namespace MWWorld bool World::isCellExterior() const { - Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); + CellStore *currentCell = mWorldScene->getCurrentCell(); if (currentCell) { return currentCell->mCell->isExterior(); @@ -1410,7 +1386,7 @@ namespace MWWorld bool World::isCellQuasiExterior() const { - Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); + CellStore *currentCell = mWorldScene->getCurrentCell(); if (currentCell) { if (!(currentCell->mCell->mData.mFlags & ESM::Cell::QuasiEx)) @@ -1587,7 +1563,7 @@ namespace MWWorld void World::dropObjectOnGround (const Ptr& actor, const Ptr& object, int amount) { - MWWorld::Ptr::CellStore* cell = actor.getCell(); + MWWorld::CellStore* cell = actor.getCell(); ESM::Position pos = actor.getRefData().getPosition(); @@ -1684,7 +1660,7 @@ namespace MWWorld } bool - World::isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const + World::isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const { if (!(cell->mCell->mData.mFlags & ESM::Cell::HasWater)) { return false; @@ -1704,9 +1680,9 @@ namespace MWWorld return mRendering->vanityRotateCamera(rot); } - void World::setCameraDistance(float dist, bool adjust, bool override) + void World::setCameraDistance(float dist, bool adjust, bool override_) { - return mRendering->setCameraDistance(dist, adjust, override);; + return mRendering->setCameraDistance(dist, adjust, override_); } void World::setupPlayer() @@ -1734,7 +1710,7 @@ namespace MWWorld int World::canRest () { - Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); + CellStore *currentCell = mWorldScene->getCurrentCell(); Ptr player = mPlayer->getPlayer(); RefData &refdata = player.getRefData(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1cee7d50f..b8a61c471 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -79,7 +79,7 @@ namespace MWWorld World (const World&); World& operator= (const World&); - Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cellStore); + Ptr getPtrViaHandle (const std::string& handle, CellStore& cellStore); int mActivationDistanceOverride; std::string mFacedHandle; @@ -121,7 +121,7 @@ namespace MWWorld float getObjectActivationDistance (); void removeContainerScripts(const Ptr& reference); - void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell); + void addContainerScripts(const Ptr& reference, CellStore* cell); void PCDropped (const Ptr& item); void processDoors(float duration); @@ -413,7 +413,7 @@ namespace MWWorld ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; - virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const; + virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { From ce624e024b0225afe3815ef65a4f9ce3b506bd55 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Dec 2013 14:03:25 +0100 Subject: [PATCH 064/120] make sure player record stays in place across cleanups --- apps/openmw/mwworld/store.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index c25197319..233f2f702 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -292,6 +292,20 @@ namespace MWWorld } }; + template <> + inline void Store::clearDynamic() + { + std::map::iterator iter = mDynamic.begin(); + + while (iter!=mDynamic.end()) + if (iter->first=="player") + ++iter; + else + mDynamic.erase (iter++); + + mShared.clear(); + } + template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); From a7b42b867bb559511886973d3b8ecfaa986588d3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Dec 2013 14:18:43 +0100 Subject: [PATCH 065/120] more cleanup --- apps/openmw/mwworld/worldimp.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b2d18a27f..539c959b3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -238,7 +238,6 @@ namespace MWWorld setupPlayer(); renderPlayer(); - mRendering->resetCamera(); MWBase::Environment::get().getWindowManager()->updatePlayer(); @@ -289,6 +288,15 @@ namespace MWWorld mStore.setUp(); mCells.clear(); + + mProjectiles.clear(); + mDoorStates.clear(); + + mGodMode = false; + mSky = true; + mTeleportEnabled = true; + mPlayIntro = 0; + mFacedDistance = FLT_MAX; } void World::ensureNeededRecords() @@ -1701,6 +1709,7 @@ namespace MWWorld { mRendering->renderPlayer(mPlayer->getPlayer()); mPhysics->addActor(mPlayer->getPlayer()); + mRendering->resetCamera(); } void World::setupExternalRendering (MWRender::ExternalRendering& rendering) From 8b7889f8e54d1e834ee983a6ac8cb18dfced7c2c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Dec 2013 14:22:08 +0100 Subject: [PATCH 066/120] setup player after loading a saved game --- apps/openmw/mwstate/statemanagerimp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 09e574e84..9df1e2dc0 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -161,6 +161,10 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl Settings::Manager::setString ("character", "Saves", slot->mPath.parent_path().filename().string()); + + MWBase::Environment::get().getWorld()->setupPlayer(); + MWBase::Environment::get().getWorld()->renderPlayer(); + MWBase::Environment::get().getWindowManager()->updatePlayer(); } MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) From ee6ddc34045cdd8207c14971ad0b310856ea5f34 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Dec 2013 14:56:30 +0100 Subject: [PATCH 067/120] block saving while chargen is in progress --- apps/openmw/mwgui/mainmenu.cpp | 3 ++- apps/openmw/mwstate/statemanagerimp.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index ff8ab8c93..da1992474 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -97,7 +97,8 @@ namespace MWGui MWBase::Environment::get().getStateManager()->characterEnd()) buttons.push_back("loadgame"); - if (state==MWBase::StateManager::State_Running) + if (state==MWBase::StateManager::State_Running && + MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) buttons.push_back("savegame"); buttons.push_back("options"); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9df1e2dc0..293a9e232 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -60,6 +60,8 @@ void MWState::StateManager::newGame (bool bypass) MWBase::Environment::get().getWorld()->startNewGame(); MWBase::Environment::get().getWindowManager()->setNewGame (true); } + else + MWBase::Environment::get().getWorld()->setGlobalInt ("chargenstate", -1); mState = State_Running; } From 14eff87339a27c5a30c4e3f47791eed8678d52b5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Dec 2013 11:17:14 +0100 Subject: [PATCH 068/120] removed some junk from ESM store --- apps/openmw/mwworld/esmstore.hpp | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index ebb086cee..d5da5a866 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -24,10 +24,8 @@ namespace MWWorld Store mBirthSigns; Store mClasses; Store mClothes; - Store mContChange; Store mContainers; Store mCreatures; - Store mCreaChange; Store mDialogs; Store mDoors; Store mEnchants; @@ -40,7 +38,6 @@ namespace MWWorld Store mLockpicks; Store mMiscItems; Store mNpcs; - Store mNpcChange; Store mProbes; Store mRaces; Store mRegions; @@ -103,7 +100,7 @@ namespace MWWorld { // Cell store needs access to this for tracking moved references mCells.mEsmStore = this; - + mStores[ESM::REC_ACTI] = &mActivators; mStores[ESM::REC_ALCH] = &mPotions; mStores[ESM::REC_APPA] = &mAppas; @@ -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; @@ -287,11 +281,6 @@ namespace MWWorld return mClothes; } - template <> - inline const Store &ESMStore::get() const { - return mContChange; - } - template <> inline const Store &ESMStore::get() const { return mContainers; @@ -302,11 +291,6 @@ namespace MWWorld return mCreatures; } - template <> - inline const Store &ESMStore::get() const { - return mCreaChange; - } - template <> inline const Store &ESMStore::get() const { return mDialogs; @@ -367,11 +351,6 @@ namespace MWWorld return mNpcs; } - template <> - inline const Store &ESMStore::get() const { - return mNpcChange; - } - template <> inline const Store &ESMStore::get() const { return mProbes; From 674931a8512240e6cd080a17b1a039937370d4ad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Dec 2013 14:24:14 +0100 Subject: [PATCH 069/120] remove terminating 0 from strings read from ESM records --- components/esm/esmreader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index f02ed2d6e..4e1860bab 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -302,6 +302,9 @@ std::string ESMReader::getString(int size) char *ptr = &mBuffer[0]; getExact(ptr, size); + if (size>0 && ptr[size-1]==0) + --size; + // Convert to UTF8 and return if (mEncoder) return mEncoder->getUtf8(ptr, size); From 1c13a9037adc13a50e40c5f66650c5fe509b7a04 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Dec 2013 13:17:28 +0100 Subject: [PATCH 070/120] save and load dynamic records --- apps/openmw/mwbase/mechanicsmanager.hpp | 36 ++++++------- apps/openmw/mwbase/world.hpp | 7 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 +++ .../mwmechanics/mechanicsmanagerimp.hpp | 20 ++++---- apps/openmw/mwstate/statemanagerimp.cpp | 29 +++++++++-- apps/openmw/mwworld/esmstore.cpp | 50 +++++++++++++++++++ apps/openmw/mwworld/esmstore.hpp | 7 +++ apps/openmw/mwworld/store.hpp | 33 ++++++++++++ apps/openmw/mwworld/worldimp.cpp | 22 ++++++++ apps/openmw/mwworld/worldimp.hpp | 6 +++ 10 files changed, 189 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 3ab234de1..eeeab77e8 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -101,28 +101,30 @@ namespace MWBase float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; ///< Perform a persuasion action on NPC - virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; - ///< Forces an object to refresh its animation state. + virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; + ///< Forces an object to refresh its animation state. - virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; - ///< Run animation for a MW-reference. Calls to this function for references that are currently not - /// in the scene should be ignored. - /// - /// \param mode 0 normal, 1 immediate start, 2 immediate loop - /// \param count How many times the animation should be run + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + ///< Run animation for a MW-reference. Calls to this function for references that are currently not + /// in the scene should be ignored. + /// + /// \param mode 0 normal, 1 immediate start, 2 immediate loop + /// \param count How many times the animation should be run - virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the scene should be ignored. + virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; + ///< Skip the animation for the given MW-reference for one frame. Calls to this function for + /// references that are currently not in the scene should be ignored. - virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0; + virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0; - /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently - /// paused we may want to do it manually (after equipping permanent enchantment) - virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0; + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently + /// paused we may want to do it manually (after equipping permanent enchantment) + virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0; - virtual void toggleAI() = 0; - virtual bool isAIActive() = 0; + virtual void toggleAI() = 0; + virtual bool isAIActive() = 0; + + virtual void playerLoaded() = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7d1678a11..717012f72 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -30,6 +30,7 @@ namespace OEngine namespace ESM { class ESMReader; + class ESMWriter; struct Position; struct Cell; struct Class; @@ -98,6 +99,12 @@ namespace MWBase 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) = 0; + virtual OEngine::Render::Fader* getFader() = 0; ///< \ŧodo remove this function. Rendering details should not be exposed. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 1316baaeb..b6a7a7b75 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -701,4 +701,12 @@ namespace MWMechanics { return mAI; } + + void MechanicsManager::playerLoaded() + { + mUpdatePlayer = true; + mClassSelected = true; + mRaceSelected = true; + mAI = true; + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index ec03b457b..ebc879d26 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -98,18 +98,20 @@ namespace MWMechanics void toLower(std::string npcFaction); ///< Perform a persuasion action on NPC - virtual void forceStateUpdate(const MWWorld::Ptr &ptr); + virtual void forceStateUpdate(const MWWorld::Ptr &ptr); - virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); - virtual void skipAnimation(const MWWorld::Ptr& ptr); - virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName); + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + virtual void skipAnimation(const MWWorld::Ptr& ptr); + virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName); - /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently - /// paused we may want to do it manually (after equipping permanent enchantment) - virtual void updateMagicEffects (const MWWorld::Ptr& ptr); + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently + /// 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 toggleAI(); + virtual bool isAIActive(); + + virtual void playerLoaded(); }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 293a9e232..94219b8fc 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -11,6 +11,7 @@ #include "../mwbase/journal.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -103,8 +104,10 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot ESM::ESMWriter writer; writer.setFormat (ESM::Header::CurrentFormat); writer.setRecordCount ( - 1+ // saved game header - MWBase::Environment::get().getJournal()->countSavedGameRecords()); + 1 // saved game header + +MWBase::Environment::get().getJournal()->countSavedGameRecords() + +MWBase::Environment::get().getWorld()->countSavedGameRecords() + ); writer.save (stream); @@ -113,7 +116,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.endRecord (ESM::REC_SAVE); MWBase::Environment::get().getJournal()->write (writer); - /// \todo write saved game data + MWBase::Environment::get().getWorld()->write (writer); writer.close(); @@ -149,6 +152,19 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl 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: + + MWBase::Environment::get().getWorld()->readRecord (reader, n.val); + break; + default: // ignore invalid records @@ -167,6 +183,13 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl MWBase::Environment::get().getWorld()->setupPlayer(); MWBase::Environment::get().getWorld()->renderPlayer(); MWBase::Environment::get().getWindowManager()->updatePlayer(); + MWBase::Environment::get().getMechanicsManager()->playerLoaded(); + + // for testing purpose only + ESM::Position pos; + pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); } MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index f1bff11a2..cb4e441fc 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -139,4 +139,54 @@ 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); + mNpcs.write (writer); + mSpells.write (writer); + mWeapons.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_NPC_: + case ESM::REC_SPEL: + case ESM::REC_WEAP: + + mStores[type]->read (reader); + return true; + + default: + + return false; + } + } + } // end namespace diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index d5da5a866..e6730c307 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -209,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 <> diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 233f2f702..df957408d 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -6,6 +6,8 @@ #include #include +#include + #include "recordcmp.hpp" namespace MWWorld @@ -18,10 +20,16 @@ namespace MWWorld virtual void listIdentifier(std::vector &list) const {} virtual size_t getSize() const = 0; + virtual int getDynamicSize() const { return 0; } virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} + + virtual void write (ESM::ESMWriter& writer) const {} + + virtual void read (ESM::ESMReader& reader) {} + ///< Read into dynamic storage }; template @@ -212,6 +220,11 @@ namespace MWWorld return mShared.size(); } + int getDynamicSize() const + { + return mDynamic.size(); + } + void listIdentifier(std::vector &list) const { list.reserve(list.size() + getSize()); typename std::vector::const_iterator it = mShared.begin(); @@ -290,6 +303,26 @@ namespace MWWorld bool erase(const T &item) { return erase(item.mId); } + + void write (ESM::ESMWriter& writer) const + { + for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); + ++iter) + { + writer.startRecord (T::sRecordId); + writer.writeHNString ("NAME", iter->second.mId); + iter->second.save (writer); + writer.endRecord (T::sRecordId); + } + } + + void read (ESM::ESMReader& reader) + { + T record; + record.mId = reader.getHNString ("NAME"); + record.load (reader); + insert (record); + } }; template <> diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 82b2301db..bfcd0ae1c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -282,7 +282,10 @@ namespace MWWorld mWorldScene->changeToVoid(); if (mPlayer) + { + mPlayer->setCell (0); mPlayer->getPlayer().getRefData() = RefData(); + } mStore.clearDynamic(); mStore.setUp(); @@ -299,6 +302,25 @@ namespace MWWorld mFacedDistance = FLT_MAX; } + int World::countSavedGameRecords() const + { + return mStore.countSavedGameRecords(); + } + + void World::write (ESM::ESMWriter& writer) const + { + mStore.write (writer); + } + + void World::readRecord (ESM::ESMReader& reader, int32_t type) + { + if (!mStore.readRecord (reader, type)) + { + /// \todo handle other world state records + + } + } + void World::ensureNeededRecords() { if (!mStore.get().search("sCompanionShare")) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b09b42e94..40245b78d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -171,6 +171,12 @@ namespace MWWorld virtual void clear(); + virtual int countSavedGameRecords() const; + + virtual void write (ESM::ESMWriter& writer) const; + + virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual OEngine::Render::Fader* getFader(); ///< \ŧodo remove this function. Rendering details should not be exposed. From 1fdd43bbb75f516b990ae995df9ef0dedaa901b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 10 Dec 2013 12:31:18 +0100 Subject: [PATCH 071/120] removed a redundant new --- apps/openmw/mwworld/worldimp.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bfcd0ae1c..c4615c099 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -255,9 +255,7 @@ namespace MWWorld mPlayIntro = 2; // global variables - delete mGlobalVariables; - mGlobalVariables = 0; - mGlobalVariables = new Globals (mStore); + *mGlobalVariables = Globals (mStore); // set new game mark mGlobalVariables->setInt ("chargenstate", 1); From 51bfa5cde3be379ceb1ebc541bbb830dc05c8f68 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 10 Dec 2013 15:09:58 +0100 Subject: [PATCH 072/120] rewrote global variable storage (using ESM variant type now) --- apps/openmw/mwworld/globals.cpp | 132 ++++++------------------------- apps/openmw/mwworld/globals.hpp | 49 ++++-------- apps/openmw/mwworld/worldimp.cpp | 75 +++++++++--------- apps/openmw/mwworld/worldimp.hpp | 3 +- 4 files changed, 80 insertions(+), 179 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index a905f8aae..19bfa1529 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -7,15 +7,14 @@ namespace MWWorld { - std::vector Globals::getGlobals () const + std::vector Globals::getGlobals() const { - std::vector retval; - Collection::const_iterator it; - for(it = mVariables.begin(); it != mVariables.end(); ++it){ - retval.push_back(it->first); - } + std::vector ids; - return retval; + for (Collection::const_iterator iter = mVariables.begin(); iter!=mVariables.end(); ++iter) + ids.push_back (iter->first); + + return ids; } Globals::Collection::const_iterator Globals::find (const std::string& name) const @@ -38,112 +37,27 @@ namespace MWWorld return iter; } - Globals::Globals (const MWWorld::ESMStore& store) + void Globals::fill (const MWWorld::ESMStore& store) { - const MWWorld::Store &globals = store.get(); - MWWorld::Store::iterator iter = globals.begin(); - for (; iter != globals.end(); ++iter) + mVariables.clear(); + + const MWWorld::Store& globals = store.get(); + + for (MWWorld::Store::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 +67,13 @@ 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 ' '; + } } } - diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index 681bd560e..587dd2092 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace MWWorld { @@ -13,49 +14,29 @@ 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 > Collection; - private: - + + typedef std::map Collection; + Collection mVariables; // type, value - + Collection::const_iterator find (const std::string& name) const; Collection::iterator find (const std::string& name); - - public: - - Globals (const MWWorld::ESMStore& store); - - 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. - + public: + + const ESM::Variant& operator[] (const std::string& name) const; + + 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 getGlobals () const; + std::vector getGlobals() const; + + void fill (const MWWorld::ESMStore& store); + ///< Replace variables with variables from \a store with default values. }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c4615c099..7e9647167 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -172,9 +172,9 @@ namespace MWWorld { if (mSky && (isCellExterior() || isCellQuasiExterior())) { - mRendering->skySetHour (mGlobalVariables->getFloat ("gamehour")); - mRendering->skySetDate (mGlobalVariables->getInt ("day"), - mGlobalVariables->getInt ("month")); + mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); + mRendering->skySetDate (mGlobalVariables["day"].getInteger(), + mGlobalVariables["month"].getInteger()); mRendering->skyEnable(); } @@ -187,7 +187,7 @@ namespace MWWorld const std::vector& contentFiles, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride) - : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), + : mPlayer (0), mLocalScripts (mStore), mSky (true), mCells (mStore, mEsm), mActivationDistanceOverride (mActivationDistanceOverride), mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true), mLevitationEnabled(false), @@ -227,7 +227,7 @@ namespace MWWorld mStore.setUp(); mStore.movePlayerRecord(); - mGlobalVariables = new Globals (mStore); + mGlobalVariables.fill (mStore); mWorldScene = new Scene(*mRendering, mPhysics); } @@ -254,12 +254,9 @@ namespace MWWorld // FIXME: should be set to 1, but the sound manager won't pause newly started sounds mPlayIntro = 2; - // global variables - *mGlobalVariables = Globals (mStore); - // set new game mark - mGlobalVariables->setInt ("chargenstate", 1); - mGlobalVariables->setInt ("pcrace", 3); + mGlobalVariables["chargenstate"].setInteger (1); + mGlobalVariables["pcrace"].setInteger (3); // we don't want old weather to persist on a new game delete mWeatherManager; @@ -298,6 +295,8 @@ namespace MWWorld mTeleportEnabled = true; mPlayIntro = 0; mFacedDistance = FLT_MAX; + + mGlobalVariables.fill (mStore); } int World::countSavedGameRecords() const @@ -358,7 +357,6 @@ namespace MWWorld { delete mWeatherManager; delete mWorldScene; - delete mGlobalVariables; delete mRendering; delete mPhysics; @@ -436,7 +434,7 @@ namespace MWWorld else if (name=="month") setMonth (value); else - mGlobalVariables->setInt (name, value); + mGlobalVariables[name].setInteger (value); } void World::setGlobalFloat (const std::string& name, float value) @@ -448,27 +446,27 @@ namespace MWWorld else if (name=="month") setMonth (value); else - mGlobalVariables->setFloat (name, value); + mGlobalVariables[name].setFloat (value); } int World::getGlobalInt (const std::string& name) const { - return mGlobalVariables->getInt (name); + return mGlobalVariables[name].getInteger(); } float World::getGlobalFloat (const std::string& name) const { - return mGlobalVariables->getFloat (name); + return mGlobalVariables[name].getFloat(); } char World::getGlobalVariableType (const std::string& name) const { - return mGlobalVariables->getType (name); + return mGlobalVariables.getType (name); } - std::vector World::getGlobals () const + std::vector World::getGlobals() const { - return mGlobalVariables->getGlobals(); + return mGlobalVariables.getGlobals(); } std::string World::getCellName (const MWWorld::CellStore *cell) const @@ -618,14 +616,15 @@ namespace MWWorld mWeatherManager->advanceTime (hours); - hours += mGlobalVariables->getFloat ("gamehour"); + hours += mGlobalVariables["gamehour"].getFloat(); setHour (hours); int days = hours / 24; if (days>0) - mGlobalVariables->setInt ("dayspassed", days + mGlobalVariables->getInt ("dayspassed")); + mGlobalVariables["dayspassed"].setInteger ( + days + mGlobalVariables["dayspassed"].getInteger()); } void World::setHour (double hour) @@ -637,14 +636,14 @@ namespace MWWorld hour = std::fmod (hour, 24); - mGlobalVariables->setFloat ("gamehour", hour); + mGlobalVariables["gamehour"].setFloat (hour); mRendering->skySetHour (hour); mWeatherManager->setHour (hour); if (days>0) - setDay (days + mGlobalVariables->getInt ("day")); + setDay (days + mGlobalVariables["day"].getInteger()); } void World::setDay (int day) @@ -652,7 +651,7 @@ namespace MWWorld if (day<1) day = 1; - int month = mGlobalVariables->getInt ("month"); + int month = mGlobalVariables["month"].getInteger(); while (true) { @@ -667,14 +666,14 @@ namespace MWWorld else { month = 0; - mGlobalVariables->setInt ("year", mGlobalVariables->getInt ("year")+1); + mGlobalVariables["year"].setInteger (mGlobalVariables["year"].getInteger()+1); } day -= days; } - mGlobalVariables->setInt ("day", day); - mGlobalVariables->setInt ("month", month); + mGlobalVariables["day"].setInteger (day); + mGlobalVariables["month"].setInteger (month); mRendering->skySetDate (day, month); @@ -691,30 +690,30 @@ namespace MWWorld int days = getDaysPerMonth (month); - if (mGlobalVariables->getInt ("day")>days) - mGlobalVariables->setInt ("day", days); + if (mGlobalVariables["day"].getInteger()>days) + mGlobalVariables["day"].setInteger (days); - mGlobalVariables->setInt ("month", month); + mGlobalVariables["month"].setInteger (month); if (years>0) - mGlobalVariables->setInt ("year", years+mGlobalVariables->getInt ("year")); + mGlobalVariables["year"].setInteger (years+mGlobalVariables["year"].getInteger()); - mRendering->skySetDate (mGlobalVariables->getInt ("day"), month); + mRendering->skySetDate (mGlobalVariables["day"].getInteger(), month); } int World::getDay() const { - return mGlobalVariables->getInt("day"); + return mGlobalVariables["day"].getInteger(); } int World::getMonth() const { - return mGlobalVariables->getInt("month"); + return mGlobalVariables["month"].getInteger(); } int World::getYear() const { - return mGlobalVariables->getInt("year"); + return mGlobalVariables["year"].getInteger(); } std::string World::getMonthName (int month) const @@ -739,8 +738,8 @@ namespace MWWorld TimeStamp World::getTimeStamp() const { - return TimeStamp (mGlobalVariables->getFloat ("gamehour"), - mGlobalVariables->getInt ("dayspassed")); + return TimeStamp (mGlobalVariables["gamehour"].getFloat(), + mGlobalVariables["dayspassed"].getInteger()); } bool World::toggleSky() @@ -776,7 +775,7 @@ namespace MWWorld float World::getTimeScaleFactor() const { - return mGlobalVariables->getFloat ("timescale"); + return mGlobalVariables["timescale"].getFloat(); } void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) @@ -1267,7 +1266,7 @@ namespace MWWorld if (Misc::StringUtils::ciEqual (ids[i], record.mRace)) break; - mGlobalVariables->setInt ("pcrace", (i == ids.size()) ? 0 : i+1); + mGlobalVariables["pcrace"].setInteger (i == ids.size() ? 0 : i+1); const ESM::NPC *player = mPlayer->getPlayer().get()->mBase; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 40245b78d..92c99733e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -11,6 +11,7 @@ #include "localscripts.hpp" #include "timestamp.hpp" #include "fallback.hpp" +#include "globals.hpp" #include "../mwbase/world.hpp" @@ -64,7 +65,7 @@ namespace MWWorld std::vector mEsm; MWWorld::ESMStore mStore; LocalScripts mLocalScripts; - MWWorld::Globals *mGlobalVariables; + MWWorld::Globals mGlobalVariables; MWWorld::PhysicsSystem *mPhysics; bool mSky; From b38bfe1f214aa39cf1e7f183b3b77ff2f39c9f8c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 10 Dec 2013 15:22:38 +0100 Subject: [PATCH 073/120] removed a redundant function for listing global variables --- apps/openmw/mwbase/world.hpp | 2 -- apps/openmw/mwscript/interpretercontext.cpp | 16 +++++++++++++--- apps/openmw/mwscript/miscextensions.cpp | 5 +++-- apps/openmw/mwworld/globals.cpp | 10 ---------- apps/openmw/mwworld/globals.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 5 ----- apps/openmw/mwworld/worldimp.hpp | 2 -- 7 files changed, 16 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 717012f72..740114aff 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -164,8 +164,6 @@ namespace MWBase virtual char getGlobalVariableType (const std::string& name) const = 0; ///< Return ' ', if there is no global variable with this name. - virtual std::vector getGlobals () const = 0; - virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const = 0; ///< Return name of the cell. /// diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index a977d3440..aedaec208 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -156,10 +156,20 @@ namespace MWScript MWBase::Environment::get().getWorld()->setGlobalFloat (name, value); } - std::vector InterpreterContext::getGlobals () const + std::vector InterpreterContext::getGlobals() const { - MWBase::World *world = MWBase::Environment::get().getWorld(); - return world->getGlobals(); + std::vector ids; + + const MWWorld::Store& globals = + MWBase::Environment::get().getWorld()->getStore().get(); + + for (MWWorld::Store::iterator iter = globals.begin(); iter!=globals.end(); + ++iter) + { + ids.push_back (iter->mId); + } + + return ids; } char InterpreterContext::getGlobalType (const std::string& name) const diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index d7b147970..8ca97d288 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -652,13 +652,14 @@ namespace MWScript void printGlobalVars(Interpreter::Runtime &runtime) { - Interpreter::Context& context = runtime.getContext(); + InterpreterContext& context = + static_cast (runtime.getContext()); std::stringstream str; str<< "Global variables:"; MWBase::World *world = MWBase::Environment::get().getWorld(); - std::vector names = world->getGlobals(); + std::vector names = context.getGlobals(); for(size_t i = 0;i < names.size();++i) { char type = world->getGlobalVariableType (names[i]); diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 19bfa1529..d8e96ddc3 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -7,16 +7,6 @@ namespace MWWorld { - std::vector Globals::getGlobals() const - { - std::vector ids; - - for (Collection::const_iterator iter = mVariables.begin(); iter!=mVariables.end(); ++iter) - ids.push_back (iter->first); - - return ids; - } - Globals::Collection::const_iterator Globals::find (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index 587dd2092..ad140b0c1 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -33,8 +33,6 @@ namespace MWWorld char getType (const std::string& name) const; ///< If there is no global variable with this name, ' ' is returned. - std::vector getGlobals() const; - void fill (const MWWorld::ESMStore& store); ///< Replace variables with variables from \a store with default values. }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7e9647167..c4e63fad0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -464,11 +464,6 @@ namespace MWWorld return mGlobalVariables.getType (name); } - std::vector World::getGlobals() const - { - return mGlobalVariables.getGlobals(); - } - std::string World::getCellName (const MWWorld::CellStore *cell) const { if (!cell) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 92c99733e..845668449 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -237,8 +237,6 @@ namespace MWWorld virtual char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name. - virtual std::vector getGlobals () const; - virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const; ///< Return name of the cell. /// From fc37c77a9101972374cddbbe82d6079aa3468c2d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Dec 2013 12:19:25 +0100 Subject: [PATCH 074/120] store global variables in saved game files --- apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/globals.cpp | 40 +++++++++++++++++++++++++ apps/openmw/mwworld/globals.hpp | 18 +++++++++++ apps/openmw/mwworld/worldimp.cpp | 11 ++++--- 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 94219b8fc..a8f5631a0 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -161,6 +161,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl case ESM::REC_NPC_: case ESM::REC_SPEL: case ESM::REC_WEAP: + case ESM::REC_GLOB: MWBase::Environment::get().getWorld()->readRecord (reader, n.val); break; diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index d8e96ddc3..879ffa8e3 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -3,6 +3,11 @@ #include +#include + +#include +#include + #include "esmstore.hpp" namespace MWWorld @@ -66,4 +71,39 @@ namespace MWWorld 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; + } } diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index ad140b0c1..8f521c8a6 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -5,9 +5,17 @@ #include #include +#include + #include #include +namespace ESM +{ + class ESMWriter; + class ESMReader; +} + namespace MWWorld { class ESMStore; @@ -35,6 +43,16 @@ namespace MWWorld 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? + }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c4e63fad0..92091097c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -301,20 +301,23 @@ namespace MWWorld int World::countSavedGameRecords() const { - return mStore.countSavedGameRecords(); + return + mStore.countSavedGameRecords() + +mGlobalVariables.countSavedGameRecords(); } void World::write (ESM::ESMWriter& writer) const { mStore.write (writer); + mGlobalVariables.write (writer); } void World::readRecord (ESM::ESMReader& reader, int32_t type) { - if (!mStore.readRecord (reader, type)) + if (!mStore.readRecord (reader, type) && + !mGlobalVariables.readRecord (reader, type)) { - /// \todo handle other world state records - + throw std::runtime_error ("unknown record in saved game"); } } From 74793c1c2f5d34bf6f5954d9bca8eafbf0eb5ea9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Dec 2013 13:15:38 +0100 Subject: [PATCH 075/120] globals script cleanup; fixed potential case folding bug --- apps/openmw/mwbase/scriptmanager.hpp | 2 -- apps/openmw/mwscript/globalscripts.cpp | 41 +++++++++++++---------- apps/openmw/mwscript/globalscripts.hpp | 9 +++-- apps/openmw/mwscript/scriptmanagerimp.cpp | 5 --- apps/openmw/mwscript/scriptmanagerimp.hpp | 2 -- apps/openmw/mwstate/statemanagerimp.cpp | 7 ++++ apps/openmw/mwworld/worldimp.cpp | 3 -- 7 files changed, 37 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwbase/scriptmanager.hpp b/apps/openmw/mwbase/scriptmanager.hpp index 32df2bfa3..ae146e064 100644 --- a/apps/openmw/mwbase/scriptmanager.hpp +++ b/apps/openmw/mwbase/scriptmanager.hpp @@ -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) diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 608725ae6..d55ad0063 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" @@ -15,25 +17,12 @@ namespace MWScript GlobalScripts::GlobalScripts (const MWWorld::ESMStore& store) : mStore (store) { - reset(); - } - - void GlobalScripts::reset() - { - mScripts.clear(); - addScript ("Main"); - - MWWorld::Store::iterator iter = - mStore.get().begin(); - - for (; iter != mStore.get().end(); ++iter) { - addScript (iter->mScript); - } + addStartup(); } void GlobalScripts::addScript (const std::string& name) { - if (mScripts.find (name)==mScripts.end()) + if (mScripts.find (Misc::StringUtils::lowerCase (name))==mScripts.end()) if (const ESM::Script *script = mStore.get().find (name)) { Locals locals; @@ -46,7 +35,8 @@ namespace MWScript void GlobalScripts::removeScript (const std::string& name) { - std::map >::iterator iter = mScripts.find (name); + std::map >::iterator iter = + mScripts.find (Misc::StringUtils::lowerCase (name)); if (iter!=mScripts.end()) iter->second.first = false; @@ -55,7 +45,7 @@ namespace MWScript bool GlobalScripts::isRunning (const std::string& name) const { std::map >::const_iterator iter = - mScripts.find (name); + mScripts.find (Misc::StringUtils::lowerCase (name)); if (iter==mScripts.end()) return false; @@ -76,4 +66,21 @@ namespace MWScript } } } + + void GlobalScripts::clear() + { + mScripts.clear(); + } + + void GlobalScripts::addStartup() + { + addScript ("main"); + + for (MWWorld::Store::iterator iter = + mStore.get().begin(); + iter != mStore.get().end(); ++iter) + { + addScript (iter->mScript); + } + } } diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 628919d1d..67b619d1a 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -6,7 +6,7 @@ #include "locals.hpp" -namespace MWWorld +namespace MWWorld { struct ESMStore; } @@ -22,8 +22,6 @@ namespace MWScript GlobalScripts (const MWWorld::ESMStore& store); - void reset(); - void addScript (const std::string& name); void removeScript (const std::string& name); @@ -32,6 +30,11 @@ namespace MWScript void run(); ///< run all active global scripts + + void clear(); + + void addStartup(); + ///< Add startup script }; } diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 14fe5b7fd..be9082eb6 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -222,9 +222,4 @@ namespace MWScript throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId); } - - void ScriptManager::resetGlobalScripts() - { - mGlobalScripts.reset(); - } } diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index 7bb98ffbd..1a856e0c5 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -61,8 +61,6 @@ namespace MWScript ///< Compile script with the given namen /// \return Success? - virtual void resetGlobalScripts(); - virtual std::pair compileAll(); ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a8f5631a0..e1086f121 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -12,19 +12,24 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwscript/globalscripts.hpp" + void MWState::StateManager::cleanup() { if (mState!=State_NoGame) { MWBase::Environment::get().getDialogueManager()->clear(); MWBase::Environment::get().getJournal()->clear(); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().clear(); MWBase::Environment::get().getWorld()->clear(); + mState = State_NoGame; mCharacterManager.clearCurrentCharacter(); mTimePlayed = 0; @@ -64,6 +69,8 @@ void MWState::StateManager::newGame (bool bypass) else MWBase::Environment::get().getWorld()->setGlobalInt ("chargenstate", -1); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); + mState = State_Running; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 92091097c..c10556fa9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -21,7 +21,6 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/scriptmanager.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/movement.hpp" @@ -262,8 +261,6 @@ namespace MWWorld delete mWeatherManager; mWeatherManager = 0; mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); - - MWBase::Environment::get().getScriptManager()->resetGlobalScripts(); } void World::clear() From 2a35c7d33a825f293b07769f87ccf7949f2a06da Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Dec 2013 13:16:32 +0100 Subject: [PATCH 076/120] fixed running global scripts a second time after they have been stopped --- apps/openmw/mwscript/globalscripts.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index d55ad0063..1400d6675 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -22,7 +22,11 @@ namespace MWScript void GlobalScripts::addScript (const std::string& name) { - if (mScripts.find (Misc::StringUtils::lowerCase (name))==mScripts.end()) + std::map >::iterator iter = + mScripts.find (Misc::StringUtils::lowerCase (name)); + + if (iter==mScripts.end()) + { if (const ESM::Script *script = mStore.get().find (name)) { Locals locals; @@ -31,6 +35,9 @@ 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) From 3590fa40bd13c3e0b95ee8783b685266e2a261c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 15 Dec 2013 16:16:50 +0100 Subject: [PATCH 077/120] store global script state in saved game files --- apps/openmw/mwscript/globalscripts.cpp | 58 ++++++++++++++++++++++ apps/openmw/mwscript/globalscripts.hpp | 17 +++++++ apps/openmw/mwscript/locals.cpp | 66 +++++++++++++++++++++++++ apps/openmw/mwscript/locals.hpp | 4 ++ apps/openmw/mwstate/statemanagerimp.cpp | 7 +++ components/CMakeLists.txt | 2 +- components/compiler/locals.cpp | 42 ++++++++-------- components/compiler/locals.hpp | 20 ++++---- components/esm/defs.hpp | 1 + components/esm/globalscript.cpp | 25 ++++++++++ components/esm/globalscript.hpp | 24 +++++++++ components/esm/locals.cpp | 28 +++++++++++ components/esm/locals.hpp | 27 ++++++++++ components/esm/variant.hpp | 2 +- 14 files changed, 290 insertions(+), 33 deletions(-) create mode 100644 components/esm/globalscript.cpp create mode 100644 components/esm/globalscript.hpp create mode 100644 components/esm/locals.cpp create mode 100644 components/esm/locals.hpp diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 1400d6675..8f269a015 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwworld/esmstore.hpp" @@ -90,4 +91,61 @@ namespace MWScript addScript (iter->mScript); } } + + int GlobalScripts::countSavedGameRecords() const + { + return mScripts.size(); + } + + void GlobalScripts::write (ESM::ESMWriter& writer) const + { + for (std::map >::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 >::iterator iter = + mScripts.find (script.mId); + + if (iter==mScripts.end()) + { + if (const ESM::Script *scriptRecord = mStore.get().search (script.mId)) + { + std::pair 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; + } } diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 67b619d1a..cf716c8e4 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -4,8 +4,16 @@ #include #include +#include + #include "locals.hpp" +namespace ESM +{ + class ESMWriter; + class ESMReader; +} + namespace MWWorld { struct ESMStore; @@ -35,6 +43,15 @@ namespace MWScript 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? }; } diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 180a2791b..094fe085a 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -1,6 +1,8 @@ #include "locals.hpp" #include +#include +#include #include @@ -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& names = declarations.get (type); + + for (int i2=0; i2 (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 >::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 + } + } + } } diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index deae0d44e..d17d1be2d 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -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); }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index e1086f121..93650fc44 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -114,6 +114,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot 1 // saved game header +MWBase::Environment::get().getJournal()->countSavedGameRecords() +MWBase::Environment::get().getWorld()->countSavedGameRecords() + +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() ); writer.save (stream); @@ -124,6 +125,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot MWBase::Environment::get().getJournal()->write (writer); MWBase::Environment::get().getWorld()->write (writer); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer); writer.close(); @@ -173,6 +175,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl MWBase::Environment::get().getWorld()->readRecord (reader, n.val); break; + case ESM::REC_GSCR: + + MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val); + break; + default: // ignore invalid records diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3223ab1a7..6f01216f1 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate + savedgame journalentry queststate locals globalscript ) add_component_dir (misc diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index d93e73849..e2b1c5c96 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -15,27 +15,27 @@ namespace Compiler { case 's': return mShorts; case 'l': return mLongs; - case 'f': return mFloats; + case 'f': return mFloats; } - + throw std::logic_error ("unknown variable type"); } - + int Locals::searchIndex (char type, const std::string& name) const { const std::vector& collection = get (type); - + std::vector::const_iterator iter = std::find (collection.begin(), collection.end(), name); - + if (iter==collection.end()) return -1; - + return iter-collection.begin(); } - + bool Locals::search (char type, const std::string& name) const - { + { return searchIndex (type, name)!=-1; } @@ -45,10 +45,10 @@ namespace Compiler { case 's': return mShorts; case 'l': return mLongs; - case 'f': return mFloats; + case 'f': return mFloats; } - - throw std::logic_error ("unknown variable type"); + + throw std::logic_error ("unknown variable type"); } char Locals::getType (const std::string& name) const @@ -58,35 +58,35 @@ namespace Compiler if (search ('l', name)) return 'l'; - + if (search ('f', name)) return 'f'; - + return ' '; } - + int Locals::getIndex (const std::string& name) const { int index = searchIndex ('s', name); - + if (index!=-1) return index; - + index = searchIndex ('l', name); if (index!=-1) return index; - return searchIndex ('f', name); + return searchIndex ('f', name); } - + void Locals::write (std::ostream& localFile) const { localFile << get ('s').size() << ' ' << get ('l').size() << ' ' << get ('f').size() << std::endl; - + std::copy (get ('s').begin(), get ('s').end(), std::ostream_iterator (localFile, " ")); std::copy (get ('l').begin(), get ('l').end(), @@ -94,12 +94,12 @@ namespace Compiler std::copy (get ('f').begin(), get ('f').end(), std::ostream_iterator (localFile, " ")); } - + void Locals::declare (char type, const std::string& name) { get (type).push_back (name); } - + void Locals::clear() { get ('s').clear(); diff --git a/components/compiler/locals.hpp b/components/compiler/locals.hpp index e54b7798c..d5bf05253 100644 --- a/components/compiler/locals.hpp +++ b/components/compiler/locals.hpp @@ -8,35 +8,35 @@ namespace Compiler { /// \brief Local variable declarations - + class Locals { std::vector mShorts; std::vector mLongs; std::vector mFloats; - + int searchIndex (char type, const std::string& name) const; bool search (char type, const std::string& name) const; - - std::vector& get (char type); - + + std::vector& get (char type); + public: - + char getType (const std::string& name) const; ///< 's': short, 'l': long, 'f': float, ' ': does not exist. - + int getIndex (const std::string& name) const; ///< return index for local variable \a name (-1: does not exist). - + const std::vector& get (char type) const; void write (std::ostream& localFile) const; ///< write declarations to file. - + void declare (char type, const std::string& name); ///< declares a variable. - + void clear(); ///< remove all declarations. }; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 03091d9d8..4cf0b1dac 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -87,6 +87,7 @@ enum RecNameInts REC_SAVE = 0x45564153, REC_JOUR = 0x524f55a4, REC_QUES = 0x53455551, + REC_GSCR = 0x52435347, // format 1 REC_FILT = 0x544C4946 diff --git a/components/esm/globalscript.cpp b/components/esm/globalscript.cpp new file mode 100644 index 000000000..dcbd91140 --- /dev/null +++ b/components/esm/globalscript.cpp @@ -0,0 +1,25 @@ + +#include "globalscript.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::GlobalScript::load (ESMReader &esm) +{ + mId = esm.getHNString ("NAME"); + + mLocals.load (esm); + + mRunning = 0; + esm.getHNOT (mRunning, "RUN_"); +} + +void ESM::GlobalScript::save (ESMWriter &esm) const +{ + esm.writeHNString ("NAME", mId); + + mLocals.save (esm); + + if (mRunning) + esm.writeHNT ("RUN_", mRunning); +} \ No newline at end of file diff --git a/components/esm/globalscript.hpp b/components/esm/globalscript.hpp new file mode 100644 index 000000000..4fb8b7c48 --- /dev/null +++ b/components/esm/globalscript.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_ESM_GLOBALSCRIPT_H +#define OPENMW_ESM_GLOBALSCRIPT_H + +#include "locals.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + /// \brief Storage structure for global script state (only used in saved games) + + struct GlobalScript + { + std::string mId; + Locals mLocals; + int mRunning; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif diff --git a/components/esm/locals.cpp b/components/esm/locals.cpp new file mode 100644 index 000000000..9c470a025 --- /dev/null +++ b/components/esm/locals.cpp @@ -0,0 +1,28 @@ + +#include "locals.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::Locals::load (ESMReader &esm) +{ + while (esm.isNextSub ("LOCA")) + { + std::string id = esm.getHString(); + + Variant value; + value.read (esm, Variant::Format_Info); + + mVariables.push_back (std::make_pair (id, value)); + } +} + +void ESM::Locals::save (ESMWriter &esm) const +{ + for (std::vector >::const_iterator iter (mVariables.begin()); + iter!=mVariables.end(); ++iter) + { + esm.writeHNString ("LOCA", iter->first); + iter->second.write (esm, Variant::Format_Info); + } +} \ No newline at end of file diff --git a/components/esm/locals.hpp b/components/esm/locals.hpp new file mode 100644 index 000000000..af5afb23b --- /dev/null +++ b/components/esm/locals.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_ESM_LOCALS_H +#define OPENMW_ESM_LOCALS_H + +#include +#include + +#include "variant.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + /// \brief Storage structure for local variables (only used in saved games) + /// + /// \note This is not a top-level record. + + struct Locals + { + std::vector > mVariables; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index 2bba60a15..8ba9bb34f 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -33,7 +33,7 @@ namespace ESM { Format_Global, Format_Gmst, - Format_Info + Format_Info // also used for local variables in saved game files }; Variant(); From bf4ffe94dc4a6cb27f71c16911037094fe446bfa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 15 Dec 2013 16:19:45 +0100 Subject: [PATCH 078/120] fixed a memory leak in the script record --- components/esm/loadscpt.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 30460c17a..de679e815 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -26,24 +26,24 @@ void Script::load(ESMReader &esm) if (esm.isNextSub("SCVR")) { int s = mData.mStringTableSize; - char* tmp = new char[s]; - esm.getHExact(tmp, s); + + std::vector tmp (s); + esm.getHExact (&tmp[0], s); // Set up the list of variable names mVarNames.resize(mData.mNumShorts + mData.mNumLongs + mData.mNumFloats); // The tmp buffer is a null-byte separated string list, we // just have to pick out one string at a time. - char* str = tmp; + char* str = &tmp[0]; for (size_t i = 0; i < mVarNames.size(); i++) { mVarNames[i] = std::string(str); str += mVarNames[i].size() + 1; - if (str - tmp > s) + if (str - &tmp[0] > s) esm.fail("String table overflow"); } - delete[] tmp; } // Script mData From fd9f8c34f6065d2645db9bd1443df00939fa020a Mon Sep 17 00:00:00 2001 From: mrcheko Date: Sun, 15 Dec 2013 18:50:25 +0200 Subject: [PATCH 079/120] bug fix http://bugs.openmw.org/issues/428 --- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwinput/inputmanagerimp.cpp | 7 +++-- apps/openmw/mwmechanics/actors.cpp | 16 +++++------- apps/openmw/mwmechanics/character.cpp | 32 ++++++++++++++++++++--- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 ++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 ++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 9 files changed, 58 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 740114aff..ea8619b3a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -43,6 +43,7 @@ namespace MWRender { class ExternalRendering; class Animation; + class Camera; } namespace MWMechanics @@ -112,6 +113,8 @@ namespace MWBase virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; + virtual MWRender::Camera* getCamera() const = 0; + virtual void setWaterHeight(const float height) = 0; virtual void toggleWater() = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 850a62bec..47fb979d7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -181,7 +181,8 @@ namespace MWInput switch (action) { case A_GameMenu: - toggleMainMenu (); + if(MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Running) + toggleMainMenu (); break; case A_Screenshot: screenshot(); @@ -301,7 +302,9 @@ namespace MWInput return; // Disable movement in Gui mode - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode() + || MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).isDead() ) + return; // Configure player movement according to keyboard input. Actual movement will diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 19c2dac0c..c7ab0322d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -571,19 +571,15 @@ namespace MWMechanics stats.resurrect(); continue; } - - MWBase::Environment::get().getStateManager()->endGame(); } - if(iter->second->isDead()) - continue; + if (iter->second->kill()) + { + ++mDeathCount[cls.getId(iter->first)]; - iter->second->kill(); - - ++mDeathCount[cls.getId(iter->first)]; - - if(cls.isEssential(iter->first)) - MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); + if(cls.isEssential(iter->first)) + MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); + } } } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 68f87ef4c..7c7f40e97 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -26,12 +26,14 @@ #include "creaturestats.hpp" #include "security.hpp" +#include "../mwrender/camera.hpp" #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/statemanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -1052,10 +1054,20 @@ void CharacterController::forceStateUpdate() } } -void CharacterController::kill() +bool CharacterController::kill() { - if(mDeathState != CharState_None) - return; + if( isDead() ) + { + //state=end game only when player's death animation is over + if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) + && MWBase::Environment::get().getWindowManager()->getMode () != MWGui::GM_MainMenu ) + { + MWBase::Environment::get().getStateManager()->endGame(); + MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setHealth(0); + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + } + return false; + } if(mPtr.getTypeName() == typeid(ESM::NPC).name()) { @@ -1093,6 +1105,18 @@ void CharacterController::kill() if(mAnimation) { + //switch to 3rd person before player's death animation + if (mPtr.getRefData().getHandle()=="player") + { + if(MWBase::Environment::get().getWorld()->getCamera()->isVanityOrPreviewModeEnabled() ) + { + MWBase::Environment::get().getWorld()->getCamera()->togglePreviewMode(false); + MWBase::Environment::get().getWorld()->getCamera()->toggleVanityMode(false); + } + if(MWBase::Environment::get().getWorld()->getCamera()->isFirstPerson()) + MWBase::Environment::get().getWorld()->togglePOV(); + } + mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->disable(mCurrentIdle); @@ -1100,6 +1124,8 @@ void CharacterController::kill() mIdleState = CharState_None; mCurrentIdle.clear(); + + return true; } void CharacterController::resurrect() diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0b55534a6..5e7a7c6d4 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -188,7 +188,7 @@ public: void skipAnim(); bool isAnimPlaying(const std::string &groupName); - void kill(); + bool kill(); void resurrect(); bool isDead() const { return mDeathState != CharState_None; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2eb2b1523..8aca3b489 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -221,6 +221,11 @@ OEngine::Render::Fader* RenderingManager::getFader() return mRendering.getFader(); } + MWRender::Camera* RenderingManager::getCamera() const +{ + return mCamera; +} + void RenderingManager::removeCell (MWWorld::CellStore *store) { mObjects.removeCell(store); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 2d0813912..5bbc3055d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -98,6 +98,8 @@ public: SkyManager* getSkyManager(); Compositors* getCompositors(); + MWRender::Camera* getCamera() const; + void toggleLight(); bool toggleRenderMode(int mode); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c4e63fad0..2676be4b7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -400,6 +400,11 @@ namespace MWWorld return mCells.getInterior (name); } + MWRender::Camera* World::getCamera() const + { + return mRendering->getCamera(); + } + MWWorld::Player& World::getPlayer() { return *mPlayer; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 845668449..7c24adfa8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -185,6 +185,8 @@ namespace MWWorld virtual CellStore *getInterior (const std::string& name); + virtual MWRender::Camera* getCamera() const; + virtual void setWaterHeight(const float height); virtual void toggleWater(); From 1cf1d49bc43d717db5b3d2f4ca6334cb721a423f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 16 Dec 2013 11:39:24 +0100 Subject: [PATCH 080/120] fix to content file reading error reporting in case of missing dependency --- apps/openmw/mwworld/esmstore.cpp | 2 +- components/esm/esmreader.cpp | 5 +++++ components/esm/esmreader.hpp | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index cb4e441fc..62b91c2e4 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -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); } diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 4e1860bab..ebdb1e41f 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -8,6 +8,11 @@ namespace ESM using namespace Misc; + std::string ESMReader::getName() const + { + return mCtx.filename; + } + ESM_Context ESMReader::getContext() { // Update the file position before returning diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 3bf194c4e..897c8fe73 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -38,6 +38,7 @@ public: int getFormat() const; const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } + std::string getName() const; /************************************************************************* * From f50ff0b1c4df394bc451e1fbd137e846cf81e39c Mon Sep 17 00:00:00 2001 From: mrcheko Date: Mon, 16 Dec 2013 15:40:47 +0200 Subject: [PATCH 081/120] reworked http://bugs.openmw.org/issues/428 --- apps/openmw/engine.cpp | 54 +++++++++++++------------ apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +++-- apps/openmw/mwmechanics/actors.cpp | 1 - apps/openmw/mwmechanics/character.cpp | 19 +-------- apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 10 ++++- apps/openmw/mwworld/worldimp.hpp | 4 +- 8 files changed, 49 insertions(+), 52 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8fc36a5d5..97c2844eb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -94,35 +94,39 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getSoundManager()->update(frametime); // 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. + + if (changed) // keep change flag for another frame, if cell changed happened in local script + MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWorld()->advanceTime( + frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + + // update actors + MWBase::Environment::get().getMechanicsManager()->update(frametime, + MWBase::Environment::get().getWindowManager()->isGuiMode()); + if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) { - 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. - - if (changed) // keep change flag for another frame, if cell changed happened in local script - MWBase::Environment::get().getWorld()->markCellAsUnchanged(); - - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->advanceTime( - frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); - - // update actors - MWBase::Environment::get().getMechanicsManager()->update(frametime, - MWBase::Environment::get().getWindowManager()->isGuiMode()); - - // update world - MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); - - // update game state - MWBase::Environment::get().getStateManager()->update (frametime); + MWWorld::Ptr player = mEnvironment.getWorld()->getPlayer().getPlayer(); + if(MWWorld::Class::get(player).getCreatureStats(player).isDead()) + MWBase::Environment::get().getStateManager()->endGame(); } + + // update world + MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); + + // update game state + MWBase::Environment::get().getStateManager()->update (frametime); // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ea8619b3a..f7041a47b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -43,7 +43,6 @@ namespace MWRender { class ExternalRendering; class Animation; - class Camera; } namespace MWMechanics @@ -113,7 +112,7 @@ namespace MWBase virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; - virtual MWRender::Camera* getCamera() const = 0; + virtual void useDeathCamera() = 0; virtual void setWaterHeight(const float height) = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 47fb979d7..e6e349c4d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -181,8 +181,9 @@ namespace MWInput switch (action) { case A_GameMenu: - if(MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Running) - toggleMainMenu (); + if(!(MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running + && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_MainMenu)) + toggleMainMenu (); break; case A_Screenshot: screenshot(); @@ -303,8 +304,8 @@ namespace MWInput // Disable movement in Gui mode if (MWBase::Environment::get().getWindowManager()->isGuiMode() - || MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).isDead() ) - return; + || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running) + return; // Configure player movement according to keyboard input. Actual movement will diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c7ab0322d..7180eb883 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -19,7 +19,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" - #include "../mwbase/statemanager.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7c7f40e97..9a19ac7fa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -26,14 +26,12 @@ #include "creaturestats.hpp" #include "security.hpp" -#include "../mwrender/camera.hpp" #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/statemanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -1058,11 +1056,10 @@ bool CharacterController::kill() { if( isDead() ) { - //state=end game only when player's death animation is over + //player's death animation is over if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) - && MWBase::Environment::get().getWindowManager()->getMode () != MWGui::GM_MainMenu ) + && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu ) { - MWBase::Environment::get().getStateManager()->endGame(); MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setHealth(0); MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); } @@ -1105,18 +1102,6 @@ bool CharacterController::kill() if(mAnimation) { - //switch to 3rd person before player's death animation - if (mPtr.getRefData().getHandle()=="player") - { - if(MWBase::Environment::get().getWorld()->getCamera()->isVanityOrPreviewModeEnabled() ) - { - MWBase::Environment::get().getWorld()->getCamera()->togglePreviewMode(false); - MWBase::Environment::get().getWorld()->getCamera()->toggleVanityMode(false); - } - if(MWBase::Environment::get().getWorld()->getCamera()->isFirstPerson()) - MWBase::Environment::get().getWorld()->togglePOV(); - } - mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->disable(mCurrentIdle); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 94219b8fc..bad4de03d 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -70,6 +70,7 @@ void MWState::StateManager::newGame (bool bypass) void MWState::StateManager::endGame() { mState = State_Ended; + MWBase::Environment::get().getWorld()->useDeathCamera(); } void MWState::StateManager::saveGame (const std::string& description, const Slot *slot) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2676be4b7..357101e45 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -400,9 +400,15 @@ namespace MWWorld return mCells.getInterior (name); } - MWRender::Camera* World::getCamera() const + void World::useDeathCamera() { - return mRendering->getCamera(); + if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() ) + { + mRendering->getCamera()->togglePreviewMode(false); + mRendering->getCamera()->toggleVanityMode(false); + } + if(mRendering->getCamera()->isFirstPerson()) + togglePOV(); } MWWorld::Player& World::getPlayer() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7c24adfa8..fb9c4cb68 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -42,6 +42,7 @@ namespace MWRender class SkyManager; class CellRender; class Animation; + class Camera; } struct ContentLoader; @@ -185,7 +186,8 @@ namespace MWWorld virtual CellStore *getInterior (const std::string& name); - virtual MWRender::Camera* getCamera() const; + //switch to POV before showing player's death animation + virtual void useDeathCamera(); virtual void setWaterHeight(const float height); From a854eb73db8e0629cf5c707b69ccbb7b2a1d4943 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Mon, 16 Dec 2013 21:02:21 +0200 Subject: [PATCH 082/120] StateRunning check returns --- apps/openmw/engine.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 97c2844eb..5b8872b0f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -93,22 +93,30 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) if (mUseSound) MWBase::Environment::get().getSoundManager()->update(frametime); - // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + 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(); + 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. + // 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. - if (changed) // keep change flag for another frame, if cell changed happened in local script - MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + if (changed) // keep change flag for another frame, if cell changed happened in local script + MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWorld()->advanceTime( + frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + + // update game state + MWBase::Environment::get().getStateManager()->update (frametime); + } - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->advanceTime( - frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); // update actors MWBase::Environment::get().getMechanicsManager()->update(frametime, @@ -125,9 +133,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // update world MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); - // update game state - MWBase::Environment::get().getStateManager()->update (frametime); - // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); unsigned int tri, batch; From c22e38f825827d408833de11b19bcf5a8210206f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 17 Dec 2013 21:19:05 +0100 Subject: [PATCH 083/120] removing 255 content file limitation --- apps/esmtool/esmtool.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 5 +- apps/openmw/mwworld/livecellref.hpp | 7 ++- apps/openmw/mwworld/manualref.hpp | 5 +- apps/openmw/mwworld/store.cpp | 8 +-- components/esm/cellref.cpp | 11 +++- components/esm/cellref.hpp | 10 +++- components/esm/loadcell.cpp | 86 ++++++++++++----------------- components/esm/loadcell.hpp | 8 +-- 9 files changed, 74 insertions(+), 68 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 27980096e..3bbdaef35 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -244,7 +244,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) if(quiet) continue; - std::cout << " Refnum: " << ref.mRefnum << std::endl; + std::cout << " Refnum: " << ref.mRefNum.mIndex << std::endl; std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n"; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 0c145ab60..06ae083ce 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -38,7 +38,7 @@ namespace MWWorld void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) { // Get existing reference, in case we need to overwrite it. - typename std::list::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefnum); + typename std::list::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. @@ -148,13 +148,14 @@ 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)) { // 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; } diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 415351e78..558639a3b 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -31,6 +31,11 @@ namespace MWWorld virtual ~LiveCellRefBase() { } }; + 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 @@ -51,8 +56,6 @@ namespace MWWorld // The object that this instance is based on. const X* mBase; }; - -// template bool operator==(const LiveCellRef& ref, int pRefnum); } #endif diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 1cdcd8484..f138e3732 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -25,6 +25,8 @@ namespace MWWorld { LiveCellRef ref; ref.mBase = instance; + ref.mRef.mRefNum.mIndex = 0; + ref.mRef.mRefNum.mContentFile = -1; mRef = ref; mPtr = Ptr (&boost::any_cast&> (mRef), 0); @@ -65,7 +67,8 @@ namespace MWWorld // initialise ESM::CellRef& cellRef = mPtr.getCellRef(); cellRef.mRefID = name; - cellRef.mRefnum = -1; + cellRef.mRefNum.mIndex = 0; + cellRef.mRefNum.mContentFile = -1; cellRef.mScale = 1; cellRef.mFactIndex = 0; cellRef.mCharge = -1; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 512883f1a..9ba2d8133 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -10,7 +10,7 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) // and we merge all this data into one Cell object. However, we can't simply search for the cell id, // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they // are not available until both cells have been loaded! So first, proceed as usual. - + // All cells have a name record, even nameless exterior cells. std::string idLower = Misc::StringUtils::lowerCase(id); ESM::Cell *cell = new ESM::Cell; @@ -40,7 +40,7 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) // We should not need to test for duplicates, as this part of the code is pre-cell merge. cell->mMovedRefs.push_back(cMRef); // But there may be duplicates here! - ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); if (iter == cellAlt->mLeasedRefs.end()) cellAlt->mLeasedRefs.push_back(ref); else @@ -76,11 +76,11 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) // merge lists of leased references, use newer data in case of conflict for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); ++it) { // remove reference from current leased ref tracker and add it to new cell - ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefnum); + ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); if (itold != oldcell->mMovedRefs.end()) { ESM::MovedCellRef target0 = *itold; ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefnum); + ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); wipecell->mLeasedRefs.erase(it_lease); *itold = *it; } diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index e91059b26..23a95a4ab 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -5,7 +5,8 @@ void ESM::CellRef::save(ESMWriter &esm) const { - esm.writeHNT("FRMR", mRefnum); + esm.writeHNT("FRMR", mRefNum.mIndex); + /// \todo read content file index (if present) esm.writeHNCString("NAME", mRefID); if (mScale != 1.0) { @@ -58,7 +59,8 @@ void ESM::CellRef::save(ESMWriter &esm) const void ESM::CellRef::blank() { - mRefnum = 0; + mRefNum.mIndex = 0; + mRefNum.mContentFile = -1; mRefID.clear(); mScale = 1; mOwner.clear(); @@ -84,4 +86,9 @@ void ESM::CellRef::blank() mPos.pos[i] = 0; mPos.rot[i] = 0; } +} + +bool ESM::operator== (const CellRef::RefNum& left, const CellRef::RefNum& right) +{ + return left.mIndex==right.mIndex && left.mContentFile==right.mContentFile; } \ No newline at end of file diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 47cb0b99e..ef2523869 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -19,7 +19,13 @@ namespace ESM { public: - int mRefnum; // Reference number + struct RefNum + { + int mIndex; + int mContentFile; // -1 no content file + }; + + RefNum mRefNum; // Reference number std::string mRefID; // ID of object being referenced float mScale; // Scale applied to mesh @@ -87,6 +93,8 @@ namespace ESM void blank(); }; + + bool operator== (const CellRef::RefNum& left, const CellRef::RefNum& right); } #endif \ No newline at end of file diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index c22c1b22b..ba4195370 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -9,20 +9,42 @@ #include "esmwriter.hpp" #include "defs.hpp" +namespace +{ + ///< Translate 8bit/24bit code (stored in refNum.mIndex) into a proper refNum + void adjustRefNum (ESM::CellRef::RefNum& refNum, ESM::ESMReader& reader) + { + int local = (refNum.mIndex & 0xff000000) >> 24; + + if (local) + { + // If the most significant 8 bits are used, then this reference already exists. + // In this case, do not spawn a new reference, but overwrite the old one. + refNum.mIndex &= 0x00ffffff; // delete old plugin ID + refNum.mContentFile = reader.getGameFiles()[local-1].index; + } + else + { + // This is an addition by the present plugin. Set the corresponding plugin index. + refNum.mContentFile = reader.getIndex(); + } + } +} + namespace ESM { unsigned int Cell::sRecordId = REC_CELL; -/// Some overloaded compare operators. -bool operator==(const MovedCellRef& ref, int pRefnum) -{ - return (ref.mRefnum == pRefnum); -} + // Some overloaded compare operators. + bool operator== (const MovedCellRef& ref, const CellRef::RefNum& refNum) + { + return ref.mRefNum == refNum; + } -bool operator==(const CellRef& ref, int pRefnum) -{ - return (ref.mRefnum == pRefnum); -} + bool operator== (const CellRef& ref, const CellRef::RefNum& refNum) + { + return ref.mRefNum == refNum; + } void Cell::load(ESMReader &esm, bool saveContext) @@ -163,49 +185,17 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) //esm.getHNOT(NAM0, "NAM0"); } - esm.getHNT(ref.mRefnum, "FRMR"); + esm.getHNT (ref.mRefNum.mIndex, "FRMR"); ref.mRefID = esm.getHNString("NAME"); // Identify references belonging to a parent file and adapt the ID accordingly. - int local = (ref.mRefnum & 0xff000000) >> 24; - size_t global = esm.getIndex() + 1; - if (local) - { - // If the most significant 8 bits are used, then this reference already exists. - // In this case, do not spawn a new reference, but overwrite the old one. - ref.mRefnum &= 0x00ffffff; // delete old plugin ID - const std::vector &masters = esm.getGameFiles(); - global = masters[local-1].index + 1; - ref.mRefnum |= global << 24; // insert global plugin ID - } - else - { - // This is an addition by the present plugin. Set the corresponding plugin index. - ref.mRefnum |= global << 24; // insert global plugin ID - } + adjustRefNum (ref.mRefNum, esm); // getHNOT will not change the existing value if the subrecord is // missing ref.mScale = 1.0; esm.getHNOT(ref.mScale, "XSCL"); - // TODO: support loading references from saves, there are tons of keys not recognized yet. - // The following is just an incomplete list. - if (esm.isNextSub("ACTN")) - esm.skipHSub(); - if (esm.isNextSub("STPR")) - esm.skipHSub(); - if (esm.isNextSub("ACDT")) - esm.skipHSub(); - if (esm.isNextSub("ACSC")) - esm.skipHSub(); - if (esm.isNextSub("ACSL")) - esm.skipHSub(); - if (esm.isNextSub("CHRD")) - esm.skipHSub(); - else if (esm.isNextSub("CRED")) // ??? - esm.skipHSub(); - ref.mOwner = esm.getHNOString("ANAM"); ref.mGlob = esm.getHNOString("BNAM"); ref.mSoul = esm.getHNOString("XSOL"); @@ -271,16 +261,10 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) { - esm.getHT(mref.mRefnum); + esm.getHT(mref.mRefNum.mIndex); esm.getHNOT(mref.mTarget, "CNDT"); - // Identify references belonging to a parent file and adapt the ID accordingly. - int local = (mref.mRefnum & 0xff000000) >> 24; - size_t global = esm.getIndex() + 1; - mref.mRefnum &= 0x00ffffff; // delete old plugin ID - const std::vector &masters = esm.getGameFiles(); - global = masters[local-1].index + 1; - mref.mRefnum |= global << 24; // insert global plugin ID + adjustRefNum (mref.mRefNum, esm); return true; } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 61d586b9d..b0340e945 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -27,7 +27,7 @@ class ESMWriter; class MovedCellRef { public: - int mRefnum; + CellRef::RefNum mRefNum; // Target cell (if exterior) int mTarget[2]; @@ -37,9 +37,9 @@ public: // introduces a henchman (which no one uses), so we may need this as well. }; -/// Overloaded copare operator used to search inside a list of cell refs. -bool operator==(const MovedCellRef& ref, int pRefnum); -bool operator==(const CellRef& ref, int pRefnum); +/// Overloaded compare operator used to search inside a list of cell refs. +bool operator==(const MovedCellRef& ref, const CellRef::RefNum& refNum); +bool operator==(const CellRef& ref, const CellRef::RefNum& refNum); typedef std::list MovedCellRefTracker; typedef std::list CellRefTracker; From 3816a09c6fd98d4d0b4ede58b8891c9ee845df26 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Thu, 19 Dec 2013 22:08:34 +0200 Subject: [PATCH 084/120] bug 428 ask to load recent saved game --- apps/openmw/mwbase/statemanager.hpp | 2 ++ apps/openmw/mwmechanics/character.cpp | 6 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 44 ++++++++++++++++++++++++- apps/openmw/mwstate/statemanagerimp.hpp | 3 ++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 8548a74f7..cd907408a 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -44,6 +44,8 @@ namespace MWBase virtual bool hasQuitRequest() const = 0; + virtual void askLoadRecent() = 0; + virtual State getState() const = 0; virtual void newGame (bool bypass = false) = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9a19ac7fa..614d697ec 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -32,6 +32,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/statemanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -1057,11 +1058,10 @@ bool CharacterController::kill() if( isDead() ) { //player's death animation is over - if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) - && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu ) + if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) ) { MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setHealth(0); - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + MWBase::Environment::get().getStateManager()->askLoadRecent(); } return false; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index bad4de03d..9e6395812 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -32,7 +32,7 @@ void MWState::StateManager::cleanup() } MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::string& game) -: mQuitRequest (false), mState (State_NoGame), mCharacterManager (saves, game), mTimePlayed (0) +: mQuitRequest (false), mAskLoadRecent(false), mState (State_NoGame), mCharacterManager (saves, game), mTimePlayed (0) { } @@ -47,6 +47,48 @@ bool MWState::StateManager::hasQuitRequest() const return mQuitRequest; } +void MWState::StateManager::askLoadRecent() +{ + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_MainMenu) + return; + + if( !mAskLoadRecent ) + { + if(MWBase::Environment::get().getStateManager()->getCurrentCharacter()->begin() + == MWBase::Environment::get().getStateManager()->getCurrentCharacter()->end() )//no saves + { + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + } + else + { + MWState::Slot lastSave = *getCurrentCharacter()->begin(); + std::vector buttons; + buttons.push_back("Yes"); + buttons.push_back("No"); + std::string message = "The most recent Save Game is '" + lastSave.mProfile.mDescription + "'.\n Would you like to load it?"; + 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; diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 78b578766..a2abcfd1b 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -12,6 +12,7 @@ namespace MWState class StateManager : public MWBase::StateManager { bool mQuitRequest; + bool mAskLoadRecent; State mState; CharacterManager mCharacterManager; double mTimePlayed; @@ -28,6 +29,8 @@ namespace MWState virtual bool hasQuitRequest() const; + virtual void askLoadRecent(); + virtual State getState() const; virtual void newGame (bool bypass = false); From 8eb2696f6ccf690a23f927dbe031e2c1e3f2d9b0 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Fri, 20 Dec 2013 14:04:59 +0200 Subject: [PATCH 085/120] using gmst string --- apps/openmw/mwstate/statemanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9e6395812..a408a9fb7 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -54,8 +54,7 @@ void MWState::StateManager::askLoadRecent() if( !mAskLoadRecent ) { - if(MWBase::Environment::get().getStateManager()->getCurrentCharacter()->begin() - == MWBase::Environment::get().getStateManager()->getCurrentCharacter()->end() )//no saves + if(getCurrentCharacter()->begin() == getCurrentCharacter()->end() )//no saves { MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); } @@ -65,7 +64,10 @@ void MWState::StateManager::askLoadRecent() std::vector buttons; buttons.push_back("Yes"); buttons.push_back("No"); - std::string message = "The most recent Save Game is '" + lastSave.mProfile.mDescription + "'.\n Would you like to load it?"; + 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; } From 43dd3b8ef22f691a7e55b176aafaba9714660ccb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 6 Jan 2014 13:53:20 +0100 Subject: [PATCH 086/120] removed redundant deletion flag from CellRef --- apps/esmtool/esmtool.cpp | 5 +- apps/opencs/model/world/ref.cpp | 3 +- apps/opencs/model/world/refcollection.cpp | 3 +- apps/openmw/mwworld/cellstore.cpp | 177 ++++++++-------------- apps/openmw/mwworld/cellstore.hpp | 7 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/openmw/mwworld/store.cpp | 9 +- components/esm/cellref.hpp | 3 - components/esm/loadcell.cpp | 13 +- components/esm/loadcell.hpp | 2 +- 10 files changed, 91 insertions(+), 133 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 27980096e..a0593e60d 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -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); @@ -251,6 +253,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Uses/health: '" << ref.mCharge << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; + std::cout << " Deleted: " << deleted << std::endl; } } diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index 74f60419b..cf9e496ee 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -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); + cell.addRef (mId); } \ No newline at end of file diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 696aeefaa..7c95c2d30 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -14,7 +14,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()); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 0c145ab60..88f422a1d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -35,32 +35,30 @@ namespace MWWorld { template - void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) + void CellRefList::load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore) { - // Get existing reference, in case we need to overwrite it. - typename std::list::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 &store = esmStore.get(); - const X *ptr = store.search(ref.mRefID); - /// \note no longer redundant - changed to Store::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 (iter != mList.end()) - *iter = LiveRef(ref, ptr); - else - mList.push_back(LiveRef(ref, ptr)); + if (const X *ptr = store.search (ref.mRefID)) + { + typename std::list::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 = liveCellRef; + else + mList.push_back (liveCellRef); + } + else + { + std::cerr + << "Error: could not resolve cell reference " << ref.mRefID + << " (dropping reference)" << std::endl; } } @@ -117,16 +115,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)); } } @@ -135,7 +130,7 @@ namespace MWWorld void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector &esm) { - assert (mCell); + assert (mCell); if (mCell->mContextList.empty()) return; // this is a dynamically generated cell -> skipping. @@ -150,102 +145,25 @@ 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)) { // 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); 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(*it); - //ESM::CellRef &ref = const_cast(it->second); - - std::string lowerCase; - - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - 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, false, store); } } @@ -274,4 +192,39 @@ 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"; + } + } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 8a01caf18..b109557f9 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -25,7 +25,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) { @@ -154,6 +154,11 @@ namespace MWWorld void loadRefs(const MWWorld::ESMStore &store, std::vector &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. + }; } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 62b91c2e4..cab10ee51 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -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); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 512883f1a..44c814e81 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -10,7 +10,7 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) // and we merge all this data into one Cell object. However, we can't simply search for the cell id, // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they // are not available until both cells have been loaded! So first, proceed as usual. - + // All cells have a name record, even nameless exterior cells. std::string idLower = Misc::StringUtils::lowerCase(id); ESM::Cell *cell = new ESM::Cell; @@ -30,11 +30,10 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // implementation when the oher implementation works as well. - cell->getNextRef(esm, ref); - std::string lowerCase; + bool deleted = false; + cell->getNextRef(esm, ref, deleted); - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + Misc::StringUtils::toLower (ref.mRefID); // Add data required to make reference appear in the correct cell. // We should not need to test for duplicates, as this part of the code is pre-cell merge. diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 47cb0b99e..04451535b 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -71,9 +71,6 @@ namespace ESM // -1 is not blocked, otherwise it is blocked. signed char mReferenceBlocked; - // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. - int mDeleted; - // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza // Brindisi Dorom", where it has the value 100. Also only for // activators. diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index c22c1b22b..0d69b0263 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -141,7 +141,7 @@ std::string Cell::getDescription() const } } -bool Cell::getNextRef(ESMReader &esm, CellRef &ref) +bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) { // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) @@ -259,12 +259,13 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) //esm.getHNOT(NAM0, "NAM0"); } - if (esm.isNextSub("DELE")) { + if (esm.isNextSub("DELE")) + { esm.skipHSub(); - ref.mDeleted = 2; // Deleted, will not respawn. - // TODO: find out when references do respawn. - } else - ref.mDeleted = 0; + deleted = true; + } + else + deleted = false; return true; } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 61d586b9d..38aaa0494 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -141,7 +141,7 @@ struct Cell All fields of the CellRef struct are overwritten. You can safely reuse one memory location without blanking it between calls. */ - static bool getNextRef(ESMReader &esm, CellRef &ref); + static bool getNextRef(ESMReader &esm, CellRef &ref, bool& deleted); /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. From aba72ffefe9aec66b86ccf537054ce8366e8c0b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jan 2014 02:12:41 +0100 Subject: [PATCH 087/120] Fix up the merge a bit --- apps/openmw/mwmechanics/actors.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c488d4d2b..53adc694c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -797,22 +797,22 @@ namespace MWMechanics } } - // Apply soultrap - if (iter->first.getTypeName() == typeid(ESM::Creature).name()) - { - SoulTrap soulTrap (iter->first); - stats.getActiveSpells().visitEffectSources(soulTrap); - } - - // Reset magic effects and recalculate derived effects - // One case where we need this is to make sure bound items are removed upon death - stats.setMagicEffects(MWMechanics::MagicEffects()); - calculateCreatureStatModifiers(iter->first, 0); - if (iter->second->kill()) { ++mDeathCount[cls.getId(iter->first)]; + // Apply soultrap + if (iter->first.getTypeName() == typeid(ESM::Creature).name()) + { + SoulTrap soulTrap (iter->first); + stats.getActiveSpells().visitEffectSources(soulTrap); + } + + // Reset magic effects and recalculate derived effects + // One case where we need this is to make sure bound items are removed upon death + stats.setMagicEffects(MWMechanics::MagicEffects()); + calculateCreatureStatModifiers(iter->first, 0); + if(cls.isEssential(iter->first)) MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); } From 5ea25dc26958267e39d04461ce571284566a404c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 11 Jan 2014 15:34:32 +0100 Subject: [PATCH 088/120] player state cleanup --- apps/openmw/mwworld/player.cpp | 10 ++++++++++ apps/openmw/mwworld/player.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 1 + 3 files changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index c59445402..a2777d489 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -171,4 +171,14 @@ namespace MWWorld if (mMarkedCell) markedPosition = mMarkedPosition; } + + void Player::clear() + { + mCellStore = 0; + mSign.clear(); + mMarkedCell = 0; + mAutoMove = false; + mForwardBackward = 0; + mTeleported = false; + } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 1df848111..fef577cec 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -86,6 +86,8 @@ namespace MWWorld bool wasTeleported() const; void setTeleported(bool teleported); + + void clear(); }; } #endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 83885e5d5..5224ffdce 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -267,6 +267,7 @@ namespace MWWorld void World::clear() { mLocalScripts.clear(); + mPlayer->clear(); // enable collision if (!mPhysics->toggleCollisionMode()) From e453468eff18e769b0478fdf9f1fc87bd924d98a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 12 Jan 2014 19:23:08 +0100 Subject: [PATCH 089/120] moved CellRef loading code to the CellRef class --- components/esm/cellref.cpp | 70 ++++++++++++++++++++++++++++++++++++- components/esm/cellref.hpp | 3 ++ components/esm/loadcell.cpp | 69 +----------------------------------- 3 files changed, 73 insertions(+), 69 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 23a95a4ab..bdb0e23de 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -1,12 +1,80 @@ #include "cellref.hpp" +#include "esmreader.hpp" #include "esmwriter.hpp" +void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) +{ + // NAM0 sometimes appears here, sometimes further on + mNam0 = 0; + if (esm.isNextSub ("NAM0")) + esm.getHT (mNam0); + + if (wideRefNum) + esm.getHNT (mRefNum, "FRMR", 8); + else + esm.getHNT (mRefNum.mIndex, "FRMR"); + + mRefID = esm.getHNString ("NAME"); + + mScale = 1.0; + esm.getHNOT (mScale, "XSCL"); + + mOwner = esm.getHNOString ("ANAM"); + mGlob = esm.getHNOString ("BNAM"); + mSoul = esm.getHNOString ("XSOL"); + + mFaction = esm.getHNOString ("CNAM"); + mFactIndex = -2; + esm.getHNOT (mFactIndex, "INDX"); + + mGoldValue = 1; + mCharge = -1; + mEnchantmentCharge = -1; + + esm.getHNOT (mEnchantmentCharge, "XCHG"); + + esm.getHNOT (mCharge, "INTV"); + + esm.getHNOT (mGoldValue, "NAM9"); + + // Present for doors that teleport you to another cell. + if (esm.isNextSub ("DODT")) + { + mTeleport = true; + esm.getHT (mDoorDest); + mDestCell = esm.getHNOString ("DNAM"); + } + else + mTeleport = false; + + mLockLevel = -1; + esm.getHNOT (mLockLevel, "FLTV"); + mKey = esm.getHNOString ("KNAM"); + mTrap = esm.getHNOString ("TNAM"); + + mReferenceBlocked = -1; + mFltv = 0; + esm.getHNOT (mReferenceBlocked, "UNAM"); + esm.getHNOT (mFltv, "FLTV"); + + esm.getHNOT(mPos, "DATA", 24); + + // Number of references in the cell? Maximum once in each cell, + // but not always at the beginning, and not always right. In other + // words, completely useless. + // Update: Well, maybe not completely useless. This might actually be + // number_of_references + number_of_references_moved_here_Across_boundaries, + // and could be helpful for collecting these weird moved references. + if (esm.isNextSub ("NAM0")) + esm.getHT (mNam0); +} + void ESM::CellRef::save(ESMWriter &esm) const { esm.writeHNT("FRMR", mRefNum.mIndex); - /// \todo read content file index (if present) + esm.writeHNCString("NAME", mRefID); if (mScale != 1.0) { diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 60c2bc625..3d80a51bd 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -8,6 +8,7 @@ namespace ESM { class ESMWriter; + class ESMReader; /* Cell reference. This represents ONE object (of many) inside the cell. The cell references are not loaded as part of the normal @@ -86,6 +87,8 @@ namespace ESM // Position and rotation of this object within the cell Position mPos; + void load (ESMReader& esm, bool wideRefNum = false); + void save(ESMWriter &esm) const; void blank(); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 1fe92ffb1..efd6979b4 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -177,78 +177,11 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) // That should be it, I haven't seen any other fields yet. } - // NAM0 sometimes appears here, sometimes further on - ref.mNam0 = 0; - if (esm.isNextSub("NAM0")) - { - esm.getHT(ref.mNam0); - //esm.getHNOT(NAM0, "NAM0"); - } - - esm.getHNT (ref.mRefNum.mIndex, "FRMR"); - ref.mRefID = esm.getHNString("NAME"); + ref.load (esm); // Identify references belonging to a parent file and adapt the ID accordingly. adjustRefNum (ref.mRefNum, esm); - // getHNOT will not change the existing value if the subrecord is - // missing - ref.mScale = 1.0; - esm.getHNOT(ref.mScale, "XSCL"); - - ref.mOwner = esm.getHNOString("ANAM"); - ref.mGlob = esm.getHNOString("BNAM"); - ref.mSoul = esm.getHNOString("XSOL"); - - ref.mFaction = esm.getHNOString("CNAM"); - ref.mFactIndex = -2; - esm.getHNOT(ref.mFactIndex, "INDX"); - - ref.mGoldValue = 1; - ref.mCharge = -1; - ref.mEnchantmentCharge = -1; - - esm.getHNOT(ref.mEnchantmentCharge, "XCHG"); - - esm.getHNOT(ref.mCharge, "INTV"); - - esm.getHNOT(ref.mGoldValue, "NAM9"); - - // Present for doors that teleport you to another cell. - if (esm.isNextSub("DODT")) - { - ref.mTeleport = true; - esm.getHT(ref.mDoorDest); - ref.mDestCell = esm.getHNOString("DNAM"); - } else { - ref.mTeleport = false; - } - - // Integer, despite the name suggesting otherwise - ref.mLockLevel = -1; - esm.getHNOT(ref.mLockLevel, "FLTV"); - ref.mKey = esm.getHNOString("KNAM"); - ref.mTrap = esm.getHNOString("TNAM"); - - ref.mReferenceBlocked = -1; - ref.mFltv = 0; - esm.getHNOT(ref.mReferenceBlocked, "UNAM"); - esm.getHNOT(ref.mFltv, "FLTV"); - - esm.getHNOT(ref.mPos, "DATA", 24); - - // Number of references in the cell? Maximum once in each cell, - // but not always at the beginning, and not always right. In other - // words, completely useless. - // Update: Well, maybe not completely useless. This might actually be - // number_of_references + number_of_references_moved_here_Across_boundaries, - // and could be helpful for collecting these weird moved references. - if (esm.isNextSub("NAM0")) - { - esm.getHT(ref.mNam0); - //esm.getHNOT(NAM0, "NAM0"); - } - if (esm.isNextSub("DELE")) { esm.skipHSub(); From 8c5f3135462e0b6e44de4733d917d66c2dfdaed1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jan 2014 12:25:35 +0100 Subject: [PATCH 090/120] added savedgame-specifc record structs for objects state --- components/CMakeLists.txt | 2 +- components/esm/cellid.cpp | 26 +++++++++++++++++++ components/esm/cellid.hpp | 28 ++++++++++++++++++++ components/esm/defs.hpp | 1 + components/esm/loadcell.cpp | 24 +++++++++++++++++ components/esm/loadcell.hpp | 3 +++ components/esm/objectstate.cpp | 47 ++++++++++++++++++++++++++++++++++ components/esm/objectstate.hpp | 36 ++++++++++++++++++++++++++ components/esm/player.cpp | 44 +++++++++++++++++++++++++++++++ components/esm/player.hpp | 32 +++++++++++++++++++++++ 10 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 components/esm/cellid.cpp create mode 100644 components/esm/cellid.hpp create mode 100644 components/esm/objectstate.cpp create mode 100644 components/esm/objectstate.hpp create mode 100644 components/esm/player.cpp create mode 100644 components/esm/player.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index dbf8c1132..4c0bff59d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript + savedgame journalentry queststate locals globalscript player objectstate cellid ) add_component_dir (misc diff --git a/components/esm/cellid.cpp b/components/esm/cellid.cpp new file mode 100644 index 000000000..5bc8b7aef --- /dev/null +++ b/components/esm/cellid.cpp @@ -0,0 +1,26 @@ + +#include "cellid.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::CellId::load (ESMReader &esm) +{ + mWorldspace = esm.getHNString ("SPAC"); + + if (esm.isNextSub ("CIDX")) + { + esm.getHT (mIndex, 8); + mPaged = true; + } + else + mPaged = false; +} + +void ESM::CellId::save (ESMWriter &esm) const +{ + esm.writeHNString ("SPAC", mWorldspace); + + if (mPaged) + esm.writeHNT ("CIDX", mIndex, 8); +} \ No newline at end of file diff --git a/components/esm/cellid.hpp b/components/esm/cellid.hpp new file mode 100644 index 000000000..54dbdae78 --- /dev/null +++ b/components/esm/cellid.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_ESM_CELLID_H +#define OPENMW_ESM_CELLID_H + +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + struct CellId + { + struct CellIndex + { + int mX; + int mY; + }; + + std::string mWorldspace; + CellIndex mIndex; + bool mPaged; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif \ No newline at end of file diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 4cf0b1dac..2b956d216 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -88,6 +88,7 @@ enum RecNameInts REC_JOUR = 0x524f55a4, REC_QUES = 0x53455551, REC_GSCR = 0x52435347, + REC_PLAY = 0x504c4159, // format 1 REC_FILT = 0x544C4946 diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index efd6979b4..649e3175d 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -3,11 +3,15 @@ #include #include #include + #include +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" +#include "cellid.hpp" namespace { @@ -221,4 +225,24 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) mAmbi.mFog = 0; mAmbi.mFogDensity = 0; } + + CellId Cell::getCellId() const + { + CellId id; + + id.mPaged = (mData.mFlags & Interior); + + if (id.mPaged) + { + id.mWorldspace = "default"; + id.mIndex.mX = mData.mX; + id.mIndex.mY = mData.mY; + } + else + { + id.mWorldspace = Misc::StringUtils::lowerCase (mName); + } + + return id; + } } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 85b3d8954..643119e67 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -18,6 +18,7 @@ namespace ESM { class ESMReader; class ESMWriter; + class CellId; /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another @@ -150,6 +151,8 @@ struct Cell void blank(); ///< Set record to default state (does not touch the ID/index). + + CellId getCellId() const; }; } #endif diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp new file mode 100644 index 000000000..b13b6c226 --- /dev/null +++ b/components/esm/objectstate.cpp @@ -0,0 +1,47 @@ + +#include "objectstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::ObjectState::load (ESMReader &esm) +{ + mRef.load (esm, true); + + mHasLocals = 0; + esm.getHNOT (mHasLocals, "HLOC"); + + if (mHasLocals) + mLocals.load (esm); + + mEnabled = 1; + esm.getHNOT (mEnabled, "ENAB"); + + mCount = 1; + esm.getHNOT (mCount, "COUN"); + + esm.getHNT (mPosition, "POS_", 24); + + esm.getHNT (mLocalRotation, "LROT", 12); +} + +void ESM::ObjectState::save (ESMWriter &esm) const +{ + mRef.save (esm); + + if (mHasLocals) + { + esm.writeHNT ("HLOC", mHasLocals); + mLocals.save (esm); + } + + if (!mEnabled) + esm.writeHNT ("ENAB", mEnabled); + + if (mCount!=1) + esm.writeHNT ("COUN", mCount); + + esm.writeHNT ("POS_", mPosition, 24); + + esm.writeHNT ("LROT", mLocalRotation, 12); +} \ No newline at end of file diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp new file mode 100644 index 000000000..bbbc4798f --- /dev/null +++ b/components/esm/objectstate.hpp @@ -0,0 +1,36 @@ +#ifndef OPENMW_ESM_OBJECTSTATE_H +#define OPENMW_ESM_OBJECTSTATE_H + +#include +#include + +#include "cellref.hpp" +#include "locals.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + ///< \brief Save state for objects, that do not use custom data + struct ObjectState + { + std::string mId; + + CellRef mRef; + + unsigned char mHasLocals; + Locals mLocals; + unsigned char mEnabled; + int mCount; + ESM::Position mPosition; + float mLocalRotation[3]; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif \ No newline at end of file diff --git a/components/esm/player.cpp b/components/esm/player.cpp new file mode 100644 index 000000000..13602fb67 --- /dev/null +++ b/components/esm/player.cpp @@ -0,0 +1,44 @@ + +#include "player.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::Player::load (ESMReader &esm) +{ + mObject.load (esm); + + mCellId.load (esm); + + esm.getHNT (mLastKnownExteriorPosition, "LKEP", 12); + + if (esm.isNextSub ("MARK")) + { + mHasMark = true; + esm.getHT (mMarkedPosition, 24); + mMarkedCell.load (esm); + } + else + mHasMark = false; + + mAutoMove = 0; + esm.getHNOT (mAutoMove, "AMOV"); +} + +void ESM::Player::save (ESMWriter &esm) const +{ + mObject.save (esm); + + mCellId.save (esm); + + esm.writeHNT ("LKEP", mLastKnownExteriorPosition, 12); + + if (mHasMark) + { + esm.writeHNT ("MARK", mMarkedPosition, 24); + mMarkedCell.save (esm); + } + + if (mAutoMove) + esm.writeHNT ("AMOV", mAutoMove); +} \ No newline at end of file diff --git a/components/esm/player.hpp b/components/esm/player.hpp new file mode 100644 index 000000000..3f7db17f7 --- /dev/null +++ b/components/esm/player.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_ESM_PLAYER_H +#define OPENMW_ESM_PLAYER_H + +#include + +#include "objectstate.hpp" +#include "cellid.hpp" +#include "defs.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct Player + { + ObjectState mObject; + CellId mCellId; + float mLastKnownExteriorPosition[3]; + unsigned char mHasMark; + ESM::Position mMarkedPosition; + CellId mMarkedCell; + unsigned char mAutoMove; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif \ No newline at end of file From d8d4f1a15e0bd49155031dd7fffdd3012e99af31 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jan 2014 12:02:45 +0100 Subject: [PATCH 091/120] some fixes to record structs --- components/esm/cellref.cpp | 7 +++++-- components/esm/cellref.hpp | 2 +- components/esm/loadcell.cpp | 2 +- components/esm/objectstate.cpp | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index bdb0e23de..b9f630290 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -71,9 +71,12 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) esm.getHT (mNam0); } -void ESM::CellRef::save(ESMWriter &esm) const +void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum) const { - esm.writeHNT("FRMR", mRefNum.mIndex); + if (wideRefNum) + esm.writeHNT ("FRMR", mRefNum, 8); + else + esm.writeHNT ("FRMR", mRefNum.mIndex, 4); esm.writeHNCString("NAME", mRefID); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 3d80a51bd..01b546d5a 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -89,7 +89,7 @@ namespace ESM void load (ESMReader& esm, bool wideRefNum = false); - void save(ESMWriter &esm) const; + void save(ESMWriter &esm, bool wideRefNum = false) const; void blank(); }; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 649e3175d..cfd73554a 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -230,7 +230,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) { CellId id; - id.mPaged = (mData.mFlags & Interior); + id.mPaged = !(mData.mFlags & Interior); if (id.mPaged) { diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index b13b6c226..56289acae 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -27,7 +27,7 @@ void ESM::ObjectState::load (ESMReader &esm) void ESM::ObjectState::save (ESMWriter &esm) const { - mRef.save (esm); + mRef.save (esm, true); if (mHasLocals) { From c300cd93752ad23dd3db600433ba2e7c9e447720 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jan 2014 12:03:23 +0100 Subject: [PATCH 092/120] loading/saving of some player state (cell/coordinates and some other bits) --- apps/openmw/mwbase/world.hpp | 7 ++- apps/openmw/mwstate/statemanagerimp.cpp | 13 +++--- apps/openmw/mwworld/livecellref.cpp | 21 +++++++++ apps/openmw/mwworld/livecellref.hpp | 57 +++++++++++++++++++++++ apps/openmw/mwworld/player.cpp | 60 +++++++++++++++++++++++-- apps/openmw/mwworld/player.hpp | 6 +++ apps/openmw/mwworld/refdata.cpp | 21 +++++++++ apps/openmw/mwworld/refdata.hpp | 9 ++++ apps/openmw/mwworld/worldimp.cpp | 21 ++++++++- apps/openmw/mwworld/worldimp.hpp | 6 ++- 10 files changed, 210 insertions(+), 11 deletions(-) create mode 100644 apps/openmw/mwworld/livecellref.cpp diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 06f6d6fac..eaf411d20 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -37,6 +37,7 @@ namespace ESM struct Potion; struct Spell; struct NPC; + struct CellId; } namespace MWRender @@ -105,12 +106,14 @@ namespace MWBase virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; virtual OEngine::Render::Fader* getFader() = 0; - ///< \ŧodo remove this function. Rendering details should not be exposed. + ///< \todo remove this function. Rendering details should not be exposed. virtual MWWorld::CellStore *getExterior (int x, int y) = 0; virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; + virtual MWWorld::CellStore *getCell (const ESM::CellId& id) = 0; + virtual void useDeathCamera() = 0; virtual void setWaterHeight(const float height) = 0; @@ -236,6 +239,8 @@ namespace MWBase virtual void changeToExteriorCell (const ESM::Position& position) = 0; ///< Move to exterior cell. + virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position) = 0; + virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0; ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 11b2d546f..2eb54a125 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include @@ -216,6 +218,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl case ESM::REC_SPEL: case ESM::REC_WEAP: case ESM::REC_GLOB: + case ESM::REC_PLAY: MWBase::Environment::get().getWorld()->readRecord (reader, n.val); break; @@ -245,11 +248,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl MWBase::Environment::get().getWindowManager()->updatePlayer(); MWBase::Environment::get().getMechanicsManager()->playerLoaded(); - // for testing purpose only - ESM::Position pos; - pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; - pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); + 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()); } MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp new file mode 100644 index 000000000..a12d20e6a --- /dev/null +++ b/apps/openmw/mwworld/livecellref.cpp @@ -0,0 +1,21 @@ + +#include "livecellref.hpp" + +#include + +void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state) +{ + mRef = state.mRef; + mData = RefData (state); +} + +void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const +{ + state.mRef = mRef; + mData.write (state); +} + +bool MWWorld::LiveCellRefBase::checkStateImp (const ESM::ObjectState& state) +{ + return true; +} \ No newline at end of file diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 558639a3b..46f49df78 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -7,6 +7,11 @@ #include "refdata.hpp" +namespace ESM +{ + class ObjectState; +} + namespace MWWorld { class Ptr; @@ -29,6 +34,24 @@ namespace MWWorld LiveCellRefBase(std::string type, const ESM::CellRef &cref=ESM::CellRef()); /* Need this for the class to be recognized as polymorphic */ virtual ~LiveCellRefBase() { } + + protected: + + void loadImp (const ESM::ObjectState& state); + ///< Load state into a LiveCellRef, that has already been initialised with base and + /// class. + /// + /// \attention Must not be called with an invalid \a state. + + void saveImp (ESM::ObjectState& state) const; + ///< Save LiveCellRef state into \a state. + + static bool checkStateImp (const ESM::ObjectState& state); + ///< Check if state is valid and report errors. + /// + /// \return Valid? + /// + /// \note Does not check if the RefId exists. }; inline bool operator== (const LiveCellRefBase& cellRef, const ESM::CellRef::RefNum refNum) @@ -55,7 +78,41 @@ namespace MWWorld // The object that this instance is based on. const X* mBase; + + void load (const ESM::ObjectState& state); + ///< Load state into a LiveCellRef, that has already been initialised with base and class. + /// + /// \attention Must not be called with an invalid \a state. + + void save (ESM::ObjectState& state) const; + ///< Save LiveCellRef state into \a state. + + static bool checkState (const ESM::ObjectState& state); + ///< Check if state is valid and report errors. + /// + /// \return Valid? + /// + /// \note Does not check if the RefId exists. }; + + template + void LiveCellRef::load (const ESM::ObjectState& state) + { + loadImp (state); + } + + template + void LiveCellRef::save (ESM::ObjectState& state) const + { + saveImp (state); + } + + template + bool LiveCellRef::checkState (const ESM::ObjectState& state) + { + return checkStateImp (state); + } + } #endif diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index a2777d489..14e310432 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,6 +1,13 @@ #include "player.hpp" +#include + +#include +#include +#include +#include + #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) @@ -181,4 +185,54 @@ namespace MWWorld mForwardBackward = 0; mTeleported = false; } + + void Player::write (ESM::ESMWriter& writer) const + { + ESM::Player player; + + mPlayer.save (player.mObject); + player.mCellId = mCellStore->mCell->getCellId(); + + /// \todo sign + /// \todo last know exterior position + /// \todo mark + + 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"); + } + + mPlayer.load (player.mObject); + + mCellStore = MWBase::Environment::get().getWorld()->getCell (player.mCellId); + + /// \todo sign + /// \todo last know exterior position + /// \todo mark + + mAutoMove = player.mAutoMove!=0; + + mForwardBackward = 0; + mTeleported = false; + + return true; + } + + return false; + } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index fef577cec..7eb023a2b 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -11,6 +11,8 @@ namespace ESM { struct NPC; + class ESMWriter; + class ESMReader; } namespace MWBase @@ -88,6 +90,10 @@ namespace MWWorld void setTeleported(bool teleported); void clear(); + + void write (ESM::ESMWriter& writer) const; + + bool readRecord (ESM::ESMReader& reader, int32_t type); }; } #endif diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 87d0efe19..8d48078b1 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -3,6 +3,8 @@ #include +#include + #include "customdata.hpp" #include "cellstore.hpp" @@ -52,6 +54,14 @@ namespace MWWorld mLocalRotation.rot[2]=0; } + RefData::RefData (const ESM::ObjectState& objectState) + : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled), + mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0) + { + for (int i=0; i<3; ++i) + mLocalRotation.rot[i] = objectState.mLocalRotation[i]; + } + RefData::RefData (const RefData& refData) : mBaseNode(0), mCustomData (0) { @@ -66,6 +76,17 @@ namespace MWWorld } } + void RefData::write (ESM::ObjectState& objectState) const + { + objectState.mHasLocals = false; + objectState.mEnabled = mEnabled; + objectState.mCount = mCount; + objectState.mPosition = mPosition; + + for (int i=0; i<3; ++i) + objectState.mLocalRotation[i] = mLocalRotation.rot[i]; + } + RefData& RefData::operator= (const RefData& refData) { try diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 07841e470..d9f5697bd 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -14,6 +14,7 @@ namespace ESM { class Script; class CellRef; + class ObjectState; } namespace MWWorld @@ -55,10 +56,18 @@ namespace MWWorld /// to reset the position as the orignal data is still held in the CellRef RefData (const ESM::CellRef& cellRef); + RefData (const ESM::ObjectState& objectState); + ///< Ignores local variables and custom data (not enough context available here to + /// perform these operations). + RefData (const RefData& refData); ~RefData(); + void write (ESM::ObjectState& objectState) const; + ///< Ignores local variables and custom data (not enough context available here to + /// perform these operations). + RefData& operator= (const RefData& refData); /// Return OGRE handle (may be empty). diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5224ffdce..8edba0892 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -309,12 +310,14 @@ namespace MWWorld { mStore.write (writer); mGlobalVariables.write (writer); + mPlayer->write (writer); } void World::readRecord (ESM::ESMReader& reader, int32_t type) { if (!mStore.readRecord (reader, type) && - !mGlobalVariables.readRecord (reader, type)) + !mGlobalVariables.readRecord (reader, type) && + !mPlayer->readRecord (reader, type)) { throw std::runtime_error ("unknown record in saved game"); } @@ -402,6 +405,14 @@ namespace MWWorld return mCells.getInterior (name); } + CellStore *World::getCell (const ESM::CellId& id) + { + if (id.mPaged) + return getExterior (id.mIndex.mX, id.mIndex.mY); + else + return getInterior (id.mWorldspace); + } + void World::useDeathCamera() { if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() ) @@ -802,6 +813,14 @@ namespace MWWorld addContainerScripts(getPlayer().getPlayer(), getPlayer().getPlayer().getCell()); } + void World::changeToCell (const ESM::CellId& cellId, const ESM::Position& position) + { + if (cellId.mPaged) + changeToExteriorCell (position); + else + changeToInteriorCell (cellId.mWorldspace, position); + } + void World::markCellAsUnchanged() { return mWorldScene->markCellAsUnchanged(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d7befcc6e..58a6111c5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -181,12 +181,14 @@ namespace MWWorld virtual void readRecord (ESM::ESMReader& reader, int32_t type); virtual OEngine::Render::Fader* getFader(); - ///< \ŧodo remove this function. Rendering details should not be exposed. + ///< \todo remove this function. Rendering details should not be exposed. virtual CellStore *getExterior (int x, int y); virtual CellStore *getInterior (const std::string& name); + virtual CellStore *getCell (const ESM::CellId& id); + //switch to POV before showing player's death animation virtual void useDeathCamera(); @@ -314,6 +316,8 @@ namespace MWWorld virtual void changeToExteriorCell (const ESM::Position& position); ///< Move to exterior cell. + virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position); + virtual const ESM::Cell *getExterior (const std::string& cellName) const; ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. From ce00639d31eea587cc8e921c94914479ccd711bf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jan 2014 10:51:52 +0100 Subject: [PATCH 093/120] added missing birthsign field to player state record --- components/esm/player.cpp | 4 ++++ components/esm/player.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/components/esm/player.cpp b/components/esm/player.cpp index 13602fb67..d5ddc74d0 100644 --- a/components/esm/player.cpp +++ b/components/esm/player.cpp @@ -23,6 +23,8 @@ void ESM::Player::load (ESMReader &esm) mAutoMove = 0; esm.getHNOT (mAutoMove, "AMOV"); + + mBirthsign = esm.getHNString ("SIGN"); } void ESM::Player::save (ESMWriter &esm) const @@ -41,4 +43,6 @@ void ESM::Player::save (ESMWriter &esm) const if (mAutoMove) esm.writeHNT ("AMOV", mAutoMove); + + esm.writeHNString ("SIGN", mBirthsign); } \ No newline at end of file diff --git a/components/esm/player.hpp b/components/esm/player.hpp index 3f7db17f7..bd618457e 100644 --- a/components/esm/player.hpp +++ b/components/esm/player.hpp @@ -23,6 +23,7 @@ namespace ESM ESM::Position mMarkedPosition; CellId mMarkedCell; unsigned char mAutoMove; + std::string mBirthsign; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 1b7697a4b21dd6b1af49eedcbfdf8598a9b4c732 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jan 2014 13:07:57 +0100 Subject: [PATCH 094/120] handle missing player specific state during load/save --- apps/openmw/mwworld/player.cpp | 54 +++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 14e310432..f03abe5bc 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -193,9 +193,20 @@ namespace MWWorld mPlayer.save (player.mObject); player.mCellId = mCellStore->mCell->getCellId(); - /// \todo sign - /// \todo last know exterior position - /// \todo mark + 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; @@ -214,16 +225,43 @@ namespace MWWorld if (!mPlayer.checkState (player.mObject)) { // this is the one object we can not silently drop. - throw std::runtime_error ("invalid player state record"); + throw std::runtime_error ("invalid player state record (object state)"); } mPlayer.load (player.mObject); - mCellStore = MWBase::Environment::get().getWorld()->getCell (player.mCellId); + MWBase::World& world = *MWBase::Environment::get().getWorld(); - /// \todo sign - /// \todo last know exterior position - /// \todo mark + mCellStore = world.getCell (player.mCellId); + + if (!player.mBirthsign.empty() && + !world.getStore().get().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().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; From 6584a01d01190ed9d2bccc6ebdc4ab6dd87f07fa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jan 2014 14:53:25 +0100 Subject: [PATCH 095/120] reset reference to player NPC record during cleanup --- apps/openmw/mwworld/worldimp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8edba0892..9704239d7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -276,15 +276,16 @@ namespace MWWorld mWorldScene->changeToVoid(); + mStore.clearDynamic(); + mStore.setUp(); + if (mPlayer) { mPlayer->setCell (0); mPlayer->getPlayer().getRefData() = RefData(); + mPlayer->set (mStore.get().find ("player")); } - mStore.clearDynamic(); - mStore.setUp(); - mCells.clear(); mProjectiles.clear(); From 14e64c180f0b685327c51a22ba78f81a296e0a28 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jan 2014 15:06:58 +0100 Subject: [PATCH 096/120] on load check player record for dangling ID references --- apps/openmw/mwworld/esmstore.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index cab10ee51..c5c826d47 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -161,9 +161,9 @@ void ESMStore::setUp() mClasses.write (writer); mClothes.write (writer); mEnchants.write (writer); - mNpcs.write (writer); mSpells.write (writer); mWeapons.write (writer); + mNpcs.write (writer); } bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type) @@ -176,11 +176,25 @@ void ESMStore::setUp() case ESM::REC_CLAS: case ESM::REC_CLOT: case ESM::REC_ENCH: - case ESM::REC_NPC_: case ESM::REC_SPEL: case ESM::REC_WEAP: + case ESM::REC_NPC_: mStores[type]->read (reader); + + if (type==ESM::REC_NPC_) + { + // NPC record will always be last and we know that there can be only one + // dynamic NPC record (player) -> We are done here with dynamic record laoding + setUp(); + + const ESM::NPC *player = mNpcs.find ("player"); + + if (!mRaces.find (player->mRace) || + !mClasses.find (player->mClass)) + throw std::runtime_error ("Invalid player record (race or class unavilable"); + } + return true; default: From 0f6089851759129daca3ce9995df6a170f7cf077 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 21 Jan 2014 14:13:13 +0100 Subject: [PATCH 097/120] adding missing cleanup for SoundManager --- apps/openmw/mwbase/soundmanager.hpp | 2 ++ apps/openmw/mwsound/soundmanagerimp.cpp | 9 +++++++++ apps/openmw/mwsound/soundmanagerimp.hpp | 2 ++ apps/openmw/mwstate/statemanagerimp.cpp | 2 ++ 4 files changed, 15 insertions(+) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 4d764597c..1b3719e60 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -147,6 +147,8 @@ namespace MWBase virtual void update(float duration) = 0; virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0; + + virtual void clear() = 0; }; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 304c87191..95a4cd1dc 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -705,4 +705,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(); + } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index f62e62d50..bc8ef1db7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -148,6 +148,8 @@ namespace MWSound virtual void update(float duration); virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up); + + virtual void clear(); }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 2eb54a125..8571e93ff 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -15,6 +15,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -27,6 +28,7 @@ void MWState::StateManager::cleanup() { if (mState!=State_NoGame) { + MWBase::Environment::get().getSoundManager()->clear(); MWBase::Environment::get().getDialogueManager()->clear(); MWBase::Environment::get().getJournal()->clear(); MWBase::Environment::get().getScriptManager()->getGlobalScripts().clear(); From 9ebe66e693bcd38ddc6f2175e1a1e01f07095826 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 21 Jan 2014 14:50:58 +0100 Subject: [PATCH 098/120] improved cleanup; failed loads will now drop back into the main menu instead of crashing --- apps/openmw/mwgui/savegamedialog.cpp | 7 +++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.cpp | 9 +++++++-- apps/openmw/mwsound/soundmanagerimp.cpp | 10 ++++++++-- apps/openmw/mwworld/worldimp.cpp | 2 +- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 04461fef9..552489bc4 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -8,6 +8,7 @@ #include "../mwbase/statemanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwstate/character.hpp" @@ -123,6 +124,12 @@ namespace MWGui } setVisible(false); + + if (MWBase::Environment::get().getStateManager()->getState()== + MWBase::StateManager::State_NoGame) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + } } void SaveGameDialog::onCharacterSelected(MyGUI::ComboBox *sender, size_t pos) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9e57f5041..27d37eacf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -14,6 +14,7 @@ #include #include "../mwbase/inputmanager.hpp" +#include "../mwbase/statemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -709,6 +710,10 @@ namespace MWGui mToolTips->onFrame(frameDuration); + if (MWBase::Environment::get().getStateManager()->getState()== + MWBase::StateManager::State_NoGame) + return; + if (mDragAndDrop->mIsOnDragAndDrop) { assert(mDragAndDrop->mDraggedWidget); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f97d7bebf..55ead476b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -30,6 +30,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" // FIXME #include "../mwbase/windowmanager.hpp" // FIXME +#include "../mwbase/statemanager.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -329,6 +330,12 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) void RenderingManager::update (float duration, bool paused) { + mVideoPlayer->update (); + + if (MWBase::Environment::get().getStateManager()->getState()== + MWBase::StateManager::State_NoGame) + return; + MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayer().getPlayer(); @@ -365,8 +372,6 @@ void RenderingManager::update (float duration, bool paused) mOcclusionQuery->update(duration); - mVideoPlayer->update (); - mRendering.update(duration); Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 95a4cd1dc..827ecd643 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -6,6 +6,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/statemanager.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" @@ -607,8 +608,13 @@ namespace MWSound { if(!mOutput->isInitialized()) return; - updateSounds(duration); - updateRegionSound(duration); + + if (MWBase::Environment::get().getStateManager()->getState()!= + MWBase::StateManager::State_NoGame) + { + updateSounds(duration); + updateRegionSound(duration); + } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9704239d7..706701fa8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1335,7 +1335,7 @@ namespace MWWorld updateWindowManager (); - if (mPlayer->getPlayer().getCell()->isExterior()) + if (!paused && mPlayer->getPlayer().getCell()->isExterior()) { ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); From 22cb4784b5079bb8d3d453bdb076dfc4b438d1d4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 23 Jan 2014 11:29:40 +0100 Subject: [PATCH 099/120] store cell state in saved game files (no references yet) --- apps/openmw/mwstate/statemanagerimp.cpp | 127 +++++++++++++----------- apps/openmw/mwstate/statemanagerimp.hpp | 2 +- apps/openmw/mwworld/cells.cpp | 96 ++++++++++++++++++ apps/openmw/mwworld/cells.hpp | 17 +++- apps/openmw/mwworld/cellstore.cpp | 21 ++++ apps/openmw/mwworld/cellstore.hpp | 10 +- apps/openmw/mwworld/worldimp.cpp | 8 +- components/CMakeLists.txt | 2 +- components/esm/cellstate.cpp | 17 ++++ components/esm/cellstate.hpp | 25 +++++ components/esm/defs.hpp | 3 +- 11 files changed, 261 insertions(+), 67 deletions(-) create mode 100644 components/esm/cellstate.cpp create mode 100644 components/esm/cellstate.hpp diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 8571e93ff..7020678d0 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -24,9 +24,9 @@ #include "../mwscript/globalscripts.hpp" -void MWState::StateManager::cleanup() +void MWState::StateManager::cleanup (bool force) { - if (mState!=State_NoGame) + if (mState!=State_NoGame || force) { MWBase::Environment::get().getSoundManager()->clear(); MWBase::Environment::get().getDialogueManager()->clear(); @@ -184,77 +184,86 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot void MWState::StateManager::loadGame (const Character *character, const Slot *slot) { - cleanup(); - - mTimePlayed = slot->mProfile.mTimePlayed; - - ESM::ESMReader reader; - reader.open (slot->mPath.string()); - - while (reader.hasMoreRecs()) + try { - ESM::NAME n = reader.getRecName(); - reader.getRecHeader(); + cleanup(); - switch (n.val) + mTimePlayed = slot->mProfile.mTimePlayed; + + ESM::ESMReader reader; + reader.open (slot->mPath.string()); + + while (reader.hasMoreRecs()) { - case ESM::REC_SAVE: + ESM::NAME n = reader.getRecName(); + reader.getRecHeader(); - // don't need to read that here - reader.skipRecord(); - break; + switch (n.val) + { + case ESM::REC_SAVE: - case ESM::REC_JOUR: - case ESM::REC_QUES: + // don't need to read that here + reader.skipRecord(); + break; - MWBase::Environment::get().getJournal()->readRecord (reader, n.val); - break; + case ESM::REC_JOUR: + case ESM::REC_QUES: - case ESM::REC_ALCH: - case ESM::REC_ARMO: - case ESM::REC_BOOK: - case ESM::REC_CLAS: - case ESM::REC_CLOT: - case ESM::REC_ENCH: - case ESM::REC_NPC_: - case ESM::REC_SPEL: - case ESM::REC_WEAP: - case ESM::REC_GLOB: - case ESM::REC_PLAY: + MWBase::Environment::get().getJournal()->readRecord (reader, n.val); + break; - MWBase::Environment::get().getWorld()->readRecord (reader, n.val); - break; + case ESM::REC_ALCH: + case ESM::REC_ARMO: + case ESM::REC_BOOK: + case ESM::REC_CLAS: + case ESM::REC_CLOT: + case ESM::REC_ENCH: + case ESM::REC_NPC_: + case ESM::REC_SPEL: + case ESM::REC_WEAP: + case ESM::REC_GLOB: + case ESM::REC_PLAY: + case ESM::REC_CSTA: - case ESM::REC_GSCR: + MWBase::Environment::get().getWorld()->readRecord (reader, n.val); + break; - MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val); - break; + case ESM::REC_GSCR: - default: + MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val); + break; - // ignore invalid records - /// \todo log error - reader.skipRecord(); + default: + + // ignore invalid records + /// \todo log error + reader.skipRecord(); + } } + + mCharacterManager.setCurrentCharacter(character); + + mState = State_Running; + + Settings::Manager::setString ("character", "Saves", + slot->mPath.parent_path().filename().string()); + + MWBase::Environment::get().getWorld()->setupPlayer(); + MWBase::Environment::get().getWorld()->renderPlayer(); + MWBase::Environment::get().getWindowManager()->updatePlayer(); + MWBase::Environment::get().getMechanicsManager()->playerLoaded(); + + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + ESM::CellId cellId = ptr.getCell()->mCell->getCellId(); + + MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition()); + } + catch (const std::exception& e) + { + std::cerr << "failed to load saved game: " << e.what() << std::endl; + cleanup (true); } - - mCharacterManager.setCurrentCharacter(character); - - mState = State_Running; - - Settings::Manager::setString ("character", "Saves", - slot->mPath.parent_path().filename().string()); - - MWBase::Environment::get().getWorld()->setupPlayer(); - MWBase::Environment::get().getWorld()->renderPlayer(); - MWBase::Environment::get().getWindowManager()->updatePlayer(); - MWBase::Environment::get().getMechanicsManager()->playerLoaded(); - - 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()); } MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index a2abcfd1b..d6bb7575d 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -19,7 +19,7 @@ namespace MWState private: - void cleanup(); + void cleanup (bool force = false); public: diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index c844b689e..ead12567f 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -1,5 +1,10 @@ #include "cells.hpp" +#include +#include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -59,6 +64,30 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore& return ptr; } +void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, const CellStore& cell) const +{ + ESM::CellState cellState; + + cell.saveState (cellState); + + writer.startRecord (ESM::REC_CSTA); + cellState.mId.save (writer); + cellState.save (writer); + /// \todo write references + 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& reader) : mStore (store), mReader (reader), mIdCache (40, std::pair ("", (CellStore*)0)), /// \todo make cache size configurable @@ -121,6 +150,14 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name) return &result->second; } +MWWorld::CellStore *MWWorld::Cells::getCell (const ESM::CellId& id) +{ + if (id.mPaged) + return getExterior (id.mIndex.mX, id.mIndex.mY); + + return getInterior (id.mWorldspace); +} + MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell, bool searchInContainers) { @@ -271,3 +308,62 @@ void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector::const_iterator iter (mInteriors.begin()); + iter!=mInteriors.end(); ++iter) + if (hasState (iter->second)) + ++count; + + for (std::map, 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, CellStore>::const_iterator iter (mExteriors.begin()); + iter!=mExteriors.end(); ++iter) + if (hasState (iter->second)) + writeCell (writer, iter->second); + + for (std::map::const_iterator iter (mInteriors.begin()); + iter!=mInteriors.end(); ++iter) + if (hasState (iter->second)) + writeCell (writer, iter->second); +} + +bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type) +{ + if (type==ESM::REC_CSTA) + { + ESM::CellState state; + state.mId.load (reader); + + CellStore *cellStore = 0; + + try + { + cellStore = getCell (state.mId); + } + catch (...) + { + // silently drop cells that don't exist anymore + /// \todo log + } + + state.load (reader); + cellStore->loadState (state); + reader.skipRecord(); + + return true; + } + + return false; +} \ No newline at end of file diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 31de2f60e..27e107646 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -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& reader); - ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole - /// world CellStore *getExterior (int x, int y); CellStore *getInterior (const std::string& name); + CellStore *getCell (const ESM::CellId& id); + Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false); ///< \param searchInContainers Only affect loaded cells. /// @note name must be lower case @@ -56,6 +63,12 @@ namespace MWWorld /// @note Due to the current implementation of getPtr this only supports one Ptr per cell. /// @note name must be lower case void getExteriorPtrs (const std::string& name, std::vector& out); + + int countSavedGameRecords() const; + + void write (ESM::ESMWriter& writer) const; + + bool readRecord (ESM::ESMReader& reader, int32_t type); }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index cffa0537a..3cbf85e8e 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -230,4 +233,22 @@ namespace MWWorld << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; } } + + void CellStore::loadState (const ESM::CellState& state) + { + if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater) + mWaterLevel = state.mWaterLevel; + + mWaterLevel = state.mWaterLevel; + } + + void CellStore::saveState (ESM::CellState& state) const + { + state.mId = mCell->getCellId(); + + if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater) + state.mWaterLevel = mWaterLevel; + + state.mWaterLevel = mWaterLevel; + } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 1da219a9e..64843e7a4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -7,6 +7,11 @@ #include "livecellref.hpp" #include "esmstore.hpp" +namespace ESM +{ + struct CellState; +} + namespace MWWorld { @@ -133,6 +138,10 @@ namespace MWWorld Ptr searchInContainer (const std::string& id); + void loadState (const ESM::CellState& state); + + void saveState (ESM::CellState& state) const; + private: template @@ -158,7 +167,6 @@ namespace MWWorld ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. - }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 706701fa8..f8321d74e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -304,13 +304,16 @@ namespace MWWorld { return mStore.countSavedGameRecords() - +mGlobalVariables.countSavedGameRecords(); + +mGlobalVariables.countSavedGameRecords() + +1 // player record + +mCells.countSavedGameRecords(); } void World::write (ESM::ESMWriter& writer) const { mStore.write (writer); mGlobalVariables.write (writer); + mCells.write (writer); mPlayer->write (writer); } @@ -318,7 +321,8 @@ namespace MWWorld { if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && - !mPlayer->readRecord (reader, type)) + !mPlayer->readRecord (reader, type) && + !mCells.readRecord (reader, type)) { throw std::runtime_error ("unknown record in saved game"); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 4c0bff59d..d9ab8129d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate ) add_component_dir (misc diff --git a/components/esm/cellstate.cpp b/components/esm/cellstate.cpp new file mode 100644 index 000000000..1f7e8197e --- /dev/null +++ b/components/esm/cellstate.cpp @@ -0,0 +1,17 @@ + +#include "cellstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::CellState::load (ESMReader &esm) +{ + mWaterLevel = 0; + esm.getHNOT (mWaterLevel, "WLVL"); +} + +void ESM::CellState::save (ESMWriter &esm) const +{ + if (!mId.mPaged) + esm.writeHNT ("WLVL", mWaterLevel); +} \ No newline at end of file diff --git a/components/esm/cellstate.hpp b/components/esm/cellstate.hpp new file mode 100644 index 000000000..cd0db3067 --- /dev/null +++ b/components/esm/cellstate.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESM_CELLSTATE_H +#define OPENMW_ESM_CELLSTATE_H + +#include "cellid.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + /// \note Does not include references + struct CellState + { + CellId mId; + + float mWaterLevel; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif \ No newline at end of file diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 2b956d216..1ca6e88fc 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -88,7 +88,8 @@ enum RecNameInts REC_JOUR = 0x524f55a4, REC_QUES = 0x53455551, REC_GSCR = 0x52435347, - REC_PLAY = 0x504c4159, + REC_PLAY = 0x59414c50, + REC_CSTA = 0x41545343, // format 1 REC_FILT = 0x544C4946 From dd7d80ffbc6e5b7eca0cef25d18c1d71fcc83742 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 23 Jan 2014 12:51:25 +0100 Subject: [PATCH 100/120] removed a redundant field from object state --- components/esm/objectstate.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index bbbc4798f..c599bb973 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -17,8 +17,6 @@ namespace ESM ///< \brief Save state for objects, that do not use custom data struct ObjectState { - std::string mId; - CellRef mRef; unsigned char mHasLocals; From 419e3a7d30f223088d16dfdc1a838b59b5cf6121 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 23 Jan 2014 12:51:42 +0100 Subject: [PATCH 101/120] write references in cells to saved game file --- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 50 +++++++++++++++++++++++++++++++ apps/openmw/mwworld/cellstore.hpp | 2 ++ components/esm/defs.hpp | 1 + 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index ead12567f..77ea3856c 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -73,7 +73,7 @@ void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, const CellStore& cell) c writer.startRecord (ESM::REC_CSTA); cellState.mId.save (writer); cellState.save (writer); - /// \todo write references + cell.writeReferences (writer); writer.endRecord (ESM::REC_CSTA); } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 3cbf85e8e..b8cd15f53 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -32,6 +34,30 @@ namespace return MWWorld::Ptr(); } + + template + void writeReferenceCollection (ESM::ESMWriter& writer, + const MWWorld::CellRefList& collection) + { + if (!collection.mList.empty()) + { + // section header + writer.writeHNT ("CSEC", collection.mList.front().mBase->sRecordId); + + // references + for (typename MWWorld::CellRefList::List::const_iterator + iter (collection.mList.begin()); + iter!=collection.mList.end(); ++iter) + { + RecordType state; + iter->save (state); + + writer.startRecord (ESM::REC_OBJE); + state.save (writer); + writer.endRecord (ESM::REC_OBJE); + } + } + } } namespace MWWorld @@ -251,4 +277,28 @@ namespace MWWorld state.mWaterLevel = mWaterLevel; } + + void CellStore::writeReferences (ESM::ESMWriter& writer) const + { + writeReferenceCollection (writer, mActivators); + writeReferenceCollection (writer, mPotions); + writeReferenceCollection (writer, mAppas); + writeReferenceCollection (writer, mArmors); + writeReferenceCollection (writer, mBooks); + writeReferenceCollection (writer, mClothes); + writeReferenceCollection (writer, mContainers); + writeReferenceCollection (writer, mCreatures); + writeReferenceCollection (writer, mDoors); + writeReferenceCollection (writer, mIngreds); + writeReferenceCollection (writer, mCreatureLists); + writeReferenceCollection (writer, mItemLists); + writeReferenceCollection (writer, mLights); + writeReferenceCollection (writer, mLockpicks); + writeReferenceCollection (writer, mMiscItems); + writeReferenceCollection (writer, mNpcs); + writeReferenceCollection (writer, mProbes); + writeReferenceCollection (writer, mRepairs); + writeReferenceCollection (writer, mStatics); + writeReferenceCollection (writer, mWeapons); + } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 64843e7a4..feebfe90a 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -142,6 +142,8 @@ namespace MWWorld void saveState (ESM::CellState& state) const; + void writeReferences (ESM::ESMWriter& writer) const; + private: template diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 1ca6e88fc..74d987df8 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -90,6 +90,7 @@ enum RecNameInts REC_GSCR = 0x52435347, REC_PLAY = 0x59414c50, REC_CSTA = 0x41545343, + REC_OBJE = 0x454a424f, // format 1 REC_FILT = 0x544C4946 From 460089c0aa1079764de73ff27f160ce0c337c845 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 23 Jan 2014 12:53:55 +0100 Subject: [PATCH 102/120] ignore deleted references that did not came from a content file --- apps/openmw/mwworld/cellstore.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index b8cd15f53..aea4e5b6a 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -49,6 +49,9 @@ namespace 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); From 786ed6ca5b462f3e28f6db2a647f6ca2fba361d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Jan 2014 20:56:24 +0100 Subject: [PATCH 103/120] Include some required Ogre headers explicitely --- apps/opencs/view/render/scenewidget.cpp | 1 + apps/openmw/mwrender/characterpreview.cpp | 1 + apps/openmw/mwrender/occlusionquery.cpp | 1 + apps/openmw/mwrender/shadows.cpp | 1 + apps/openmw/mwrender/water.cpp | 1 + components/nifogre/ogrenifloader.cpp | 4 +++- libs/openengine/ogre/renderer.cpp | 1 + 7 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index c8b37e9bb..620586bd2 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace CSVRender { diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 643225515..b1ec2d5ff 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index a69511acd..246103471 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "renderconst.hpp" diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 21bbe51b6..9ebb0ab08 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0a4db30e9..9e3105168 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "sky.hpp" #include "renderingmanager.hpp" diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 63e905766..b97d1dbe9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -36,6 +35,9 @@ #include #include #include +#include +#include +#include #include diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 9e5ec5414..c86697497 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include From 295aed3533592f3bc09d688c923a38a634668817 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jan 2014 17:49:16 +0100 Subject: [PATCH 104/120] Implement savegame screenshots --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwgui/savegamedialog.cpp | 28 ++++++++++++++++++ apps/openmw/mwrender/renderingmanager.cpp | 35 +++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 9 ++++++ apps/openmw/mwworld/worldimp.cpp | 5 ++++ apps/openmw/mwworld/worldimp.hpp | 1 + components/esm/savedgame.cpp | 8 ++++++ components/esm/savedgame.hpp | 3 +- 9 files changed, 89 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index eaf411d20..99346bc6f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -412,6 +412,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 diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 552489bc4..91993b0be 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,6 +1,9 @@ #include "savegamedialog.hpp" #include "widgets.hpp" +#include +#include + #include #include @@ -166,6 +169,7 @@ namespace MWGui if (pos == MyGUI::ITEM_NONE) { mInfoText->setCaption(""); + mScreenshot->setImageTexture(""); return; } @@ -199,5 +203,29 @@ namespace MWGui << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mInfoText->setCaptionWithReplacing(text.str()); + + // Decode screenshot + std::vector 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); } } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 55ead476b..84cc0ac23 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -289,6 +289,9 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) void RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + Ogre::Image im; + im.encode(".jpg"); + Ogre::SceneNode *child = mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); @@ -966,6 +969,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(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 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) { diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5631c9470..f62ca8b3c 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -213,6 +213,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); protected: virtual void windowResized(int x, int y); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 7020678d0..6251c49c4 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -8,6 +8,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" @@ -151,6 +153,13 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot 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 diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f8321d74e..46ed31217 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1810,6 +1810,11 @@ namespace MWWorld mRendering->frameStarted(dt, paused); } + void World::screenshot(Ogre::Image &image, int w, int h) + { + mRendering->screenshot(image, w, h); + } + void World::activateDoor(const MWWorld::Ptr& door) { if (mDoorStates.find(door) != mDoorStates.end()) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 58a6111c5..0e0bb2814 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -504,6 +504,7 @@ namespace MWWorld virtual void playVideo(const std::string& name, bool allowSkipping); virtual void stopVideo(); virtual void frameStarted (float dt, bool paused); + virtual void screenshot (Ogre::Image& image, int w, int h); /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 55b17289c..d6887f170 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -19,6 +19,11 @@ void ESM::SavedGame::load (ESMReader &esm) while (esm.isNextSub ("DEPE")) mContentFiles.push_back (esm.getHString()); + + esm.getSubNameIs("SCRN"); + esm.getSubHeader(); + mScreenshot.resize(esm.getSubSize()); + esm.getExact(&mScreenshot[0], mScreenshot.size()); } void ESM::SavedGame::save (ESMWriter &esm) const @@ -35,4 +40,7 @@ void ESM::SavedGame::save (ESMWriter &esm) const iter!=mContentFiles.end(); ++iter) esm.writeHNString ("DEPE", *iter); + esm.startSubRecord("SCRN"); + esm.write(&mScreenshot[0], mScreenshot.size()); + esm.endRecord("SCRN"); } diff --git a/components/esm/savedgame.hpp b/components/esm/savedgame.hpp index 6c11d318f..9c7bf551d 100644 --- a/components/esm/savedgame.hpp +++ b/components/esm/savedgame.hpp @@ -31,8 +31,7 @@ namespace ESM TimeStamp mInGameTime; double mTimePlayed; std::string mDescription; - - /// \todo add field for screenshot + std::vector mScreenshot; // raw jpg-encoded data void load (ESMReader &esm); void save (ESMWriter &esm) const; From f09328ca845306f2a033157ee924ba7d91b5ef48 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jan 2014 13:34:56 +0100 Subject: [PATCH 105/120] Clear global map overlay when starting/loading a game --- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwgui/mapwindow.cpp | 19 +++++++++++++---- apps/openmw/mwgui/mapwindow.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ apps/openmw/mwrender/globalmap.cpp | 25 +++++++++++------------ apps/openmw/mwrender/globalmap.hpp | 3 +++ apps/openmw/mwrender/renderingmanager.cpp | 3 --- apps/openmw/mwstate/statemanagerimp.cpp | 6 ++++-- apps/openmw/mwworld/worldimp.cpp | 1 + 10 files changed, 49 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c39de4400..4d47e7eb7 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -285,6 +285,9 @@ namespace MWBase /// Should the cursor be visible? virtual bool getCursorVisible() = 0; + + /// Clear all savegame-specific data + virtual void clear() = 0; }; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index ba6114262..c09b4fea0 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -434,7 +434,7 @@ namespace MWGui static int _counter=0; - MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", + MyGUI::Button* markerWidget = mGlobalMapOverlay->createWidget("ButtonImage", widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast(_counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); @@ -499,10 +499,11 @@ namespace MWGui mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - for (unsigned int i=0; igetChildCount (); ++i) + // force markers to foreground + for (unsigned int i=0; igetChildCount (); ++i) { - if (mGlobalMapImage->getChildAt (i)->getName().substr(0,4) == "Door") - mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + if (mGlobalMapOverlay->getChildAt (i)->getName().substr(0,4) == "Door") + mGlobalMapOverlay->getChildAt (i)->castType()->setImageResource("DoorMarker"); } globalMapUpdatePlayer(); @@ -573,4 +574,14 @@ 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)); + } + } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 7df2105dc..dec27199a 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -92,6 +92,9 @@ namespace MWGui virtual void open(); + /// Clear all savegame-specific data + void clear(); + 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); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e11d1afcc..8e49d6614 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1381,4 +1381,9 @@ namespace MWGui Settings::Manager::setFloat(setting + " h", "Windows", h); } + void WindowManager::clear() + { + mMap->clear(); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9838a667f..68dc947af 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -280,6 +280,9 @@ namespace MWGui virtual bool getCursorVisible(); + /// Clear all savegame-specific data + virtual void clear(); + private: bool mConsoleOnlyScripts; diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 120a83fae..522bbb321 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -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 buffer; - buffer.resize(mWidth * mHeight); - - // initialize to (0, 0, 0, 0) - for (int p=0; pgetBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mWidth*mHeight*4); - mOverlayTexture->getBuffer()->unlock(); + clear(); loadingListener->loadingOff(); } @@ -227,9 +216,19 @@ 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 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); + } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index aad9adcc4..20f40de99 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -31,6 +31,9 @@ namespace MWRender void exploreCell (int cellX, int cellY); + /// Clears the overlay + void clear(); + private: std::string mCacheDir; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 56096b2f5..f9dd4e566 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -290,9 +290,6 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) void RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { - Ogre::Image im; - im.encode(".jpg"); - Ogre::SceneNode *child = mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 6251c49c4..e94f790c7 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -35,6 +35,7 @@ void MWState::StateManager::cleanup (bool force) 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(); @@ -73,8 +74,8 @@ void MWState::StateManager::askLoadRecent() { MWState::Slot lastSave = *getCurrentCharacter()->begin(); std::vector buttons; - buttons.push_back("Yes"); - buttons.push_back("No"); + 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); @@ -257,6 +258,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl 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(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9d07d0119..e5138eaea 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -248,6 +248,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->updatePlayer(); + // FIXME: this will add cell 0,0 as visible on the global map ESM::Position pos; const int cellSize = 8192; pos.pos[0] = cellSize/2; From 9c0ed6955041285dfc9df39be6e06634a70c3239 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jan 2014 15:10:25 +0100 Subject: [PATCH 106/120] Fix CellRef loading issue causing a startup script failure when TR_Mainland.esm is loaded. --- components/esm/cellref.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index b9f630290..19427af0c 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -18,6 +18,11 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) mRefID = esm.getHNString ("NAME"); + // Again, UNAM sometimes appears after NAME and sometimes later. + // Or perhaps this UNAM means something different? + mReferenceBlocked = -1; + esm.getHNOT (mReferenceBlocked, "UNAM"); + mScale = 1.0; esm.getHNOT (mScale, "XSCL"); @@ -54,7 +59,6 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) mKey = esm.getHNOString ("KNAM"); mTrap = esm.getHNOString ("TNAM"); - mReferenceBlocked = -1; mFltv = 0; esm.getHNOT (mReferenceBlocked, "UNAM"); esm.getHNOT (mFltv, "FLTV"); @@ -162,4 +166,4 @@ void ESM::CellRef::blank() bool ESM::operator== (const CellRef::RefNum& left, const CellRef::RefNum& right) { return left.mIndex==right.mIndex && left.mContentFile==right.mContentFile; -} \ No newline at end of file +} From 28185e20174b994b28cbc52cb636219781eff654 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jan 2014 15:54:24 +0100 Subject: [PATCH 107/120] Death/godmode fixes: Revive player *after* character update, since there might be fall damage. --- apps/openmw/engine.cpp | 12 ++++---- apps/openmw/mwmechanics/actors.cpp | 40 ++++++++++++++------------- apps/openmw/mwmechanics/character.cpp | 1 - 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b2c0c1968..66dea4f1d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -89,6 +89,8 @@ 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) { @@ -105,7 +107,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) if (changed) // keep change flag for another frame, if cell changed happened in local script MWBase::Environment::get().getWorld()->markCellAsUnchanged(); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) + if (!paused) MWBase::Environment::get().getWorld()->advanceTime( frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); @@ -116,18 +118,18 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // 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()->getPlayer().getPlayer(); - if(MWWorld::Class::get(player).getCreatureStats(player).isDead()) + 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(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 51e91a954..34cfe16fa 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -771,6 +771,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++) @@ -804,7 +822,6 @@ namespace MWMechanics stat.setModified(1, 0); stats.setHealth(stat); } - stats.resurrect(); continue; } @@ -818,6 +835,9 @@ namespace MWMechanics spells.purge(iter->first.getRefData().getHandle()); } + // 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)]; @@ -839,24 +859,6 @@ namespace MWMechanics } } } - - 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) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ee0d07731..40e6cde69 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1153,7 +1153,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)); } From bdb03926c29d837bb23ce436a998e10b277a9426 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jan 2014 16:13:45 +0100 Subject: [PATCH 108/120] Fix crash when loading another game after dying --- apps/openmw/mwworld/worldimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e5138eaea..076fcfdb6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1783,6 +1783,12 @@ namespace MWWorld void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); + + // At this point the Animation object is live, and the CharacterController associated with it must be created. + // It has to be done at this point: resetCamera below does animation->setViewMode -> CharacterController::forceStateUpdate + // so we should make sure not to use a "stale" controller for that. + MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); + mPhysics->addActor(mPlayer->getPlayer()); mRendering->resetCamera(); } From 79a9c4e048a839156ff084251bac3b8bdcca2dbe Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jan 2014 16:33:39 +0100 Subject: [PATCH 109/120] Clear mShared before populating it. Fixes an issue with duplicate records (e.g. dialogue keywords) after loading a savegame. --- apps/openmw/mwworld/store.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index df957408d..7bd00d6bf 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -201,6 +201,7 @@ namespace MWWorld void setUp() { //std::sort(mStatic.begin(), mStatic.end(), RecordCmp()); + mShared.clear(); mShared.reserve(mStatic.size()); typename std::map::iterator it = mStatic.begin(); for (; it != mStatic.end(); ++it) { From e62bf8fca9900a7c747d03ffa2afd6a3f99e8504 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jan 2014 16:41:26 +0100 Subject: [PATCH 110/120] Remove some garbage --- apps/openmw/mwgui/journalbooks.cpp | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index dbea10e77..8caea770e 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -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 (); } From e0de76a6f714100df72135476cc9738bc6babf87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jan 2014 18:20:17 +0100 Subject: [PATCH 111/120] Save/load global map --- apps/openmw/mwbase/windowmanager.hpp | 5 ++ apps/openmw/mwgui/mapwindow.cpp | 17 +++++ apps/openmw/mwgui/mapwindow.hpp | 9 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 10 +++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 + apps/openmw/mwrender/globalmap.cpp | 99 ++++++++++++++++++++++++- apps/openmw/mwrender/globalmap.hpp | 10 ++- apps/openmw/mwstate/statemanagerimp.cpp | 7 ++ components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 1 + components/esm/globalmap.cpp | 26 +++++++ components/esm/globalmap.hpp | 34 +++++++++ 12 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 components/esm/globalmap.cpp create mode 100644 components/esm/globalmap.hpp diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4d47e7eb7..fa0fe888b 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -33,6 +33,8 @@ namespace OEngine namespace ESM { struct Class; + class ESMReader; + class ESMWriter; } namespace MWWorld @@ -288,6 +290,9 @@ namespace MWBase /// 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; }; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index c09b4fea0..9ed3bf80f 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -584,4 +584,21 @@ namespace MWGui 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 > exploredCells; + mGlobalMapRender->readRecord(reader, type, exploredCells); + + for (std::vector >::iterator it = exploredCells.begin(); it != exploredCells.end(); ++it) + { + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first, it->second); + if (cell && !cell->mName.empty()) + addVisitedLocation(cell->mName, it->first, it->second); + } + } } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index dec27199a..6ace7dc0f 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -8,6 +8,12 @@ namespace MWRender class GlobalMap; } +namespace ESM +{ + class ESMReader; + class ESMWriter; +} + namespace Loading { class Listener; @@ -95,6 +101,9 @@ namespace MWGui /// 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); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8e49d6614..66bd805af 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1386,4 +1386,14 @@ namespace MWGui mMap->clear(); } + void WindowManager::write(ESM::ESMWriter &writer) + { + mMap->write(writer); + } + + void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type) + { + mMap->readRecord(reader, type); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 68dc947af..bc440d818 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -283,6 +283,9 @@ namespace MWGui /// 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; diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 522bbb321..6fbcfdc6b 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -12,6 +12,8 @@ #include +#include + #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) { @@ -231,4 +231,99 @@ namespace MWRender 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 >& 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"); + } + } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 20f40de99..5fe878cd4 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -10,6 +10,12 @@ namespace Loading class Listener; } +namespace ESM +{ + class ESMWriter; + class ESMReader; +} + namespace MWRender { @@ -34,13 +40,15 @@ namespace MWRender /// Clears the overlay void clear(); + void write (ESM::ESMWriter& writer); + void readRecord (ESM::ESMReader& reader, int32_t type, std::vector >& exploredCells); + private: std::string mCacheDir; std::vector< std::pair > mExploredCells; Ogre::TexturePtr mOverlayTexture; - std::vector mExploredBuffer; int mWidth; int mHeight; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index e94f790c7..a396d78c5 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -174,6 +174,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot +MWBase::Environment::get().getJournal()->countSavedGameRecords() +MWBase::Environment::get().getWorld()->countSavedGameRecords() +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() + + 1 // global map ); writer.save (stream); @@ -185,6 +186,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot 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(); @@ -243,6 +245,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl 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 diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d9ab8129d..d73bcaf74 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap ) add_component_dir (misc diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 74d987df8..40ef7ecb6 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -91,6 +91,7 @@ enum RecNameInts REC_PLAY = 0x59414c50, REC_CSTA = 0x41545343, REC_OBJE = 0x454a424f, + REC_GMAP = 0x50414d47, // format 1 REC_FILT = 0x544C4946 diff --git a/components/esm/globalmap.cpp b/components/esm/globalmap.cpp new file mode 100644 index 000000000..1fa5f907e --- /dev/null +++ b/components/esm/globalmap.cpp @@ -0,0 +1,26 @@ +#include "globalmap.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" +#include "defs.hpp" + +unsigned int ESM::GlobalMap::sRecordId = ESM::REC_GMAP; + +void ESM::GlobalMap::load (ESMReader &esm) +{ + esm.getHNT(mBounds, "BNDS"); + + esm.getSubNameIs("DATA"); + esm.getSubHeader(); + mImageData.resize(esm.getSubSize()); + esm.getExact(&mImageData[0], mImageData.size()); +} + +void ESM::GlobalMap::save (ESMWriter &esm) const +{ + esm.writeHNT("BNDS", mBounds); + + esm.startSubRecord("DATA"); + esm.write(&mImageData[0], mImageData.size()); + esm.endRecord("DATA"); +} diff --git a/components/esm/globalmap.hpp b/components/esm/globalmap.hpp new file mode 100644 index 000000000..5d036c736 --- /dev/null +++ b/components/esm/globalmap.hpp @@ -0,0 +1,34 @@ +#ifndef OPENMW_COMPONENTS_ESM_GLOBALMAP_H +#define OPENMW_COMPONENTS_ESM_GLOBALMAP_H + +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + ///< \brief An image containing the explored areas on the global map. + struct GlobalMap + { + static unsigned int sRecordId; + + // The minimum and maximum cell coordinates + struct Bounds + { + int mMinX, mMaxX, mMinY, mMaxY; + }; + + Bounds mBounds; + + std::vector mImageData; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; + +} + +#endif From 29c3a288e3525ca29cef275e66536dded60a3683 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 27 Jan 2014 13:27:42 +0100 Subject: [PATCH 112/120] load and save of reference in cells (without CustomData state) --- apps/openmw/engine.cpp | 9 +- apps/openmw/mwbase/world.hpp | 4 +- apps/openmw/mwstate/statemanagerimp.cpp | 40 +++++- apps/openmw/mwstate/statemanagerimp.hpp | 4 + apps/openmw/mwworld/cells.cpp | 9 +- apps/openmw/mwworld/cells.hpp | 3 +- apps/openmw/mwworld/cellstore.cpp | 163 +++++++++++++++++++++++- apps/openmw/mwworld/cellstore.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 5 +- apps/openmw/mwworld/worldimp.hpp | 3 +- components/esm/defs.hpp | 1 - 11 files changed, 222 insertions(+), 21 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 66dea4f1d..08f9cdb5c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -127,7 +127,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) if(!paused && player.getClass().getCreatureStats(player).isDead()) MWBase::Environment::get().getStateManager()->endGame(); } - + // update world MWBase::Environment::get().getWorld()->update(frametime, paused); @@ -282,12 +282,7 @@ 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); + mContentFiles.push_back(file); } void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 64104f2ba..cbf363581 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -2,6 +2,7 @@ #define GAME_MWBASE_WORLD_H #include +#include #include @@ -102,7 +103,8 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap) = 0; virtual OEngine::Render::Fader* getFader() = 0; ///< \todo remove this function. Rendering details should not be exposed. diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a396d78c5..fb2d10bbf 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include @@ -43,6 +45,31 @@ void MWState::StateManager::cleanup (bool force) } } +std::map MWState::StateManager::buildContentFileIndexMap (const ESM::ESMReader& reader) + const +{ + const std::vector& current = + MWBase::Environment::get().getWorld()->getContentFiles(); + + const std::vector& prev = reader.getGameFiles(); + + std::map map; + + for (int iPrev = 0; iPrev (prev.size()); ++iPrev) + { + std::string id = Misc::StringUtils::lowerCase (prev[iPrev].name); + + for (int iCurrent = 0; iCurrent (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) { @@ -167,7 +194,16 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); std::ofstream stream (slot->mPath.string().c_str()); + ESM::ESMWriter writer; + + const std::vector& current = + MWBase::Environment::get().getWorld()->getContentFiles(); + + for (std::vector::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 @@ -205,6 +241,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl ESM::ESMReader reader; reader.open (slot->mPath.string()); + std::map contentFileMap = buildContentFileIndexMap (reader); + while (reader.hasMoreRecs()) { ESM::NAME n = reader.getRecName(); @@ -237,7 +275,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl case ESM::REC_PLAY: case ESM::REC_CSTA: - MWBase::Environment::get().getWorld()->readRecord (reader, n.val); + MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap); break; case ESM::REC_GSCR: diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index d6bb7575d..46ade236b 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -1,6 +1,8 @@ #ifndef GAME_STATE_STATEMANAGER_H #define GAME_STATE_STATEMANAGER_H +#include + #include "../mwbase/statemanager.hpp" #include @@ -21,6 +23,8 @@ namespace MWState void cleanup (bool force = false); + std::map buildContentFileIndexMap (const ESM::ESMReader& reader) const; + public: StateManager (const boost::filesystem::path& saves, const std::string& game); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 26ec14a6d..965c9fc5d 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -352,7 +352,8 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer) const writeCell (writer, iter->second); } -bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type) +bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap) { if (type==ESM::REC_CSTA) { @@ -373,7 +374,11 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type) state.load (reader); cellStore->loadState (state); - reader.skipRecord(); + + if (cellStore->mState!=CellStore::State_Loaded) + cellStore->load (mStore, mReader); + + cellStore->readReferences (reader, contentFileMap); return true; } diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 1b0fe6724..7ee8a3f6c 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -73,7 +73,8 @@ namespace MWWorld void write (ESM::ESMWriter& writer) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap); }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index aea4e5b6a..88c241e1a 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -41,9 +41,6 @@ namespace { if (!collection.mList.empty()) { - // section header - writer.writeHNT ("CSEC", collection.mList.front().mBase->sRecordId); - // references for (typename MWWorld::CellRefList::List::const_iterator iter (collection.mList.begin()); @@ -55,12 +52,51 @@ namespace RecordType state; iter->save (state); - writer.startRecord (ESM::REC_OBJE); + writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId); state.save (writer); - writer.endRecord (ESM::REC_OBJE); } } } + + template + void readReferenceCollection (ESM::ESMReader& reader, + MWWorld::CellRefList& collection, const std::map& contentFileMap) + { + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + + RecordType state; + state.load (reader); + + std::map::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::checkState (state)) + return; // not valid anymore with current content files -> skip + + const T *record = esmStore.get().search (state.mRef.mRefID); + + if (!record) + return; + + for (typename MWWorld::CellRefList::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 ref (record); + ref.load (state); + collection.mList.push_back (ref); + } } namespace MWWorld @@ -304,4 +340,121 @@ namespace MWWorld writeReferenceCollection (writer, mStatics); writeReferenceCollection (writer, mWeapons); } + + void CellStore::readReferences (ESM::ESMReader& reader, + const std::map& contentFileMap) + { + while (reader.isNextSub ("OBJE")) + { + unsigned int id = 0; + reader.getHT (id); + + switch (id) + { + case ESM::REC_ACTI: + + readReferenceCollection (reader, mActivators, contentFileMap); + break; + + case ESM::REC_ALCH: + + readReferenceCollection (reader, mPotions, contentFileMap); + break; + + case ESM::REC_APPA: + + readReferenceCollection (reader, mAppas, contentFileMap); + break; + + case ESM::REC_ARMO: + + readReferenceCollection (reader, mArmors, contentFileMap); + break; + + case ESM::REC_BOOK: + + readReferenceCollection (reader, mBooks, contentFileMap); + break; + + case ESM::REC_CLOT: + + readReferenceCollection (reader, mClothes, contentFileMap); + break; + + case ESM::REC_CONT: + + readReferenceCollection (reader, mContainers, contentFileMap); + break; + + case ESM::REC_CREA: + + readReferenceCollection (reader, mCreatures, contentFileMap); + break; + + case ESM::REC_DOOR: + + readReferenceCollection (reader, mDoors, contentFileMap); + break; + + case ESM::REC_INGR: + + readReferenceCollection (reader, mIngreds, contentFileMap); + break; + + case ESM::REC_LEVC: + + readReferenceCollection (reader, mCreatureLists, contentFileMap); + break; + + case ESM::REC_LEVI: + + readReferenceCollection (reader, mItemLists, contentFileMap); + break; + + case ESM::REC_LIGH: + + readReferenceCollection (reader, mLights, contentFileMap); + break; + + case ESM::REC_LOCK: + + readReferenceCollection (reader, mLockpicks, contentFileMap); + break; + + case ESM::REC_MISC: + + readReferenceCollection (reader, mMiscItems, contentFileMap); + break; + + case ESM::REC_NPC_: + + readReferenceCollection (reader, mNpcs, contentFileMap); + break; + + case ESM::REC_PROB: + + readReferenceCollection (reader, mProbes, contentFileMap); + break; + + case ESM::REC_REPA: + + readReferenceCollection (reader, mRepairs, contentFileMap); + break; + + case ESM::REC_STAT: + + readReferenceCollection (reader, mStatics, contentFileMap); + break; + + case ESM::REC_WEAP: + + readReferenceCollection (reader, mWeapons, contentFileMap); + break; + + default: + + throw std::runtime_error ("unknown type in cell reference section"); + } + } + } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index feebfe90a..a4f219013 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -144,6 +144,8 @@ namespace MWWorld void writeReferences (ESM::ESMWriter& writer) const; + void readReferences (ESM::ESMReader& reader, const std::map& contentFileMap); + private: template diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 076fcfdb6..26cb34977 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -324,12 +324,13 @@ namespace MWWorld mPlayer->write (writer); } - void World::readRecord (ESM::ESMReader& reader, int32_t type) + void World::readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap) { if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && !mPlayer->readRecord (reader, type) && - !mCells.readRecord (reader, type)) + !mCells.readRecord (reader, type, contentFileMap)) { throw std::runtime_error ("unknown record in saved game"); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0fb4ed1ea..b99509322 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -179,7 +179,8 @@ namespace MWWorld virtual void write (ESM::ESMWriter& writer) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, int32_t type, + const std::map& contentFileMap); virtual OEngine::Render::Fader* getFader(); ///< \todo remove this function. Rendering details should not be exposed. diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 40ef7ecb6..1b0125e78 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -90,7 +90,6 @@ enum RecNameInts REC_GSCR = 0x52435347, REC_PLAY = 0x59414c50, REC_CSTA = 0x41545343, - REC_OBJE = 0x454a424f, REC_GMAP = 0x50414d47, // format 1 From a623f038504232f152b04a79d7bd790f0565f1db Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 28 Jan 2014 13:49:59 +0100 Subject: [PATCH 113/120] reduced object state for objects in containers --- components/esm/cellref.cpp | 31 +++++++++++++++++-------------- components/esm/cellref.hpp | 2 +- components/esm/objectstate.cpp | 14 ++++++++------ components/esm/objectstate.hpp | 2 +- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 19427af0c..00b15f4a3 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -75,7 +75,7 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) esm.getHT (mNam0); } -void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum) const +void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const { if (wideRefNum) esm.writeHNT ("FRMR", mRefNum, 8); @@ -107,29 +107,32 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum) const esm.writeHNT("NAM9", mGoldValue); } - if (mTeleport) + if (mTeleport && !inInventory) { esm.writeHNT("DODT", mDoorDest); esm.writeHNOCString("DNAM", mDestCell); } - if (mLockLevel != -1) { + if (mLockLevel != -1 && !inInventory) esm.writeHNT("FLTV", mLockLevel); - } - esm.writeHNOCString("KNAM", mKey); - esm.writeHNOCString("TNAM", mTrap); - if (mReferenceBlocked != -1) { + if (!inInventory) + esm.writeHNOCString ("KNAM", mKey); + + if (!inInventory) + esm.writeHNOCString ("TNAM", mTrap); + + if (mReferenceBlocked != -1) esm.writeHNT("UNAM", mReferenceBlocked); - } - if (mFltv != 0) { - esm.writeHNT("FLTV", mFltv); - } - esm.writeHNT("DATA", mPos, 24); - if (mNam0 != 0) { + if (mFltv != 0 && !inInventory) + esm.writeHNT("FLTV", mFltv); + + if (!inInventory) + esm.writeHNT("DATA", mPos, 24); + + if (mNam0 != 0 && !inInventory) esm.writeHNT("NAM0", mNam0); - } } void ESM::CellRef::blank() diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 0cd6a3673..16f6603a2 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -89,7 +89,7 @@ namespace ESM void load (ESMReader& esm, bool wideRefNum = false); - void save(ESMWriter &esm, bool wideRefNum = false) const; + void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false) const; void blank(); }; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 56289acae..21585e09d 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -25,9 +25,9 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNT (mLocalRotation, "LROT", 12); } -void ESM::ObjectState::save (ESMWriter &esm) const +void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const { - mRef.save (esm, true); + mRef.save (esm, true, inInventory); if (mHasLocals) { @@ -35,13 +35,15 @@ void ESM::ObjectState::save (ESMWriter &esm) const mLocals.save (esm); } - if (!mEnabled) + if (!mEnabled && !inInventory) esm.writeHNT ("ENAB", mEnabled); if (mCount!=1) esm.writeHNT ("COUN", mCount); - esm.writeHNT ("POS_", mPosition, 24); - - esm.writeHNT ("LROT", mLocalRotation, 12); + if (!inInventory) + { + esm.writeHNT ("POS_", mPosition, 24); + esm.writeHNT ("LROT", mLocalRotation, 12); + } } \ No newline at end of file diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index c599bb973..34226ea91 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -27,7 +27,7 @@ namespace ESM float mLocalRotation[3]; void load (ESMReader &esm); - void save (ESMWriter &esm) const; + void save (ESMWriter &esm, bool inInventory = false) const; }; } From e0537a3253022246d473bc179a3d9a6629562b14 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 28 Jan 2014 13:53:24 +0100 Subject: [PATCH 114/120] made object state polymorphic --- components/esm/objectstate.cpp | 4 +++- components/esm/objectstate.hpp | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 21585e09d..6aa820599 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -46,4 +46,6 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("POS_", mPosition, 24); esm.writeHNT ("LROT", mLocalRotation, 12); } -} \ No newline at end of file +} + +ESM::ObjectState::~ObjectState() {} \ No newline at end of file diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 34226ea91..9c9ca5f2e 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,8 +26,10 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; - void load (ESMReader &esm); - void save (ESMWriter &esm, bool inInventory = false) const; + virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm, bool inInventory = false) const; + + virtual ~ObjectState(); }; } From ec7cb90ca466f11bcb67ee34271af5f46f896e3c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 30 Jan 2014 11:50:13 +0100 Subject: [PATCH 115/120] added support for serialisation of CustomData state --- apps/openmw/mwworld/class.cpp | 4 ++++ apps/openmw/mwworld/class.hpp | 13 +++++++++++++ apps/openmw/mwworld/livecellref.cpp | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 6c00b949c..6e43b8dc2 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -367,4 +367,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 {} } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index ec22d0306..6e3a56907 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -9,6 +9,11 @@ #include "ptr.hpp" +namespace ESM +{ + struct ObjectState; +} + namespace Ogre { class Vector3; @@ -299,6 +304,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. diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index a12d20e6a..d71704fd7 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -3,16 +3,24 @@ #include +#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 (this)); + mClass->writeAdditionalState (ptr, state); } bool MWWorld::LiveCellRefBase::checkStateImp (const ESM::ObjectState& state) From 900532a6ca2e5bb8394c1a96fb6f6d36792ef27b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 30 Jan 2014 12:37:33 +0100 Subject: [PATCH 116/120] store additional state of lights in saved game files --- apps/openmw/mwclass/light.cpp | 21 +++++++++++++++++++++ apps/openmw/mwclass/light.hpp | 8 ++++++++ apps/openmw/mwworld/cellstore.cpp | 5 +++-- components/CMakeLists.txt | 2 +- components/esm/lightstate.cpp | 21 +++++++++++++++++++++ components/esm/lightstate.hpp | 19 +++++++++++++++++++ 6 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 components/esm/lightstate.cpp create mode 100644 components/esm/lightstate.hpp diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index cc56ec4c8..ddb2c16d6 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -2,6 +2,7 @@ #include "light.hpp" #include +#include #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 (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state2.mTime; + } + + void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const + { + ESM::LightState& state2 = dynamic_cast (state); + + ensureCustomData (ptr); + + state2.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index c15228a6a..5568e1727 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -71,6 +71,14 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; std::pair 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. }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 88c241e1a..77fdc971d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -331,7 +332,7 @@ namespace MWWorld writeReferenceCollection (writer, mIngreds); writeReferenceCollection (writer, mCreatureLists); writeReferenceCollection (writer, mItemLists); - writeReferenceCollection (writer, mLights); + writeReferenceCollection (writer, mLights); writeReferenceCollection (writer, mLockpicks); writeReferenceCollection (writer, mMiscItems); writeReferenceCollection (writer, mNpcs); @@ -413,7 +414,7 @@ namespace MWWorld case ESM::REC_LIGH: - readReferenceCollection (reader, mLights, contentFileMap); + readReferenceCollection (reader, mLights, contentFileMap); break; case ESM::REC_LOCK: diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d73bcaf74..f37a537c5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate ) add_component_dir (misc diff --git a/components/esm/lightstate.cpp b/components/esm/lightstate.cpp new file mode 100644 index 000000000..1ef040823 --- /dev/null +++ b/components/esm/lightstate.cpp @@ -0,0 +1,21 @@ + +#include "lightstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::LightState::load (ESMReader &esm) +{ + ObjectState::load (esm); + + mTime = 0; + esm.getHNOT (mTime, "LTIM"); +} + +void ESM::LightState::save (ESMWriter &esm, bool inInventory) const +{ + ObjectState::save (esm, inInventory); + + if (mTime) + esm.writeHNT ("LTIM", mTime); +} \ No newline at end of file diff --git a/components/esm/lightstate.hpp b/components/esm/lightstate.hpp new file mode 100644 index 000000000..a22735e07 --- /dev/null +++ b/components/esm/lightstate.hpp @@ -0,0 +1,19 @@ +#ifndef OPENMW_ESM_LIGHTSTATE_H +#define OPENMW_ESM_LIGHTSTATE_H + +#include "objectstate.hpp" + +namespace ESM +{ + // format 0, saved games only + + struct LightState : public ObjectState + { + float mTime; + + virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm, bool inInventory = false) const; + }; +} + +#endif From dd674566a2aa85b4ed62dc4438777a97868e7ec8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 31 Jan 2014 13:25:32 +0100 Subject: [PATCH 117/120] store content of containers in saved game files --- apps/openmw/mwclass/container.cpp | 23 ++++++ apps/openmw/mwclass/container.hpp | 8 ++ apps/openmw/mwworld/cellstore.cpp | 5 +- apps/openmw/mwworld/containerstore.cpp | 100 +++++++++++++++++++++++++ apps/openmw/mwworld/containerstore.hpp | 9 ++- apps/openmw/mwworld/livecellref.hpp | 12 ++- apps/openmw/mwworld/ptr.cpp | 8 ++ apps/openmw/mwworld/ptr.hpp | 2 + components/CMakeLists.txt | 2 +- components/esm/containerstate.cpp | 16 ++++ components/esm/containerstate.hpp | 20 +++++ components/esm/inventorystate.cpp | 60 +++++++++++++++ components/esm/inventorystate.hpp | 28 +++++++ components/esm/objectstate.cpp | 4 +- 14 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 components/esm/containerstate.cpp create mode 100644 components/esm/containerstate.hpp create mode 100644 components/esm/inventorystate.cpp create mode 100644 components/esm/inventorystate.hpp diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index f89a6bce0..546d6538c 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -2,6 +2,7 @@ #include "container.hpp" #include +#include #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 (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. + readState (state2.mInventory); + } + + void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const + { + ESM::ContainerState& state2 = dynamic_cast (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. + writeState (state2.mInventory); + } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 006e4bd22..c97867d35 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -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; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 77fdc971d..154a2d1e7 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -326,7 +327,7 @@ namespace MWWorld writeReferenceCollection (writer, mArmors); writeReferenceCollection (writer, mBooks); writeReferenceCollection (writer, mClothes); - writeReferenceCollection (writer, mContainers); + writeReferenceCollection (writer, mContainers); writeReferenceCollection (writer, mCreatures); writeReferenceCollection (writer, mDoors); writeReferenceCollection (writer, mIngreds); @@ -384,7 +385,7 @@ namespace MWWorld case ESM::REC_CONT: - readReferenceCollection (reader, mContainers, contentFileMap); + readReferenceCollection (reader, mContainers, contentFileMap); break; case ESM::REC_CREA: diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 0c4226f9b..2d5a9bbd3 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -55,6 +57,43 @@ namespace return MWWorld::Ptr(); } + + template + void getState (MWWorld::CellRefList& collection, const ESM::ObjectState& state) + { + if (!MWWorld::LiveCellRef::checkState (state)) + return; // not valid anymore with current content files -> skip + + const T *record = MWBase::Environment::get().getWorld()->getStore(). + get().search (state.mRef.mRefID); + + if (!record) + return; + + MWWorld::LiveCellRef ref (record); + ref.load (state); + ref.mRef.mRefNum.mContentFile = -1; + collection.mList.push_back (ref); + } + + template + void storeState (const MWWorld::LiveCellRef& ref, ESM::ObjectState& state) + { + ref.save (state); + } + + template + void storeStates (const MWWorld::CellRefList& collection, + std::vector > >& states) + { + for (typename MWWorld::CellRefList::List::const_iterator iter (collection.mList.begin()); + iter!=collection.mList.end(); ++iter) + { + ESM::ObjectState state; + storeState (*iter, state); + states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, -1))); + } + } } const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; @@ -495,6 +534,67 @@ 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); + storeStates (books, state.mItems); + storeStates (clothes, state.mItems); + storeStates (ingreds, state.mItems); + storeStates (lockpicks, state.mItems); + storeStates (miscItems, state.mItems); + storeStates (probes, state.mItems); + storeStates (repairs, state.mItems); + storeStates (weapons, state.mItems); + + state.mLights.clear(); + + for (MWWorld::CellRefList::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, -1)); + } +} + +void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) +{ + clear(); + + for (std::vector > >::const_iterator + iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter) + { + 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: getState (armors, iter->first); break; + case ESM::REC_BOOK: getState (books, iter->first); break; + case ESM::REC_CLOT: getState (clothes, iter->first); break; + case ESM::REC_INGR: getState (ingreds, iter->first); break; + case ESM::REC_LOCK: getState (lockpicks, iter->first); break; + case ESM::REC_MISC: getState (miscItems, iter->first); break; + case ESM::REC_PROB: getState (probes, iter->first); break; + case ESM::REC_REPA: getState (repairs, iter->first); break; + case ESM::REC_WEAP: getState (weapons, iter->first); break; + + default: + + std::cerr << "invalid item type in inventory state" << std::endl; + } + } + + for (std::vector >::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) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 0a1728740..3bdefb1ec 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -8,6 +8,7 @@ namespace ESM { struct InventoryList; + struct InventoryState; } namespace MWWorld @@ -123,6 +124,10 @@ namespace MWWorld Ptr search (const std::string& id); + void writeState (ESM::InventoryState& state) const; + + void readState (const ESM::InventoryState& state); + friend class ContainerStoreIterator; }; @@ -172,7 +177,7 @@ namespace MWWorld ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - void copy (const ContainerStoreIterator& src); + void copy (const ContainerStoreIterator& src); void incType(); @@ -200,7 +205,7 @@ namespace MWWorld ContainerStoreIterator operator++ (int); - ContainerStoreIterator& operator= (const ContainerStoreIterator& rhs); + ContainerStoreIterator& operator= (const ContainerStoreIterator& rhs); bool isEqual (const ContainerStoreIterator& iter) const; diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 46f49df78..b2089fa7a 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -35,6 +35,14 @@ namespace MWWorld /* 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); @@ -79,12 +87,12 @@ namespace MWWorld // The object that this instance is based on. const X* mBase; - void load (const ESM::ObjectState& state); + 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. - void save (ESM::ObjectState& state) const; + virtual void save (ESM::ObjectState& state) const; ///< Save LiveCellRef state into \a state. static bool checkState (const ESM::ObjectState& state); diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 384bd71b1..67bfe4900 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -21,6 +21,14 @@ const std::string& MWWorld::Ptr::getTypeName() const throw std::runtime_error("Can't get type name from an empty object."); } +MWWorld::LiveCellRefBase *MWWorld::Ptr::getBase() const +{ + if (!mRef) + throw std::runtime_error ("Can't access cell ref pointed to by null Ptr"); + + return mRef; +} + ESM::CellRef& MWWorld::Ptr::getCellRef() const { assert(mRef); diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 8b70382d0..1212619d0 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -52,6 +52,8 @@ namespace MWWorld throw std::runtime_error(str.str()); } + MWWorld::LiveCellRefBase *getBase() const; + ESM::CellRef& getCellRef() const; RefData& getRefData() const; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f37a537c5..854d1f1ae 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate ) add_component_dir (misc diff --git a/components/esm/containerstate.cpp b/components/esm/containerstate.cpp new file mode 100644 index 000000000..5dcf17733 --- /dev/null +++ b/components/esm/containerstate.cpp @@ -0,0 +1,16 @@ + +#include "containerstate.hpp" + +void ESM::ContainerState::load (ESMReader &esm) +{ + ObjectState::load (esm); + + mInventory.load (esm); +} + +void ESM::ContainerState::save (ESMWriter &esm, bool inInventory) const +{ + ObjectState::save (esm, inInventory); + + mInventory.save (esm); +} \ No newline at end of file diff --git a/components/esm/containerstate.hpp b/components/esm/containerstate.hpp new file mode 100644 index 000000000..1ecf2b46e --- /dev/null +++ b/components/esm/containerstate.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_ESM_CONTAINERSTATE_H +#define OPENMW_ESM_CONTAINERSTATE_H + +#include "objectstate.hpp" +#include "inventorystate.hpp" + +namespace ESM +{ + // format 0, saved games only + + struct ContainerState : public ObjectState + { + InventoryState mInventory; + + virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm, bool inInventory = false) const; + }; +} + +#endif diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp new file mode 100644 index 000000000..4d8cbc622 --- /dev/null +++ b/components/esm/inventorystate.cpp @@ -0,0 +1,60 @@ + +#include "inventorystate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace +{ + void read (ESM::ESMReader &esm, ESM::ObjectState& state, int& slot) + { + slot = -1; + esm.getHNOT (slot, "SLOT"); + + state.load (esm); + } + + void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, unsigned int type, int slot) + { + esm.writeHNT ("IOBJ", type); + + if (slot!=-1) + esm.writeHNT ("SLOT", slot); + + state.save (esm, true); + } +} + +void ESM::InventoryState::load (ESMReader &esm) +{ + while (esm.isNextSub ("IOBJ")) + { + unsigned int id = 0; + esm.getHT (id); + + if (id==ESM::REC_LIGH) + { + LightState state; + int slot; + read (esm, state, slot); + mLights.push_back (std::make_pair (state, slot)); + } + else + { + ObjectState state; + int slot; + read (esm, state, slot); + mItems.push_back (std::make_pair (state, std::make_pair (id, slot))); + } + } +} + +void ESM::InventoryState::save (ESMWriter &esm) const +{ + for (std::vector > >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) + write (esm, iter->first, iter->second.first, iter->second.second); + + for (std::vector >::const_iterator iter (mLights.begin()); + iter!=mLights.end(); ++iter) + write (esm, iter->first, ESM::REC_LIGH, iter->second); +} \ No newline at end of file diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp new file mode 100644 index 000000000..3cfffbccc --- /dev/null +++ b/components/esm/inventorystate.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_ESM_INVENTORYSTATE_H +#define OPENMW_ESM_INVENTORYSTATE_H + +#include "objectstate.hpp" +#include "lightstate.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + /// \brief State for inventories and containers + struct InventoryState + { + // anything but lights (type, slot) + std::vector > > mItems; + + // lights (slot) + std::vector > mLights; + + virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm) const; + }; +} + +#endif diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 6aa820599..be00f3ef6 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -20,9 +20,9 @@ void ESM::ObjectState::load (ESMReader &esm) mCount = 1; esm.getHNOT (mCount, "COUN"); - esm.getHNT (mPosition, "POS_", 24); + esm.getHNOT (mPosition, "POS_", 24); - esm.getHNT (mLocalRotation, "LROT", 12); + esm.getHNOT (mLocalRotation, "LROT", 12); } void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const From bcc5894e2d820b7497f2381ddef8af7da61cf836 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 1 Feb 2014 15:24:01 +0100 Subject: [PATCH 118/120] changed implementation functions for container serialisation from free functions to member functions (will need some polymorphism later) --- apps/openmw/mwworld/containerstore.cpp | 69 +++++++++++++------------- apps/openmw/mwworld/containerstore.hpp | 11 ++++ 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 2d5a9bbd3..7d12c7b6e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -57,42 +57,43 @@ namespace return MWWorld::Ptr(); } +} - template - void getState (MWWorld::CellRefList& collection, const ESM::ObjectState& state) +template +void MWWorld::ContainerStore::getState (CellRefList& collection, const ESM::ObjectState& state) +{ + if (!LiveCellRef::checkState (state)) + return; // not valid anymore with current content files -> skip + + const T *record = MWBase::Environment::get().getWorld()->getStore(). + get().search (state.mRef.mRefID); + + if (!record) + return; + + LiveCellRef ref (record); + ref.load (state); + ref.mRef.mRefNum.mContentFile = -1; + collection.mList.push_back (ref); +} + +template +void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::ObjectState& state) + const +{ + ref.save (state); +} + +template +void MWWorld::ContainerStore::storeStates (const CellRefList& collection, + std::vector > >& states) const +{ + for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); + iter!=collection.mList.end(); ++iter) { - if (!MWWorld::LiveCellRef::checkState (state)) - return; // not valid anymore with current content files -> skip - - const T *record = MWBase::Environment::get().getWorld()->getStore(). - get().search (state.mRef.mRefID); - - if (!record) - return; - - MWWorld::LiveCellRef ref (record); - ref.load (state); - ref.mRef.mRefNum.mContentFile = -1; - collection.mList.push_back (ref); - } - - template - void storeState (const MWWorld::LiveCellRef& ref, ESM::ObjectState& state) - { - ref.save (state); - } - - template - void storeStates (const MWWorld::CellRefList& collection, - std::vector > >& states) - { - for (typename MWWorld::CellRefList::List::const_iterator iter (collection.mList.begin()); - iter!=collection.mList.end(); ++iter) - { - ESM::ObjectState state; - storeState (*iter, state); - states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, -1))); - } + ESM::ObjectState state; + storeState (*iter, state); + states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, -1))); } } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 3bdefb1ec..5e305d408 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -57,6 +57,17 @@ 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 + void getState (CellRefList& collection, const ESM::ObjectState& state); + + template + void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; + + template + void storeStates (const CellRefList& collection, + std::vector > >& states) + const; + public: ContainerStore(); From d2ec3ffdc89f55eb496eaf4623ad04a879637412 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 1 Feb 2014 17:07:08 +0100 Subject: [PATCH 119/120] handle equipped items when serialising inventory state --- apps/openmw/mwworld/containerstore.cpp | 48 ++++++++++++++++---------- apps/openmw/mwworld/containerstore.hpp | 13 +++++-- apps/openmw/mwworld/inventorystore.cpp | 22 ++++++++++++ apps/openmw/mwworld/inventorystore.hpp | 9 +++++ 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 7d12c7b6e..86cf3bbde 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -60,43 +60,53 @@ namespace } template -void MWWorld::ContainerStore::getState (CellRefList& collection, const ESM::ObjectState& state) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState (CellRefList& collection, + const ESM::ObjectState& state) { if (!LiveCellRef::checkState (state)) - return; // not valid anymore with current content files -> skip + return ContainerStoreIterator (this); // not valid anymore with current content files -> skip const T *record = MWBase::Environment::get().getWorld()->getStore(). get().search (state.mRef.mRefID); if (!record) - return; + return ContainerStoreIterator (this); LiveCellRef ref (record); ref.load (state); ref.mRef.mRefNum.mContentFile = -1; collection.mList.push_back (ref); + + return ContainerStoreIterator (this, --collection.mList.end()); } template -void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::ObjectState& state) - const +void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::ObjectState& state) const { ref.save (state); } template void MWWorld::ContainerStore::storeStates (const CellRefList& collection, - std::vector > >& states) const + std::vector > >& states, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { ESM::ObjectState state; storeState (*iter, state); - states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, -1))); + 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) {} @@ -541,15 +551,15 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const storeStates (potions, state.mItems); storeStates (appas, state.mItems); - storeStates (armors, state.mItems); + storeStates (armors, state.mItems, true); storeStates (books, state.mItems); - storeStates (clothes, state.mItems); + storeStates (clothes, state.mItems, true); storeStates (ingreds, state.mItems); - storeStates (lockpicks, state.mItems); + storeStates (lockpicks, state.mItems, true); storeStates (miscItems, state.mItems); - storeStates (probes, state.mItems); + storeStates (probes, state.mItems, true); storeStates (repairs, state.mItems); - storeStates (weapons, state.mItems); + storeStates (weapons, state.mItems, true); state.mLights.clear(); @@ -558,7 +568,7 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const { ESM::LightState objectState; storeState (*iter, objectState); - state.mLights.push_back (std::make_pair (objectState, -1)); + state.mLights.push_back (std::make_pair (objectState, getSlot (*iter))); } } @@ -569,19 +579,21 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) for (std::vector > >::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: getState (armors, 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: getState (clothes, 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: getState (lockpicks, 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: getState (probes, 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: getState (weapons, iter->first); break; + case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; default: diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 5e305d408..2e01eb856 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -58,15 +58,22 @@ namespace MWWorld void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true); template - void getState (CellRefList& collection, const ESM::ObjectState& state); + ContainerStoreIterator getState (CellRefList& collection, + const ESM::ObjectState& state); template void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; template void storeStates (const CellRefList& collection, - std::vector > >& states) - const; + std::vector > >& 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: diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 82b827e75..93573b401 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -42,6 +42,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 (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 Date: Sat, 1 Feb 2014 17:36:23 +0100 Subject: [PATCH 120/120] added creature/NPC state to saved games (only container/inventory for now) --- apps/openmw/mwclass/creature.cpp | 23 ++++++++++++++++++++++ apps/openmw/mwclass/creature.hpp | 10 +++++++++- apps/openmw/mwclass/npc.cpp | 27 ++++++++++++++++++++++++-- apps/openmw/mwclass/npc.hpp | 10 +++++++++- apps/openmw/mwworld/cellstore.cpp | 10 ++++++---- apps/openmw/mwworld/containerstore.hpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/creaturestate.cpp | 16 +++++++++++++++ components/esm/creaturestate.hpp | 20 +++++++++++++++++++ components/esm/npcstate.cpp | 16 +++++++++++++++ components/esm/npcstate.hpp | 20 +++++++++++++++++++ components/esm/player.hpp | 4 ++-- 12 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 components/esm/creaturestate.cpp create mode 100644 components/esm/creaturestate.hpp create mode 100644 components/esm/npcstate.cpp create mode 100644 components/esm/npcstate.hpp diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a97268318..1174f1bd2 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -2,6 +2,7 @@ #include "creature.hpp" #include +#include #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" @@ -613,6 +614,28 @@ namespace MWClass return 0; } + void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) + const + { + const ESM::CreatureState& state2 = dynamic_cast (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. + readState (state2.mInventory); + } + + void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const + { + ESM::CreatureState& state2 = dynamic_cast (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore. + writeState (state2.mInventory); + } + const ESM::GameSetting* Creature::fMinWalkSpeedCreature; const ESM::GameSetting* Creature::fMaxWalkSpeedCreature; const ESM::GameSetting *Creature::fEncumberedMoveEffect; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index d518d0056..484afdaf5 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -84,7 +84,7 @@ namespace MWClass virtual bool isEssential (const MWWorld::Ptr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) - + virtual int getServices (const MWWorld::Ptr& actor) const; virtual bool isPersistent (const MWWorld::Ptr& ptr) const; @@ -118,6 +118,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. }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f93a3e342..7c0f0b6ea 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -514,7 +515,7 @@ namespace MWClass weapon.getCellRef().mCharge = weapmaxhealth; damage *= float(weapon.getCellRef().mCharge) / weapmaxhealth; } - + if (!MWBase::Environment::get().getWorld()->getGodModeState()) weapon.getCellRef().mCharge -= std::min(std::max(1, (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge); @@ -964,7 +965,7 @@ namespace MWClass return ref->mBase->mFlags & ESM::NPC::Essential; } - + void Npc::registerSelf() { boost::shared_ptr instance (new Npc); @@ -1233,6 +1234,28 @@ namespace MWClass return 0; } + void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) + const + { + const ESM::NpcState& state2 = dynamic_cast (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mInventoryStore. + readState (state2.mInventory); + } + + void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const + { + ESM::NpcState& state2 = dynamic_cast (state); + + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mInventoryStore. + writeState (state2.mInventory); + } + const ESM::GameSetting *Npc::fMinWalkSpeed; const ESM::GameSetting *Npc::fMaxWalkSpeed; const ESM::GameSetting *Npc::fEncumberedMoveEffect; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 497d0ced8..237746de8 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -131,7 +131,7 @@ namespace MWClass ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) virtual int getServices (const MWWorld::Ptr& actor) const; - + virtual bool isPersistent (const MWWorld::Ptr& ptr) const; virtual std::string getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const; @@ -152,6 +152,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. }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 154a2d1e7..42c954afb 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -328,7 +330,7 @@ namespace MWWorld writeReferenceCollection (writer, mBooks); writeReferenceCollection (writer, mClothes); writeReferenceCollection (writer, mContainers); - writeReferenceCollection (writer, mCreatures); + writeReferenceCollection (writer, mCreatures); writeReferenceCollection (writer, mDoors); writeReferenceCollection (writer, mIngreds); writeReferenceCollection (writer, mCreatureLists); @@ -336,7 +338,7 @@ namespace MWWorld writeReferenceCollection (writer, mLights); writeReferenceCollection (writer, mLockpicks); writeReferenceCollection (writer, mMiscItems); - writeReferenceCollection (writer, mNpcs); + writeReferenceCollection (writer, mNpcs); writeReferenceCollection (writer, mProbes); writeReferenceCollection (writer, mRepairs); writeReferenceCollection (writer, mStatics); @@ -390,7 +392,7 @@ namespace MWWorld case ESM::REC_CREA: - readReferenceCollection (reader, mCreatures, contentFileMap); + readReferenceCollection (reader, mCreatures, contentFileMap); break; case ESM::REC_DOOR: @@ -430,7 +432,7 @@ namespace MWWorld case ESM::REC_NPC_: - readReferenceCollection (reader, mNpcs, contentFileMap); + readReferenceCollection (reader, mNpcs, contentFileMap); break; case ESM::REC_PROB: diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 2e01eb856..68bad4b9b 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -130,7 +130,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; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 854d1f1ae..f2b16d4d5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -40,7 +40,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate ) add_component_dir (misc diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp new file mode 100644 index 000000000..43cde3025 --- /dev/null +++ b/components/esm/creaturestate.cpp @@ -0,0 +1,16 @@ + +#include "creaturestate.hpp" + +void ESM::CreatureState::load (ESMReader &esm) +{ + ObjectState::load (esm); + + mInventory.load (esm); +} + +void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const +{ + ObjectState::save (esm, inInventory); + + mInventory.save (esm); +} \ No newline at end of file diff --git a/components/esm/creaturestate.hpp b/components/esm/creaturestate.hpp new file mode 100644 index 000000000..f7f9b8038 --- /dev/null +++ b/components/esm/creaturestate.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_ESM_CREATURESTATE_H +#define OPENMW_ESM_CREATURESTATE_H + +#include "objectstate.hpp" +#include "inventorystate.hpp" + +namespace ESM +{ + // format 0, saved games only + + struct CreatureState : public ObjectState + { + InventoryState mInventory; + + virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm, bool inInventory = false) const; + }; +} + +#endif diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp new file mode 100644 index 000000000..c452611a0 --- /dev/null +++ b/components/esm/npcstate.cpp @@ -0,0 +1,16 @@ + +#include "npcstate.hpp" + +void ESM::NpcState::load (ESMReader &esm) +{ + ObjectState::load (esm); + + mInventory.load (esm); +} + +void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const +{ + ObjectState::save (esm, inInventory); + + mInventory.save (esm); +} \ No newline at end of file diff --git a/components/esm/npcstate.hpp b/components/esm/npcstate.hpp new file mode 100644 index 000000000..ceb18b88b --- /dev/null +++ b/components/esm/npcstate.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_ESM_NPCSTATE_H +#define OPENMW_ESM_NPCSTATE_H + +#include "objectstate.hpp" +#include "inventorystate.hpp" + +namespace ESM +{ + // format 0, saved games only + + struct NpcState : public ObjectState + { + InventoryState mInventory; + + virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm, bool inInventory = false) const; + }; +} + +#endif diff --git a/components/esm/player.hpp b/components/esm/player.hpp index bd618457e..0d70ee090 100644 --- a/components/esm/player.hpp +++ b/components/esm/player.hpp @@ -3,7 +3,7 @@ #include -#include "objectstate.hpp" +#include "npcstate.hpp" #include "cellid.hpp" #include "defs.hpp" @@ -16,7 +16,7 @@ namespace ESM struct Player { - ObjectState mObject; + NpcState mObject; CellId mCellId; float mLastKnownExteriorPosition[3]; unsigned char mHasMark;