From f6f6b5604afd9d6269cc0aed93bb47f05107d0de Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Jun 2014 23:11:38 +0200 Subject: [PATCH 01/15] Fix loading a savegame when some of its content files were disabled Fixes #1380 --- apps/openmw/mwworld/cells.cpp | 2 ++ apps/openmw/mwworld/globals.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 3b758f866..16c1b497c 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -314,6 +314,8 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type, catch (...) { // silently drop cells that don't exist anymore + reader.skipRecord(); + return true; /// \todo log } diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 663af640b..15ba27498 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -100,7 +100,7 @@ namespace MWWorld if (iter!=mVariables.end()) iter->second.read (reader, ESM::Variant::Format_Global); else - reader.skipHRecord(); + reader.skipRecord(); return true; } From 5df9ff8e2c73668bd25710af3f172735e8f640ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Jun 2014 23:32:05 +0200 Subject: [PATCH 02/15] Respect CMAKE_INSTALL_PREFIX in the global openmw.cfg Fixes installing to /usr/local (Bug #1378) --- CMakeLists.txt | 8 ++++---- files/openmw.cfg | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f349e223..f724b4204 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,13 +90,13 @@ endif(UNIX AND NOT APPLE) # Location of morrowind data files if (APPLE) set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") - set(MORROWIND_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") + set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") elseif(UNIX) - set(MORROWIND_DATA_FILES "/usr/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") - set(MORROWIND_RESOURCE_FILES "/usr/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files") + set(MORROWIND_DATA_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") + set(OPENMW_RESOURCE_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files") else() set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") - set(MORROWIND_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") + set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") endif(APPLE) if (WIN32) diff --git a/files/openmw.cfg b/files/openmw.cfg index 15fde1bcb..4633141a6 100644 --- a/files/openmw.cfg +++ b/files/openmw.cfg @@ -1,4 +1,4 @@ data="?global?data" data="?mw?Data Files" data-local="?user?data" -resources=${MORROWIND_RESOURCE_FILES} +resources=${OPENMW_RESOURCE_FILES} From 8b33c087e0da487d8307a9c0f417bbaf22774614 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Jun 2014 14:46:41 +0200 Subject: [PATCH 03/15] Properly handle exceptions when saving the game Add message boxes when an exception occurs while loading or saving the game --- apps/openmw/mwstate/statemanagerimp.cpp | 157 ++++++++++++++---------- 1 file changed, 89 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index dafb8323a..29b5318d7 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -149,91 +149,105 @@ void MWState::StateManager::endGame() void MWState::StateManager::saveGame (const std::string& description, const Slot *slot) { - ESM::SavedGame profile; + try + { + ESM::SavedGame profile; - MWBase::World& world = *MWBase::Environment::get().getWorld(); + MWBase::World& world = *MWBase::Environment::get().getWorld(); - MWWorld::Ptr player = world.getPlayerPtr(); + MWWorld::Ptr player = world.getPlayerPtr(); - profile.mContentFiles = world.getContentFiles(); + profile.mContentFiles = world.getContentFiles(); - profile.mPlayerName = player.getClass().getName (player); - profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel(); + profile.mPlayerName = player.getClass().getName (player); + profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel(); - std::string classId = player.get()->mBase->mClass; - if (world.getStore().get().isDynamic(classId)) - profile.mPlayerClassName = world.getStore().get().find(classId)->mName; - else - profile.mPlayerClassId = classId; - - profile.mPlayerCell = world.getCellName(); - - profile.mInGameTime.mGameHour = world.getTimeStamp().getHour(); - profile.mInGameTime.mDay = world.getDay(); - profile.mInGameTime.mMonth = world.getMonth(); - profile.mInGameTime.mYear = world.getYear(); - profile.mTimePlayed = mTimePlayed; - profile.mDescription = description; - - int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing - Ogre::Image screenshot; - world.screenshot(screenshot, screenshotW, screenshotH); - Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); - profile.mScreenshot.resize(encoded->size()); - encoded->read(&profile.mScreenshot[0], encoded->size()); - - if (!slot) - slot = mCharacterManager.getCurrentCharacter()->createSlot (profile); - else - slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); + std::string classId = player.get()->mBase->mClass; + if (world.getStore().get().isDynamic(classId)) + profile.mPlayerClassName = world.getStore().get().find(classId)->mName; + else + profile.mPlayerClassId = classId; + + profile.mPlayerCell = world.getCellName(); + + profile.mInGameTime.mGameHour = world.getTimeStamp().getHour(); + profile.mInGameTime.mDay = world.getDay(); + profile.mInGameTime.mMonth = world.getMonth(); + profile.mInGameTime.mYear = world.getYear(); + profile.mTimePlayed = mTimePlayed; + profile.mDescription = description; + + int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing + Ogre::Image screenshot; + world.screenshot(screenshot, screenshotW, screenshotH); + Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); + profile.mScreenshot.resize(encoded->size()); + encoded->read(&profile.mScreenshot[0], encoded->size()); + + if (!slot) + slot = mCharacterManager.getCurrentCharacter()->createSlot (profile); + else + slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); - boost::filesystem::ofstream stream (slot->mPath, std::ios::binary); + boost::filesystem::ofstream stream (slot->mPath, std::ios::binary); - ESM::ESMWriter writer; + ESM::ESMWriter writer; - const std::vector& current = - MWBase::Environment::get().getWorld()->getContentFiles(); + 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); + int recordCount = 1 // saved game header + +MWBase::Environment::get().getJournal()->countSavedGameRecords() + +MWBase::Environment::get().getWorld()->countSavedGameRecords() + +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() + +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() + +MWBase::Environment::get().getWindowManager()->countSavedGameRecords(); + writer.setRecordCount (recordCount); - 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.save (stream); - writer.setFormat (ESM::Header::CurrentFormat); - int recordCount = 1 // saved game header - +MWBase::Environment::get().getJournal()->countSavedGameRecords() - +MWBase::Environment::get().getWorld()->countSavedGameRecords() - +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() - +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() - +MWBase::Environment::get().getWindowManager()->countSavedGameRecords(); - writer.setRecordCount (recordCount); + Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + listener.setProgressRange(recordCount); + listener.setLabel("#{sNotifyMessage4}"); - writer.save (stream); + Loading::ScopedLoad load(&listener); - Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); - listener.setProgressRange(recordCount); - listener.setLabel("#{sNotifyMessage4}"); + writer.startRecord (ESM::REC_SAVE); + slot->mProfile.save (writer); + writer.endRecord (ESM::REC_SAVE); + listener.increaseProgress(); - Loading::ScopedLoad load(&listener); + MWBase::Environment::get().getJournal()->write (writer, listener); + MWBase::Environment::get().getDialogueManager()->write (writer, listener); + MWBase::Environment::get().getWorld()->write (writer, listener); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener); + MWBase::Environment::get().getWindowManager()->write(writer, listener); - writer.startRecord (ESM::REC_SAVE); - slot->mProfile.save (writer); - writer.endRecord (ESM::REC_SAVE); - listener.increaseProgress(); + // Ensure we have written the number of records that was estimated + if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record + std::cerr << "Warning: number of written savegame records does not match. Estimated: " << recordCount+1 << ", written: " << writer.getRecordCount() << std::endl; - MWBase::Environment::get().getJournal()->write (writer, listener); - MWBase::Environment::get().getDialogueManager()->write (writer, listener); - MWBase::Environment::get().getWorld()->write (writer, listener); - MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener); - MWBase::Environment::get().getWindowManager()->write(writer, listener); + writer.close(); - // Ensure we have written the number of records that was estimated - if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record - std::cerr << "Warning: number of written savegame records does not match. Estimated: " << recordCount+1 << ", written: " << writer.getRecordCount() << std::endl; + Settings::Manager::setString ("character", "Saves", + slot->mPath.parent_path().filename().string()); + } + catch (const std::exception& e) + { + std::stringstream error; + error << "Failed to save game: " << e.what(); - writer.close(); + std::cerr << error.str() << std::endl; - Settings::Manager::setString ("character", "Saves", - slot->mPath.parent_path().filename().string()); + std::vector buttons; + buttons.push_back("#{sOk}"); + MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons); + } } void MWState::StateManager::quickSave (std::string name) @@ -371,10 +385,17 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl } catch (const std::exception& e) { - std::cerr << "failed to load saved game: " << e.what() << std::endl; + std::stringstream error; + error << "Failed to load saved game: " << e.what(); + + std::cerr << error.str() << std::endl; cleanup (true); MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + + std::vector buttons; + buttons.push_back("#{sOk}"); + MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons); } } From 68afac6a190066b5dea06d028418f6153b350c1a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Jun 2014 19:47:39 +0200 Subject: [PATCH 04/15] Fix large size_t being truncated to int --- 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 348b7c1df..ef5d5858b 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -117,7 +117,7 @@ namespace MWGui std::string directory = Misc::StringUtils::lowerCase (Settings::Manager::getString ("character", "Saves")); - int selectedIndex = MyGUI::ITEM_NONE; + size_t selectedIndex = MyGUI::ITEM_NONE; for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it) { From 996e49c534f3f9fdc0efe860e8ebd74a51cb0458 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Jun 2014 20:24:35 +0200 Subject: [PATCH 05/15] Change CharacterManager to use list instead of vector Solves a crash when deleting all savegames of a character due to mCurrent being invalidated --- apps/openmw/mwbase/statemanager.hpp | 4 +-- apps/openmw/mwstate/charactermanager.cpp | 37 ++++++++++++++---------- apps/openmw/mwstate/charactermanager.hpp | 11 +++++-- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 121a73a48..006be921b 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWSTATE_STATEMANAGER_H #define GAME_MWSTATE_STATEMANAGER_H -#include +#include #include namespace MWState @@ -24,7 +24,7 @@ namespace MWBase State_Running }; - typedef std::vector::const_iterator CharacterIterator; + typedef std::list::const_iterator CharacterIterator; private: diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 822e2d88e..d773904db 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -49,20 +49,17 @@ MWState::Character *MWState::CharacterManager::getCurrentCharacter (bool create) void MWState::CharacterManager::deleteSlot(const MWState::Character *character, const MWState::Slot *slot) { - int index = character - &mCharacters[0]; + std::list::iterator it = findCharacter(character); - if (index<0 || index>=static_cast (mCharacters.size())) - throw std::logic_error ("invalid character"); - - mCharacters[index].deleteSlot(slot); + it->deleteSlot(slot); - if (mCharacters[index].begin() == mCharacters[index].end()) + if (character->begin() == character->end()) { // All slots deleted, cleanup and remove this character - mCharacters[index].cleanup(); + it->cleanup(); if (character == mCurrent) mCurrent = NULL; - mCharacters.erase(mCharacters.begin() + index); + mCharacters.erase(it); } } @@ -78,14 +75,24 @@ void MWState::CharacterManager::createCharacter() mCurrent = &mCharacters.back(); } -void MWState::CharacterManager::setCurrentCharacter (const Character *character) +std::list::iterator MWState::CharacterManager::findCharacter(const MWState::Character* character) { - int index = character - &mCharacters[0]; - - if (index<0 || index>=static_cast (mCharacters.size())) + std::list::iterator it = mCharacters.begin(); + for (; it != mCharacters.end(); ++it) + { + if (&*it == character) + break; + } + if (it == mCharacters.end()) throw std::logic_error ("invalid character"); + return it; +} + +void MWState::CharacterManager::setCurrentCharacter (const Character *character) +{ + std::list::iterator it = findCharacter(character); - mCurrent = &mCharacters[index]; + mCurrent = &*it; } void MWState::CharacterManager::clearCurrentCharacter() @@ -93,12 +100,12 @@ void MWState::CharacterManager::clearCurrentCharacter() mCurrent = 0; } -std::vector::const_iterator MWState::CharacterManager::begin() const +std::list::const_iterator MWState::CharacterManager::begin() const { return mCharacters.begin(); } -std::vector::const_iterator MWState::CharacterManager::end() const +std::list::const_iterator MWState::CharacterManager::end() const { return mCharacters.end(); } diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index 869d34f21..adf9d2ef4 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -11,7 +11,10 @@ namespace MWState { boost::filesystem::path mPath; int mNext; - std::vector mCharacters; + + // Uses std::list, so that mCurrent stays valid when characters are deleted + std::list mCharacters; + Character *mCurrent; std::string mGame; @@ -23,6 +26,8 @@ namespace MWState CharacterManager& operator= (const CharacterManager&); ///< Not implemented + std::list::iterator findCharacter(const MWState::Character* character); + public: CharacterManager (const boost::filesystem::path& saves, const std::string& game); @@ -39,9 +44,9 @@ namespace MWState void clearCurrentCharacter(); - std::vector::const_iterator begin() const; + std::list::const_iterator begin() const; - std::vector::const_iterator end() const; + std::list::const_iterator end() const; }; } From 16ceb382f4aa6c52e1976f8db8a307e9676d0349 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Jun 2014 20:40:06 +0200 Subject: [PATCH 06/15] Ignore raycasting shapes for weapon collision tests Fixes dead bodies being in the way when they shouldn't. --- libs/openengine/bullet/physic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 235300b43..8d9ac3c22 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -615,6 +615,7 @@ namespace Physic btCollisionObject *object) { DeepestNotMeContactTestResultCallback callback(filter, origin); + callback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor; dynamicsWorld->contactTest(object, callback); return std::make_pair(callback.mObject, callback.mContactPoint); } From d2ad2e0f31fcc6b269d35e5e42de74535dd16d38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Jun 2014 20:44:59 +0200 Subject: [PATCH 07/15] Re-enable collision when an actor is resurrected --- apps/openmw/mwmechanics/actors.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8dcccfdb3..3d7e7e283 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -989,7 +989,11 @@ namespace MWMechanics if(!stats.isDead()) { if(iter->second->isDead()) + { + // Actor has been resurrected. Notify the CharacterController and re-enable collision. + MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true); iter->second->resurrect(); + } if(!stats.isDead()) continue; From 577ed3943b3f0edfd22741eaa694fe74b76bad41 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Jun 2014 23:26:43 +0200 Subject: [PATCH 08/15] Show wallpaper when loading a savegame --- apps/openmw/mwgui/loadingscreen.cpp | 22 ++++++++++--------- apps/openmw/mwgui/loadingscreen.hpp | 4 ---- apps/openmw/mwworld/scene.cpp | 4 ---- .../loadinglistener/loadinglistener.hpp | 3 --- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7c915ebeb..f1bbc68cd 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" @@ -26,7 +27,6 @@ namespace MWGui , WindowBase("openmw_loading_screen.layout") , mLastRenderTime(0.f) , mLastWallpaperChangeTime(0.f) - , mFirstLoad(true) , mProgress(0) , mVSyncWasEnabled(false) { @@ -77,7 +77,11 @@ namespace MWGui mWindow->setVSyncEnabled(false); #endif - if (!mFirstLoad) + bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() + == MWBase::StateManager::State_NoGame); + + + if (!showWallpaper) { mBackgroundImage->setImageTexture(""); int width = mWindow->getWidth(); @@ -103,12 +107,12 @@ namespace MWGui setVisible(true); - if (mFirstLoad) + if (showWallpaper) { changeWallpaper(); } - MWBase::Environment::get().getWindowManager()->pushGuiMode(mFirstLoad ? GM_LoadingWallpaper : GM_Loading); + MWBase::Environment::get().getWindowManager()->pushGuiMode(showWallpaper ? GM_LoadingWallpaper : GM_Loading); } void LoadingScreen::loadingOff() @@ -188,11 +192,6 @@ namespace MWGui draw(); } - void LoadingScreen::removeWallpaper() - { - mFirstLoad = false; - } - void LoadingScreen::draw() { const float loadingScreenFps = 20.f; @@ -201,7 +200,10 @@ namespace MWGui { mLastRenderTime = mTimer.getMilliseconds (); - if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 5000*1) + bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState() + == MWBase::StateManager::State_NoGame); + + if (showWallpaper && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 5000*1) { mLastWallpaperChangeTime = mTimer.getMilliseconds (); changeWallpaper(); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 96e0e1ed4..f198d625d 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -29,8 +29,6 @@ namespace MWGui virtual void setVisible(bool visible); - virtual void removeWallpaper(); - LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw); virtual ~LoadingScreen(); @@ -42,8 +40,6 @@ namespace MWGui void updateWindow(Ogre::RenderWindow* rw) { mWindow = rw; } private: - bool mFirstLoad; - Ogre::SceneManager* mSceneMgr; Ogre::RenderWindow* mWindow; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 32bf773bd..f753ae1f4 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -347,8 +347,6 @@ namespace MWWorld MWBase::Environment::get().getWorld()->adjustSky(); mCellChanged = true; - - loadingListener->removeWallpaper(); } //We need the ogre renderer and a scene node. @@ -449,8 +447,6 @@ namespace MWWorld mCellChanged = true; MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.5); - - loadingListener->removeWallpaper(); } void Scene::changeToExteriorCell (const ESM::Position& position) diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index f6a7b71e9..47962015c 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -18,9 +18,6 @@ namespace Loading virtual void setProgressRange (size_t range) = 0; virtual void setProgress (size_t value) = 0; virtual void increaseProgress (size_t increase = 1) = 0; - - /// Indicate the scene is now ready to be shown - virtual void removeWallpaper() = 0; }; // Used for stopping a loading sequence when the object goes out of scope From bbc5b125abd7ccaafe7a0ce206a7c8229685f840 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Jun 2014 00:16:32 +0200 Subject: [PATCH 09/15] Rewrite journal GUI quest index - Use quest names as identifiers, not quest IDs. This ensures that quests with different IDs, but the same name (e.g. A2_4_MiloCaiusGone and A2_4_MiloGone) are merged properly, as they should. - Switch display from BookPage to MWList. Handles word-wrapping and scrolling properly. - Fixes a bug where the quest index would not be updated when opened. --- apps/openmw/mwgui/journalbooks.cpp | 35 +++--------------- apps/openmw/mwgui/journalbooks.hpp | 3 +- apps/openmw/mwgui/journalviewmodel.cpp | 35 +++++++++++++----- apps/openmw/mwgui/journalviewmodel.hpp | 9 ++--- apps/openmw/mwgui/journalwindow.cpp | 50 ++++++++++++++++---------- apps/openmw/mwgui/list.cpp | 12 ++++++- apps/openmw/mwgui/list.hpp | 5 ++- files/mygui/openmw_journal.layout | 4 +-- files/mygui/openmw_journal_skin.xml | 24 +++++++++++++ files/mygui/openmw_list.skin.xml | 1 + 10 files changed, 111 insertions(+), 67 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 683fe9208..70f156922 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -148,22 +148,6 @@ namespace mTypesetter->lineBreak (); } }; - - struct AddQuestLink : AddContent - { - AddQuestLink (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* style) : - AddContent (typesetter, style) - { - } - - void operator () (MWGui::JournalViewModel::QuestId id, MWGui::JournalViewModel::Utf8Span name) - { - MWGui::BookTypesetter::Style* style = mTypesetter->createHotStyle (mBodyStyle, MyGUI::Colour::Black, linkHot, linkActive, id); - - mTypesetter->write (style, name); - mTypesetter->lineBreak (); - } - }; } namespace MWGui @@ -206,7 +190,7 @@ book JournalBooks::createJournalBook () BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); - mModel->visitJournalEntries (0, AddJournalEntry (typesetter, body, header, true)); + mModel->visitJournalEntries ("", AddJournalEntry (typesetter, body, header, true)); return typesetter->complete (); } @@ -227,16 +211,17 @@ book JournalBooks::createTopicBook (uintptr_t topicId) return typesetter->complete (); } -book JournalBooks::createQuestBook (uintptr_t questId) +book JournalBooks::createQuestBook (const std::string& questName) { BookTypesetter::Ptr typesetter = createTypesetter (); BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); - mModel->visitQuestName (questId, AddQuestName (typesetter, header)); + AddQuestName addName (typesetter, header); + addName(to_utf8_span(questName.c_str())); - mModel->visitJournalEntries (questId, AddJournalEntry (typesetter, body, header, false)); + mModel->visitJournalEntries (questName, AddJournalEntry (typesetter, body, header, false)); return typesetter->complete (); } @@ -279,16 +264,6 @@ book JournalBooks::createTopicIndexBook (char character) return typesetter->complete (); } -book JournalBooks::createQuestIndexBook (bool activeOnly) -{ - BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF); - BookTypesetter::Style* base = typesetter->createStyle ("", MyGUI::Colour::Black); - - mModel->visitQuestNames (activeOnly, AddQuestLink (typesetter, base)); - - return typesetter->complete (); -} - BookTypesetter::Ptr JournalBooks::createTypesetter () { //TODO: determine page size from layout... diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 819bda0fd..6ae2ba82a 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -18,10 +18,9 @@ namespace MWGui Book createEmptyJournalBook (); Book createJournalBook (); Book createTopicBook (uintptr_t topicId); - Book createQuestBook (uintptr_t questId); + Book createQuestBook (const std::string& questName); Book createTopicIndexBook (); Book createTopicIndexBook (char character); - Book createQuestIndexBook (bool showAll); private: BookTypesetter::Ptr createTypesetter (); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 5994c6e21..1feb92b02 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -195,10 +195,12 @@ struct JournalViewModelImpl : JournalViewModel }; - void visitQuestNames (bool active_only, boost::function visitor) const + void visitQuestNames (bool active_only, boost::function visitor) const { MWBase::Journal * journal = MWBase::Environment::get ().getJournal (); + std::set visitedQuests; + for (MWBase::Journal::TQuestIter i = journal->questBegin (); i != journal->questEnd (); ++i) { if (active_only && i->second.isFinished ()) @@ -209,7 +211,15 @@ struct JournalViewModelImpl : JournalViewModel // Note that even with Tribunal, some quests still don't have quest names. I'm assuming those are not supposed // to appear in the quest book. if (!quest.getName().empty()) - visitor (reinterpret_cast (&i->second), toUtf8Span (quest.getName())); + { + // Don't list the same quest name twice + if (visitedQuests.find(quest.getName()) != visitedQuests.end()) + continue; + + visitor (quest.getName()); + + visitedQuests.insert(quest.getName()); + } } } @@ -258,20 +268,29 @@ struct JournalViewModelImpl : JournalViewModel } }; - void visitJournalEntries (QuestId questId, boost::function visitor) const + void visitJournalEntries (const std::string& questName, boost::function visitor) const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); - if (questId != 0) + if (!questName.empty()) { - MWDialogue::Quest const * quest = reinterpret_cast (questId); + std::vector quests; + for (MWBase::Journal::TQuestIter questIt = journal->questBegin(); questIt != journal->questEnd(); ++questIt) + { + if (Misc::StringUtils::ciEqual(questIt->second.getName(), questName)) + quests.push_back(&questIt->second); + } for(MWBase::Journal::TEntryIter i = journal->begin(); i != journal->end (); ++i) { - for (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j) + for (std::vector::iterator questIt = quests.begin(); questIt != quests.end(); ++questIt) { - if (i->mInfoId == j->mInfoId) - visitor (JournalEntryImpl (this, i)); + MWDialogue::Quest const* quest = *questIt; + for (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j) + { + if (i->mInfoId == j->mInfoId) + visitor (JournalEntryImpl (this, i)); + } } } } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 9efdeae54..feb9457c6 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -70,11 +70,12 @@ namespace MWGui /// provides access to the name of the quest with the specified identifier virtual void visitQuestName (TopicId topicId, boost::function visitor) const = 0; - /// walks the active and optionally completed, quests providing the quest id and name - virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; + /// walks the active and optionally completed, quests providing the name + virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; - /// walks over the journal entries related to the specified quest identified by its id - virtual void visitJournalEntries (QuestId questId, boost::function visitor) const = 0; + /// walks over the journal entries related to all quests with the given name + /// If \a questName is empty, simply visits all journal entries + virtual void visitJournalEntries (const std::string& questName, boost::function visitor) const = 0; /// provides the name of the topic specified by its id virtual void visitTopicName (TopicId topicId, boost::function visitor) const = 0; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index f3c9e9c73..0940b7fef 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -19,6 +19,7 @@ #include "imagebutton.hpp" #include "journalviewmodel.hpp" #include "journalbooks.hpp" +#include "list.hpp" namespace { @@ -38,7 +39,6 @@ namespace static char const TopicsList [] = "TopicsList"; static char const TopicsPage [] = "TopicsPage"; static char const QuestsList [] = "QuestsList"; - static char const QuestsPage [] = "QuestsPage"; static char const LeftBookPage [] = "LeftBookPage"; static char const RightBookPage [] = "RightBookPage"; static char const LeftTopicIndex [] = "LeftTopicIndex"; @@ -110,6 +110,9 @@ namespace adviseButtonClick (ShowAllBTN, &JournalWindowImpl::notifyShowAll ); adviseButtonClick (ShowActiveBTN, &JournalWindowImpl::notifyShowActive); + MWGui::Widgets::MWList* list = getWidget(QuestsList); + list->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyQuestClicked); + { MWGui::BookPage::ClickCallback callback; @@ -129,14 +132,6 @@ namespace getPage (RightTopicIndex)->adviseLinkClicked (callback); } - { - MWGui::BookPage::ClickCallback callback; - - callback = boost::bind (&JournalWindowImpl::notifyQuestClicked, this, _1); - - getPage (QuestsPage)->adviseLinkClicked (callback); - } - adjustButton(OptionsBTN, true); adjustButton(PrevPageBTN); adjustButton(NextPageBTN); @@ -271,6 +266,10 @@ namespace //TODO: figure out how to make "options" page overlay book page // correctly, so that text may show underneath getPage (RightBookPage)->showPage (Book (), 0); + + // If in quest mode, ensure the quest list is updated + if (mQuestMode) + notifyQuests(getWidget(QuestsList)); } void pushBook (Book book, unsigned int page) @@ -349,9 +348,9 @@ namespace setVisible (JournalBTN, true); } - void notifyQuestClicked (intptr_t questId) + void notifyQuestClicked (const std::string& name, int id) { - Book book = createQuestBook (questId); + Book book = createQuestBook (name); if (mStates.size () > 1) replaceBook (book, 0); @@ -409,9 +408,21 @@ namespace setVisible (ShowActiveBTN, false); } + struct AddQuestNamesToList + { + AddQuestNamesToList(MWGui::Widgets::MWList* list) : mList(list) {} + + MWGui::Widgets::MWList* mList; + void operator () (const std::string& name) + { + mList->addItem(name); + } + }; + void notifyQuests(MyGUI::Widget* _sender) { mQuestMode = true; + setVisible (LeftTopicIndex, false); setVisible (RightTopicIndex, false); setVisible (TopicsList, false); @@ -419,23 +430,26 @@ namespace setVisible (ShowAllBTN, !mAllQuests); setVisible (ShowActiveBTN, mAllQuests); - showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests)); + MWGui::Widgets::MWList* list = getWidget(QuestsList); + list->clear(); + + AddQuestNamesToList add(list); + + mModel->visitQuestNames(!mAllQuests, add); + + list->adjustSize(); } void notifyShowAll(MyGUI::Widget* _sender) { mAllQuests = true; - setVisible (ShowAllBTN, !mAllQuests); - setVisible (ShowActiveBTN, mAllQuests); - showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests)); + notifyQuests(_sender); } void notifyShowActive(MyGUI::Widget* _sender) { mAllQuests = false; - setVisible (ShowAllBTN, !mAllQuests); - setVisible (ShowActiveBTN, mAllQuests); - showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests)); + notifyQuests(_sender); } void notifyCancel(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index 19f20eeee..ca2989646 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -65,8 +65,10 @@ namespace MWGui { if (*it != "") { + if (mListItemSkin.empty()) + throw std::runtime_error("MWList needs a ListItemSkin property"); MyGUI::Button* button = mScrollView->createWidget( - "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), + mListItemSkin, MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); button->setCaption((*it)); button->getSubWidgetText()->setWordWrap(true); @@ -102,6 +104,14 @@ namespace MWGui mScrollView->setViewOffset(MyGUI::IntPoint(0, -viewPosition)); } + void MWList::setPropertyOverride(const std::string &_key, const std::string &_value) + { + if (_key == "ListItemSkin") + mListItemSkin = _value; + else + Base::setPropertyOverride(_key, _value); + } + bool MWList::hasItem(const std::string& name) { return (std::find(mItems.begin(), mItems.end(), name) != mItems.end()); diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index dcfe7931a..acf078a2c 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -22,7 +22,7 @@ namespace MWGui /** * Event: Item selected with the mouse. - * signature: void method(std::string itemName) + * signature: void method(std::string itemName, int index) */ EventHandle_StringInt eventItemSelected; @@ -49,6 +49,8 @@ namespace MWGui MyGUI::Widget* getItemWidget(const std::string& name); ///< get widget for an item name, useful to set up tooltip + virtual void setPropertyOverride(const std::string& _key, const std::string& _value); + protected: void initialiseOverride(); @@ -60,6 +62,7 @@ namespace MWGui private: MyGUI::ScrollView* mScrollView; MyGUI::Widget* mClient; + std::string mListItemSkin; std::vector mItems; diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 34421d431..c460aa41a 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -82,9 +82,7 @@ - - - + diff --git a/files/mygui/openmw_journal_skin.xml b/files/mygui/openmw_journal_skin.xml index ca6d309d7..71a2a7865 100644 --- a/files/mygui/openmw_journal_skin.xml +++ b/files/mygui/openmw_journal_skin.xml @@ -12,4 +12,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 4dbc3da45..b2f9c1bef 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -157,6 +157,7 @@ + From d777739425772b9a16a880e1daac5b96c3f510d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Jun 2014 00:44:32 +0200 Subject: [PATCH 10/15] Fix a crash on exit when projectiles were active --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 548a871ce..52ca17314 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -368,6 +368,9 @@ namespace MWWorld World::~World() { + // Must be cleared before mRendering is destroyed + mProjectileManager->clear(); + delete mWeatherManager; delete mWorldScene; delete mRendering; From 17b15a6f4f69330669d82007d79340cbe0338852 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Jun 2014 01:12:31 +0200 Subject: [PATCH 11/15] Fix overlapping text in SpellWindow when the window is too small --- apps/openmw/mwgui/spellwindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index fb5a80cc7..77da56fa4 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -190,6 +190,7 @@ namespace MWGui costChance->setNeedMouseFocus(false); costChance->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell()); + t->setSize(mWidth-12-costChance->getTextSize().width, t->getHeight()); mHeight += spellHeight; } @@ -255,6 +256,8 @@ namespace MWGui if (store.getSelectedEnchantItem() != store.end()) costCharge->setStateSelected(item == *store.getSelectedEnchantItem()); + t->setSize(mWidth-12-costCharge->getTextSize().width, t->getHeight()); + mHeight += spellHeight; } @@ -287,6 +290,8 @@ namespace MWGui groupWidget2->setCaptionWithReplacing(label2); groupWidget2->setTextAlign(MyGUI::Align::Right); groupWidget2->setNeedMouseFocus(false); + + groupWidget->setSize(mWidth-8-groupWidget2->getTextSize().width, groupWidget->getHeight()); } mHeight += 24; From d7f3cd75ac736f93e1fd9a251e073a26bd35e47f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Jun 2014 16:04:18 +0200 Subject: [PATCH 12/15] Rewrite journal GUI topic list to use MWList --- apps/openmw/mwgui/journalbooks.cpp | 10 -------- apps/openmw/mwgui/journalbooks.hpp | 2 +- apps/openmw/mwgui/journalviewmodel.cpp | 4 +-- apps/openmw/mwgui/journalviewmodel.hpp | 4 +-- apps/openmw/mwgui/journalwindow.cpp | 34 +++++++++++++++++++++----- files/mygui/openmw_journal.layout | 4 +-- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 70f156922..7ffe9e6a4 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -254,16 +254,6 @@ book JournalBooks::createTopicIndexBook () return typesetter->complete (); } -book JournalBooks::createTopicIndexBook (char character) -{ - BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF); - BookTypesetter::Style* style = typesetter->createStyle ("", MyGUI::Colour::Black); - - mModel->visitTopicNamesStartingWith (character, AddTopicLink (typesetter, style)); - - return typesetter->complete (); -} - BookTypesetter::Ptr JournalBooks::createTypesetter () { //TODO: determine page size from layout... diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 6ae2ba82a..8f87825f0 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -18,9 +18,9 @@ namespace MWGui Book createEmptyJournalBook (); Book createJournalBook (); Book createTopicBook (uintptr_t topicId); + Book createTopicBook (const std::string& topicId); Book createQuestBook (const std::string& questName); Book createTopicIndexBook (); - Book createTopicIndexBook (char character); private: BookTypesetter::Ptr createTypesetter (); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 1feb92b02..b9ddb7daa 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -312,7 +312,7 @@ struct JournalViewModelImpl : JournalViewModel visitor (toUtf8Span (topic.getName())); } - void visitTopicNamesStartingWith (char character, boost::function < void (TopicId , Utf8Span) > visitor) const + void visitTopicNamesStartingWith (char character, boost::function < void (const std::string&) > visitor) const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); @@ -321,7 +321,7 @@ struct JournalViewModelImpl : JournalViewModel if (i->first [0] != std::tolower (character, mLocale)) continue; - visitor (TopicId (&i->second), toUtf8Span (i->second.getName())); + visitor (i->second.getName()); } } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index feb9457c6..4b827d1ab 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -80,8 +80,8 @@ namespace MWGui /// provides the name of the topic specified by its id virtual void visitTopicName (TopicId topicId, boost::function visitor) const = 0; - /// walks over the topics whose names start with the specified character providing the topics id and name - virtual void visitTopicNamesStartingWith (char character, boost::function < void (TopicId , Utf8Span) > visitor) const = 0; + /// walks over the topics whose names start with the specified character providing the topics name + virtual void visitTopicNamesStartingWith (char character, boost::function < void (const std::string&) > visitor) const = 0; /// walks over the topic entries for the topic specified by its identifier virtual void visitTopicEntries (TopicId topicId, boost::function visitor) const = 0; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 0940b7fef..fa27b4ef0 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -3,6 +3,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/journal.hpp" #include "list.hpp" #include @@ -37,7 +38,6 @@ namespace static char const PageOneNum [] = "PageOneNum"; static char const PageTwoNum [] = "PageTwoNum"; static char const TopicsList [] = "TopicsList"; - static char const TopicsPage [] = "TopicsPage"; static char const QuestsList [] = "QuestsList"; static char const LeftBookPage [] = "LeftBookPage"; static char const RightBookPage [] = "RightBookPage"; @@ -113,12 +113,14 @@ namespace MWGui::Widgets::MWList* list = getWidget(QuestsList); list->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyQuestClicked); + MWGui::Widgets::MWList* topicsList = getWidget(TopicsList); + topicsList->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyTopicSelected); + { MWGui::BookPage::ClickCallback callback; callback = boost::bind (&JournalWindowImpl::notifyTopicClicked, this, _1); - getPage (TopicsPage)->adviseLinkClicked (callback); getPage (LeftBookPage)->adviseLinkClicked (callback); getPage (RightBookPage)->adviseLinkClicked (callback); } @@ -348,6 +350,19 @@ namespace setVisible (JournalBTN, true); } + void notifyTopicSelected (const std::string& topic, int id) + { + const MWBase::Journal* journal = MWBase::Environment::get().getJournal(); + intptr_t topicId = 0; /// \todo get rid of intptr ids + for(MWBase::Journal::TTopicIter i = journal->topicBegin(); i != journal->topicEnd (); ++i) + { + if (Misc::StringUtils::ciEqual(i->first, topic)) + topicId = intptr_t (&i->second); + } + + notifyTopicClicked(topicId); + } + void notifyQuestClicked (const std::string& name, int id) { Book book = createQuestBook (name); @@ -394,7 +409,14 @@ namespace setVisible (RightTopicIndex, false); setVisible (TopicsList, true); - showList (TopicsList, TopicsPage, createTopicIndexBook ((char)character)); + MWGui::Widgets::MWList* list = getWidget(TopicsList); + list->clear(); + + AddNamesToList add(list); + + mModel->visitTopicNamesStartingWith((char) character, add); + + list->adjustSize(); } void notifyTopics(MyGUI::Widget* _sender) @@ -408,9 +430,9 @@ namespace setVisible (ShowActiveBTN, false); } - struct AddQuestNamesToList + struct AddNamesToList { - AddQuestNamesToList(MWGui::Widgets::MWList* list) : mList(list) {} + AddNamesToList(MWGui::Widgets::MWList* list) : mList(list) {} MWGui::Widgets::MWList* mList; void operator () (const std::string& name) @@ -433,7 +455,7 @@ namespace MWGui::Widgets::MWList* list = getWidget(QuestsList); list->clear(); - AddQuestNamesToList add(list); + AddNamesToList add(list); mModel->visitQuestNames(!mAllQuests, add); diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index c460aa41a..5524f5520 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -77,9 +77,7 @@ - - - + From ce14a6413b8f9b3dc2066815e86abc1c4506895a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Jun 2014 22:35:26 +0200 Subject: [PATCH 13/15] Small optimization to ESM::Variant --- components/esm/variant.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index a7859d128..217ec4407 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -6,6 +6,15 @@ #include "esmreader.hpp" #include "variantimp.hpp" +#include "defs.hpp" + +namespace +{ + const uint32_t STRV = ESM::FourCC<'S','T','R','V'>::value; + const uint32_t INTV = ESM::FourCC<'I','N','T','V'>::value; + const uint32_t FLTV = ESM::FourCC<'F','L','T','V'>::value; +} + ESM::Variant::Variant() : mType (VT_None), mData (0) {} ESM::Variant::~Variant() @@ -90,15 +99,17 @@ void ESM::Variant::read (ESMReader& esm, Format format) esm.getSubName(); NAME name = esm.retSubName(); - if (name=="STRV") + + + if (name==STRV) { type = VT_String; } - else if (name=="INTV") + else if (name==INTV) { type = VT_Int; } - else if (name=="FLTV") + else if (name==FLTV) { type = VT_Float; } @@ -111,11 +122,11 @@ void ESM::Variant::read (ESMReader& esm, Format format) esm.getSubName(); NAME name = esm.retSubName(); - if (name=="INTV") + if (name==INTV) { type = VT_Int; } - else if (name=="FLTV") + else if (name==FLTV) { type = VT_Float; } @@ -279,4 +290,4 @@ bool ESM::operator== (const Variant& left, const Variant& right) bool ESM::operator!= (const Variant& left, const Variant& right) { return !(left==right); -} \ No newline at end of file +} From 7376cb9b61f63a1f9f02c31227faeca96abcbd9f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Jun 2014 22:49:37 +0200 Subject: [PATCH 14/15] Fix loading ESX files cleaned with testool (Fixes #1382) --- components/esm/loadregn.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index da03e009f..0c3ccbffb 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -12,10 +12,26 @@ void Region::load(ESMReader &esm) { mName = esm.getHNOString("FNAM"); + esm.getSubNameIs("WEAT"); + esm.getSubHeader(); if (esm.getVer() == VER_12) - esm.getHNExact(&mData, sizeof(mData) - 2, "WEAT"); + { + mData.mA = 0; + mData.mB = 0; + esm.getExact(&mData, sizeof(mData) - 2); + } else if (esm.getVer() == VER_13) - esm.getHNExact(&mData, sizeof(mData), "WEAT"); + { + // May include the additional two bytes (but not necessarily) + if (esm.getSubSize() == sizeof(mData)) + esm.getExact(&mData, sizeof(mData)); + else + { + mData.mA = 0; + mData.mB = 0; + esm.getExact(&mData, sizeof(mData)-2); + } + } else esm.fail("Don't know what to do in this version"); From 00775035af1fbf562b1a6d4e4735ce352c0974ac Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Jun 2014 01:03:12 +0200 Subject: [PATCH 15/15] Add missing hasItemHealth for lockpicks/probes (Fixes #1385) --- apps/openmw/mwclass/lockpick.hpp | 3 +++ apps/openmw/mwclass/probe.hpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index a7cf3791f..8f5a699d9 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -64,6 +64,9 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health + + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } + ///< \return Item health data available? (default implementation: false) }; } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 832169f8b..a959e6c42 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -64,6 +64,9 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health + + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const { return true; } + ///< \return Item health data available? (default implementation: false) }; }