From 927ae00454d9e91db30040764df639938b486709 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 21:15:23 +0200 Subject: [PATCH 01/35] Fix code that stopped animation immediately after starting it, due to thinking it has completed (Fixes #1370) --- apps/openmw/mwmechanics/character.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index db4e59929..67d506e43 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -832,6 +832,8 @@ bool CharacterController::updateWeaponState() MWRender::Animation::Group_UpperBody, false, weapSpeed, mAttackType+" max attack", mAttackType+" min hit", 1.0f-complete, 0); + + complete = 0.f; mUpperBodyState = UpperCharState_MaxAttackToMinHit; } else if (mHitState == CharState_KnockDown) From 2ec324c80bb834ea543786725fffe60e2110034a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Jun 2014 17:10:02 +0200 Subject: [PATCH 02/35] Consider all splash screens in the Splash folder (Fixes #1416) --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f1bbc68cd..f6d6b8135 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -136,7 +136,7 @@ namespace MWGui Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) { - Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash_*.tga"); + Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash/*.tga"); mResources.insert(mResources.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); } } From b470596206c21ece3fd77e0159d15fc4d68197e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Jun 2014 17:48:40 +0200 Subject: [PATCH 03/35] Handle failed savegame file operations (Fixes #1413) --- apps/openmw/mwstate/statemanagerimp.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 0e56365d6..7a70944dc 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -233,6 +233,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.close(); + if (stream.fail()) + throw std::runtime_error("Write operation failed"); + Settings::Manager::setString ("character", "Saves", slot->mPath.parent_path().filename().string()); } @@ -246,6 +249,10 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot std::vector buttons; buttons.push_back("#{sOk}"); MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons); + + // If no file was written, clean up the slot + if (slot && !boost::filesystem::exists(slot->mPath)) + mCharacterManager.getCurrentCharacter()->deleteSlot(slot); } } From a0bff03560b4413500161c5d45ba38bf41d25341 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Jun 2014 17:58:03 +0200 Subject: [PATCH 04/35] Fix not handling failbit/badbit in ifstream (Bug #1355) --- components/translation/translation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index 423c3971a..976ae926d 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -32,6 +32,9 @@ namespace Translation boost::filesystem::ifstream stream ( dataFileCollections.getCollection (extension).getPath (fileName)); + // Configure the stream to throw exception upon error + stream.exceptions ( boost::filesystem::ifstream::failbit | boost::filesystem::ifstream::badbit ); + if (!stream.is_open()) throw std::runtime_error ("failed to open translation file: " + fileName); @@ -41,6 +44,7 @@ namespace Translation void Storage::loadDataFromStream(ContainerType& container, std::istream& stream) { + // NOTE: does not handle failbit/badbit. stream must be set up beforehand to throw in these cases. std::string line; while (!stream.eof()) { From 69855097cac627c679587f983d97f11634c37502 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Jun 2014 18:00:39 +0200 Subject: [PATCH 05/35] Fix an always true condition (Bug #1355) --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 67d506e43..2d4bd8744 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -977,7 +977,8 @@ bool CharacterController::updateWeaponState() } //if playing combat animation and lowerbody is not busy switch to whole body animation - if((weaptype != WeapType_None || UpperCharState_UnEquipingWeap) && animPlaying) + if((weaptype != WeapType_None || mUpperBodyState == UpperCharState_UnEquipingWeap + || mUpperBodyState == UpperCharState_EquipingWeap) && animPlaying) { if( mMovementState != CharState_None || mJumpState != JumpState_None || From 823ccb1b3d7bcdbc3b864e937c667cfe456a6e7c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Jun 2014 18:48:12 +0200 Subject: [PATCH 06/35] Don't batch statics that have "references persist" set (temporary fix for Arkngthand door - Fixes #1386) --- apps/openmw/mwclass/static.cpp | 5 ++++- apps/openmw/mwrender/objects.cpp | 4 ++-- apps/openmw/mwrender/objects.hpp | 2 +- components/esm/loadstat.cpp | 1 + components/esm/loadstat.hpp | 2 ++ 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 4ac41350f..8768bde06 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -14,9 +14,12 @@ namespace MWClass { void Static::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { + MWWorld::LiveCellRef *ref = + ptr.get(); + const std::string model = getModel(ptr); if (!model.empty()) { - renderingInterface.getObjects().insertModel(ptr, model); + renderingInterface.getObjects().insertModel(ptr, model, !ref->mBase->mPersistent); } } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 7953a3117..d9e20e1f8 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -73,7 +73,7 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) ptr.getRefData().setBaseNode(insert); } -void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh) +void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool batch) { insertBegin(ptr); @@ -99,7 +99,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh) mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()].merge(bounds); - if(ptr.getTypeName() == typeid(ESM::Static).name() && + if(batch && Settings::Manager::getBool("use static geometry", "Objects") && anim->canBatch()) { diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 665a1e657..02e974e2d 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -41,7 +41,7 @@ public: , mRootNode(NULL) {} ~Objects(){} - void insertModel(const MWWorld::Ptr& ptr, const std::string &model); + void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool batch=false); ObjectAnimation* getAnimation(const MWWorld::Ptr &ptr); diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index a71f22dc2..53d1b4bb5 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -10,6 +10,7 @@ namespace ESM void Static::load(ESMReader &esm) { + mPersistent = esm.getRecordFlags() & 0x0400; mModel = esm.getHNString("MODL"); } void Static::save(ESMWriter &esm) const diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index d912d1058..45b05136a 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -26,6 +26,8 @@ struct Static std::string mId, mModel; + bool mPersistent; + void load(ESMReader &esm); void save(ESMWriter &esm) const; From b9dadff5a378ae818f80c1a6250d48c9368bfe29 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Jun 2014 19:21:37 +0200 Subject: [PATCH 07/35] Recognize DELE subrecords at the end of the record (Fixes #1414) --- apps/openmw/mwworld/esmstore.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index cd6cc4a16..12831e7dc 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -99,6 +99,13 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) } it->second->load(esm, id); + // DELE can also occur after the usual subrecords + if (esm.isNextSub("DELE")) { + esm.skipRecord(); + it->second->eraseStatic(id); + continue; + } + if (n.val==ESM::REC_DIAL) { dialogue = const_cast(mDialogs.find(id)); } else { From 98d7b6672a894f345ab2a13de4a6138ae769d649 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Jun 2014 01:42:43 +0200 Subject: [PATCH 08/35] Make MODL subrecord optional for potions (Fixes #1419) --- components/esm/loadalch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index f6bfc6a11..aac88482f 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -10,7 +10,7 @@ namespace ESM void Potion::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); + mModel = esm.getHNOString("MODL"); mIcon = esm.getHNOString("TEXT"); // not ITEX here for some reason mScript = esm.getHNOString("SCRI"); mName = esm.getHNOString("FNAM"); From d2dca270678502169036fd44ce6d4c436c500509 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Jun 2014 11:25:10 +0200 Subject: [PATCH 09/35] Correct wrong assertions (Fixes #1425) --- apps/openmw/mwgui/quickkeysmenu.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index e14217177..eda9daeff 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -162,7 +162,7 @@ namespace MWGui void QuickKeysMenu::onAssignItem(MWWorld::Ptr item) { - assert (mSelectedIndex > 0); + assert (mSelectedIndex >= 0); ItemWidget* button = mQuickKeyButtons[mSelectedIndex]; while (button->getChildCount()) // Destroy number label MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0)); @@ -184,7 +184,7 @@ namespace MWGui void QuickKeysMenu::onAssignMagicItem (MWWorld::Ptr item) { - assert (mSelectedIndex > 0); + assert (mSelectedIndex >= 0); ItemWidget* button = mQuickKeyButtons[mSelectedIndex]; while (button->getChildCount()) // Destroy number label MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0)); @@ -203,7 +203,7 @@ namespace MWGui void QuickKeysMenu::onAssignMagic (const std::string& spellId) { - assert (mSelectedIndex > 0); + assert (mSelectedIndex >= 0); ItemWidget* button = mQuickKeyButtons[mSelectedIndex]; while (button->getChildCount()) // Destroy number label MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0)); From a3752da79f3785ed814d0ca75fe201269449c2cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Jun 2014 19:50:39 +0200 Subject: [PATCH 10/35] Store Always Run control state in settings --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 +++- files/settings-default.cfg | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 943453a39..f75dc7ff0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -117,7 +117,7 @@ namespace MWInput , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) - , mAlwaysRunActive(false) + , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) , mControlsDisabled(false) { @@ -819,6 +819,8 @@ namespace MWInput { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; mAlwaysRunActive = !mAlwaysRunActive; + + Settings::Manager::setBool("always run", "Input", mAlwaysRunActive); } void InputManager::resetIdleTime() diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 9eed2c7d9..2ed3d6cb9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -168,6 +168,8 @@ camera y multiplier = 1.0 ui y multiplier = 1.0 +always run = false + [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false From cdd53862cbda2677bfed35477ccf6b4e518047e3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Jun 2014 21:37:50 +0200 Subject: [PATCH 11/35] Increase width of dialogue topic list (Fixes #1440) --- files/mygui/openmw_dialogue_window.layout | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index 78daa0705..5a7cd772d 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,28 +4,28 @@ - + - - + + - + - - + - + From 5488fe1ab3bacdffed8aa934882ef4b6b525ebe3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Jun 2014 03:40:14 +0200 Subject: [PATCH 12/35] Change npc training skills to prefer skills with lowest ID if skill values are the same (Fixes #1445) --- apps/openmw/mwgui/trainingwindow.cpp | 46 ++++++++++++++++------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 9a2c3b805..6463db3d7 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -16,6 +16,24 @@ #include "tooltips.hpp" +namespace +{ +// Sorts a container descending by skill value. If skill value is equal, sorts ascending by skill ID. +// pair +bool sortSkills (const std::pair& left, const std::pair& right) +{ + if (left == right) + return false; + + if (left.second > right.second) + return true; + else if (left.second < right.second) + return false; + + return left.first < right.first; +} +} + namespace MWGui { @@ -52,29 +70,17 @@ namespace MWGui MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); // NPC can train you in his best 3 skills - std::vector< std::pair > bestSkills; - bestSkills.push_back (std::make_pair(-1, -1)); - bestSkills.push_back (std::make_pair(-1, -1)); - bestSkills.push_back (std::make_pair(-1, -1)); + std::vector< std::pair > skills; for (int i=0; i bestSkills[j].second) - { - if (j<2) - { - bestSkills[j+1] = bestSkills[j]; - } - bestSkills[j] = std::make_pair(i, value); - break; - } - } + skills.push_back(std::make_pair(i, value)); } + std::sort(skills.begin(), skills.end(), sortSkills); + MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator (); MyGUI::Gui::getInstance ().destroyWidgets (widgets); @@ -86,20 +92,20 @@ namespace MWGui for (int i=0; i<3; ++i) { int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer - (mPtr,pcStats.getSkill (bestSkills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); + (mPtr,pcStats.getSkill (skills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); MyGUI::Button* button = mTrainingOptions->createWidget("SandTextButton", MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default); button->setEnabled(price <= playerGold); - button->setUserData(bestSkills[i].first); + button->setUserData(skills[i].first); button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected); - button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[bestSkills[i].first] + "} - " + boost::lexical_cast(price)); + button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[skills[i].first] + "} - " + boost::lexical_cast(price)); button->setSize(button->getTextSize ().width+12, button->getSize().height); - ToolTips::createSkillToolTip (button, bestSkills[i].first); + ToolTips::createSkillToolTip (button, skills[i].first); } center(); From 1bab74a98dd7448ab70d7d2ab1cdcd8a12a22b9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Jun 2014 03:42:29 +0200 Subject: [PATCH 13/35] Fix punishment for stealing 0 value items (Fixes #1435) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 900ea72ca..f39a4b961 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -929,7 +929,10 @@ namespace MWMechanics else if (type == OT_Murder) arg = store.find("iCrimeKilling")->getInt(); else if (type == OT_Theft) + { arg *= store.find("fCrimeStealing")->getFloat(); + arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen + } MWBase::Environment::get().getWindowManager()->messageBox("#{sCrimeMessage}"); ptr.getClass().getNpcStats(ptr).setBounty(ptr.getClass().getNpcStats(ptr).getBounty() From e796fa23130a4476839ee862454f1561766dae01 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Jun 2014 22:18:53 +0200 Subject: [PATCH 14/35] Add another french morrowind font workaround (Fixes #1447) --- apps/openmw/mwgui/fontloader.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp index 9d47bc38d..b7c2007b4 100644 --- a/apps/openmw/mwgui/fontloader.cpp +++ b/apps/openmw/mwgui/fontloader.cpp @@ -258,12 +258,16 @@ namespace MWGui code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - // More hacks! The french game uses U+2019, which is nowhere to be found in - // the CP437 encoding of the font. Fall back to 39 (regular apostrophe) - if (i == 39 && mEncoding == ToUTF8::CP437) + // More hacks! The french game uses several win1252 characters that are not included + // in the cp437 encoding of the font. Fall back to similar available characters. + // Same for U+2013 + std::map additional; + additional[39] = 0x2019; // apostrophe + additional[45] = 0x2013; // dash + if (additional.find(i) != additional.end() && mEncoding == ToUTF8::CP437) { MyGUI::xml::ElementPtr code = codes->createChild("Code"); - code->addAttribute("index", 0x2019); + code->addAttribute("index", additional[i]); code->addAttribute("coord", MyGUI::utility::toString(x1) + " " + MyGUI::utility::toString(y1) + " " + MyGUI::utility::toString(w) + " " From 7721e541910063ea2b74462168bbdc05e1eaaa60 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 00:22:00 +0200 Subject: [PATCH 15/35] Use descriptive names for save files and character folders (Fixes #1449) --- apps/openmw/mwstate/character.cpp | 30 ++++++++++++++------ apps/openmw/mwstate/character.hpp | 1 - apps/openmw/mwstate/charactermanager.cpp | 35 ++++++++++++++++-------- apps/openmw/mwstate/charactermanager.hpp | 7 +++-- apps/openmw/mwstate/statemanagerimp.cpp | 16 +++++++---- 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 5fe80ce0c..6f569f078 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -54,9 +54,28 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) Slot slot; std::ostringstream stream; - stream << mNext++; + + // The profile description is user-supplied, so we need to escape the path + for (std::string::const_iterator it = profile.mDescription.begin(); it != profile.mDescription.end(); ++it) + { + if (std::isalnum(*it)) // Ignores multibyte characters and non alphanumeric characters + stream << *it; + else + stream << "_"; + } slot.mPath = mPath / stream.str(); + + // Append an index if necessary to ensure a unique file + int i=0; + while (boost::filesystem::exists(slot.mPath)) + { + std::ostringstream test; + test << stream.str(); + test << " - " << ++i; + slot.mPath = mPath / test.str(); + } + slot.mProfile = profile; slot.mTimeStamp = std::time (0); @@ -64,7 +83,7 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) } MWState::Character::Character (const boost::filesystem::path& saves, const std::string& game) -: mPath (saves), mNext (0) +: mPath (saves) { if (!boost::filesystem::is_directory (mPath)) { @@ -82,13 +101,6 @@ MWState::Character::Character (const boost::filesystem::path& saves, const std:: addSlot (slotPath, game); } catch (...) {} // ignoring bad saved game files for now - - std::istringstream stream (slotPath.filename().string()); - - int index = 0; - - if ((stream >> index) && index>=mNext) - mNext = index+1; } std::sort (mSlots.begin(), mSlots.end()); diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index 874533289..4703f0cca 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -26,7 +26,6 @@ namespace MWState boost::filesystem::path mPath; std::vector mSlots; - int mNext; void addSlot (const boost::filesystem::path& path, const std::string& game); diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index d773904db..91d728ae0 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -8,7 +8,7 @@ MWState::CharacterManager::CharacterManager (const boost::filesystem::path& saves, const std::string& game) -: mPath (saves), mNext (0), mCurrent (0), mGame (game) +: mPath (saves), mCurrent (0), mGame (game) { if (!boost::filesystem::is_directory (mPath)) { @@ -28,21 +28,14 @@ MWState::CharacterManager::CharacterManager (const boost::filesystem::path& save if (character.begin()!=character.end()) mCharacters.push_back (character); } - - std::istringstream stream (characterDir.filename().string()); - - int index = 0; - - if ((stream >> index) && index>=mNext) - mNext = index+1; } } } -MWState::Character *MWState::CharacterManager::getCurrentCharacter (bool create) +MWState::Character *MWState::CharacterManager::getCurrentCharacter (bool create, const std::string& name) { if (!mCurrent && create) - createCharacter(); + createCharacter(name); return mCurrent; } @@ -63,13 +56,31 @@ void MWState::CharacterManager::deleteSlot(const MWState::Character *character, } } -void MWState::CharacterManager::createCharacter() +void MWState::CharacterManager::createCharacter(const std::string& name) { std::ostringstream stream; - stream << mNext++; + + // The character name is user-supplied, so we need to escape the path + for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) + { + if (std::isalnum(*it)) // Ignores multibyte characters and non alphanumeric characters + stream << *it; + else + stream << "_"; + } boost::filesystem::path path = mPath / stream.str(); + // Append an index if necessary to ensure a unique directory + int i=0; + while (boost::filesystem::exists(path)) + { + std::ostringstream test; + test << stream.str(); + test << " - " << ++i; + path = mPath / test.str(); + } + mCharacters.push_back (Character (path, mGame)); mCurrent = &mCharacters.back(); diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index adf9d2ef4..c44c10b5a 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -10,7 +10,6 @@ namespace MWState class CharacterManager { boost::filesystem::path mPath; - int mNext; // Uses std::list, so that mCurrent stays valid when characters are deleted std::list mCharacters; @@ -32,13 +31,15 @@ namespace MWState CharacterManager (const boost::filesystem::path& saves, const std::string& game); - Character *getCurrentCharacter (bool create = true); + Character *getCurrentCharacter (bool create, const std::string& name); ///< \param create Create a new character, if there is no current character. + /// \param name The character name to use in case a new character is created. void deleteSlot(const MWState::Character *character, const MWState::Slot *slot); - void createCharacter(); + void createCharacter(const std::string& name); ///< Create new character within saved game management + /// \param name Name for the character (does not need to be unique) void setCurrentCharacter (const Character *character); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 7a70944dc..68cb91eb9 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -184,9 +184,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot encoded->read(&profile.mScreenshot[0], encoded->size()); if (!slot) - slot = mCharacterManager.getCurrentCharacter()->createSlot (profile); + slot = getCurrentCharacter()->createSlot (profile); else - slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); + slot = getCurrentCharacter()->updateSlot (slot, profile); boost::filesystem::ofstream stream (slot->mPath, std::ios::binary); @@ -252,7 +252,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot // If no file was written, clean up the slot if (slot && !boost::filesystem::exists(slot->mPath)) - mCharacterManager.getCurrentCharacter()->deleteSlot(slot); + getCurrentCharacter()->deleteSlot(slot); } } @@ -419,7 +419,10 @@ void MWState::StateManager::deleteGame(const MWState::Character *character, cons MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { - return mCharacterManager.getCurrentCharacter (create); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + std::string name = player.getClass().getName(player); + + return mCharacterManager.getCurrentCharacter (create, name); } MWState::StateManager::CharacterIterator MWState::StateManager::characterBegin() @@ -440,11 +443,12 @@ void MWState::StateManager::update (float duration) if (mAskLoadRecent) { int iButton = MWBase::Environment::get().getWindowManager()->readPressedButton(); - if(iButton==0) + MWState::Character *curCharacter = getCurrentCharacter(false); + if(iButton==0 && curCharacter) { mAskLoadRecent = false; //Load last saved game for current character - MWState::Character *curCharacter = getCurrentCharacter(); + MWState::Slot lastSave = *curCharacter->begin(); loadGame(curCharacter, &lastSave); } From e0d6670ac452162b096b883edf806a91e3e60d5e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 01:57:54 +0200 Subject: [PATCH 16/35] Move video skip detection to WindowManager Fixes a bug where skipping using Esc would not work if a mouse button had been pressed previously --- apps/openmw/mwgui/confirmationdialog.cpp | 8 ++++---- apps/openmw/mwgui/mainmenu.cpp | 4 ++-- apps/openmw/mwgui/videowidget.cpp | 15 ++------------- apps/openmw/mwgui/videowidget.hpp | 12 ++++-------- apps/openmw/mwgui/windowmanagerimp.cpp | 24 +++++++++++++++++++++--- apps/openmw/mwgui/windowmanagerimp.hpp | 6 ++++++ 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 89f477598..57c88bfa2 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -30,9 +30,9 @@ namespace MWGui void ConfirmationDialog::exit() { - eventCancelClicked(); - setVisible(false); + + eventCancelClicked(); } void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) @@ -42,8 +42,8 @@ namespace MWGui void ConfirmationDialog::onOkButtonClicked(MyGUI::Widget* _sender) { - eventOkClicked(); - setVisible(false); + + eventOkClicked(); } } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index b5cd61f59..1d47d3b76 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -167,7 +167,7 @@ namespace MWGui mVideo = mVideoBackground->createWidget("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); - mVideo->playVideo("video\\menu_background.bik", false); + mVideo->playVideo("video\\menu_background.bik"); } MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); @@ -204,7 +204,7 @@ namespace MWGui if (!mVideo->update()) { // If finished playing, start again - mVideo->playVideo("video\\menu_background.bik", 0); + mVideo->playVideo("video\\menu_background.bik"); } } } diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 8430c1c7b..cfd837a95 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -4,17 +4,12 @@ namespace MWGui { VideoWidget::VideoWidget() - : mAllowSkipping(true) { - eventKeyButtonPressed += MyGUI::newDelegate(this, &VideoWidget::onKeyPressed); - setNeedKeyFocus(true); } -void VideoWidget::playVideo(const std::string &video, bool allowSkipping) +void VideoWidget::playVideo(const std::string &video) { - mAllowSkipping = allowSkipping; - mPlayer.playVideo(video); setImageTexture(mPlayer.getTextureName()); @@ -30,19 +25,13 @@ int VideoWidget::getVideoHeight() return mPlayer.getVideoHeight(); } -void VideoWidget::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) -{ - if (_key == MyGUI::KeyCode::Escape && mAllowSkipping) - mPlayer.stopVideo(); -} - bool VideoWidget::update() { mPlayer.update(); return mPlayer.isPlaying(); } -void VideoWidget::cleanup() +void VideoWidget::stop() { mPlayer.close(); } diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index 9360c8359..ad3d4d5e3 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -9,7 +9,7 @@ namespace MWGui { /** - * Widget that plays a video. Can be skipped by pressing Esc. + * Widget that plays a video. */ class VideoWidget : public MyGUI::ImageBox { @@ -18,7 +18,7 @@ namespace MWGui VideoWidget(); - void playVideo (const std::string& video, bool allowSkipping); + void playVideo (const std::string& video); int getVideoWidth(); int getVideoHeight(); @@ -26,15 +26,11 @@ namespace MWGui /// @return Is the video still playing? bool update(); - /// Free video player resources (done automatically on destruction) - void cleanup(); + /// Stop video and free resources (done automatically on destruction) + void stop(); private: - bool mAllowSkipping; - MWRender::VideoPlayer mPlayer; - - void onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char); }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 35ee2adc9..7ebdb6a83 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -202,8 +202,12 @@ namespace MWGui MyGUI::Align::Default, "Overlay"); mVideoBackground->setImageTexture("black.png"); mVideoBackground->setVisible(false); + mVideoBackground->setNeedMouseFocus(true); + mVideoBackground->setNeedKeyFocus(true); mVideoWidget = mVideoBackground->createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Default); + mVideoWidget->setNeedMouseFocus(true); + mVideoWidget->setNeedKeyFocus(true); } void WindowManager::initUI() @@ -263,7 +267,7 @@ namespace MWGui mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); - mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows"); mHud->setVisible(mHudEnabled); @@ -1559,7 +1563,15 @@ namespace MWGui void WindowManager::playVideo(const std::string &name, bool allowSkipping) { - mVideoWidget->playVideo("video\\" + name, allowSkipping); + mVideoWidget->playVideo("video\\" + name); + + mVideoWidget->eventKeyButtonPressed.clear(); + mVideoBackground->eventKeyButtonPressed.clear(); + if (allowSkipping) + { + mVideoWidget->eventKeyButtonPressed += MyGUI::newDelegate(this, &WindowManager::onVideoKeyPressed); + mVideoBackground->eventKeyButtonPressed += MyGUI::newDelegate(this, &WindowManager::onVideoKeyPressed); + } // Turn off all rendering except for the GUI mRendering->getScene()->clearSpecialCaseRenderQueues(); @@ -1587,7 +1599,7 @@ namespace MWGui mRendering->getWindow()->update(); } - mVideoWidget->cleanup(); + mVideoWidget->stop(); setCursorVisible(cursorWasVisible); @@ -1628,4 +1640,10 @@ namespace MWGui if(input == mCurrentModals.top()) mCurrentModals.pop(); } + + void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) + { + if (_key == MyGUI::KeyCode::Escape) + mVideoWidget->stop(); + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index b1dbf3a24..aee6cef47 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -12,6 +12,9 @@ #include "../mwbase/windowmanager.hpp" +#include +#include + namespace MyGUI { class Gui; @@ -424,6 +427,9 @@ namespace MWGui void onCursorChange(const std::string& name); void onKeyFocusChanged(MyGUI::Widget* widget); + // Key pressed while playing a video + void onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char); + void sizeVideo(int screenWidth, int screenHeight); }; } From 881ae33b74d374a444c37e9a2114213c771d98ac Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 02:15:09 +0200 Subject: [PATCH 17/35] Don't allow Creatures with no movement abilities to move (Fixes #1457) --- apps/openmw/mwclass/creature.cpp | 4 +++- apps/openmw/mwworld/physicssystem.cpp | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1a6e4e321..5744ebb9b 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -345,7 +345,9 @@ namespace MWClass getCreatureStats(ptr).setAttacked(true); // Self defense - if (!attacker.isEmpty() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80) + if (!attacker.isEmpty() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80 + && (canWalk(ptr) || canFly(ptr) || canSwim(ptr))) // No retaliation for totally static creatures + // (they have no movement or attacks anyway) MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); if(!successful) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b0b00c6db..85d41a478 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -193,6 +193,11 @@ namespace MWWorld const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); + // Early-out for totally static creatures + // (Not sure if gravity should still apply?) + if (!ptr.getClass().canWalk(ptr) && !isFlying && !ptr.getClass().canSwim(ptr)) + return position; + /* Anything to collide with? */ OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); if(!physicActor || !physicActor->getCollisionMode()) From 311acfa8ff7a875373adf9a731b8239b3b596ae3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 02:27:38 +0200 Subject: [PATCH 18/35] Add delete button to save load menu (Fixes #1453) --- apps/openmw/mwgui/savegamedialog.cpp | 28 +++++++++++++++++------ apps/openmw/mwgui/savegamedialog.hpp | 4 ++++ files/mygui/openmw_savegame_dialog.layout | 10 +++++--- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index ef5d5858b..e5390d5a6 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -30,11 +30,13 @@ namespace MWGui getWidget(mInfoText, "InfoText"); getWidget(mOkButton, "OkButton"); getWidget(mCancelButton, "CancelButton"); + getWidget(mDeleteButton, "DeleteButton"); getWidget(mSaveList, "SaveList"); getWidget(mSaveNameEdit, "SaveNameEdit"); getWidget(mSpacer, "Spacer"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked); + mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked); mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected); mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick); @@ -54,13 +56,16 @@ namespace MWGui onSlotSelected(sender, pos); if (pos != MyGUI::ITEM_NONE && MyGUI::InputManager::getInstance().isShiftPressed()) - { - ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - dialog->open("#{sMessage3}"); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed); - dialog->eventCancelClicked.clear(); - } + confirmDeleteSave(); + } + + void SaveGameDialog::confirmDeleteSave() + { + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + dialog->open("#{sMessage3}"); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed); + dialog->eventCancelClicked.clear(); } void SaveGameDialog::onDeleteSlotConfirmed() @@ -175,6 +180,9 @@ namespace MWGui mCharacterSelection->setVisible(load); mSpacer->setUserString("Hidden", load ? "false" : "true"); + mDeleteButton->setUserString("Hidden", load ? "false" : "true"); + mDeleteButton->setVisible(load); + if (!load) { mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter (false); @@ -188,6 +196,12 @@ namespace MWGui exit(); } + void SaveGameDialog::onDeleteButtonClicked(MyGUI::Widget *sender) + { + if (mCurrentSlot) + confirmDeleteSave(); + } + void SaveGameDialog::onConfirmationGiven() { accept(true); diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 9f44d5370..80cfad279 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -24,8 +24,11 @@ namespace MWGui void setLoadOrSave(bool load); private: + void confirmDeleteSave(); + void onCancelButtonClicked (MyGUI::Widget* sender); void onOkButtonClicked (MyGUI::Widget* sender); + void onDeleteButtonClicked (MyGUI::Widget* sender); void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos); // Slot selected (mouse click or arrow keys) void onSlotSelected (MyGUI::ListBox* sender, size_t pos); @@ -51,6 +54,7 @@ namespace MWGui MyGUI::EditBox* mInfoText; MyGUI::Button* mOkButton; MyGUI::Button* mCancelButton; + MyGUI::Button* mDeleteButton; MyGUI::ListBox* mSaveList; MyGUI::EditBox* mSaveNameEdit; MyGUI::Widget* mSpacer; diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index ceb1a8428..701533636 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -2,8 +2,8 @@ - - + + @@ -49,10 +49,14 @@ - + + + + + From 271aac3fcc2b317996c829076e492a41f7ebde72 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 02:47:02 +0200 Subject: [PATCH 19/35] Savegame dialog: Grey out buttons if no save is selected --- apps/openmw/mwgui/savegamedialog.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index e5390d5a6..caa0cbb36 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -112,6 +112,7 @@ namespace MWGui mCurrentCharacter = NULL; mCurrentSlot = NULL; mSaveList->removeAllItems(); + onSlotSelected(mSaveList, MyGUI::ITEM_NONE); MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager(); if (mgr->characterBegin() == mgr->characterEnd()) @@ -239,10 +240,8 @@ namespace MWGui } else { - if (mCurrentCharacter && mCurrentSlot) - { - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot); - } + assert (mCurrentCharacter && mCurrentSlot); + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot); } } @@ -292,6 +291,9 @@ namespace MWGui void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos) { + mOkButton->setEnabled(pos != MyGUI::ITEM_NONE || mSaving); + mDeleteButton->setEnabled(pos != MyGUI::ITEM_NONE); + if (pos == MyGUI::ITEM_NONE) { mCurrentSlot = NULL; From c0c1db44907a4719773c7f734fefeb599a32eeda Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 03:28:21 +0200 Subject: [PATCH 20/35] Don't list non-usable items in QuickKeysMenu selection (Fixes #1427) --- apps/openmw/mwgui/quickkeysmenu.cpp | 2 ++ apps/openmw/mwgui/sortfilteritemmodel.cpp | 5 +++++ apps/openmw/mwgui/sortfilteritemmodel.hpp | 1 + 3 files changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index eda9daeff..f52a4b941 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -24,6 +24,7 @@ #include "spellwindow.hpp" #include "itemwidget.hpp" +#include "sortfilteritemmodel.hpp" namespace MWGui @@ -134,6 +135,7 @@ namespace MWGui } mItemSelectionDialog->setVisible(true); mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyUsableItems); mAssignDialog->setVisible (false); } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index b8dcbcbbb..93e5432ca 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -14,6 +14,7 @@ #include #include "../mwworld/class.hpp" +#include "../mwworld/nullaction.hpp" namespace { @@ -126,6 +127,10 @@ namespace MWGui && !base.get()->mBase->mData.mIsScroll) return false; + if ((mFilter & Filter_OnlyUsableItems) && typeid(*base.getClass().use(base)) == typeid(MWWorld::NullAction) + && base.getClass().getScript(base).empty()) + return false; + return true; } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index c7feaa3b9..4af35e7a8 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -36,6 +36,7 @@ namespace MWGui static const int Filter_OnlyEnchanted = (1<<1); static const int Filter_OnlyEnchantable = (1<<2); static const int Filter_OnlyChargedSoulstones = (1<<3); + static const int Filter_OnlyUsableItems = (1<<4); // Only items with a Use action private: From 65d5311037f821098580a92c9577c025f59fdb84 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 04:10:34 +0200 Subject: [PATCH 21/35] Revert "Don't try to show exceptions in a message box if SDL was not initialized" According to SDL docs, "This function may be called at any time, even before SDL_Init()". Also fixes an issue where message boxes weren't working due to SDL_Quit already having been called by ~Engine. This reverts commit 39eea24dc3866760cc40b79b6d57ebbc6799fc73. Conflicts: apps/openmw/main.cpp --- apps/openmw/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 3098d953e..302a9cf64 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include #include "engine.hpp" #if defined(_WIN32) && !defined(_CONSOLE) @@ -286,7 +287,7 @@ int main(int argc, char**argv) catch (std::exception &e) { #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE - if (isatty(fileno(stdin)) || !SDL_WasInit(SDL_INIT_VIDEO)) + if (isatty(fileno(stdin))) std::cerr << "\nERROR: " << e.what() << std::endl; else #endif From 4119038f1d772bdd9afde02ad1e7b965005ead1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 14:46:44 +0200 Subject: [PATCH 22/35] Remove an old workaround (Fixes #1458) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f75dc7ff0..279f7c2af 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -919,11 +919,6 @@ namespace MWInput mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } } - - // Printscreen key should not be allowed because it's captured by system screenshot function - // We check this explicitely here to fix up pre-0.26 config files. Can be removed after a few versions - if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Screenshot), ICS::Control::INCREASE) == SDLK_PRINTSCREEN) - mInputBinder->addKeyBinding(mInputBinder->getControl(A_Screenshot), SDLK_F12, ICS::Control::INCREASE); } std::string InputManager::getActionDescription (int action) From e28888df394739094e93e9b98576392cb56c3234 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 10 Jun 2014 14:51:51 +0200 Subject: [PATCH 23/35] fix for dejavu location --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7038e05ba..d67b724ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,7 +432,7 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF(BUILD_OPENCS) # Install licenses - INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" ) + INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) ENDIF (DPKG_PROGRAM) From 3bf599248ec8103e4226d7d88efe73aa62f47734 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 14:58:09 +0200 Subject: [PATCH 24/35] CMake cleanup: Remove distribution-specific install stuff (unused) --- CMakeLists.txt | 75 ++++++++++++------------------- apps/launcher/CMakeLists.txt | 4 -- apps/mwiniimporter/CMakeLists.txt | 5 --- apps/opencs/CMakeLists.txt | 4 -- apps/openmw/CMakeLists.txt | 4 -- 5 files changed, 29 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3632f1e08..8e5ba6cd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,13 +80,6 @@ option(USE_FFMPEG "use ffmpeg for sound" ON) # OS X deployment option(OPENMW_OSX_DEPLOYMENT OFF) -if(UNIX AND NOT APPLE) - option(BUILD_WITH_DPKG "enable dpkg-based install for debian and debian derivatives" OFF) - if(BUILD_WITH_DPKG) - find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems") - endif(BUILD_WITH_DPKG) -endif(UNIX AND NOT APPLE) - # Location of morrowind data files if (APPLE) set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") @@ -395,46 +388,36 @@ if (CMAKE_COMPILER_IS_GNUCC) endif (CMAKE_COMPILER_IS_GNUCC) IF(NOT WIN32 AND NOT APPLE) - ## Debian and non debian Linux building + # Linux building # Paths - IF (DPKG_PROGRAM) - ## Debian specific - SET(CMAKE_INSTALL_PREFIX "/usr") - SET(DATAROOTDIR "share" CACHE PATH "Sets the root of data directories to a non-default location") - SET(DATADIR "share/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") - SET(ICONDIR "share/pixmaps" CACHE PATH "Set icon dir") - SET(SYSCONFDIR "../etc/openmw" CACHE PATH "Set config dir") - ELSE () - ## Non debian specific - SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") - SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") - SET(DATADIR "${DATAROOTDIR}/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") - SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir") - SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.") - SET(SYSCONFDIR "/etc/openmw" CACHE PATH "Set config dir") - - # Install binaries - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) - IF(BUILD_LAUNCHER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_LAUNCHER) - IF(BUILD_BSATOOL) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_BSATOOL) - IF(BUILD_ESMTOOL) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_ESMTOOL) - IF(BUILD_MWINIIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_MWINIIMPORTER) - IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_OPENCS) - - # Install licenses - INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" ) - INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) - ENDIF (DPKG_PROGRAM) + SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") + SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") + SET(DATADIR "${DATAROOTDIR}/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") + SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir") + SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.") + SET(SYSCONFDIR "/etc/openmw" CACHE PATH "Set config dir") + + # Install binaries + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) + IF(BUILD_LAUNCHER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_LAUNCHER) + IF(BUILD_BSATOOL) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_BSATOOL) + IF(BUILD_ESMTOOL) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_ESMTOOL) + IF(BUILD_MWINIIMPORTER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_MWINIIMPORTER) + IF(BUILD_OPENCS) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_OPENCS) + + # Install licenses + INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" ) + INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index ec721a5e5..d7733ba0e 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -119,10 +119,6 @@ endif(NOT WIN32) -if(DPKG_PROGRAM) - INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher) -endif() - if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(omwlauncher gcov) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 702f66513..deab88ce2 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -22,8 +22,3 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(mwiniimport gcov) endif() - -if(DPKG_PROGRAM) - INSTALL(TARGETS mwiniimport RUNTIME DESTINATION games COMPONENT mwiniimport) -endif() - diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f18ac0bca..dd31aa81b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -199,10 +199,6 @@ target_link_libraries(opencs components ) -if(DPKG_PROGRAM) - INSTALL(TARGETS opencs RUNTIME DESTINATION games COMPONENT opencs) -endif() - if(APPLE) INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) endif() diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8310e8abf..7c047adef 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -142,10 +142,6 @@ if(APPLE) endif() endif(APPLE) -if(DPKG_PROGRAM) - INSTALL(TARGETS openmw RUNTIME DESTINATION games COMPONENT openmw) -endif(DPKG_PROGRAM) - if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw gcov) From 1ed3f092c142488072d4915d9edd47f6660fa4ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 15:42:50 +0200 Subject: [PATCH 25/35] Implement text replacement for journal topic responses (Fixes #1429) --- apps/openmw/mwbase/journal.hpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 4 +-- apps/openmw/mwdialogue/journalentry.cpp | 28 ++++++++++++++----- apps/openmw/mwdialogue/journalentry.hpp | 10 +++++-- apps/openmw/mwdialogue/journalimp.cpp | 7 +++-- apps/openmw/mwdialogue/journalimp.hpp | 2 +- apps/openmw/mwdialogue/topic.cpp | 5 ---- apps/openmw/mwdialogue/topic.hpp | 2 -- 8 files changed, 37 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index a49ebb9bc..c43ebeb8f 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -59,7 +59,7 @@ namespace MWBase virtual int getJournalIndex (const std::string& id) const = 0; ///< Get the journal index. - virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName) = 0; + virtual void addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor) = 0; virtual TEntryIter begin() const = 0; ///< Iterator pointing to the begin of the main journal. diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 57681b7fb..c1a623418 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -294,7 +294,7 @@ namespace MWDialogue { if (iter->mId == info->mId) { - MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor.getClass().getName(mActor)); + MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor); break; } } @@ -472,7 +472,7 @@ namespace MWDialogue { if (iter->mId == info->mId) { - MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor.getClass().getName(mActor)); + MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor); break; } } diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 55574bf3e..b92d7cace 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -5,16 +5,21 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwscript/interpretercontext.hpp" + + namespace MWDialogue { Entry::Entry() {} - Entry::Entry (const std::string& topic, const std::string& infoId) + Entry::Entry (const std::string& topic, const std::string& infoId, const MWWorld::Ptr& actor) : mInfoId (infoId) { const ESM::Dialogue *dialogue = @@ -24,8 +29,17 @@ namespace MWDialogue iter!=dialogue->mInfo.end(); ++iter) if (iter->mId == mInfoId) { - /// \todo text replacement - mText = iter->mResponse; + if (actor.isEmpty()) + { + MWScript::InterpreterContext interpreterContext(NULL,MWWorld::Ptr()); + mText = Interpreter::fixDefinesDialog(iter->mResponse, interpreterContext); + } + else + { + MWScript::InterpreterContext interpreterContext(&actor.getRefData().getLocals(),actor); + mText = Interpreter::fixDefinesDialog(iter->mResponse, interpreterContext); + } + return; } @@ -49,8 +63,8 @@ namespace MWDialogue JournalEntry::JournalEntry() {} - JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId) - : Entry (topic, infoId), mTopic (topic) + JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId, const MWWorld::Ptr& actor) + : Entry (topic, infoId, actor), mTopic (topic) {} JournalEntry::JournalEntry (const ESM::JournalEntry& record) @@ -65,7 +79,7 @@ namespace MWDialogue JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index) { - return JournalEntry (topic, idFromIndex (topic, index)); + return JournalEntry (topic, idFromIndex (topic, index), MWWorld::Ptr()); } std::string JournalEntry::idFromIndex (const std::string& topic, int index) @@ -90,7 +104,7 @@ namespace MWDialogue StampedJournalEntry::StampedJournalEntry (const std::string& topic, const std::string& infoId, int day, int month, int dayOfMonth) - : JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) + : JournalEntry (topic, infoId, MWWorld::Ptr()), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) {} StampedJournalEntry::StampedJournalEntry (const ESM::JournalEntry& record) diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index a77ba4f7c..3ae3efcc8 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -8,6 +8,11 @@ namespace ESM struct JournalEntry; } +namespace MWWorld +{ + class Ptr; +} + namespace MWDialogue { /// \brief Basic quest/dialogue/topic entry @@ -19,7 +24,8 @@ namespace MWDialogue Entry(); - Entry (const std::string& topic, const std::string& infoId); + /// actor is optional + Entry (const std::string& topic, const std::string& infoId, const MWWorld::Ptr& actor); Entry (const ESM::JournalEntry& record); @@ -37,7 +43,7 @@ namespace MWDialogue JournalEntry(); - JournalEntry (const std::string& topic, const std::string& infoId); + JournalEntry (const std::string& topic, const std::string& infoId, const MWWorld::Ptr& actor); JournalEntry (const ESM::JournalEntry& record); diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 04aa0534d..1429415e5 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -9,6 +9,7 @@ #include #include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -103,12 +104,12 @@ namespace MWDialogue quest.setIndex (index); } - void Journal::addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName) + void Journal::addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor) { Topic& topic = getTopic (topicId); - JournalEntry entry(topicId, infoId); - entry.mActorName = actorName; + JournalEntry entry(topicId, infoId, actor); + entry.mActorName = actor.getClass().getName(actor); topic.addEntry (entry); } diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index 00511f47c..17b764436 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -38,7 +38,7 @@ namespace MWDialogue virtual int getJournalIndex (const std::string& id) const; ///< Get the journal index. - virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName); + virtual void addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor); virtual TEntryIter begin() const; ///< Iterator pointing to the begin of the main journal. diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index f7df305c7..ea39174b8 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -58,9 +58,4 @@ namespace MWDialogue { return mEntries.end(); } - - JournalEntry Topic::getEntry (const std::string& infoId) const - { - return JournalEntry (mTopic, infoId); - } } diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp index 02fa6d524..cbff2296c 100644 --- a/apps/openmw/mwdialogue/topic.hpp +++ b/apps/openmw/mwdialogue/topic.hpp @@ -53,8 +53,6 @@ namespace MWDialogue TEntryIter end() const; ///< Iterator pointing past the end of the journal for this topic. - - JournalEntry getEntry (const std::string& infoId) const; }; } From a90245147bfc40994cc5bf7a0785077762f21755 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 16:00:02 +0200 Subject: [PATCH 26/35] Don't reset history when ForceGreeting is used and a dialogue window was already open for the same actor (Fixes #1423) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +++++- apps/openmw/mwgui/dialogue.cpp | 12 ++++++++---- apps/openmw/mwgui/dialogue.hpp | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c1a623418..aca287854 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -140,7 +140,11 @@ namespace MWDialogue mActorKnownTopics.clear(); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->startDialogue(actor, actor.getClass().getName (actor)); + + // If the dialogue window was already open, keep the existing history + bool resetHistory = (!MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue)); + + win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI updateTopics(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 441e31e32..e7dd74eee 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -366,10 +366,11 @@ namespace MWGui } } - void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) + void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory) { mGoodbye = false; mEnabled = true; + bool sameActor = (mPtr == actor); mPtr = actor; mTopicsList->setEnabled(true); setTitle(npcName); @@ -378,9 +379,12 @@ namespace MWGui mTopicsList->clear(); - for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) - delete (*it); - mHistoryContents.clear(); + if (resetHistory || !sameActor) + { + for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) + delete (*it); + mHistoryContents.clear(); + } for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) delete (*it); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index fcb1338b5..4e0ca5dde 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -111,7 +111,7 @@ namespace MWGui void notifyLinkClicked (TypesetBook::InteractiveId link); - void startDialogue(MWWorld::Ptr actor, std::string npcName); + void startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory); void setKeywords(std::list keyWord); void addResponse (const std::string& text, const std::string& title=""); From 2dd54dbcfcef832ce2c3fe49f31cecf741e316f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 16:36:22 +0200 Subject: [PATCH 27/35] Implement ClearInfoActor script instruction (Fixes #1422) --- apps/openmw/mwbase/dialoguemanager.hpp | 3 +++ apps/openmw/mwbase/journal.hpp | 5 +++++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 9 +++++++++ apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 5 ++++- apps/openmw/mwdialogue/journalimp.cpp | 10 ++++++++++ apps/openmw/mwdialogue/journalimp.hpp | 5 +++++ apps/openmw/mwdialogue/topic.cpp | 13 +++++++++++++ apps/openmw/mwdialogue/topic.hpp | 2 ++ apps/openmw/mwscript/dialogueextensions.cpp | 14 ++++++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 4 +++- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 2 ++ 12 files changed, 71 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index dfb002cfc..d0e64b23c 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -76,6 +76,9 @@ namespace MWBase /// @return faction1's opinion of faction2 virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0; + + /// Removes the last added topic response for the given actor from the journal + virtual void clearInfoActor (const MWWorld::Ptr& actor) const = 0; }; } diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index c43ebeb8f..938cec74b 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -60,6 +60,11 @@ namespace MWBase ///< Get the journal index. virtual void addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor) = 0; + /// \note topicId must be lowercase + + virtual void removeLastAddedTopicResponse (const std::string& topicId, const std::string& actorName) = 0; + ///< Removes the last topic response added for the given topicId and actor name. + /// \note topicId must be lowercase virtual TEntryIter begin() const = 0; ///< Iterator pointing to the begin of the main journal. diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index aca287854..aa7df1fd4 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -698,6 +698,15 @@ namespace MWDialogue return diff; } + void DialogueManager::clearInfoActor(const MWWorld::Ptr &actor) const + { + if (actor == mActor && !mLastTopic.empty()) + { + MWBase::Environment::get().getJournal()->removeLastAddedTopicResponse( + mLastTopic, actor.getClass().getName(actor)); + } + } + std::vector ParseHyperText(const std::string& text) { std::vector result; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 94f8f3ec1..6553ddc01 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -40,7 +40,7 @@ namespace MWDialogue bool mTalkedTo; int mChoice; - std::string mLastTopic; + std::string mLastTopic; // last topic ID, lowercase bool mIsInChoice; float mTemporaryDispositionChange; @@ -99,6 +99,9 @@ namespace MWDialogue /// @return faction1's opinion of faction2 virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const; + + /// Removes the last added topic response for the given actor from the journal + virtual void clearInfoActor (const MWWorld::Ptr& actor) const; }; diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 1429415e5..9497347e3 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -113,6 +113,16 @@ namespace MWDialogue topic.addEntry (entry); } + void Journal::removeLastAddedTopicResponse(const std::string &topicId, const std::string &actorName) + { + Topic& topic = getTopic (topicId); + + topic.removeLastAddedResponse(actorName); + + if (topic.begin() == topic.end()) + mTopics.erase(mTopics.find(topicId)); // All responses removed -> remove topic + } + int Journal::getJournalIndex (const std::string& id) const { TQuestContainer::const_iterator iter = mQuests.find (id); diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index 17b764436..d15b909fa 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -39,6 +39,11 @@ namespace MWDialogue ///< Get the journal index. virtual void addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor); + /// \note topicId must be lowercase + + virtual void removeLastAddedTopicResponse (const std::string& topicId, const std::string& actorName); + ///< Removes the last topic response added for the given topicId and actor name. + /// \note topicId must be lowercase virtual TEntryIter begin() const; ///< Iterator pointing to the begin of the main journal. diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index ea39174b8..c1a45f841 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -58,4 +58,17 @@ namespace MWDialogue { return mEntries.end(); } + + void Topic::removeLastAddedResponse (const std::string& actorName) + { + for (std::vector::reverse_iterator it = mEntries.rbegin(); + it != mEntries.rend(); ++it) + { + if (it->mActorName == actorName) + { + mEntries.erase( (++it).base() ); // erase doesn't take a reverse_iterator + return; + } + } + } } diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp index cbff2296c..72486ef8a 100644 --- a/apps/openmw/mwdialogue/topic.hpp +++ b/apps/openmw/mwdialogue/topic.hpp @@ -48,6 +48,8 @@ namespace MWDialogue virtual std::string getName() const; + void removeLastAddedResponse (const std::string& actorName); + TEntryIter begin() const; ///< Iterator pointing to the begin of the journal for this topic. diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 9dde65ab2..45eeccf18 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -235,6 +235,18 @@ namespace MWScript } }; + template + class OpClearInfoActor : public Interpreter::Opcode0 + { + public: + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWBase::Environment::get().getDialogueManager()->clearInfoActor(ptr); + } + }; + void installOpcodes (Interpreter::Interpreter& interpreter) { @@ -256,6 +268,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFactionExplicit, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeModFactionReaction, new OpModFactionReaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeGetFactionReaction, new OpGetFactionReaction); + interpreter.installSegment5 (Compiler::Dialogue::opcodeClearInfoActor, new OpClearInfoActor); + interpreter.installSegment5 (Compiler::Dialogue::opcodeClearInfoActorExplicit, new OpClearInfoActor); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 24b0b6f7a..91d0f031f 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -393,5 +393,7 @@ op 0x2000241: onKnockoutExplicit op 0x2000242: ModFactionReaction op 0x2000243: GetFactionReaction op 0x2000244: Activate, explicit +op 0x2000245: ClearInfoActor +op 0x2000246: ClearInfoActor, explicit -opcodes 0x2000245-0x3ffffff unused +opcodes 0x2000247-0x3ffffff unused diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 0f726a52d..61464e5c2 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -181,6 +181,7 @@ namespace Compiler opcodeSameFactionExplicit); extensions.registerInstruction("modfactionreaction", "ccl", opcodeModFactionReaction); extensions.registerFunction("getfactionreaction", 'l', "ccl", opcodeGetFactionReaction); + extensions.registerInstruction("clearinfoactor", "", opcodeClearInfoActor, opcodeClearInfoActorExplicit); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 8796c53c5..4b22e4b9c 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -154,6 +154,8 @@ namespace Compiler const int opcodeSameFactionExplicit = 0x20001b6; const int opcodeModFactionReaction = 0x2000242; const int opcodeGetFactionReaction = 0x2000243; + const int opcodeClearInfoActor = 0x2000245; + const int opcodeClearInfoActorExplicit = 0x2000246; } namespace Gui From 6ba112619ae3362c91ddfc180ae034f49f044eaa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 16:46:13 +0200 Subject: [PATCH 28/35] Fix dropped items ending up inaccessible when standing in objects with no collision (Fixes #1441) --- 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 ebdac7ba1..bf752734f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1703,14 +1703,15 @@ namespace MWWorld Ogre::Vector3 orig = Ogre::Vector3(pos.pos); + orig.z += 20; Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); - float len = (pos.pos[2] >= 0) ? pos.pos[2] : -pos.pos[2]; - len += 100.0; + float len = 100.0; std::pair hit = mPhysics->castRay(orig, dir, len); - pos.pos[2] = hit.second.z; + if (hit.first) + pos.pos[2] = hit.second.z; // copy the object and set its count int origCount = object.getRefData().getCount(); From 3788fb042e4b739892c347183a7d148fb0bf47be Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 17:47:59 +0200 Subject: [PATCH 29/35] Implement MenuTest script instruction (Fixes #1454) --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 23 +++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ apps/openmw/mwgui/windowpinnablebase.cpp | 6 ++++ apps/openmw/mwgui/windowpinnablebase.hpp | 1 + apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/guiextensions.cpp | 42 ++++++++++++++++++++++++ components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + 9 files changed, 80 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 2dfa50eb5..0f45542ba 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -328,6 +328,8 @@ namespace MWBase /** Used when one Modal adds another Modal \param input Pointer to the current modal, to ensure proper modal is removed **/ virtual void removeCurrentModal(MWGui::WindowModal* input) = 0; + + virtual void pinWindow (MWGui::GuiWindow window) = 0; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7ebdb6a83..b49bfbfa6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1646,4 +1646,27 @@ namespace MWGui if (_key == MyGUI::KeyCode::Escape) mVideoWidget->stop(); } + + void WindowManager::pinWindow(GuiWindow window) + { + switch (window) + { + case GW_Inventory: + mInventoryWindow->setPinned(true); + break; + case GW_Map: + mMap->setPinned(true); + break; + case GW_Magic: + mSpellWindow->setPinned(true); + break; + case GW_Stats: + mStatsWindow->setPinned(true); + break; + default: + break; + } + + updateVisible(); + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index aee6cef47..dd41635ad 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -319,6 +319,8 @@ namespace MWGui \param input Pointer to the current modal, to ensure proper modal is removed **/ virtual void removeCurrentModal(WindowModal* input); + virtual void pinWindow (MWGui::GuiWindow window); + private: bool mConsoleOnlyScripts; diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 47364337c..919d315f2 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -25,6 +25,12 @@ namespace MWGui onPinToggled(); } + void WindowPinnableBase::setPinned(bool pinned) + { + if (pinned != mPinned) + onPinButtonClicked(mPinButton); + } + void WindowPinnableBase::setPinButtonVisible(bool visible) { mPinButton->setVisible(visible); diff --git a/apps/openmw/mwgui/windowpinnablebase.hpp b/apps/openmw/mwgui/windowpinnablebase.hpp index cd393f918..3aad60988 100644 --- a/apps/openmw/mwgui/windowpinnablebase.hpp +++ b/apps/openmw/mwgui/windowpinnablebase.hpp @@ -12,6 +12,7 @@ namespace MWGui public: WindowPinnableBase(const std::string& parLayout); bool pinned() { return mPinned; } + void setPinned (bool pinned); void setPinButtonVisible(bool visible); private: diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 91d0f031f..1576bf0af 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -57,7 +57,8 @@ op 0x20028: RemoveSoulGem, explicit reference op 0x20029: PCRaiseRank, explicit reference op 0x2002a: PCLowerRank, explicit reference op 0x2002b: PCJoinFaction, explicit reference -opcodes 0x2002c-0x3ffff unused +op 0x2002c: MenuTest +opcodes 0x2002d-0x3ffff unused Segment 4: (not implemented yet) diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index be241a564..333be5be6 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -162,6 +162,47 @@ namespace MWScript } }; + class OpMenuTest : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + int arg=0; + if(arg0>0) + { + arg = runtime[0].mInteger; + runtime.pop(); + } + + + if (arg == 0) + { + MWGui::GuiMode modes[] = { MWGui::GM_Inventory, MWGui::GM_Container }; + + for (int i=0; i<2; ++i) + { + if (MWBase::Environment::get().getWindowManager()->containsMode(modes[i])) + MWBase::Environment::get().getWindowManager()->removeGuiMode(modes[i]); + } + } + else + { + MWGui::GuiWindow gw = MWGui::GW_None; + if (arg == 3) + gw = MWGui::GW_Stats; + if (arg == 4) + gw = MWGui::GW_Inventory; + if (arg == 5) + gw = MWGui::GW_Magic; + if (arg == 6) + gw = MWGui::GW_Map; + + MWBase::Environment::get().getWindowManager()->pinWindow(gw); + } + } + }; + void installOpcodes (Interpreter::Interpreter& interpreter) { @@ -200,6 +241,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Gui::opcodeShowMap, new OpShowMap); interpreter.installSegment5 (Compiler::Gui::opcodeFillMap, new OpFillMap); + interpreter.installSegment3 (Compiler::Gui::opcodeMenuTest, new OpMenuTest); } } } diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 61464e5c2..b9e36db80 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -216,6 +216,7 @@ namespace Compiler extensions.registerInstruction ("showmap", "S", opcodeShowMap); extensions.registerInstruction ("fillmap", "", opcodeFillMap); + extensions.registerInstruction ("menutest", "/l", opcodeMenuTest); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 4b22e4b9c..14f4db060 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -177,6 +177,7 @@ namespace Compiler const int opcodeToggleFullHelp = 0x2000151; const int opcodeShowMap = 0x20001a0; const int opcodeFillMap = 0x20001a1; + const int opcodeMenuTest = 0x2002c; } namespace Misc From 5a955279bb3b3f2f9e3bbadf67454cb91a040589 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 18:29:20 +0200 Subject: [PATCH 30/35] Fix main menu background showing when resizing window during load --- apps/openmw/mwgui/mainmenu.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 1d47d3b76..ca7e877cc 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -68,10 +68,10 @@ namespace MWGui { if (visible) updateMenu(); - else - showBackground( - MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && - MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); + + showBackground( + MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && + MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); OEngine::GUI::Layout::setVisible (visible); } @@ -220,7 +220,6 @@ namespace MWGui MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState(); - showBackground(state == MWBase::StateManager::State_NoGame); mVersionText->setVisible(state == MWBase::StateManager::State_NoGame); std::vector buttons; From 7b5482f25bad75275e14be4b67422303e7cf9da9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 18:31:39 +0200 Subject: [PATCH 31/35] Fix character selection caption when there is no character in settings.cfg --- apps/openmw/mwgui/savegamedialog.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index caa0cbb36..a35415e75 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -163,6 +163,8 @@ namespace MWGui } mCharacterSelection->setIndexSelected(selectedIndex); + if (selectedIndex == MyGUI::ITEM_NONE) + mCharacterSelection->setCaption("Select Character ..."); fillSaveList(); From 47172fb8a2945b8703175c5a8b2bdd74d0b525ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 19:23:42 +0200 Subject: [PATCH 32/35] ContentModel: Don't confuse file path with file name (Fixes #1352) --- .../contentselector/model/contentmodel.cpp | 31 ++++++++++--------- .../contentselector/model/contentmodel.hpp | 4 +-- components/contentselector/model/esmfile.hpp | 2 ++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 0d274474c..f5bc2369a 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -239,7 +239,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const return false; EsmFile *file = item(index.row()); - QString fileName = file->filePath(); + QString fileName = file->fileName(); bool success = false; switch(role) @@ -266,7 +266,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const if (success) { - success = setCheckState(fileName, value.toBool()); + success = setCheckState(file->filePath(), value.toBool()); emit dataChanged(index, index); } } @@ -277,19 +277,19 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const int checkValue = value.toInt(); bool success = false; bool setState = false; - if ((checkValue==Qt::Checked) && !isChecked(fileName)) + if ((checkValue==Qt::Checked) && !isChecked(file->filePath())) { setState = true; success = true; } - else if ((checkValue == Qt::Checked) && isChecked (fileName)) + else if ((checkValue == Qt::Checked) && isChecked (file->filePath())) setState = true; else if (checkValue == Qt::Unchecked) setState = true; if (setState) { - setCheckState(fileName, success); + setCheckState(file->filePath(), success); emit dataChanged(index, index); } @@ -517,10 +517,10 @@ void ContentSelectorModel::ContentModel::sortFiles() } } -bool ContentSelectorModel::ContentModel::isChecked(const QString& name) const +bool ContentSelectorModel::ContentModel::isChecked(const QString& filepath) const { - if (mCheckStates.contains(name)) - return (mCheckStates[name] == Qt::Checked); + if (mCheckStates.contains(filepath)) + return (mCheckStates[filepath] == Qt::Checked); return false; } @@ -543,12 +543,12 @@ void ContentSelectorModel::ContentModel::refreshModel() emit dataChanged (index(0,0), index(rowCount()-1,0)); } -bool ContentSelectorModel::ContentModel::setCheckState(const QString &name, bool checkState) +bool ContentSelectorModel::ContentModel::setCheckState(const QString &filepath, bool checkState) { - if (name.isEmpty()) + if (filepath.isEmpty()) return false; - const EsmFile *file = item(name); + const EsmFile *file = item(filepath); if (!file) return false; @@ -558,8 +558,8 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString &name, bool if (checkState) state = Qt::Checked; - mCheckStates[name] = state; - emit dataChanged(indexFromItem(item(name)), indexFromItem(item(name))); + mCheckStates[filepath] = state; + emit dataChanged(indexFromItem(item(filepath)), indexFromItem(item(filepath))); if (file->isGameFile()) refreshModel(); @@ -586,7 +586,10 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString &name, bool { foreach (const EsmFile *downstreamFile, mFiles) { - if (downstreamFile->gameFiles().contains(name)) + QFileInfo fileInfo(filepath); + QString filename = fileInfo.fileName(); + + if (downstreamFile->gameFiles().contains(filename)) { if (mCheckStates.contains(downstreamFile->filePath())) mCheckStates[downstreamFile->filePath()] = Qt::Unchecked; diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 8c8c2124b..6d147bce9 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -45,8 +45,8 @@ namespace ContentSelectorModel const EsmFile *item(const QString &name) const; bool isEnabled (QModelIndex index) const; - bool isChecked(const QString &name) const; - bool setCheckState(const QString &name, bool isChecked); + bool isChecked(const QString &filepath) const; + bool setCheckState(const QString &filepath, bool isChecked); void setCheckStates (const QStringList &fileList, bool isChecked); ContentFileList checkedItems() const; void uncheckAll(); diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index ca24b52d1..7e1edcaba 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -53,6 +53,8 @@ namespace ContentSelectorModel inline QDateTime modified() const { return mModified; } inline float format() const { return mFormat; } inline QString filePath() const { return mPath; } + + /// @note Contains file names, not paths. inline const QStringList &gameFiles() const { return mGameFiles; } inline QString description() const { return mDescription; } inline QString toolTip() const { return sToolTip.arg(mAuthor) From 07d20c212bcd7dbe162e63de662f2928e95bfbeb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Jun 2014 21:34:47 +0200 Subject: [PATCH 33/35] Fix crash activating quick key 1 --- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index f52a4b941..328ef21fb 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -247,7 +247,7 @@ namespace MWGui void QuickKeysMenu::activateQuickKey(int index) { - assert (index-1 > 0); + assert (index-1 >= 0); ItemWidget* button = mQuickKeyButtons[index-1]; QuickKeyType type = mAssigned[index-1]; From 14a9f0ebf8d54608057f8a40e632a5859b721eb3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Jun 2014 02:24:17 +0200 Subject: [PATCH 34/35] Handle Quadratic and Linear attenuation independently (Fixes #1456) --- apps/openmw/mwrender/animation.cpp | 36 ++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9ed4cb6d3..dd900f79c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -356,28 +356,40 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScene objlist->mControllers.push_back(Ogre::Controller(src, dest, func)); bool interior = !(mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior()); - bool quadratic = fallback->getFallbackBool("LightAttenuation_OutQuadInLin") ? - !interior : fallback->getFallbackBool("LightAttenuation_UseQuadratic"); + + static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin"); + static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic"); + static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue"); + static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); + static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear"); + static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); + static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue"); + + bool quadratic = useQuadratic && (!outQuadInLin || !interior); + // with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero, // so we ignore lights if their attenuation falls below this factor. const float threshold = 0.03; - if (!quadratic) + float quadraticAttenuation = 0; + float linearAttenuation = 0; + float activationRange = 0; + if (quadratic) { - float r = radius * fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); - float attenuation = fallback->getFallbackFloat("LightAttenuation_LinearValue") / r; - float activationRange = 1.0f / (threshold * attenuation); - olight->setAttenuation(activationRange, 0, attenuation, 0); + float r = radius * quadraticRadiusMult; + quadraticAttenuation = quadraticValue / std::pow(r, 2); + activationRange = std::sqrt(1.0f / (threshold * quadraticAttenuation)); } - else + if (useLinear) { - float r = radius * fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); - float attenuation = fallback->getFallbackFloat("LightAttenuation_QuadraticValue") / std::pow(r, 2); - float activationRange = std::sqrt(1.0f / (threshold * attenuation)); - olight->setAttenuation(activationRange, 0, 0, attenuation); + float r = radius * linearRadiusMult; + linearAttenuation = linearValue / r; + activationRange = std::max(activationRange, 1.0f / (threshold * linearAttenuation)); } + olight->setAttenuation(activationRange, 0, linearAttenuation, quadraticAttenuation); + // If there's an AttachLight bone, attach the light to that, otherwise put it in the center, if(objlist->mSkelBase && objlist->mSkelBase->getSkeleton()->hasBone("AttachLight")) objlist->mSkelBase->attachObjectToBone("AttachLight", olight); From 0f31e310885cbb1777b96899daca15d0ef430890 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Jun 2014 03:08:22 +0200 Subject: [PATCH 35/35] Allow opening journal during dialogue (Fixes #1460) --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3d2f57bf6..bb18b5aa7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -807,8 +807,9 @@ namespace MWInput if (MyGUI::InputManager::getInstance ().isModalAny()) return; - // Toggle between game mode and journal mode - if(!MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) + if((!MWBase::Environment::get().getWindowManager()->isGuiMode() + || MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Dialogue) + && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal); @@ -817,7 +818,6 @@ namespace MWInput { MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } - // .. but don't touch any other mode. } void InputManager::quickKey (int index)