From d8440e1fdc84baee8e781333da6a26b53f45119b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 20 May 2014 09:02:22 +0200 Subject: [PATCH 001/110] implemented reference record merging --- apps/opencs/model/world/cell.cpp | 5 --- apps/opencs/model/world/cell.hpp | 3 -- apps/opencs/model/world/data.cpp | 7 ++- apps/opencs/model/world/data.hpp | 1 + apps/opencs/model/world/ref.cpp | 10 ----- apps/opencs/model/world/ref.hpp | 8 ---- apps/opencs/model/world/refcollection.cpp | 52 ++++++++++++++++++----- apps/opencs/model/world/refcollection.hpp | 5 ++- components/esm/cellref.cpp | 11 +++++ components/esm/cellref.hpp | 1 + 10 files changed, 65 insertions(+), 38 deletions(-) diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index cd58fca1e4..40520a9ba7 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -18,8 +18,3 @@ void CSMWorld::Cell::load (ESM::ESMReader &esm) mId = stream.str(); } } - -void CSMWorld::Cell::addRef (const std::string& id) -{ - mRefs.push_back (std::make_pair (id, false)); -} \ No newline at end of file diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index e6f3c8c355..a47dbf45df 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -15,12 +15,9 @@ namespace CSMWorld struct Cell : public ESM::Cell { std::string mId; - std::vector > mRefs; // ID, modified - std::vector mDeletedRefs; void load (ESM::ESMReader &esm); - void addRef (const std::string& id); }; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ff33b46655..8b9d9f6dfb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -489,6 +489,7 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base delete mReader; mReader = 0; mDialogue = 0; + mRefLoadCache.clear(); mReader = new ESM::ESMReader; mReader->setEncoder (&mEncoder); @@ -513,6 +514,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) delete mReader; mReader = 0; mDialogue = 0; + mRefLoadCache.clear(); return true; } @@ -534,9 +536,12 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break; case ESM::REC_CELL: + { mCells.load (*mReader, mBase); - mRefs.load (*mReader, mCells.getSize()-1, mBase); + std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1)); + mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId]); break; + } case ESM::REC_ACTI: mReferenceables.load (*mReader, mBase, UniversalId::Type_Activator); break; case ESM::REC_ALCH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Potion); break; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index ab247b6a34..2b521c5487 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -77,6 +77,7 @@ namespace CSMWorld const ESM::Dialogue *mDialogue; // last loaded dialogue bool mBase; bool mProject; + std::map > mRefLoadCache; // not implemented Data (const Data&); diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index cf9e496ee6..44ffa92b94 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -1,12 +1,2 @@ #include "ref.hpp" - -#include "cell.hpp" - -void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string& id) -{ - mId = id; - mCell = cell.mId; - - cell.addRef (mId); -} \ No newline at end of file diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index fcf016ee24..b60cbd7e41 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -3,11 +3,6 @@ #include -namespace ESM -{ - class ESMReader; -} - namespace CSMWorld { class Cell; @@ -17,9 +12,6 @@ namespace CSMWorld { std::string mId; std::string mCell; - - void load (ESM::ESMReader &esm, Cell& cell, const std::string& id); - ///< Load cell ref and register it with \a cell. }; } diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 4fdd979097..db6e294fa5 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -3,12 +3,15 @@ #include +#include + #include "ref.hpp" #include "cell.hpp" #include "universalid.hpp" #include "record.hpp" -void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base) +void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base, + std::map& cache) { Record cell = mCells.getRecord (cellIndex); @@ -17,19 +20,48 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool CellRef ref; bool deleted = false; - while (cell2.getNextRef (reader, ref, deleted)) + + while (ESM::Cell::getNextRef (reader, ref, deleted)) { - /// \todo handle deleted and moved references - ref.load (reader, cell2, getNewId()); + ref.mCell = cell2.mId; - Record record2; - record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; - (base ? record2.mBase : record2.mModified) = ref; + /// \todo handle moved references - appendRecord (record2); + if (deleted) + { + /// \todo handle deleted references + continue; + } + + std::map::iterator iter = cache.find (ref.mRefNum); + + if (iter==cache.end()) + { + // new reference + ref.mId = getNewId(); + + Record record; + record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; + (base ? record.mBase : record.mModified) = ref; + + appendRecord (record); + + cache.insert (std::make_pair (ref.mRefNum, ref.mId)); + } + else + { + // old reference -> merge + ref.mId = iter->second; + + int index = getIndex (ref.mId); + + Record record = getRecord (index); + record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_Modified; + (base ? record.mBase : record.mModified) = ref; + + setRecord (index, record); + } } - - mCells.setRecord (cellIndex, cell); } std::string CSMWorld::RefCollection::getNewId() diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 173efba05b..45aa5758be 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_REFCOLLECTION_H #define CSM_WOLRD_REFCOLLECTION_H +#include + #include "collection.hpp" #include "ref.hpp" #include "record.hpp" @@ -22,7 +24,8 @@ namespace CSMWorld : mCells (cells), mNextId (0) {} - void load (ESM::ESMReader& reader, int cellIndex, bool base); + void load (ESM::ESMReader& reader, int cellIndex, bool base, + std::map& cache); ///< Load a sequence of references. std::string getNewId(); diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index f04e819c88..00d7dfc19e 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -172,3 +172,14 @@ bool ESM::operator== (const CellRef::RefNum& left, const CellRef::RefNum& right) { return left.mIndex==right.mIndex && left.mContentFile==right.mContentFile; } + +bool ESM::operator< (const CellRef::RefNum& left, const CellRef::RefNum& right) +{ + if (left.mIndexright.mIndex) + return false; + + return left.mContentFile Date: Tue, 20 May 2014 09:28:18 +0200 Subject: [PATCH 002/110] implemented reference record deleting --- apps/opencs/model/world/data.cpp | 2 +- apps/opencs/model/world/refcollection.cpp | 33 ++++++++++++++++++++--- apps/opencs/model/world/refcollection.hpp | 5 +++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 8b9d9f6dfb..442e73e511 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -539,7 +539,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) { mCells.load (*mReader, mBase); std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1)); - mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId]); + mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages); break; } diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index db6e294fa5..3a60c49341 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -11,7 +11,7 @@ #include "record.hpp" void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map& cache) + std::map& cache, CSMDoc::Stage::Messages& messages) { Record cell = mCells.getRecord (cellIndex); @@ -27,14 +27,39 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool /// \todo handle moved references + std::map::iterator iter = cache.find (ref.mRefNum); + if (deleted) { - /// \todo handle deleted references + if (iter==cache.end()) + { + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, + mCells.getId (cellIndex)); + + messages.push_back (std::make_pair (id, + "Attempt to delete a non-existing reference")); + + continue; + } + + int index = getIndex (iter->second); + + Record record = getRecord (index); + + if (record.mState==RecordBase::State_BaseOnly) + { + removeRows (index, 1); + cache.erase (iter); + } + else + { + record.mState = RecordBase::State_Deleted; + setRecord (index, record); + } + continue; } - std::map::iterator iter = cache.find (ref.mRefNum); - if (iter==cache.end()) { // new reference diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 45aa5758be..d80ea24694 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -3,6 +3,8 @@ #include +#include "../doc/stage.hpp" + #include "collection.hpp" #include "ref.hpp" #include "record.hpp" @@ -25,7 +27,8 @@ namespace CSMWorld {} void load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map& cache); + std::map& cache, + CSMDoc::Stage::Messages& messages); ///< Load a sequence of references. std::string getNewId(); From f4334da42ec0076c073aed1a3aec6a4a17f1ba5a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 May 2014 09:32:34 +0200 Subject: [PATCH 003/110] added changed reference tracking for cells --- apps/opencs/model/world/cell.hpp | 7 ++-- apps/opencs/model/world/columnimp.hpp | 40 +++++++++++++++++++++++ apps/opencs/model/world/refcollection.cpp | 6 ++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index a47dbf45df..8a2781590d 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -1,7 +1,7 @@ #ifndef CSM_WOLRD_CELL_H #define CSM_WOLRD_CELL_H -#include +#include #include #include @@ -16,8 +16,11 @@ namespace CSMWorld { std::string mId; - void load (ESM::ESMReader &esm); + /// These are the references modified by the edited content file. These are stored in + /// mModified only. + std::set mTouchedRefs; + void load (ESM::ESMReader &esm); }; } diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6976b454d9..6b276d1517 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -10,6 +10,7 @@ #include "columnbase.hpp" #include "columns.hpp" #include "info.hpp" +#include "cell.hpp" namespace CSMWorld { @@ -87,6 +88,45 @@ namespace CSMWorld } }; + /// \brief Specialisation that takes care of the modified reference tracking + template<> + struct RecordStateColumn : public Column + { + RecordStateColumn() + : Column (Columns::ColumnId_Modification, ColumnBase::Display_RecordState) + {} + + virtual QVariant get (const Record& record) const + { + if (record.mState==Record::State_Erased) + return static_cast (Record::State_Deleted); + + if (!record.mModified.mTouchedRefs.empty() && + !record.mState==Record::State_Deleted && + !record.mState==Record::State_ModifiedOnly) + { + static_cast (Record::State_Modified); + } + + return static_cast (record.mState); + } + + virtual void set (Record& record, const QVariant& data) + { + record.mState = static_cast (data.toInt()); + } + + virtual bool isEditable() const + { + return true; + } + + virtual bool isUserEditable() const + { + return false; + } + }; + template struct FixedRecordTypeColumn : public Column { diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 3a60c49341..1cfa4df766 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -53,6 +53,8 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool } else { + cell.mModified.mTouchedRefs.insert (Misc::StringUtils::lowerCase ( + mCells.getId (cellIndex))); record.mState = RecordBase::State_Deleted; setRecord (index, record); } @@ -60,6 +62,10 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool continue; } + if (!base) + cell.mModified.mTouchedRefs.insert (Misc::StringUtils::lowerCase ( + mCells.getId (cellIndex))); + if (iter==cache.end()) { // new reference From b3ffd5b868fe40e92b401f657a20717c36dc9a82 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 26 May 2014 01:42:11 -0400 Subject: [PATCH 004/110] Fix for bug Bug #1098 --- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index c3f94d7f10..4e36a8da9b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -165,7 +165,7 @@ namespace MWWorld virtual bool hasInventoryStore (const Ptr& ptr) const; ///< Does this object have an inventory store, i.e. equipment slots? (default implementation: false) - virtual void lock (const Ptr& ptr, int lockLevel) const; + virtual void lock (const Ptr& ptr, int lockLevel = 0) const; ///< Lock object (default implementation: throw an exception) virtual void unlock (const Ptr& ptr) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 727b200f57..b8d531a58a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2526,7 +2526,7 @@ namespace MWWorld store.remove(*it, it->getRefData().getCount(), ptr); } } - closestChest.getClass().unlock(closestChest); + closestChest.getClass().lock(closestChest); } } From 7697b9e868b13f611d67ef5355d797f106735ad8 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 26 May 2014 01:48:24 -0400 Subject: [PATCH 005/110] Ensures nothing bad will happen if we try to lock a door that never had a lock level --- apps/openmw/mwclass/container.cpp | 8 ++++++-- apps/openmw/mwclass/door.cpp | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 9498ea52df..7b62ad04f0 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -262,8 +262,12 @@ namespace MWClass { if(lockLevel!=0) ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive - else - ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the original one + else { + if(abs(ptr.getCellRef().getLockLevel())!=0) + ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one + else + ptr.getCellRef().setLockLevel(100); //There never was a locklevel, give it the default biggest one + } } void Container::unlock (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 12645c9f39..0788896297 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -192,8 +192,12 @@ namespace MWClass { if(lockLevel!=0) ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive - else - ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one + else { + if(abs(ptr.getCellRef().getLockLevel())!=0) + ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one + else + ptr.getCellRef().setLockLevel(100); + } } void Door::unlock (const MWWorld::Ptr& ptr) const From e3e51324a4376bfbad1a21871873cc79dde189f9 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 26 May 2014 23:13:37 -0400 Subject: [PATCH 006/110] Esc button exits all non-modal GUI windows --- apps/openmw/mwbase/windowmanager.hpp | 9 +- apps/openmw/mwgui/alchemywindow.cpp | 11 ++- apps/openmw/mwgui/alchemywindow.hpp | 1 + apps/openmw/mwgui/bookwindow.cpp | 13 ++- apps/openmw/mwgui/bookwindow.hpp | 2 + apps/openmw/mwgui/companionwindow.cpp | 5 ++ apps/openmw/mwgui/companionwindow.hpp | 2 + apps/openmw/mwgui/console.cpp | 5 ++ apps/openmw/mwgui/console.hpp | 105 ++++++++++++------------ apps/openmw/mwgui/container.cpp | 7 +- apps/openmw/mwgui/container.hpp | 2 + apps/openmw/mwgui/dialogue.cpp | 11 ++- apps/openmw/mwgui/dialogue.hpp | 2 + apps/openmw/mwgui/enchantingdialog.cpp | 7 +- apps/openmw/mwgui/enchantingdialog.hpp | 3 + apps/openmw/mwgui/merchantrepair.cpp | 7 +- apps/openmw/mwgui/merchantrepair.hpp | 2 + apps/openmw/mwgui/quickkeysmenu.cpp | 7 +- apps/openmw/mwgui/quickkeysmenu.hpp | 1 + apps/openmw/mwgui/recharge.cpp | 7 +- apps/openmw/mwgui/recharge.hpp | 2 + apps/openmw/mwgui/repair.cpp | 7 +- apps/openmw/mwgui/repair.hpp | 2 + apps/openmw/mwgui/scrollwindow.cpp | 11 ++- apps/openmw/mwgui/scrollwindow.hpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 7 +- apps/openmw/mwgui/settingswindow.hpp | 2 + apps/openmw/mwgui/spellbuyingwindow.cpp | 7 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 + apps/openmw/mwgui/tradewindow.cpp | 11 ++- apps/openmw/mwgui/tradewindow.hpp | 2 + apps/openmw/mwgui/trainingwindow.cpp | 7 +- apps/openmw/mwgui/trainingwindow.hpp | 2 + apps/openmw/mwgui/travelwindow.cpp | 7 +- apps/openmw/mwgui/travelwindow.hpp | 2 + apps/openmw/mwgui/waitdialog.cpp | 7 +- apps/openmw/mwgui/waitdialog.hpp | 2 + apps/openmw/mwgui/windowbase.hpp | 5 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 92 +++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 10 ++- apps/openmw/mwinput/inputmanagerimp.cpp | 20 +++-- 41 files changed, 321 insertions(+), 96 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 44ebed3e98..9c069cbc23 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -234,14 +234,19 @@ namespace MWBase virtual void addVisitedLocation(const std::string& name, int x, int y) = 0; + /// Hides dialog and schedules dialog to be deleted. virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; - ///< Hides dialog and schedules dialog to be deleted. + + ///Gracefully attempts to exit the topmost GUI mode + /** No guarentee of actually closing the window **/ + virtual void exitCurrentGuiMode() = 0; virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector(), enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0; virtual void staticMessageBox(const std::string& message) = 0; virtual void removeStaticMessageBox() = 0; + + /// returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual int readPressedButton() = 0; - ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual void onFrame (float frameDuration) = 0; diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 6524c168e1..ab04189a68 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -66,10 +66,7 @@ namespace MWGui void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mAlchemy.clear(); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); + exit(); } void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) @@ -159,6 +156,12 @@ namespace MWGui update(); } + void AlchemyWindow::exit() { + mAlchemy.clear(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); + } + void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) { removeIngredient(_sender); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 3a58ebf060..4fd4b825c0 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -19,6 +19,7 @@ namespace MWGui AlchemyWindow(); virtual void open(); + virtual void exit(); private: ItemView* mItemView; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 884d567c51..32a5255c9a 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -114,6 +114,14 @@ namespace MWGui setTakeButtonShow(true); } + void BookWindow::exit() + { + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); + } + void BookWindow::setTakeButtonShow(bool show) { mTakeButtonShow = show; @@ -128,10 +136,7 @@ namespace MWGui void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) { - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); + exit(); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index f8821ab50b..a944f56e25 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -14,6 +14,8 @@ namespace MWGui public: BookWindow(); + virtual void exit(); + void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); void nextPage(); diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 70093049da..d0ac3e7c36 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -118,6 +118,11 @@ void CompanionWindow::updateEncumbranceBar() } void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender) +{ + exit(); +} + +void CompanionWindow::exit() { if (mPtr.getTypeName() == typeid(ESM::NPC).name() && mPtr.getClass().getNpcStats(mPtr).getProfit() < 0) { diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 02e3812f0b..006d0a3c35 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -18,6 +18,8 @@ namespace MWGui public: CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); + virtual void exit(); + void open(const MWWorld::Ptr& npc); void onFrame (); diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 811f93b486..db87d0a594 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -143,6 +143,11 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); } + void Console::exit() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Console); + } + void Console::setFont(const std::string &fntName) { mHistory->setFontName(fntName); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 8901763630..ec699b317c 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -21,86 +21,83 @@ namespace MWGui { - class Console : public WindowBase, private Compiler::ErrorHandler, public ReferenceInterface - { - private: + class Console : public WindowBase, private Compiler::ErrorHandler, public ReferenceInterface + { + public: + /// Set the implicit object for script execution + void setSelectedObject(const MWWorld::Ptr& object); - Compiler::Extensions mExtensions; - MWScript::CompilerContext mCompilerContext; - std::vector mNames; - bool mConsoleOnlyScripts; + MyGUI::EditBox* mCommandLine; + MyGUI::EditBox* mHistory; - bool compile (const std::string& cmd, Compiler::Output& output); + typedef std::list StringList; - /// Report error to the user. - virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); + // History of previous entered commands + StringList mCommandHistory; + StringList::iterator mCurrent; + std::string mEditString; - /// Report a file related error - virtual void report (const std::string& message, Type type); + Console(int w, int h, bool consoleOnlyScripts); - void listNames(); - ///< Write all valid identifiers and keywords into mNames and sort them. - /// \note If mNames is not empty, this function is a no-op. - /// \note The list may contain duplicates (if a name is a keyword and an identifier at the same - /// time). + virtual void open(); + virtual void close(); - public: + virtual void exit(); - void setSelectedObject(const MWWorld::Ptr& object); - ///< Set the implicit object for script execution + void setFont(const std::string &fntName); - protected: + void onResChange(int width, int height); - virtual void onReferenceUnavailable(); + void clearHistory(); + // Print a message to the console. Messages may contain color + // code, eg. "#FFFFFF this is white". + void print(const std::string &msg); - public: - MyGUI::EditBox* mCommandLine; - MyGUI::EditBox* mHistory; + // These are pre-colored versions that you should use. - typedef std::list StringList; + /// Output from successful console command + void printOK(const std::string &msg); - // History of previous entered commands - StringList mCommandHistory; - StringList::iterator mCurrent; - std::string mEditString; + /// Error message + void printError(const std::string &msg); - Console(int w, int h, bool consoleOnlyScripts); + void execute (const std::string& command); - virtual void open(); - virtual void close(); + void executeFile (const std::string& path); - void setFont(const std::string &fntName); + protected: - void onResChange(int width, int height); + virtual void onReferenceUnavailable(); - void clearHistory(); + private: - // Print a message to the console. Messages may contain color - // code, eg. "#FFFFFF this is white". - void print(const std::string &msg); + void keyPress(MyGUI::Widget* _sender, + MyGUI::KeyCode key, + MyGUI::Char _char); - // These are pre-colored versions that you should use. + void acceptCommand(MyGUI::EditBox* _sender); - /// Output from successful console command - void printOK(const std::string &msg); + std::string complete( std::string input, std::vector &matches ); - /// Error message - void printError(const std::string &msg); + Compiler::Extensions mExtensions; + MWScript::CompilerContext mCompilerContext; + std::vector mNames; + bool mConsoleOnlyScripts; - void execute (const std::string& command); + bool compile (const std::string& cmd, Compiler::Output& output); - void executeFile (const std::string& path); + /// Report error to the user. + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); - private: + /// Report a file related error + virtual void report (const std::string& message, Type type); - void keyPress(MyGUI::Widget* _sender, - MyGUI::KeyCode key, - MyGUI::Char _char); - - void acceptCommand(MyGUI::EditBox* _sender); - - std::string complete( std::string input, std::vector &matches ); + /// Write all valid identifiers and keywords into mNames and sort them. + /// \note If mNames is not empty, this function is a no-op. + /// \note The list may contain duplicates (if a name is a keyword and an identifier at the same + /// time). + void listNames(); }; } #endif diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index a207dec0c5..609dea3857 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -263,7 +263,7 @@ namespace MWGui } } - void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) + void ContainerWindow::exit() { if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { @@ -271,6 +271,11 @@ namespace MWGui } } + void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) + { + exit(); + } + void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) { if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 3aa923a239..5446a4ab73 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -54,6 +54,8 @@ namespace MWGui void open(const MWWorld::Ptr& container, bool loot=false); virtual void close(); + virtual void exit(); + private: DragAndDrop* mDragAndDrop; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0002757947..8f8bab0252 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -264,6 +264,13 @@ namespace MWGui static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } + void DialogueWindow::exit() + { + if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + return; + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + } + void DialogueWindow::onWindowResize(MyGUI::Window* _sender) { mTopicsList->adjustSize(); @@ -281,9 +288,7 @@ namespace MWGui void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { - if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) - return; - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + exit(); } void DialogueWindow::onSelectTopic(const std::string& topic, int id) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index befbd6eeeb..9bc40bb6fa 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -103,6 +103,8 @@ namespace MWGui public: DialogueWindow(); + virtual void exit(); + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 29fe6f82d5..ccb1fab682 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -61,6 +61,11 @@ namespace MWGui onRemoveSoul(NULL); } + void EnchantingDialog::exit() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); + } + void EnchantingDialog::updateLabels() { std::stringstream enchantCost; @@ -141,7 +146,7 @@ namespace MWGui void EnchantingDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); + exit(); } void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 8bad60c8e6..7e641702e1 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -19,6 +19,9 @@ namespace MWGui virtual ~EnchantingDialog(); virtual void open(); + + virtual void exit(); + void startEnchanting(MWWorld::Ptr actor); void startSelfEnchanting(MWWorld::Ptr soulgem); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 50e7644fb9..49cc60d8aa 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -110,6 +110,11 @@ void MerchantRepair::open() center(); } +void MerchantRepair::exit() +{ + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); +} + void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { // repair @@ -128,7 +133,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); + exit(); } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 4cb39fe012..2f13873654 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -16,6 +16,8 @@ public: virtual void open(); + virtual void exit(); + void startRepair(const MWWorld::Ptr& actor); private: diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 90abbb1450..9321d2de23 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -57,6 +57,11 @@ namespace MWGui } } + void QuickKeysMenu::exit() + { + mAssignDialog->setVisible (false); + } + void QuickKeysMenu::clear() { for (int i=0; i<10; ++i) @@ -146,7 +151,7 @@ namespace MWGui void QuickKeysMenu::onCancelButtonClicked(MyGUI::Widget* sender) { - mAssignDialog->setVisible (false); + exit(); } void QuickKeysMenu::onAssignItem(MWWorld::Ptr item) diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index c0e25a517c..56a04cfbbb 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -18,6 +18,7 @@ namespace MWGui QuickKeysMenu(); ~QuickKeysMenu(); + virtual void exit(); void onItemButtonClicked(MyGUI::Widget* sender); void onMagicButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 5c4f3eb5a5..e5ea545917 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -38,6 +38,11 @@ void Recharge::open() center(); } +void Recharge::exit() +{ + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); +} + void Recharge::start (const MWWorld::Ptr &item) { std::string path = std::string("icons\\"); @@ -128,7 +133,7 @@ void Recharge::updateView() void Recharge::onCancel(MyGUI::Widget *sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); + exit(); } void Recharge::onItemClicked(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 2ffc5e10f8..5558b197e0 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -15,6 +15,8 @@ public: virtual void open(); + virtual void exit(); + void start (const MWWorld::Ptr& gem); protected: diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 1ae02599ee..29ec62887a 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -35,6 +35,11 @@ void Repair::open() center(); } +void Repair::exit() +{ + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); +} + void Repair::startRepairItem(const MWWorld::Ptr &item) { mRepair.setTool(item); @@ -134,7 +139,7 @@ void Repair::updateRepairView() void Repair::onCancel(MyGUI::Widget *sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); + exit(); } void Repair::onRepairItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index d0f5c54c4b..42539ad9e0 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -15,6 +15,8 @@ public: virtual void open(); + virtual void exit(); + void startRepairItem (const MWWorld::Ptr& item); protected: diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index a084e6453a..3d07511143 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -67,6 +67,13 @@ namespace MWGui setTakeButtonShow(true); } + void ScrollWindow::exit() + { + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + } + void ScrollWindow::setTakeButtonShow(bool show) { mTakeButtonShow = show; @@ -81,9 +88,7 @@ namespace MWGui void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + exit(); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 5feaff7bf8..17e56f3345 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -14,6 +14,7 @@ namespace MWGui ScrollWindow (); void open (MWWorld::Ptr scroll); + virtual void exit(); void setTakeButtonShow(bool show); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 78adecd3ef..4730a7295a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -242,7 +242,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); + exit(); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -510,4 +510,9 @@ namespace MWGui { updateControlsBox (); } + + void SettingsWindow::exit() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); + } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 7a6c1a5ed5..37f2c8af06 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -17,6 +17,8 @@ namespace MWGui virtual void open(); + virtual void exit(); + void updateControlsBox(); protected: diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 99b85c13cc..8d9f35daaa 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -33,6 +33,11 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); } + void SpellBuyingWindow::exit() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); + } + void SpellBuyingWindow::addSpell(const std::string& spellId) { const MWWorld::ESMStore &store = @@ -132,7 +137,7 @@ namespace MWGui void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); + exit(); } void SpellBuyingWindow::updateLabels() diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index f7ea54c89c..2a6dcfdcc4 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -25,6 +25,8 @@ namespace MWGui void startSpellBuying(const MWWorld::Ptr& actor); + virtual void exit(); + protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 558e955f0d..cb7f3b0bd4 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -136,6 +136,13 @@ namespace MWGui return mPtr.getClass().getServices(mPtr); } + void TradeWindow::exit() + { + mTradeModel->abort(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->abort(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + } + void TradeWindow::onItemSelected (int index) { const ItemStack& item = mSortModel->getItem(index); @@ -375,9 +382,7 @@ namespace MWGui void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mTradeModel->abort(); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->abort(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + exit(); } void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 2da58e72e1..420a642e81 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -35,6 +35,8 @@ namespace MWGui int getMerchantServices(); + virtual void exit(); + private: ItemView* mItemView; diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 34873b9bc7..9a2c3b8055 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -35,6 +35,11 @@ namespace MWGui center(); } + void TrainingWindow::exit() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); + } + void TrainingWindow::startTraining (MWWorld::Ptr actor) { mPtr = actor; @@ -107,7 +112,7 @@ namespace MWGui void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); + exit(); } void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 740115cdfc..1fc902b20a 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -14,6 +14,8 @@ namespace MWGui virtual void open(); + virtual void exit(); + void startTraining(MWWorld::Ptr actor); void onFrame(float dt); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 642e1a6449..79d50cdc59 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -45,6 +45,11 @@ namespace MWGui mSelect->getHeight()); } + void TravelWindow::exit() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); + } + void TravelWindow::addDestination(const std::string& travelId,ESM::Position pos,bool interior) { int price = 0; @@ -170,7 +175,7 @@ namespace MWGui void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); + exit(); } void TravelWindow::updateLabels() diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index f2a23b0486..5387bd690d 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -22,6 +22,8 @@ namespace MWGui public: TravelWindow(); + virtual void exit(); + void startTravel(const MWWorld::Ptr& actor); protected: diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 12bf97f7c9..460663682e 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -69,6 +69,11 @@ namespace MWGui mProgressBar.setVisible (false); } + void WaitDialog::exit() + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + void WaitDialog::open() { if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) @@ -160,7 +165,7 @@ namespace MWGui void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - MWBase::Environment::get().getWindowManager()->popGuiMode (); + exit(); } void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 5a66c3370e..1cf05bb06f 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -28,6 +28,8 @@ namespace MWGui virtual void open(); + virtual void exit(); + void onFrame(float dt); void bedActivated() { setCanRest(true); } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 48de9ea87c..d8bd2bd598 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -21,8 +21,13 @@ namespace MWGui // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; + ///Unhides the window virtual void open() {} + ///Hides the window virtual void close () {} + ///Gracefully exits the window + virtual void exit() {} + ///Sets the visibility of the window virtual void setVisible(bool visible); void center(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a42dca79e5..46aa781acf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -23,6 +23,8 @@ #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwsound/soundmanagerimp.hpp" + #include "console.hpp" #include "journalwindow.hpp" #include "journalviewmodel.hpp" @@ -666,6 +668,96 @@ namespace MWGui mGarbageDialogs.push_back(dialog); } + void WindowManager::exitCurrentGuiMode() { + switch(mGuiModes.back()) { + case GM_QuickKeysMenu: + mQuickKeysMenu->exit(); + break; + case GM_MainMenu: + removeGuiMode(GM_MainMenu); //Simple way to remove it + break; + case GM_Settings: + mSettingsWindow->exit(); + break; + case GM_Console: + mConsole->exit(); + break; + case GM_Scroll: + mScrollWindow->exit(); + break; + case GM_Book: + mBookWindow->exit(); + break; + case GM_Alchemy: + mAlchemyWindow->exit(); + break; + case GM_Rest: + mWaitDialog->exit(); + break; + case GM_RestBed: + mWaitDialog->exit(); + break; + case GM_Levelup: + mLevelupDialog->exit(); + break; + case GM_Name: + case GM_Race: + case GM_Class: + case GM_ClassPick: + case GM_ClassCreate: + case GM_Birth: + case GM_ClassGenerate: + case GM_Review: + break; + case GM_Inventory: + removeGuiMode(GM_Inventory); //Simple way to remove it + break; + case GM_Container: + mContainerWindow->exit(); + break; + case GM_Companion: + mCompanionWindow->exit(); + break; + case GM_Dialogue: + mDialogueWindow->exit(); + break; + case GM_Barter: + mTradeWindow->exit(); + break; + case GM_SpellBuying: + mSpellBuyingWindow->exit(); + break; + case GM_Travel: + mTravelWindow->exit(); + break; + case GM_SpellCreation: + mSpellCreationDialog->exit(); + break; + case GM_Recharge: + mRecharge->exit(); + break; + case GM_Enchanting: + mEnchantingDialog->exit(); + break; + case GM_Training: + mTrainingWindow->exit(); + break; + case GM_MerchantRepair: + mMerchantRepair->exit(); + break; + case GM_Repair: + mRepair->exit(); + break; + case GM_Journal: + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + removeGuiMode(GM_Journal); //Simple way to remove it + break; + default: + // Unsupported mode, switch back to game + break; + } + } + void WindowManager::messageBox (const std::string& message, const std::vector& buttons, enum MWGui::ShowInDialogueMode showInDialogueMode) { if (buttons.empty()) { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c98c32c524..cd87113ce1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -132,10 +132,10 @@ namespace MWGui virtual void forceHide(MWGui::GuiWindow wnd); virtual void unsetForceHide(MWGui::GuiWindow wnd); - // Disallow all inventory mode windows + /// Disallow all inventory mode windows virtual void disallowAll(); - // Allow one or more windows + /// Allow one or more windows virtual void allow(GuiWindow wnd); virtual bool isAllowed(GuiWindow wnd) const; @@ -225,7 +225,11 @@ namespace MWGui virtual void addVisitedLocation(const std::string& name, int x, int y); - virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. + ///Hides dialog and schedules dialog to be deleted. + virtual void removeDialog(OEngine::GUI::Layout* dialog); + + ///Gracefully attempts to exit the topmost GUI mode + virtual void exitCurrentGuiMode(); virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector(), enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible); virtual void staticMessageBox(const std::string& message); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf71cc1aa4..f020ef9f28 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -28,6 +28,8 @@ #include "../mwmechanics/creaturestats.hpp" +#include "../mwdialogue/dialoguemanagerimp.hpp" + using namespace ICS; namespace @@ -633,19 +635,20 @@ namespace MWInput void InputManager::toggleMainMenu() { - if (MyGUI::InputManager::getInstance ().isModalAny()) +// TODO: Find a way to send an exit command to current Modal Widget + if (MyGUI::InputManager::getInstance().isModalAny()) return; - if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getSoundManager()->resumeSounds (MWBase::SoundManager::Play_TypeSfx); - } - else + if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu { MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); MWBase::Environment::get().getSoundManager()->pauseSounds (MWBase::SoundManager::Play_TypeSfx); } + else //Close current GUI + { + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + MWBase::Environment::get().getSoundManager()->resumeSounds (MWBase::SoundManager::Play_TypeSfx); + } } void InputManager::quickLoad() { @@ -761,8 +764,7 @@ namespace MWInput } else if(MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Journal) { - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } // .. but don't touch any other mode. } From 79d0ed64d9edb2a740ba92448301503f7d7e50ba Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 26 May 2014 23:31:40 -0400 Subject: [PATCH 007/110] Undo some changes I made in the past that shouldn't exist --- apps/openmw/mwclass/container.cpp | 8 ++------ apps/openmw/mwclass/door.cpp | 8 ++------ apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 7b62ad04f0..940a36b00f 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -262,12 +262,8 @@ namespace MWClass { if(lockLevel!=0) ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive - else { - if(abs(ptr.getCellRef().getLockLevel())!=0) - ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one - else - ptr.getCellRef().setLockLevel(100); //There never was a locklevel, give it the default biggest one - } + else + ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one } void Container::unlock (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 0788896297..12645c9f39 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -192,12 +192,8 @@ namespace MWClass { if(lockLevel!=0) ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive - else { - if(abs(ptr.getCellRef().getLockLevel())!=0) - ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one - else - ptr.getCellRef().setLockLevel(100); - } + else + ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one } void Door::unlock (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 4e36a8da9b..c3f94d7f10 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -165,7 +165,7 @@ namespace MWWorld virtual bool hasInventoryStore (const Ptr& ptr) const; ///< Does this object have an inventory store, i.e. equipment slots? (default implementation: false) - virtual void lock (const Ptr& ptr, int lockLevel = 0) const; + virtual void lock (const Ptr& ptr, int lockLevel) const; ///< Lock object (default implementation: throw an exception) virtual void unlock (const Ptr& ptr) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f7297128ba..43153612d7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2526,7 +2526,7 @@ namespace MWWorld store.remove(*it, it->getRefData().getCount(), ptr); } } - closestChest.getClass().lock(closestChest); + closestChest.getClass().unlock(closestChest); } } From e0d55116a4cb6216980339fbce32c520f3fe0a11 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 27 May 2014 00:30:37 -0400 Subject: [PATCH 008/110] Dims and disabled Goodbye button in dialogs when unavailable. --- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 940a36b00f..9498ea52df 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -263,7 +263,7 @@ namespace MWClass if(lockLevel!=0) ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive else - ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one + ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the original one } void Container::unlock (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8f8bab0252..0cea50f1be 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -509,6 +509,17 @@ namespace MWGui // no scrollbar onScrollbarMoved(mScrollBar, 0); } + + MyGUI::Button* byeButton; + getWidget(byeButton, "ByeButton"); + if(MWBase::Environment::get().getDialogueManager()->isInChoice()) { + byeButton->setAlpha(.2); + byeButton->setEnabled(false); + } + else { + byeButton->setAlpha(1); + byeButton->setEnabled(true); + } } void DialogueWindow::notifyLinkClicked (TypesetBook::InteractiveId link) From e0356cf89d786d3fbc671220e32737fa9a379e23 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 27 May 2014 03:00:31 -0400 Subject: [PATCH 009/110] Added support to close modal windows with Esc --- apps/openmw/mwbase/windowmanager.hpp | 9 +++++++++ apps/openmw/mwgui/confirmationdialog.cpp | 7 ++++++- apps/openmw/mwgui/confirmationdialog.hpp | 1 + apps/openmw/mwgui/dialogue.cpp | 7 ++++++- apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/savegamedialog.cpp | 7 ++++++- apps/openmw/mwgui/savegamedialog.hpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.cpp | 22 ++++++++++++++++------ apps/openmw/mwgui/spellcreationdialog.hpp | 2 ++ apps/openmw/mwgui/windowbase.cpp | 9 +++++++++ apps/openmw/mwgui/windowbase.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.hpp | 11 +++++++++++ apps/openmw/mwinput/inputmanagerimp.cpp | 7 +++++-- 14 files changed, 76 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 9c069cbc23..69712ed037 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -57,6 +57,7 @@ namespace MWGui class InventoryWindow; class ContainerWindow; class DialogueWindow; + class WindowModal; enum ShowInDialogueMode { ShowInDialogueMode_IfPossible, @@ -314,6 +315,14 @@ namespace MWBase /// Does the current stack of GUI-windows permit saving? virtual bool isSavingAllowed() const = 0; + + /// Returns the current Modal + /** Used to send exit command to active Modal when Esc is pressed **/ + virtual MWGui::WindowModal* getCurrentModal() const = 0; + + /// Sets the current Modal + /** Used to send exit command to active Modal when Esc is pressed **/ + virtual void setCurrentModal(MWGui::WindowModal* input) = 0; }; } diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index f431f2f64c..89f477598f 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -28,13 +28,18 @@ namespace MWGui center(); } - void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) + void ConfirmationDialog::exit() { eventCancelClicked(); setVisible(false); } + void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) + { + exit(); + } + void ConfirmationDialog::onOkButtonClicked(MyGUI::Widget* _sender) { eventOkClicked(); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 47b256017f..c50873c74c 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -10,6 +10,7 @@ namespace MWGui public: ConfirmationDialog(); void open(const std::string& message); + virtual void exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0cea50f1be..762c472d87 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -51,7 +51,7 @@ namespace MWGui void PersuasionDialog::onCancel(MyGUI::Widget *sender) { - setVisible(false); + exit(); } void PersuasionDialog::onPersuade(MyGUI::Widget *sender) @@ -87,6 +87,11 @@ namespace MWGui mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); } + void PersuasionDialog::exit() + { + setVisible(false); + } + // -------------------------------------------------------------------------------------------------- Response::Response(const std::string &text, const std::string &title) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 9bc40bb6fa..fcb1338b5f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -34,6 +34,7 @@ namespace MWGui PersuasionDialog(); virtual void open(); + virtual void exit(); private: MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 6048e49b41..b36baf87bd 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -159,6 +159,11 @@ namespace MWGui } + void SaveGameDialog::exit() + { + setVisible(false); + } + void SaveGameDialog::setLoadOrSave(bool load) { mSaving = !load; @@ -177,7 +182,7 @@ namespace MWGui void SaveGameDialog::onCancelButtonClicked(MyGUI::Widget *sender) { - setVisible(false); + exit(); } void SaveGameDialog::onConfirmationGiven() diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 42c29f4bc9..9f44d53708 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -19,6 +19,8 @@ namespace MWGui virtual void open(); + virtual void exit(); + void setLoadOrSave(bool load); private: diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 1ec4bd6da4..030b8bf37c 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -75,6 +75,15 @@ namespace MWGui center(); } + void EditEffectDialog::exit() + { + setVisible(false); + if(mEditing) + eventEffectModified(mOldEffect); + else + eventEffectRemoved(mEffect); + } + void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) { setMagicEffect(effect); @@ -222,11 +231,7 @@ namespace MWGui void EditEffectDialog::onCancelButtonClicked (MyGUI::Widget* sender) { - setVisible(false); - if(mEditing) - eventEffectModified(mOldEffect); - else - eventEffectRemoved(mEffect); + exit(); } void EditEffectDialog::setSkill (int skill) @@ -313,7 +318,7 @@ namespace MWGui void SpellCreationDialog::onCancelButtonClicked (MyGUI::Widget* sender) { - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); + exit(); } void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender) @@ -367,6 +372,11 @@ namespace MWGui center(); } + void SpellCreationDialog::exit() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); + } + void SpellCreationDialog::onReferenceUnavailable () { MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index e424d73957..25c615678a 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -18,6 +18,7 @@ namespace MWGui EditEffectDialog(); virtual void open(); + virtual void exit(); void setSkill(int skill); void setAttribute(int attribute); @@ -127,6 +128,7 @@ namespace MWGui SpellCreationDialog(); virtual void open(); + virtual void exit(); void startSpellMaking(MWWorld::Ptr actor); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 87b26b814a..15b41813f5 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -2,6 +2,8 @@ #include "../mwbase/windowmanager.hpp" #include "container.hpp" +#include "../mwbase/environment.hpp" +#include "../mwgui/windowmanagerimp.hpp" using namespace MWGui; @@ -45,11 +47,18 @@ WindowModal::WindowModal(const std::string& parLayout) void WindowModal::open() { MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); + MWBase::Environment::get().getWindowManager()->setCurrentModal(this); //Set so we can escape it if needed } void WindowModal::close() { MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); + MWBase::Environment::get().getWindowManager()->setCurrentModal(NULL); +} + +void WindowModal::exit() +{ + close(); } NoDrop::NoDrop(DragAndDrop *drag, MyGUI::Widget *widget) diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index d8bd2bd598..79ab282990 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -47,6 +47,7 @@ namespace MWGui WindowModal(const std::string& parLayout); virtual void open(); virtual void close(); + virtual void exit(); }; /// A window that cannot be the target of a drag&drop action. diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 46aa781acf..5a228801af 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -136,6 +136,7 @@ namespace MWGui , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) + , currentModal(NULL) { // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index cd87113ce1..d146239017 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -82,6 +82,7 @@ namespace MWGui class Recharge; class CompanionWindow; class VideoWidget; + class WindowModal; class WindowManager : public MWBase::WindowManager { @@ -302,6 +303,14 @@ namespace MWGui /// Does the current stack of GUI-windows permit saving? virtual bool isSavingAllowed() const; + /// Returns the current Modal + /** Used to send exit command to active Modal when Esc is pressed **/ + virtual WindowModal* getCurrentModal() const {return currentModal;} + + /// Sets the current Modal + /** Used to send exit command to active Modal when Esc is pressed **/ + virtual void setCurrentModal(WindowModal* input) {currentModal = input;} + private: bool mConsoleOnlyScripts; @@ -311,6 +320,8 @@ namespace MWGui std::string mSelectedSpell; + WindowModal* currentModal; + OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; HUD *mHud; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f020ef9f28..6206985dde 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -30,6 +30,8 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" +#include "../mwgui/windowbase.hpp" + using namespace ICS; namespace @@ -635,9 +637,10 @@ namespace MWInput void InputManager::toggleMainMenu() { -// TODO: Find a way to send an exit command to current Modal Widget - if (MyGUI::InputManager::getInstance().isModalAny()) + if (MyGUI::InputManager::getInstance().isModalAny()) { + MWBase::Environment::get().getWindowManager()->getCurrentModal()->exit(); return; + } if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu { From ee7b5fa5c225aaaa9275b921c6da4935e4eb9686 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 27 May 2014 04:38:13 -0400 Subject: [PATCH 010/110] Fixed crash when Esc-ing out of Save "are you sure" dialog. --- apps/openmw/mwbase/windowmanager.hpp | 7 ++++++- apps/openmw/mwgui/windowbase.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 19 ++++++++++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 11 ++++++++--- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 69712ed037..2dfa50eb51 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -322,7 +322,12 @@ namespace MWBase /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ - virtual void setCurrentModal(MWGui::WindowModal* input) = 0; + virtual void addCurrentModal(MWGui::WindowModal* input) = 0; + + /// Removes the top Modal + /** 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; }; } diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 15b41813f5..4dcb680ec0 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -47,13 +47,13 @@ WindowModal::WindowModal(const std::string& parLayout) void WindowModal::open() { MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); - MWBase::Environment::get().getWindowManager()->setCurrentModal(this); //Set so we can escape it if needed + MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed } void WindowModal::close() { MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); - MWBase::Environment::get().getWindowManager()->setCurrentModal(NULL); + MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); } void WindowModal::exit() diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5a228801af..eb800ef9a4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -136,7 +136,7 @@ namespace MWGui , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) - , currentModal(NULL) + , mCurrentModals() { // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); @@ -1606,4 +1606,21 @@ namespace MWGui mVideoWidget->setCoord(leftPadding, topPadding, screenWidth - leftPadding*2, screenHeight - topPadding*2); } + + WindowModal* WindowManager::getCurrentModal() const + { + if(mCurrentModals.size() > 0) + return mCurrentModals.top(); + else + return NULL; + } + + void WindowManager::removeCurrentModal(WindowModal* input) + { + // Only remove the top if it matches the current pointer. A lot of things hide their visibility before showing it, + //so just popping the top would cause massive issues. + if(mCurrentModals.size() > 0) + if(input == mCurrentModals.top()) + mCurrentModals.pop(); + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index d146239017..b1dbf3a24a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -305,11 +305,16 @@ namespace MWGui /// Returns the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ - virtual WindowModal* getCurrentModal() const {return currentModal;} + virtual WindowModal* getCurrentModal() const; /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ - virtual void setCurrentModal(WindowModal* input) {currentModal = input;} + virtual void addCurrentModal(WindowModal* input) {mCurrentModals.push(input);} + + /// Removes the top Modal + /** Used when one Modal adds another Modal + \param input Pointer to the current modal, to ensure proper modal is removed **/ + virtual void removeCurrentModal(WindowModal* input); private: bool mConsoleOnlyScripts; @@ -320,7 +325,7 @@ namespace MWGui std::string mSelectedSpell; - WindowModal* currentModal; + std::stack mCurrentModals; OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; From 2b3b11d848b4ce9708f65a89ec9024ee90b2035e Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 27 May 2014 05:33:25 -0400 Subject: [PATCH 011/110] Give access to the main menu when at a choice in dialogue --- apps/openmw/mwgui/windowmanagerimp.cpp | 3 --- apps/openmw/mwinput/inputmanagerimp.cpp | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eb800ef9a4..b931cd3706 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -698,9 +698,6 @@ namespace MWGui case GM_RestBed: mWaitDialog->exit(); break; - case GM_Levelup: - mLevelupDialog->exit(); - break; case GM_Name: case GM_Race: case GM_Class: diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6206985dde..2d78e7875d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -642,6 +642,14 @@ namespace MWInput return; } + if(MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Dialogue) { //Give access to the main menu when at a choice in Dialogue + if(MWBase::Environment::get().getDialogueManager()->isInChoice()) { + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + MWBase::Environment::get().getSoundManager()->pauseSounds (MWBase::SoundManager::Play_TypeSfx); + return; + } + } + if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu { MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); From e0ba9a4bf2fec0f8b6f9fa1863ece0c5710d6dce Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 May 2014 12:39:26 +0200 Subject: [PATCH 012/110] added reference collection stage to saving operation (preparation for cell saving) --- apps/opencs/model/doc/saving.cpp | 3 ++ apps/opencs/model/doc/savingstages.cpp | 38 ++++++++++++++++++++++++++ apps/opencs/model/doc/savingstages.hpp | 16 +++++++++++ apps/opencs/model/doc/savingstate.cpp | 7 +++++ apps/opencs/model/doc/savingstate.hpp | 4 +++ apps/opencs/model/world/ref.cpp | 8 ++++++ apps/opencs/model/world/ref.hpp | 2 ++ 7 files changed, 78 insertions(+) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 27d21635eb..337784765c 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -65,7 +65,10 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteRefIdCollectionStage (mDocument, mState)); + appendStage (new CollectionReferencesStage (mDocument, mState)); + + // close file and clean up appendStage (new CloseSaveStage (mState)); appendStage (new FinalSavingStage (mDocument, mState)); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index eb93d90475..fc35e21cd1 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -9,6 +9,8 @@ #include +#include + #include "../world/infocollection.hpp" #include "document.hpp" @@ -214,6 +216,42 @@ void CSMDoc::WriteFilterStage::perform (int stage, Messages& messages) } +CSMDoc::CollectionReferencesStage::CollectionReferencesStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::CollectionReferencesStage::setup() +{ + mState.getSubRecords().clear(); + + int size = mDocument.getData().getReferences().getSize(); + + int steps = size/100; + if (size%100) ++steps; + + return steps; +} + +void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages) +{ + int size = mDocument.getData().getReferences().getSize(); + + for (int i=stage*100; i& record = + mDocument.getData().getReferences().getRecord (i); + + if (record.mState==CSMWorld::RecordBase::State_Deleted || + record.mState==CSMWorld::RecordBase::State_Modified || + record.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mId)].push_back (i); + } + } +} + + CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state) : mState (state) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index c2f0a150a9..653f3a9570 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -163,8 +163,24 @@ namespace CSMDoc virtual void perform (int stage, Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. + }; + class CollectionReferencesStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + CollectionReferencesStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; class CloseSaveStage : public Stage { diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index 8742148226..294f830496 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -25,6 +25,8 @@ void CSMDoc::SavingState::start (Document& document, bool project) mStream.clear(); + mSubRecords.clear(); + if (project) mPath = mProjectPath; else @@ -60,4 +62,9 @@ ESM::ESMWriter& CSMDoc::SavingState::getWriter() bool CSMDoc::SavingState::isProjectFile() const { return mProjectFile; +} + +std::map > CSMDoc::SavingState::getSubRecords() +{ + return mSubRecords; } \ No newline at end of file diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp index 6b45655846..64085bf0d5 100644 --- a/apps/opencs/model/doc/savingstate.hpp +++ b/apps/opencs/model/doc/savingstate.hpp @@ -2,6 +2,7 @@ #define CSM_DOC_SAVINGSTATE_H #include +#include #include @@ -24,6 +25,7 @@ namespace CSMDoc ESM::ESMWriter mWriter; boost::filesystem::path mProjectPath; bool mProjectFile; + std::map > mSubRecords; // record ID, list of subrecords public: @@ -45,6 +47,8 @@ namespace CSMDoc bool isProjectFile() const; ///< Currently saving project file? (instead of content file) + + std::map > getSubRecords(); }; diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index 44ffa92b94..d1bd771f80 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -1,2 +1,10 @@ #include "ref.hpp" + +CSMWorld::CellRef::CellRef() +{ + mRefNum.mIndex = 0; + + // special marker: This reference does not have a RefNum assign to it yet. + mRefNum.mContentFile = -2; +} \ No newline at end of file diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index b60cbd7e41..eb62434cf2 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -12,6 +12,8 @@ namespace CSMWorld { std::string mId; std::string mCell; + + CellRef(); }; } From 91f4967614795effdb0ade4cae408fc01a602313 Mon Sep 17 00:00:00 2001 From: Fil Krynicki Date: Tue, 27 May 2014 13:12:27 -0400 Subject: [PATCH 013/110] Fix for bug 1196. This bug would cause the player to jump when jump was assigned to Space and they closed a dialog with Space. I tested vanilla MW for behaviour and found that Jump was the only basic input which MW does not allow when closing dialogs (i.e. if Space is assigned to move forward, MW will move you forward after closing the dialog). There were two reasons for the bug: 1) OpenMW GUI does not consume UI events 2) Jump occurs so long as key is down (not only on first key down) To minimally fix the bug, I made it so that keypress events can be consumed by the GUI and not passed along to the player control input manager (1). However, if the player holds space, they will still jump (as the subsequent key held events will be captured and cause a jump). Unfortunately, there is no idiomatic way that I could find in the OpenMW input manager to perform events only on key down. Instead, I introduced a variable which tracks whether the jump key has been pressed for the first time within the current frame (2). Note: I was initially concerned that limiting the jump event to KeyDown and not Key Hold would cause issues with swimming, levitating, or variable height jumping. However, after a bunch of testing in vanilla MW and exploration of the OpenMW codebase I could find nothing suggesting the need to capture the jump key being held. --- apps/openmw/mwinput/inputmanagerimp.cpp | 195 ++++++++++++------------ apps/openmw/mwinput/inputmanagerimp.hpp | 1 + 2 files changed, 102 insertions(+), 94 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e2d4f8cb2d..9c263e52d2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -113,6 +113,7 @@ namespace MWInput , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) , mAlwaysRunActive(false) + , mAttemptJump(false) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -173,6 +174,11 @@ namespace MWInput MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue); } + if (action == A_Jump) + { + mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); + } + if (currentValue == 1) { // trigger action activated @@ -292,107 +298,107 @@ namespace MWInput } // Disable movement in Gui mode - if (MWBase::Environment::get().getWindowManager()->isGuiMode() - || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running) - return; - - - // Configure player movement according to keyboard input. Actual movement will - // be done in the physics system. - if (mControlSwitch["playercontrols"]) + if (!(MWBase::Environment::get().getWindowManager()->isGuiMode() + || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)) { - bool triedToMove = false; - if (actionIsActive(A_MoveLeft)) + // Configure player movement according to keyboard input. Actual movement will + // be done in the physics system. + if (mControlSwitch["playercontrols"]) { - triedToMove = true; - mPlayer->setLeftRight (-1); - } - else if (actionIsActive(A_MoveRight)) - { - triedToMove = true; - mPlayer->setLeftRight (1); - } - - if (actionIsActive(A_MoveForward)) - { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (1); - } - else if (actionIsActive(A_MoveBackward)) - { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (-1); - } - - else if(mPlayer->getAutoMove()) - { - triedToMove = true; - mPlayer->setForwardBackward (1); - } - - mPlayer->setSneak(actionIsActive(A_Sneak)); - - if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) - { - mPlayer->setUpDown (1); - triedToMove = true; - } - - if (mAlwaysRunActive) - mPlayer->setRunState(!actionIsActive(A_Run)); - else - mPlayer->setRunState(actionIsActive(A_Run)); - - // if player tried to start moving, but can't (due to being overencumbered), display a notification. - if (triedToMove) - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - mOverencumberedMessageDelay -= dt; - if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) + bool triedToMove = false; + if (actionIsActive(A_MoveLeft)) { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (actionIsActive(A_MoveRight)) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } + + if (actionIsActive(A_MoveForward)) + { + triedToMove = true; mPlayer->setAutoMove (false); - if (mOverencumberedMessageDelay <= 0) + mPlayer->setForwardBackward (1); + } + else if (actionIsActive(A_MoveBackward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } + + mPlayer->setSneak(actionIsActive(A_Sneak)); + + if (mAttemptJump && mControlSwitch["playerjumping"]) + { + mPlayer->setUpDown (1); + triedToMove = true; + } + + if (mAlwaysRunActive) + mPlayer->setRunState(!actionIsActive(A_Run)); + else + mPlayer->setRunState(actionIsActive(A_Run)); + + // if player tried to start moving, but can't (due to being overencumbered), display a notification. + if (triedToMove) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); + mOverencumberedMessageDelay -= dt; + if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) { - MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); - mOverencumberedMessageDelay = 1.0; + mPlayer->setAutoMove (false); + if (mOverencumberedMessageDelay <= 0) + { + MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); + mOverencumberedMessageDelay = 1.0; + } + } + } + + if (mControlSwitch["playerviewswitch"]) { + + // work around preview mode toggle when pressing Alt+Tab + if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { + if (mPreviewPOVDelay <= 0.5 && + (mPreviewPOVDelay += dt) > 0.5) + { + mPreviewPOVDelay = 1.f; + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + } + } else { + //disable preview mode + MWBase::Environment::get().getWorld()->togglePreviewMode(false); + if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5) { + MWBase::Environment::get().getWorld()->togglePOV(); + } + mPreviewPOVDelay = 0.f; } } } - - if (mControlSwitch["playerviewswitch"]) { - - // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { - if (mPreviewPOVDelay <= 0.5 && - (mPreviewPOVDelay += dt) > 0.5) - { - mPreviewPOVDelay = 1.f; - MWBase::Environment::get().getWorld()->togglePreviewMode(true); - } - } else { - //disable preview mode - MWBase::Environment::get().getWorld()->togglePreviewMode(false); - if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5) { - MWBase::Environment::get().getWorld()->togglePOV(); - } - mPreviewPOVDelay = 0.f; - } + if (actionIsActive(A_MoveForward) || + actionIsActive(A_MoveBackward) || + actionIsActive(A_MoveLeft) || + actionIsActive(A_MoveRight) || + actionIsActive(A_Jump) || + actionIsActive(A_Sneak) || + actionIsActive(A_TogglePOV)) + { + resetIdleTime(); + } else { + updateIdleTime(dt); } } - if (actionIsActive(A_MoveForward) || - actionIsActive(A_MoveBackward) || - actionIsActive(A_MoveLeft) || - actionIsActive(A_MoveRight) || - actionIsActive(A_Jump) || - actionIsActive(A_Sneak) || - actionIsActive(A_TogglePOV)) - { - resetIdleTime(); - } else { - updateIdleTime(dt); - } + mAttemptJump = false; // Can only jump on first frame input is on } void InputManager::setDragDrop(bool dragDrop) @@ -502,12 +508,13 @@ namespace MWInput } } - mInputBinder->keyPressed (arg); - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); + bool passToBinder = true; if (kc != OIS::KC_UNASSIGNED) - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + passToBinder = !MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + if(passToBinder) + mInputBinder->keyPressed (arg); } void InputManager::textInput(const SDL_TextInputEvent &arg) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 87fbda25cd..537c3a1827 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -161,6 +161,7 @@ namespace MWInput int mMouseWheel; bool mUserFileExists; bool mAlwaysRunActive; + bool mAttemptJump; std::map mControlSwitch; From 060a50f94a2b4746c69e26c8fec90ceb47031968 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 27 May 2014 13:50:24 -0400 Subject: [PATCH 014/110] Fixed issue with QuickKeyMenu and ItemSelectionDialog --- apps/openmw/mwgui/itemselection.cpp | 7 ++++++- apps/openmw/mwgui/itemselection.hpp | 2 ++ apps/openmw/mwgui/quickkeysmenu.cpp | 16 +++++++++++++--- apps/openmw/mwgui/quickkeysmenu.hpp | 2 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 01ea3429c3..1b197f6d80 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -26,6 +26,11 @@ namespace MWGui center(); } + void ItemSelectionDialog::exit() + { + eventDialogCanceled(); + } + void ItemSelectionDialog::openContainer(const MWWorld::Ptr& container) { mModel = new InventoryItemModel(container); @@ -53,7 +58,7 @@ namespace MWGui void ItemSelectionDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - eventDialogCanceled(); + exit(); } } diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index c9ec23cfae..28c45c6056 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -14,6 +14,8 @@ namespace MWGui public: ItemSelectionDialog(const std::string& label); + virtual void exit(); + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 9321d2de23..af4e20ca4a 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -59,7 +59,7 @@ namespace MWGui void QuickKeysMenu::exit() { - mAssignDialog->setVisible (false); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_QuickKeysMenu); } void QuickKeysMenu::clear() @@ -151,7 +151,7 @@ namespace MWGui void QuickKeysMenu::onCancelButtonClicked(MyGUI::Widget* sender) { - exit(); + mAssignDialog->setVisible (false); } void QuickKeysMenu::onAssignItem(MWWorld::Ptr item) @@ -390,6 +390,11 @@ namespace MWGui center(); } + void QuickKeysMenuAssign::exit() + { + setVisible(false); + } + void QuickKeysMenu::write(ESM::ESMWriter &writer) { writer.startRecord(ESM::REC_KEYS); @@ -513,7 +518,12 @@ namespace MWGui void MagicSelectionDialog::onCancelButtonClicked (MyGUI::Widget *sender) { - mParent->onAssignMagicCancel (); + exit(); + } + + void MagicSelectionDialog::exit() + { + mParent->onAssignMagicCancel(); } void MagicSelectionDialog::open () diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 56a04cfbbb..40c5dab565 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -70,6 +70,7 @@ namespace MWGui { public: QuickKeysMenuAssign(QuickKeysMenu* parent); + virtual void exit(); private: MyGUI::TextBox* mLabel; @@ -87,6 +88,7 @@ namespace MWGui MagicSelectionDialog(QuickKeysMenu* parent); virtual void open(); + virtual void exit(); private: MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2d78e7875d..332c8f6a7c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -642,7 +642,7 @@ namespace MWInput return; } - if(MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Dialogue) { //Give access to the main menu when at a choice in Dialogue + if(MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Dialogue) { //Give access to the main menu when at a choice in dialogue if(MWBase::Environment::get().getDialogueManager()->isInChoice()) { MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); MWBase::Environment::get().getSoundManager()->pauseSounds (MWBase::SoundManager::Play_TypeSfx); From 033f1850f9a747e3f9ba39e1955a1af948ffc1ec Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 27 May 2014 14:30:26 -0400 Subject: [PATCH 015/110] Fixed crass on character creation, allowed some character creation windows to be Esc-able --- apps/openmw/mwgui/class.cpp | 15 +++++++++++++++ apps/openmw/mwgui/class.hpp | 6 ++++++ apps/openmw/mwgui/countdialog.cpp | 13 +++++++++---- apps/openmw/mwgui/countdialog.hpp | 1 + apps/openmw/mwgui/windowbase.cpp | 5 ----- apps/openmw/mwgui/windowbase.hpp | 2 +- 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 1c8cc78403..9f6306830b 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -718,6 +718,11 @@ namespace MWGui } void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) + { + exit(); + } + + void SelectSpecializationDialog::exit() { eventCancel(); } @@ -764,6 +769,11 @@ namespace MWGui } void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) + { + exit(); + } + + void SelectAttributeDialog::exit() { eventCancel(); } @@ -855,6 +865,11 @@ namespace MWGui } void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) + { + exit(); + } + + void SelectSkillDialog::exit() { eventCancel(); } diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index f78f7541b2..5c23c834d7 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -136,6 +136,8 @@ namespace MWGui SelectSpecializationDialog(); ~SelectSpecializationDialog(); + virtual void exit(); + ESM::Class::Specialization getSpecializationId() const { return mSpecializationId; } // Events @@ -167,6 +169,8 @@ namespace MWGui SelectAttributeDialog(); ~SelectAttributeDialog(); + virtual void exit(); + ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; } // Events @@ -196,6 +200,8 @@ namespace MWGui SelectSkillDialog(); ~SelectSkillDialog(); + virtual void exit(); + ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } // Events diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 02ccbbc053..53c33b3c48 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -49,7 +49,12 @@ namespace MWGui mItemEdit->setCaption(boost::lexical_cast(maxCount)); } - void CountDialog::cancel() + void CountDialog::cancel() //Keeping this here as I don't know if anything else relies on it. + { + exit(); + } + + void CountDialog::exit() { setVisible(false); } @@ -65,16 +70,16 @@ namespace MWGui setVisible(false); } - + // essentially duplicating what the OK button does if user presses // Enter key void CountDialog::onEnterKeyPressed(MyGUI::EditBox* _sender) { eventOkClicked(NULL, mSlider->getScrollPosition()+1); - + setVisible(false); } - + void CountDialog::onEditTextChange(MyGUI::EditBox* _sender) { if (_sender->getCaption() == "") diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 06de3eb887..a00b0b223b 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -11,6 +11,7 @@ namespace MWGui CountDialog(); void open(const std::string& item, const std::string& message, const int maxCount); void cancel(); + virtual void exit(); typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 4dcb680ec0..c2515a6ded 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -56,11 +56,6 @@ void WindowModal::close() MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); } -void WindowModal::exit() -{ - close(); -} - NoDrop::NoDrop(DragAndDrop *drag, MyGUI::Widget *widget) : mDrag(drag), mWidget(widget), mTransparent(false) { diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 79ab282990..471d8ac709 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -47,7 +47,7 @@ namespace MWGui WindowModal(const std::string& parLayout); virtual void open(); virtual void close(); - virtual void exit(); + virtual void exit() {} }; /// A window that cannot be the target of a drag&drop action. From 56ff399f30729a5dcdb9f173d7c32c841570b4a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 May 2014 13:59:31 +0200 Subject: [PATCH 016/110] Say attack voiced dialogue *after* the target is set up Required for the CreatureTargetted filter to function properly --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 1f9846aa71..900ea72cad 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1019,12 +1019,13 @@ namespace MWMechanics void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) { - if (ptr.getClass().isNpc()) - MWBase::Environment::get().getDialogueManager()->say(ptr, "attack"); - ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr); if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) ptr.getClass().getCreatureStats(ptr).setHostile(true); + + // Must be done after the target is set up, so that CreatureTargetted dialogue filter works properly + if (ptr.getClass().isNpc()) + MWBase::Environment::get().getDialogueManager()->say(ptr, "attack"); } void MechanicsManager::getObjectsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) From 42ea43c3d1a0c6b525596170476eecd08799eacf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 May 2014 18:45:07 +0200 Subject: [PATCH 017/110] Fix container scripts not getting removed properly on cell change Broken by f99eda1a543c7 --- apps/openmw/mwworld/containerstore.cpp | 28 +++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 2496a6eff4..8a076c3fc0 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -229,22 +229,26 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr std::string script = item.getClass().getScript(item); if(script != "") { - CellStore *cell; + if (actorPtr == player) + { + // Items in player's inventory have cell set to 0, so their scripts will never be removed + item.mCell = 0; + } + else + { + // Set mCell to the cell of the container/actor, so that the scripts are removed properly when + // the cell of the container/actor goes inactive + item.mCell = actorPtr.getCell(); + } + + item.mContainerStore = 0; MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); - if(&(player.getClass().getContainerStore (player)) == this) - { - cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed - - // Set OnPCAdd special variable, if it is declared + // Set OnPCAdd special variable, if it is declared + // Make sure to do this *after* we have added the script to LocalScripts + if (actorPtr == player) item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1); - } - else - cell = player.getCell(); - - item.mCell = cell; - item.mContainerStore = 0; } return it; From e68600eda25d40810f037ec6c44352ba67cb54b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 May 2014 19:23:50 +0200 Subject: [PATCH 018/110] Make Activate instruction work properly even when onActivate was not called in the same frame. There are two major differences to the old implementation: - Activate can now be called on its own, e.g. in the console. In Vanilla this appears to be a no-op, so it is unlikely to be used and the potential for breakage is low. - The Action to execute is now determined when Activate is called, not when OnActivate is called. This however makes sense, since there may be a time difference between the two, and the object (or the player) could have changed in the meantime, requiring a different Action. Fixes #1166 and #1346. --- apps/openmw/engine.cpp | 7 ++----- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/interpretercontext.cpp | 17 +++++++---------- apps/openmw/mwscript/interpretercontext.hpp | 9 ++++----- apps/openmw/mwscript/miscextensions.cpp | 8 ++++++-- components/compiler/extensions0.cpp | 2 +- components/compiler/opcodes.hpp | 1 + 7 files changed, 23 insertions(+), 24 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 820863cb95..d33e5300ec 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -491,10 +491,7 @@ void OMW::Engine::activate() MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); - boost::shared_ptr action = - ptr.getClass().activate (ptr, MWBase::Environment::get().getWorld()->getPlayerPtr()); - - interpreterContext.activate (ptr, action); + interpreterContext.activate (ptr); std::string script = ptr.getClass().getScript (ptr); @@ -508,7 +505,7 @@ void OMW::Engine::activate() if (!interpreterContext.hasActivationBeenHandled()) { - interpreterContext.executeActivation(); + interpreterContext.executeActivation(ptr); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 53c80a943b..24b0b6f7aa 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -392,5 +392,6 @@ op 0x2000240: onKnockout op 0x2000241: onKnockoutExplicit op 0x2000242: ModFactionReaction op 0x2000243: GetFactionReaction +op 0x2000244: Activate, explicit -opcodes 0x2000244-0x3ffffff unused +opcodes 0x2000245-0x3ffffff unused diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 6f7968fac8..6bf50371b8 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -413,28 +413,25 @@ namespace MWScript return mActivationHandled; } - void InterpreterContext::activate (const MWWorld::Ptr& ptr, - boost::shared_ptr action) + void InterpreterContext::activate (const MWWorld::Ptr& ptr) { mActivated = ptr; mActivationHandled = false; - mAction = action; } - void InterpreterContext::executeActivation() + void InterpreterContext::executeActivation(MWWorld::Ptr ptr) { - if (!mAction.get()) - throw std::runtime_error ("activation failed, because no action to perform"); - - mAction->execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); - mActivationHandled = true; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + boost::shared_ptr action = (ptr.getClass().activate(ptr, player)); + action->execute (player); + if (mActivated == ptr) + mActivationHandled = true; } void InterpreterContext::clearActivation() { mActivated = MWWorld::Ptr(); mActivationHandled = false; - mAction.reset(); } float InterpreterContext::getSecondsPassed() const diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 9fb7fa2bf8..1137efed31 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -31,7 +31,6 @@ namespace MWScript MWWorld::Ptr mActivated; bool mActivationHandled; - boost::shared_ptr mAction; MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true); @@ -126,12 +125,12 @@ namespace MWScript bool hasActivationBeenHandled() const; - void activate (const MWWorld::Ptr& ptr, boost::shared_ptr action); - ///< Store reference acted upon and action. The actual execution of the action does not + void activate (const MWWorld::Ptr& ptr); + ///< Store reference acted upon. The actual execution of the action does not /// take place here. - void executeActivation(); - ///< Execute the action defined by the last activate call. + void executeActivation(MWWorld::Ptr ptr); + ///< Execute the activation action for this ptr. If ptr is mActivated, mark activation as handled. void clearActivation(); ///< Discard the action defined by the last activate call. diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index fa17d96af3..9d6d5e50dc 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -109,6 +109,7 @@ namespace MWScript } }; + template class OpActivate : public Interpreter::Opcode0 { public: @@ -118,7 +119,9 @@ namespace MWScript InterpreterContext& context = static_cast (runtime.getContext()); - context.executeActivation(); + MWWorld::Ptr ptr = R()(runtime); + + context.executeActivation(ptr); } }; @@ -860,7 +863,8 @@ namespace MWScript { interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); interpreter.installSegment5 (Compiler::Misc::opcodeOnActivate, new OpOnActivate); - interpreter.installSegment5 (Compiler::Misc::opcodeActivate, new OpActivate); + interpreter.installSegment5 (Compiler::Misc::opcodeActivate, new OpActivate); + interpreter.installSegment5 (Compiler::Misc::opcodeActivateExplicit, new OpActivate); interpreter.installSegment3 (Compiler::Misc::opcodeLock, new OpLock); interpreter.installSegment3 (Compiler::Misc::opcodeLockExplicit, new OpLock); interpreter.installSegment5 (Compiler::Misc::opcodeUnlock, new OpUnlock); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 4ef638ef83..0f726a52d2 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -224,7 +224,7 @@ namespace Compiler { extensions.registerFunction ("xbox", 'l', "", opcodeXBox); extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate); - extensions.registerInstruction ("activate", "", opcodeActivate); + extensions.registerInstruction ("activate", "", opcodeActivate, opcodeActivateExplicit); extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit); extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit); extensions.registerInstruction ("cast", "SS", opcodeCast, opcodeCastExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 1dff046652..8796c53c54 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -182,6 +182,7 @@ namespace Compiler const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; + const int opcodeActivateExplicit = 0x2000244; const int opcodeLock = 0x20004; const int opcodeLockExplicit = 0x20005; const int opcodeUnlock = 0x200008c; From b897080156825c577ce0fe5e476cc54fe35c6e8f Mon Sep 17 00:00:00 2001 From: Kevin Poitra Date: Wed, 28 May 2014 12:26:35 -0500 Subject: [PATCH 019/110] Started implementing sound time tracking so we can have NPCs' mouths move as they talk. --- apps/openmw/mwbase/soundmanager.hpp | 3 ++ apps/openmw/mwsound/soundmanagerimp.cpp | 41 +++++++++++++++++++++++-- apps/openmw/mwsound/soundmanagerimp.hpp | 7 +++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 15739730ba..68ec2cae8a 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -100,6 +100,9 @@ namespace MWBase virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0; ///< Stop an actor speaking + + virtual float getSoundPlayingTime(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0; + ///< Get the amount of time this sound has been playing. virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 4a3093b10d..f7c5863800 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -244,6 +244,7 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, 20.0f, 1500.0f, Play_Normal|Play_TypeVoice, 0); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); + mSoundPlayTime[sound] = std::make_pair(ptr, 0); } catch(std::exception &e) { @@ -261,7 +262,9 @@ namespace MWSound std::string filePath = "Sound/"+filename; MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0); - mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); + MWWorld::Ptr ptr = MWWorld::Ptr(); + mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); + mSoundPlayTime[sound] = std::make_pair(ptr, 0); } catch(std::exception &e) { @@ -288,6 +291,18 @@ namespace MWSound ++snditer; } } + + float SoundManager::getSoundPlayingTime(const MWWorld::Ptr &ptr) + { + typedef SoundPlayingTimeMap::iterator iter_type; + for(iter_type iterator = mSoundPlayTime.begin(); iterator != mSoundPlayTime.end(); iterator++) + { + if (iterator->second.first == ptr) + return iterator->second.second; + } + + return 0; + } MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) @@ -602,8 +617,12 @@ namespace MWSound while(snditer != mActiveSounds.end()) { if(!snditer->first->isPlaying()) - mActiveSounds.erase(snditer++); - else + { + mActiveSounds.erase(snditer); + mSoundPlayTime.erase(snditer->first); + snditer++; + } + else { const MWWorld::Ptr &ptr = snditer->second.first; if(!ptr.isEmpty()) @@ -626,6 +645,22 @@ namespace MWSound ++snditer; } } + + // Update the total playing time for all sounds. + // This is primarily used for detecting amplitude for NPC mouth animation. + + typedef SoundPlayingTimeMap::iterator it_type; + for(it_type iterator = mSoundPlayTime.begin(); iterator != mSoundPlayTime.end(); iterator++) + { + iterator->second.second += duration; + } + + std::cout << mSoundPlayTime.size() << " sounds currently playing." << std::endl; + typedef SoundPlayingTimeMap::iterator it_ty; + for(it_ty iterator = mSoundPlayTime.begin(); iterator != mSoundPlayTime.end(); iterator++) + { + std::cout << iterator->first->getPlayType() << ": " << iterator->second.second << std::endl; + } } void SoundManager::update(float duration) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index ab9dcf7345..3f6490d851 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -43,6 +43,10 @@ namespace MWSound typedef std::pair PtrIDPair; typedef std::map SoundMap; SoundMap mActiveSounds; + + typedef std::pair PtrFloatPair; + typedef std::map SoundPlayingTimeMap; + SoundPlayingTimeMap mSoundPlayTime; MWBase::SoundPtr mUnderwaterSound; @@ -104,6 +108,9 @@ namespace MWSound virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()); ///< Stop an actor speaking + + virtual float getSoundPlayingTime(const MWWorld::Ptr &reference=MWWorld::Ptr()); + ///< Get the amount of time this sound has been playing. virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder From 16a6edbd0eeceff1bf87ca0b4aa84f841846b763 Mon Sep 17 00:00:00 2001 From: Kevin Poitra Date: Wed, 28 May 2014 12:58:45 -0500 Subject: [PATCH 020/110] Fix a possible crash due to a null pointer. --- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c95a137ecc..548a871ce1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -252,7 +252,6 @@ namespace MWWorld mProjectileManager->clear(); mLocalScripts.clear(); - mPlayer->clear(); mWorldScene->changeToVoid(); @@ -261,9 +260,10 @@ namespace MWWorld if (mPlayer) { - mPlayer->setCell (0); + mPlayer->clear(); + mPlayer->setCell(0); mPlayer->getPlayer().getRefData() = RefData(); - mPlayer->set (mStore.get().find ("player")); + mPlayer->set(mStore.get().find ("player")); } mCells.clear(); From 545c3c312c43fae7e40a92076a077f7b8a726ae6 Mon Sep 17 00:00:00 2001 From: Kevin Poitra Date: Wed, 28 May 2014 13:03:40 -0500 Subject: [PATCH 021/110] Remove a superfluous clear. --- components/esm/loadclot.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index d64564d77f..16101162ee 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -46,7 +46,6 @@ void Clothing::save(ESMWriter &esm) const mName.clear(); mModel.clear(); mIcon.clear(); - mIcon.clear(); mEnchant.clear(); mScript.clear(); } From 8e55eb800900fbce38a81f6003580c02c1f1484d Mon Sep 17 00:00:00 2001 From: Kevin Poitra Date: Wed, 28 May 2014 13:06:43 -0500 Subject: [PATCH 022/110] Fix some formatting. --- components/esm/loadclot.cpp | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 16101162ee..97ccb9099f 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -8,33 +8,34 @@ namespace ESM { unsigned int Clothing::sRecordId = REC_CLOT; -void Clothing::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CTDT", 12); + void Clothing::load(ESMReader &esm) + { + mModel = esm.getHNString("MODL"); + mName = esm.getHNOString("FNAM"); + esm.getHNT(mData, "CTDT", 12); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); - mParts.load(esm); + mParts.load(esm); - mEnchant = esm.getHNOString("ENAM"); -} -void Clothing::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CTDT", mData, 12); + mEnchant = esm.getHNOString("ENAM"); + } - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); + void Clothing::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CTDT", mData, 12); - mParts.save(esm); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOCString("ENAM", mEnchant); -} + mParts.save(esm); + + esm.writeHNOCString("ENAM", mEnchant); + } void Clothing::blank() { From 18e24a2007d5318c4f084d74091ffea9277bd6be Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 May 2014 21:08:20 +0200 Subject: [PATCH 023/110] Fix old savegames causing the save list to not fill properly (Error in framelistener: Object '$dynamic0' not found) Fixes #1357 --- apps/openmw/mwgui/savegamedialog.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 6048e49b41..2b064a603f 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -134,9 +134,12 @@ namespace MWGui else { // Find the localised name for this class from the store - const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get().find( + const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get().search( it->getSignature().mPlayerClassId); - className = class_->mName; + if (class_) + className = class_->mName; + else + className = "?"; // From an older savegame format that did not support custom classes properly. } title << " (Level " << it->getSignature().mPlayerLevel << " " << className << ")"; From 3f00f004263ba43aa340af28af69891b69e0f4fb Mon Sep 17 00:00:00 2001 From: Kevin Poitra Date: Wed, 28 May 2014 14:20:04 -0500 Subject: [PATCH 024/110] Remove some debug code. --- apps/openmw/mwsound/soundmanagerimp.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f7c5863800..e778f6e343 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -654,13 +654,6 @@ namespace MWSound { iterator->second.second += duration; } - - std::cout << mSoundPlayTime.size() << " sounds currently playing." << std::endl; - typedef SoundPlayingTimeMap::iterator it_ty; - for(it_ty iterator = mSoundPlayTime.begin(); iterator != mSoundPlayTime.end(); iterator++) - { - std::cout << iterator->first->getPlayType() << ": " << iterator->second.second << std::endl; - } } void SoundManager::update(float duration) From e9ab7c85c60ef0b32cecf8ac30896a489806df77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 May 2014 21:29:09 +0200 Subject: [PATCH 025/110] Fix exception when there are spaces in INI-imported color settings --- apps/openmw/mwworld/fallback.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index 569a6b50c2..c0b21b2ef2 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -41,8 +41,9 @@ namespace MWWorld unsigned int j=0; for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); } } From 41a04b9c651bd33189bc8574e0658d22a1081f6a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 May 2014 21:50:08 +0200 Subject: [PATCH 026/110] Slightly adjust menu button position --- apps/openmw/mwgui/mainmenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index bafd04311b..0c0ad53b24 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -229,7 +229,7 @@ namespace MWGui if (state == MWBase::StateManager::State_NoGame) { // Align with the background image - int bottomPadding=48; + int bottomPadding=24; mButtonBox->setCoord (mWidth/2 - maxwidth/2, mHeight - curH - bottomPadding, maxwidth, curH); } else From 18314b17075c3b1c699ce0a52a226d85c7387461 Mon Sep 17 00:00:00 2001 From: Kevin Poitra Date: Wed, 28 May 2014 14:56:50 -0500 Subject: [PATCH 027/110] We use spaces, not tabs. --- components/esm/loadclot.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 97ccb9099f..17ecdf3ae5 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -10,31 +10,31 @@ namespace ESM void Clothing::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CTDT", 12); + mModel = esm.getHNString("MODL"); + mName = esm.getHNOString("FNAM"); + esm.getHNT(mData, "CTDT", 12); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); - mParts.load(esm); + mParts.load(esm); - mEnchant = esm.getHNOString("ENAM"); + mEnchant = esm.getHNOString("ENAM"); } void Clothing::save(ESMWriter &esm) const { - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CTDT", mData, 12); + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CTDT", mData, 12); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); - mParts.save(esm); + mParts.save(esm); - esm.writeHNOCString("ENAM", mEnchant); + esm.writeHNOCString("ENAM", mEnchant); } void Clothing::blank() From 8516b837ff8376e7a5a7737fced5133c3a93ab16 Mon Sep 17 00:00:00 2001 From: Kevin Poitra Date: Wed, 28 May 2014 15:04:35 -0500 Subject: [PATCH 028/110] Revert "Started implementing sound time tracking so we can have NPCs' mouths move as they talk." This reverts commit b897080156825c577ce0fe5e476cc54fe35c6e8f. --- apps/openmw/mwbase/soundmanager.hpp | 3 --- apps/openmw/mwsound/soundmanagerimp.cpp | 34 +++---------------------- apps/openmw/mwsound/soundmanagerimp.hpp | 7 ----- 3 files changed, 3 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 68ec2cae8a..15739730ba 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -100,9 +100,6 @@ namespace MWBase virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0; ///< Stop an actor speaking - - virtual float getSoundPlayingTime(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0; - ///< Get the amount of time this sound has been playing. virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index e778f6e343..4a3093b10d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -244,7 +244,6 @@ namespace MWSound MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, 20.0f, 1500.0f, Play_Normal|Play_TypeVoice, 0); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); - mSoundPlayTime[sound] = std::make_pair(ptr, 0); } catch(std::exception &e) { @@ -262,9 +261,7 @@ namespace MWSound std::string filePath = "Sound/"+filename; MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice, 0); - MWWorld::Ptr ptr = MWWorld::Ptr(); - mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); - mSoundPlayTime[sound] = std::make_pair(ptr, 0); + mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); } catch(std::exception &e) { @@ -291,18 +288,6 @@ namespace MWSound ++snditer; } } - - float SoundManager::getSoundPlayingTime(const MWWorld::Ptr &ptr) - { - typedef SoundPlayingTimeMap::iterator iter_type; - for(iter_type iterator = mSoundPlayTime.begin(); iterator != mSoundPlayTime.end(); iterator++) - { - if (iterator->second.first == ptr) - return iterator->second.second; - } - - return 0; - } MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) @@ -617,12 +602,8 @@ namespace MWSound while(snditer != mActiveSounds.end()) { if(!snditer->first->isPlaying()) - { - mActiveSounds.erase(snditer); - mSoundPlayTime.erase(snditer->first); - snditer++; - } - else + mActiveSounds.erase(snditer++); + else { const MWWorld::Ptr &ptr = snditer->second.first; if(!ptr.isEmpty()) @@ -645,15 +626,6 @@ namespace MWSound ++snditer; } } - - // Update the total playing time for all sounds. - // This is primarily used for detecting amplitude for NPC mouth animation. - - typedef SoundPlayingTimeMap::iterator it_type; - for(it_type iterator = mSoundPlayTime.begin(); iterator != mSoundPlayTime.end(); iterator++) - { - iterator->second.second += duration; - } } void SoundManager::update(float duration) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 3f6490d851..ab9dcf7345 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -43,10 +43,6 @@ namespace MWSound typedef std::pair PtrIDPair; typedef std::map SoundMap; SoundMap mActiveSounds; - - typedef std::pair PtrFloatPair; - typedef std::map SoundPlayingTimeMap; - SoundPlayingTimeMap mSoundPlayTime; MWBase::SoundPtr mUnderwaterSound; @@ -108,9 +104,6 @@ namespace MWSound virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()); ///< Stop an actor speaking - - virtual float getSoundPlayingTime(const MWWorld::Ptr &reference=MWWorld::Ptr()); - ///< Get the amount of time this sound has been playing. virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder From c6a4506ac2c73321089c833f0c1c6594f20b63a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 May 2014 22:32:26 +0200 Subject: [PATCH 029/110] Make console error prefix slightly less technical (see https://bugs.openmw.org/issues/1194#note-2) --- apps/openmw/mwgui/console.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 811f93b486..57de35fc52 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -61,7 +61,7 @@ namespace MWGui } catch (const std::exception& error) { - printError (std::string ("An exception has been thrown: ") + error.what()); + printError (std::string ("Error: ") + error.what()); } return false; @@ -190,7 +190,7 @@ namespace MWGui } catch (const std::exception& error) { - printError (std::string ("An exception has been thrown: ") + error.what()); + printError (std::string ("Error: ") + error.what()); } } } From a5cfa8a04978e7de82aee4ff1795ed16d759990a Mon Sep 17 00:00:00 2001 From: Digmaster Date: Thu, 29 May 2014 01:52:41 -0400 Subject: [PATCH 030/110] Removes add behavior when pressing escape while waiting. --- apps/openmw/mwgui/waitdialog.cpp | 3 ++- apps/openmw/mwgui/windowbase.cpp | 5 +++++ apps/openmw/mwgui/windowbase.hpp | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 460663682e..9c7757af93 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -71,7 +71,8 @@ namespace MWGui void WaitDialog::exit() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); + if(!mProgressBar.isVisible()) //Only exit if not currently waiting + MWBase::Environment::get().getWindowManager()->popGuiMode(); } void WaitDialog::open() diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index c2515a6ded..cc18e6694e 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -23,6 +23,11 @@ void WindowBase::setVisible(bool visible) close(); } +bool WindowBase::isVisible() +{ + return mMainWidget->getVisible(); +} + void WindowBase::center() { // Centre dialog diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 471d8ac709..81073d419a 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -29,6 +29,8 @@ namespace MWGui virtual void exit() {} ///Sets the visibility of the window virtual void setVisible(bool visible); + ///Returns the visibility state of the window + virtual bool isVisible(); void center(); /** Event : Dialog finished, OK button clicked.\n From 03d71376555050ab40e51cf8ee0e13ec010a90ee Mon Sep 17 00:00:00 2001 From: Digmaster Date: Thu, 29 May 2014 06:19:25 -0400 Subject: [PATCH 031/110] Fixes issue with pressing f1 in QuickKey menu, removed transparency in GoodBye button --- apps/openmw/mwgui/dialogue.cpp | 2 -- apps/openmw/mwinput/inputmanagerimp.cpp | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 762c472d87..5e3f93ab96 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -518,11 +518,9 @@ namespace MWGui MyGUI::Button* byeButton; getWidget(byeButton, "ByeButton"); if(MWBase::Environment::get().getDialogueManager()->isInChoice()) { - byeButton->setAlpha(.2); byeButton->setEnabled(false); } else { - byeButton->setAlpha(1); byeButton->setEnabled(true); } } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 332c8f6a7c..34e026fd70 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -791,8 +791,12 @@ namespace MWInput if (!MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1) MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_QuickKeysMenu); - else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu) - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_QuickKeysMenu); + else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu) { + while(MyGUI::InputManager::getInstance().isModalAny()) { //Handle any open Modal windows + MWBase::Environment::get().getWindowManager()->getCurrentModal()->exit(); + } + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); //And handle the actual main window + } } void InputManager::activate() From 95b3026c7e7e633029699112a73ed6c4f28ef683 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 May 2014 16:34:05 +0200 Subject: [PATCH 032/110] Fix cells being listed twice in console autocompletion when using --skip-menu=0 and loading a game --- apps/openmw/mwworld/store.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 0f8ab86824..1dfb2f9766 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -685,12 +685,14 @@ namespace MWWorld typedef std::map::iterator IntIterator; //std::sort(mInt.begin(), mInt.end(), RecordCmp()); + mSharedInt.clear(); mSharedInt.reserve(mInt.size()); for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { mSharedInt.push_back(&(it->second)); } //std::sort(mExt.begin(), mExt.end(), ExtCmp()); + mSharedExt.clear(); mSharedExt.reserve(mExt.size()); for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { mSharedExt.push_back(&(it->second)); From a6788cfb0e2d398c46ad9270576aef9ac57264cd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 May 2014 16:44:50 +0200 Subject: [PATCH 033/110] Support lights that do not have a model (Fixes #1361) --- apps/openmw/mwclass/light.cpp | 6 +- apps/openmw/mwrender/animation.cpp | 34 +++++--- apps/openmw/mwrender/objects.cpp | 123 +++++++++++++++-------------- 3 files changed, 87 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index fd45ec8592..ef4549268f 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -50,9 +50,9 @@ namespace MWClass void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { const std::string model = getModel(ptr); - if(!model.empty()) { - renderingInterface.getObjects().insertModel(ptr, model); - } + + // Insert even if model is empty, so that the light is added + renderingInterface.getObjects().insertModel(ptr, model); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a2f901b26a..9ed4cb6d3c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1257,22 +1257,30 @@ Ogre::Vector3 Animation::getEnchantmentColor(MWWorld::Ptr item) ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model) : Animation(ptr, ptr.getRefData().getBaseNode()) { - setObjectRoot(model, false); + if (!model.empty()) + { + setObjectRoot(model, false); - Ogre::Vector3 extents = getWorldBounds().getSize(); - float size = std::max(std::max(extents.x, extents.y), extents.z); + Ogre::Vector3 extents = getWorldBounds().getSize(); + float size = std::max(std::max(extents.x, extents.y), extents.z); - bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && - Settings::Manager::getBool("limit small object distance", "Viewing distance"); - // do not fade out doors. that will cause holes and look stupid - if(ptr.getTypeName().find("Door") != std::string::npos) - small = false; + bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && + Settings::Manager::getBool("limit small object distance", "Viewing distance"); + // do not fade out doors. that will cause holes and look stupid + if(ptr.getTypeName().find("Door") != std::string::npos) + small = false; - float dist = small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0.0f; - Ogre::Vector3 col = getEnchantmentColor(ptr); - setRenderProperties(mObjectRoot, (mPtr.getTypeName() == typeid(ESM::Static).name()) ? - (small ? RV_StaticsSmall : RV_Statics) : RV_Misc, - RQG_Main, RQG_Alpha, dist, !ptr.getClass().getEnchantment(ptr).empty(), &col); + float dist = small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0.0f; + Ogre::Vector3 col = getEnchantmentColor(ptr); + setRenderProperties(mObjectRoot, (mPtr.getTypeName() == typeid(ESM::Static).name()) ? + (small ? RV_StaticsSmall : RV_Statics) : RV_Misc, + RQG_Main, RQG_Alpha, dist, !ptr.getClass().getEnchantment(ptr).empty(), &col); + } + else + { + // No model given. Create an object root anyway, so that lights can be added to it if needed. + mObjectRoot = NifOgre::ObjectScenePtr (new NifOgre::ObjectScene(mInsert->getCreator())); + } } void ObjectAnimation::addLight(const ESM::Light *light) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3101100f2b..7953a31178 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -79,79 +79,82 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh) std::auto_ptr anim(new ObjectAnimation(ptr, mesh)); - Ogre::AxisAlignedBox bounds = anim->getWorldBounds(); - Ogre::Vector3 extents = bounds.getSize(); - extents *= ptr.getRefData().getBaseNode()->getScale(); - float size = std::max(std::max(extents.x, extents.y), extents.z); - - bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && - Settings::Manager::getBool("limit small object distance", "Viewing distance"); - // do not fade out doors. that will cause holes and look stupid - if(ptr.getTypeName().find("Door") != std::string::npos) - small = false; - - if (mBounds.find(ptr.getCell()) == mBounds.end()) - mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; - mBounds[ptr.getCell()].merge(bounds); - if(ptr.getTypeName() == typeid(ESM::Light).name()) anim->addLight(ptr.get()->mBase); - if(ptr.getTypeName() == typeid(ESM::Static).name() && - Settings::Manager::getBool("use static geometry", "Objects") && - anim->canBatch()) + if (!mesh.empty()) { - Ogre::StaticGeometry* sg = 0; + Ogre::AxisAlignedBox bounds = anim->getWorldBounds(); + Ogre::Vector3 extents = bounds.getSize(); + extents *= ptr.getRefData().getBaseNode()->getScale(); + float size = std::max(std::max(extents.x, extents.y), extents.z); - if (small) + bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && + Settings::Manager::getBool("limit small object distance", "Viewing distance"); + // do not fade out doors. that will cause holes and look stupid + if(ptr.getTypeName().find("Door") != std::string::npos) + small = false; + + if (mBounds.find(ptr.getCell()) == mBounds.end()) + mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; + mBounds[ptr.getCell()].merge(bounds); + + if(ptr.getTypeName() == typeid(ESM::Static).name() && + Settings::Manager::getBool("use static geometry", "Objects") && + anim->canBatch()) { - if(mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) - { - uniqueID = uniqueID+1; - sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID)); - sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); - mStaticGeometrySmall[ptr.getCell()] = sg; + Ogre::StaticGeometry* sg = 0; - sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); + if (small) + { + if(mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) + { + uniqueID = uniqueID+1; + sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID)); + sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); + mStaticGeometrySmall[ptr.getCell()] = sg; + + sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); + } + else + sg = mStaticGeometrySmall[ptr.getCell()]; } else - sg = mStaticGeometrySmall[ptr.getCell()]; - } - else - { - if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end()) { - uniqueID = uniqueID+1; - sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID)); - sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); - mStaticGeometry[ptr.getCell()] = sg; + if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end()) + { + uniqueID = uniqueID+1; + sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID)); + sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); + mStaticGeometry[ptr.getCell()] = sg; + } + else + sg = mStaticGeometry[ptr.getCell()]; } + + // This specifies the size of a single batch region. + // If it is set too high: + // - there will be problems choosing the correct lights + // - the culling will be more inefficient + // If it is set too low: + // - there will be too many batches. + if(ptr.getCell()->isExterior()) + sg->setRegionDimensions(Ogre::Vector3(2048,2048,2048)); else - sg = mStaticGeometry[ptr.getCell()]; + sg->setRegionDimensions(Ogre::Vector3(1024,1024,1024)); + + sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); + + sg->setCastShadows(true); + + sg->setRenderQueueGroup(RQG_Main); + + anim->fillBatch(sg); + /* TODO: We could hold on to this and just detach it from the scene graph, so if the Ptr + * ever needs to modify we can reattach it and rebuild the StaticGeometry object without + * it. Would require associating the Ptr with the StaticGeometry. */ + anim.reset(); } - - // This specifies the size of a single batch region. - // If it is set too high: - // - there will be problems choosing the correct lights - // - the culling will be more inefficient - // If it is set too low: - // - there will be too many batches. - if(ptr.getCell()->isExterior()) - sg->setRegionDimensions(Ogre::Vector3(2048,2048,2048)); - else - sg->setRegionDimensions(Ogre::Vector3(1024,1024,1024)); - - sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); - - sg->setCastShadows(true); - - sg->setRenderQueueGroup(RQG_Main); - - anim->fillBatch(sg); - /* TODO: We could hold on to this and just detach it from the scene graph, so if the Ptr - * ever needs to modify we can reattach it and rebuild the StaticGeometry object without - * it. Would require associating the Ptr with the StaticGeometry. */ - anim.reset(); } if(anim.get() != NULL) From 3b3b53d6655be02f9f29671944853931e692ece5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 May 2014 17:21:35 +0200 Subject: [PATCH 034/110] Support animated main menus (menu_background.bik) Closes #1362 --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 70 +++++++++++++++++++++++--- apps/openmw/mwgui/mainmenu.hpp | 8 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d33e5300ec..3647f8ccb0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -137,6 +137,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) } // update GUI + MWBase::Environment::get().getWindowManager()->onFrame(frametime); if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { @@ -145,7 +146,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); - MWBase::Environment::get().getWindowManager()->onFrame(frametime); MWBase::Environment::get().getWindowManager()->update(); } } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 0c0ad53b24..53ce8f488f 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -1,5 +1,7 @@ #include "mainmenu.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -16,6 +18,7 @@ #include "confirmationdialog.hpp" #include "imagebutton.hpp" #include "backgroundimage.hpp" +#include "videowidget.hpp" namespace MWGui { @@ -25,6 +28,7 @@ namespace MWGui , mButtonBox(0), mWidth (w), mHeight (h) , mSaveGameDialog(NULL) , mBackground(NULL) + , mVideo(NULL) { getWidget(mVersionText, "VersionText"); std::stringstream sstream; @@ -42,6 +46,8 @@ namespace MWGui std::string output = sstream.str(); mVersionText->setCaption(output); + mHasAnimatedMenu = (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("video\\menu_background.bik")); + updateMenu(); } @@ -134,14 +140,66 @@ namespace MWGui void MainMenu::showBackground(bool show) { - if (show && !mBackground) + if (mVideo && !show) { - mBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, - MyGUI::Align::Stretch, "Menu"); - mBackground->setBackgroundImage("textures\\menu_morrowind.dds"); + MyGUI::Gui::getInstance().destroyWidget(mVideo); + mVideo = NULL; } - if (mBackground) - mBackground->setVisible(show); + if (mBackground && !show) + { + MyGUI::Gui::getInstance().destroyWidget(mBackground); + mBackground = NULL; + } + + if (!show) + return; + + if (mHasAnimatedMenu) + { + if (!mVideo) + { + // Use black background to correct aspect ratio + mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, + MyGUI::Align::Default, "Menu"); + mVideoBackground->setImageTexture("black.png"); + + mVideo = mVideoBackground->createWidget("ImageBox", 0,0,1,1, + MyGUI::Align::Stretch, "Menu"); + + mVideo->playVideo("video\\menu_background.bik", false); + } + + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + int screenWidth = viewSize.width; + int screenHeight = viewSize.height; + mVideoBackground->setSize(screenWidth, screenHeight); + + double imageaspect = static_cast(mVideo->getVideoWidth())/mVideo->getVideoHeight(); + + int leftPadding = std::max(0.0, (screenWidth - screenHeight * imageaspect) / 2); + int topPadding = std::max(0.0, (screenHeight - screenWidth / imageaspect) / 2); + + mVideo->setCoord(leftPadding, topPadding, + screenWidth - leftPadding*2, screenHeight - topPadding*2); + + mVideo->setVisible(true); + } + else + { + if (!mBackground) + { + mBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, + MyGUI::Align::Stretch, "Menu"); + mBackground->setBackgroundImage("textures\\menu_morrowind.dds"); + } + mBackground->setVisible(true); + } + } + + void MainMenu::update(float dt) + { + if (mVideo) + mVideo->update(); } void MainMenu::updateMenu() diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index c274425367..ccd8df4b0b 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -9,12 +9,15 @@ namespace MWGui class ImageButton; class BackgroundImage; class SaveGameDialog; + class VideoWidget; class MainMenu : public OEngine::GUI::Layout { int mWidth; int mHeight; + bool mHasAnimatedMenu; + public: MainMenu(int w, int h); @@ -24,6 +27,8 @@ namespace MWGui virtual void setVisible (bool visible); + void update(float dt); + private: MyGUI::Widget* mButtonBox; @@ -31,6 +36,9 @@ namespace MWGui BackgroundImage* mBackground; + MyGUI::ImageBox* mVideoBackground; + VideoWidget* mVideo; // For animated main menus + std::map mButtons; void onButtonClicked (MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a42dca79e5..53752fc990 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -713,6 +713,8 @@ namespace MWGui mToolTips->onFrame(frameDuration); + mMenu->update(frameDuration); + if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_NoGame) return; From ae5063277401901eedf12d8026ae6e90ed2118bd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 May 2014 18:08:40 +0200 Subject: [PATCH 035/110] implemented cell and reference saving int OpenCS --- apps/opencs/model/doc/saving.cpp | 1 + apps/opencs/model/doc/savingstages.cpp | 103 ++++++++++++++++++++++++- apps/opencs/model/doc/savingstages.hpp | 16 ++++ apps/opencs/model/doc/savingstate.cpp | 2 +- apps/opencs/model/doc/savingstate.hpp | 2 +- 5 files changed, 121 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 337784765c..45b53f4fe8 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -67,6 +67,7 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new CollectionReferencesStage (mDocument, mState)); + appendStage (new WriteCellCollectionStage (mDocument, mState)); // close file and clean up appendStage (new CloseSaveStage (mState)); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index fc35e21cd1..4846d6c732 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -246,12 +246,113 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages) record.mState==CSMWorld::RecordBase::State_Modified || record.mState==CSMWorld::RecordBase::State_ModifiedOnly) { - mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mId)].push_back (i); + mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mCell)] + .push_back (i); } } } +CSMDoc::WriteCellCollectionStage::WriteCellCollectionStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::WriteCellCollectionStage::setup() +{ + return mDocument.getData().getCells().getSize(); +} + +void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) +{ + const CSMWorld::Record& cell = + mDocument.getData().getCells().getRecord (stage); + + std::map >::const_iterator references = + mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId)); + + if (cell.mState==CSMWorld::RecordBase::State_Modified || + cell.mState==CSMWorld::RecordBase::State_ModifiedOnly || + references!=mState.getSubRecords().end()) + { + bool interior = cell.get().mId.substr (0, 1)!="#"; + + // write cell data + mState.getWriter().startRecord (cell.mModified.sRecordId); + + mState.getWriter().writeHNOCString ("NAME", cell.get().mName); + + ESM::Cell cell2 = cell.get(); + + if (interior) + cell2.mData.mFlags |= ESM::Cell::Interior; + else + { + cell2.mData.mFlags &= ~ESM::Cell::Interior; + + std::istringstream stream (cell.get().mId.c_str()); + char ignore; + stream >> ignore >> cell2.mData.mX >> cell2.mData.mY; + } + cell2.save (mState.getWriter()); + + // write references + if (references!=mState.getSubRecords().end()) + { + // first pass: find highest RefNum + int lastRefNum = -1; + + for (std::vector::const_iterator iter (references->second.begin()); + iter!=references->second.end(); ++iter) + { + const CSMWorld::Record& ref = + mDocument.getData().getReferences().getRecord (*iter); + + if (ref.get().mRefNum.mContentFile==0 && ref.get().mRefNum.mIndex>lastRefNum) + lastRefNum = ref.get().mRefNum.mIndex; + } + + // second pass: write + for (std::vector::const_iterator iter (references->second.begin()); + iter!=references->second.end(); ++iter) + { + const CSMWorld::Record& ref = + mDocument.getData().getReferences().getRecord (*iter); + + if (ref.mState==CSMWorld::RecordBase::State_Modified || + ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + if (ref.get().mRefNum.mContentFile==-2) + { + if (lastRefNum>=0xffffff) + throw std::runtime_error ( + "RefNums exhausted in cell: " + cell.get().mId); + + ESM::CellRef ref2 = ref.get(); + ref2.mRefNum.mContentFile = 0; + ref2.mRefNum.mIndex = ++lastRefNum; + + ref2.save (mState.getWriter()); + } + else + ref.get().save (mState.getWriter()); + } + else if (ref.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } + } + } + + mState.getWriter().endRecord (cell.mModified.sRecordId); + } + else if (cell.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } +} + + CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state) : mState (state) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 653f3a9570..dcb1a86500 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -182,6 +182,22 @@ namespace CSMDoc ///< Messages resulting from this stage will be appended to \a messages. }; + class WriteCellCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + WriteCellCollectionStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + class CloseSaveStage : public Stage { SavingState& mState; diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index 294f830496..1d93a95f59 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -64,7 +64,7 @@ bool CSMDoc::SavingState::isProjectFile() const return mProjectFile; } -std::map > CSMDoc::SavingState::getSubRecords() +std::map >& CSMDoc::SavingState::getSubRecords() { return mSubRecords; } \ No newline at end of file diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp index 64085bf0d5..3abb724dea 100644 --- a/apps/opencs/model/doc/savingstate.hpp +++ b/apps/opencs/model/doc/savingstate.hpp @@ -48,7 +48,7 @@ namespace CSMDoc bool isProjectFile() const; ///< Currently saving project file? (instead of content file) - std::map > getSubRecords(); + std::map >& getSubRecords(); }; From 6a882e1e8d0113d5a619af37e98519600fd47db4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 May 2014 17:53:54 +0200 Subject: [PATCH 036/110] Don't show hidden factions in StatsWindow (e.g. Nerevarine) --- apps/openmw/mwgui/statswindow.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 6ae44e3146..246ade7bf2 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -454,20 +454,30 @@ namespace MWGui if (!mFactions.empty()) { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWMechanics::NpcStats &PCstats = player.getClass().getNpcStats(player); const std::set &expelled = PCstats.getExpelled(); - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); + bool firstFaction=true; FactionList::const_iterator end = mFactions.end(); for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) { const ESM::Faction *faction = store.get().find(it->first); + if (faction->mData.mIsHidden == 1) + continue; + + if (firstFaction) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); + + firstFaction = false; + } + MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); std::string text; From 50a72ed710bbe0261752123232bbb9151e00987f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 May 2014 17:54:45 +0200 Subject: [PATCH 037/110] Fix ghosts in Cavern Of The Incarnate having -1 health --- components/esm/loadnpc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 08f678b45f..fd3e45bdc3 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -82,7 +82,7 @@ struct NPC char mSkills[Skill::Length]; char mReputation; - short mHealth, mMana, mFatigue; + unsigned short mHealth, mMana, mFatigue; char mDisposition, mFactionID, mRank; char mUnknown; int mGold; From afc1fa49f617c55f890504d795f754de8b4b0fad Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 May 2014 20:35:57 +0200 Subject: [PATCH 038/110] Use mouse release instead of press for binding actions Resolves difficulties binding actions to mouse buttons (Fixes #1364) --- extern/oics/ICSInputControlSystem_mouse.cpp | 23 ++++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index be18ebbc0e..fb11005281 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -333,11 +333,6 @@ namespace ICS } } } - else if(mDetectingBindingListener) - { - mDetectingBindingListener->mouseButtonBindingDetected(this, - mDetectingBindingControl, btn, mDetectingBindingDirection); - } } } @@ -345,11 +340,19 @@ namespace ICS { if(mActive) { - ControlsButtonBinderMapType::const_iterator it = mControlsMouseButtonBinderMap.find((int)btn); - if(it != mControlsMouseButtonBinderMap.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } + if (!mDetectingBindingControl) + { + ControlsButtonBinderMapType::const_iterator it = mControlsMouseButtonBinderMap.find((int)btn); + if(it != mControlsMouseButtonBinderMap.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + else if(mDetectingBindingListener) + { + mDetectingBindingListener->mouseButtonBindingDetected(this, + mDetectingBindingControl, btn, mDetectingBindingDirection); + } } } From b81c7d05c60bdaf9029e40cb4632ed1695d72738 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 29 May 2014 23:16:36 +0200 Subject: [PATCH 039/110] Remove CG shaders from settings window (not fully supported on non-nvidia cards, amd profiles have an instruction limit making them useless) Can still be used by editing the config file, however. --- apps/openmw/mwgui/settingswindow.cpp | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 78adecd3ef..4b8f3ab805 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -73,17 +73,6 @@ namespace return (Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") != std::string::npos) ? "glsl" : "hlsl"; } - bool cgAvailable () - { - Ogre::Root::PluginInstanceList list = Ogre::Root::getSingleton ().getInstalledPlugins (); - for (Ogre::Root::PluginInstanceList::const_iterator it = list.begin(); it != list.end(); ++it) - { - if ((*it)->getName() == "Cg Program Manager") - return true; - } - return false; - } - const char* checkButtonType = "CheckButton"; const char* sliderType = "Slider"; @@ -366,12 +355,7 @@ namespace MWGui void SettingsWindow::onShaderModeToggled(MyGUI::Widget* _sender) { std::string val = static_cast(_sender)->getCaption(); - if (val == "cg") - { - val = hlslGlsl(); - } - else if (cgAvailable ()) - val = "cg"; + val = hlslGlsl(); static_cast(_sender)->setCaption(val); From 4778c27548cf59715ccaf8d917bdc76b5fe9658a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 30 May 2014 10:18:05 +0200 Subject: [PATCH 040/110] silenced two warnings --- apps/opencs/model/tools/referenceablecheck.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 488081f46f..1816d0808a 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -621,12 +621,6 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( } else { - if (npc.mNpdt52.mMana < 0) - messages.push_back (std::make_pair (id, npc.mId + " mana has negative value")); - - if (npc.mNpdt52.mFatigue < 0) - messages.push_back (std::make_pair (id, npc.mId + " fatigue has negative value")); - if (npc.mNpdt52.mAgility == 0) messages.push_back (std::make_pair (id, npc.mId + " agility has zero value")); From 11ce093a9e30f74a61b6371d017031227fcb20c7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 30 May 2014 18:46:18 +1000 Subject: [PATCH 041/110] Fix crashes caused when terrain materials don't get created (e.g. due to cg shader bug on Windows/D3D9). Should resolve Bug #1284. --- components/terrain/chunk.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index 0820dcc732..7ecafda5e3 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -55,6 +55,9 @@ namespace Terrain mVertexData->vertexBufferBinding->setBinding(2, uvBuffer); mVertexData->vertexBufferBinding->setBinding(3, colourBuffer); + // Assign a default material in case terrain material fails to be created + mMaterial = Ogre::MaterialManager::getSingleton().getByName("BaseWhite"); + mIndexData = OGRE_NEW Ogre::IndexData(); mIndexData->indexStart = 0; } @@ -67,11 +70,13 @@ namespace Terrain Chunk::~Chunk() { + if (!mMaterial.isNull()) + { #if TERRAIN_USE_SHADER - sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); + sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); #endif - Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); - + Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); + } OGRE_DELETE mVertexData; OGRE_DELETE mIndexData; } From ac77b07e299edd5a4a576dd24c1ccea9bcaed7ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 30 May 2014 11:18:06 +0200 Subject: [PATCH 042/110] Small fix for menu background --- apps/openmw/mwgui/mainmenu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 53ce8f488f..628f00136d 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -142,7 +142,8 @@ namespace MWGui { if (mVideo && !show) { - MyGUI::Gui::getInstance().destroyWidget(mVideo); + MyGUI::Gui::getInstance().destroyWidget(mVideoBackground); + mVideoBackground = NULL; mVideo = NULL; } if (mBackground && !show) From 8761aa579563e092d62ce7aea456213699f38a3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 30 May 2014 11:22:44 +0200 Subject: [PATCH 043/110] Loop main menu video when it's finished playing --- apps/openmw/mwgui/mainmenu.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 628f00136d..b5cd61f59c 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -200,7 +200,13 @@ namespace MWGui void MainMenu::update(float dt) { if (mVideo) - mVideo->update(); + { + if (!mVideo->update()) + { + // If finished playing, start again + mVideo->playVideo("video\\menu_background.bik", 0); + } + } } void MainMenu::updateMenu() From d26f756c53c263d080fcc62fd7d673d2798d667c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 30 May 2014 14:52:47 +0200 Subject: [PATCH 044/110] Fix several edit boxes not receiving mouse input --- files/mygui/openmw_console.skin.xml | 2 +- files/mygui/openmw_edit.skin.xml | 17 +++++------------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/files/mygui/openmw_console.skin.xml b/files/mygui/openmw_console.skin.xml index 470451a0ed..c6d60231ad 100644 --- a/files/mygui/openmw_console.skin.xml +++ b/files/mygui/openmw_console.skin.xml @@ -13,8 +13,8 @@ - + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index b10854b19e..50f37dbfc3 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -10,14 +10,12 @@ - - - - - - + + + + @@ -26,11 +24,6 @@ - - - - - @@ -41,7 +34,7 @@ - + From 6cc6172779e4df88da9accf17de1facfe04f6c03 Mon Sep 17 00:00:00 2001 From: Fil Krynicki Date: Fri, 30 May 2014 15:12:57 -0400 Subject: [PATCH 045/110] Update in response to comments. It turns out I was erroneous about problem (1) in my original commit message. I thought that in an edge case the OpenMWGUI could both handle the same event on the frame the GUI was closed. My test for this was broken. So after brainstorming many possible unsatisfactory solutions to this event handling, it's luckily not necessary! --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9c263e52d2..344da5be1a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -510,11 +510,9 @@ namespace MWInput OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); - bool passToBinder = true; if (kc != OIS::KC_UNASSIGNED) - passToBinder = !MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - if(passToBinder) - mInputBinder->keyPressed (arg); + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + mInputBinder->keyPressed (arg); } void InputManager::textInput(const SDL_TextInputEvent &arg) From 4f4a37896e3c88831db8329e240ed127adbc2408 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Fri, 30 May 2014 22:37:13 -0500 Subject: [PATCH 046/110] Check if player's CellStore is non-NULL before configuring fog. This prevents an assertion fail in getCell() when changing the view distance while in the main menu. --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 882a3d09bf..8a22c63c64 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -751,7 +751,8 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec } else if (it->second == "max viewing distance" && it->first == "Viewing distance") { - if (!MWBase::Environment::get().getWorld()->isCellExterior() && !MWBase::Environment::get().getWorld()->isCellQuasiExterior()) + if (!MWBase::Environment::get().getWorld()->isCellExterior() && !MWBase::Environment::get().getWorld()->isCellQuasiExterior() + && MWBase::Environment::get().getWorld()->getPlayerPtr().mCell) configureFog(*MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()); } else if (it->first == "Video" && ( From 16ac6e7aacc072e61ac481dd5ec99d9ffb4887be Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 May 2014 00:36:37 +0200 Subject: [PATCH 047/110] Merge DialInfo objects by subrecord instead of overwriting the object Fixes #1360 --- apps/openmw/mwworld/esmstore.cpp | 13 ++++---- components/esm/loaddial.cpp | 55 +++++++++++++++++++++----------- components/esm/loaddial.hpp | 3 +- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 03d928d2a5..cd6cc4a165 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -68,13 +68,12 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) if (it == mStores.end()) { if (n.val == ESM::REC_INFO) { - std::string id = esm.getHNOString("INAM"); - if (dialogue) { - ESM::DialInfo info; - info.mId = id; - info.load(esm); - dialogue->addInfo(info, esm.getIndex() != 0); - } else { + if (dialogue) + { + dialogue->readInfo(esm, esm.getIndex() != 0); + } + else + { std::cerr << "error: info record without dialog" << std::endl; esm.skipRecord(); } diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index ee7ddbfadf..92077b572f 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -40,21 +40,21 @@ void Dialogue::save(ESMWriter &esm) const } } - void Dialogue::blank() - { - mInfo.clear(); - } - -void Dialogue::addInfo(const ESM::DialInfo& info, bool merge) +void Dialogue::blank() { - if (!merge || mInfo.empty() || info.mNext.empty()) + mInfo.clear(); +} + +void Dialogue::readInfo(ESMReader &esm, bool merge) +{ + const std::string& id = esm.getHNOString("INAM"); + + if (!merge || mInfo.empty()) { - mLookup[info.mId] = mInfo.insert(mInfo.end(), info); - return; - } - if (info.mPrev.empty()) - { - mLookup[info.mId] = mInfo.insert(mInfo.begin(), info); + ESM::DialInfo info; + info.mId = id; + info.load(esm); + mLookup[id] = mInfo.insert(mInfo.end(), info); return; } @@ -62,11 +62,30 @@ void Dialogue::addInfo(const ESM::DialInfo& info, bool merge) std::map::iterator lookup; - lookup = mLookup.find(info.mId); + lookup = mLookup.find(id); if (lookup != mLookup.end()) { it = lookup->second; - *it = info; + + // Merge with existing record. Only the subrecords that are present in + // the new record will be overwritten. + it->load(esm); + return; + } + + // New record + ESM::DialInfo info; + info.mId = id; + info.load(esm); + + if (info.mNext.empty()) + { + mLookup[id] = mInfo.insert(mInfo.end(), info); + return; + } + if (info.mPrev.empty()) + { + mLookup[id] = mInfo.insert(mInfo.begin(), info); return; } @@ -75,7 +94,7 @@ void Dialogue::addInfo(const ESM::DialInfo& info, bool merge) { it = lookup->second; - mLookup[info.mId] = mInfo.insert(++it, info); + mLookup[id] = mInfo.insert(++it, info); return; } @@ -84,11 +103,11 @@ void Dialogue::addInfo(const ESM::DialInfo& info, bool merge) { it = lookup->second; - mLookup[info.mId] = mInfo.insert(it, info); + mLookup[id] = mInfo.insert(it, info); return; } - std::cerr << "Failed to insert info " << info.mId << std::endl; + std::cerr << "Failed to insert info " << id << std::endl; } } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 6ec5527f9f..fd46ad2109 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -47,8 +47,9 @@ struct Dialogue void load(ESMReader &esm); void save(ESMWriter &esm) const; + /// Read the next info record /// @param merge Merge with existing list, or just push each record to the end of the list? - void addInfo (const ESM::DialInfo& info, bool merge); + void readInfo (ESM::ESMReader& esm, bool merge); void blank(); ///< Set record to default state (does not touch the ID and does not change the type). From de7fcf0beba837bd1ae9071516d23229bfb0cf72 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 May 2014 13:24:13 +0200 Subject: [PATCH 048/110] Fix unhandled edge case in TradeItemModel with items that are able to stack, but are not currently stacked (e.g. after repairing a damaged item) Fixes #1368 --- apps/openmw/mwgui/itemmodel.cpp | 4 ++-- apps/openmw/mwgui/tradeitemmodel.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 55317724e3..59b54e171d 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -100,7 +100,7 @@ namespace MWGui for (size_t i=0; igetItemCount(); ++i) { const ItemStack& item = mSourceModel->getItem(i); - if (item == itemToSearch) + if (item.mBase == itemToSearch.mBase) return i; } return -1; @@ -112,7 +112,7 @@ namespace MWGui for (size_t i=0; istacks(item)) + if (it->mBase == item.mBase) { it->mCount += item.mCount; found = true; @@ -52,7 +52,7 @@ namespace MWGui bool found = false; for (; it != out.end(); ++it) { - if (it->stacks(item)) + if (it->mBase == item.mBase) { if (it->mCount < count) throw std::runtime_error("Not enough borrowed items to return"); @@ -114,7 +114,7 @@ namespace MWGui size_t i=0; for (; igetItemCount(); ++i) { - if (it->stacks(sourceModel->getItem(i))) + if (it->mBase == sourceModel->getItem(i).mBase) break; } if (i == sourceModel->getItemCount()) @@ -182,7 +182,7 @@ namespace MWGui std::vector::iterator it = mBorrowedFromUs.begin(); for (; it != mBorrowedFromUs.end(); ++it) { - if (it->stacks(item)) + if (it->mBase == item.mBase) { if (item.mCount < it->mCount) throw std::runtime_error("Lent more items than present"); From a1bdf20958b11eb1f7dc56fe5a3b826aa19c3f9e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 May 2014 13:53:36 +0200 Subject: [PATCH 049/110] Make trade balance label editable --- apps/openmw/mwgui/tradewindow.cpp | 15 +++++++++++++++ apps/openmw/mwgui/tradewindow.hpp | 3 ++- files/mygui/openmw_trade_window.layout | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index cb7f3b0bd4..03c73d1716 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -74,6 +74,8 @@ namespace MWGui mDecreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonPressed); mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); + mTotalBalance->eventEditTextChange += MyGUI::newDelegate(this, &TradeWindow::onBalanceEdited); + setCoord(400, 0, 400, 300); } @@ -410,6 +412,19 @@ namespace MWGui mBalanceButtonsState = BBS_None; } + void TradeWindow::onBalanceEdited(MyGUI::EditBox *_sender) + { + try + { + unsigned int count = boost::lexical_cast(_sender->getCaption()); + mCurrentBalance = count * (mCurrentBalance >= 0 ? 1 : -1); + updateLabels(); + } + catch (std::bad_cast&) + { + } + } + void TradeWindow::onIncreaseButtonTriggered() { if(mCurrentBalance<=-1) mCurrentBalance -= 1; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 420a642e81..cc70f1ae96 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -55,7 +55,7 @@ namespace MWGui MyGUI::Button* mIncreaseButton; MyGUI::Button* mDecreaseButton; MyGUI::TextBox* mTotalBalanceLabel; - MyGUI::TextBox* mTotalBalance; + MyGUI::EditBox* mTotalBalance; MyGUI::Widget* mBottomPane; @@ -91,6 +91,7 @@ namespace MWGui void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onBalanceEdited(MyGUI::EditBox* _sender); void onIncreaseButtonTriggered(); void onDecreaseButtonTriggered(); diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 8a1be496f4..cb00d7d50c 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -44,7 +44,7 @@ - + From 865486604f702b9468b51047474b3978b9031fce Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 May 2014 13:57:07 +0200 Subject: [PATCH 050/110] Make trade disposition changes temporary again, as in vanilla --- apps/openmw/mwbase/dialoguemanager.hpp | 2 ++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 10 ---------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 ++ 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index cab6809aa0..dfb002cfc0 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -61,6 +61,8 @@ namespace MWBase virtual void persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; + + /// @note This change is temporary and gets discarded when dialogue ends. virtual void applyDispositionChange (int delta) = 0; virtual int countSavedGameRecords() const = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index b6cef2fe7f..57681b7fb0 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -560,17 +560,7 @@ namespace MWDialogue void DialogueManager::applyDispositionChange(int delta) { - int oldTemp = mTemporaryDispositionChange; mTemporaryDispositionChange += delta; - // don't allow increasing beyond 100 or decreasing below 0 - int curDisp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); - if (curDisp + mTemporaryDispositionChange < 0) - mTemporaryDispositionChange = -curDisp; - else if (curDisp + mTemporaryDispositionChange > 100) - mTemporaryDispositionChange = 100 - curDisp; - - int diff = mTemporaryDispositionChange - oldTemp; - mPermanentDispositionChange += diff; } bool DialogueManager::checkServiceRefused() diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index db0b78d594..94f8f3ec1a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -84,6 +84,8 @@ namespace MWDialogue virtual void persuade (int type); virtual int getTemporaryDispositionChange () const; + + /// @note This change is temporary and gets discarded when dialogue ends. virtual void applyDispositionChange (int delta); virtual int countSavedGameRecords() const; From 0f1b39bca46460e420e608180d12bfe6266e3485 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 May 2014 18:28:00 +0200 Subject: [PATCH 051/110] Fix trade exploit Using the Max Sale button it was possible to "invert" the buying/selling state. --- apps/openmw/mwgui/tradewindow.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 03c73d1716..73f48c8cf4 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -302,6 +302,9 @@ namespace MWGui } } + // Is the player buying? + bool buying = (mCurrentMerchantOffer < 0); + if(mCurrentBalance > mCurrentMerchantOffer) { //if npc is a creature: reject (no haggle) @@ -315,7 +318,7 @@ namespace MWGui int a = abs(mCurrentMerchantOffer); int b = abs(mCurrentBalance); int d = 0; - if (mCurrentBalance<0) + if (buying) d = int(100 * (a - b) / a); else d = int(100 * (b - a) / a); @@ -336,7 +339,7 @@ namespace MWGui float pcTerm = (clampedDisposition - 50 + a1 + b1 + c1) * playerStats.getFatigueTerm(); float npcTerm = (d1 + e1 + f1) * sellerStats.getFatigueTerm(); float x = gmst.find("fBargainOfferMulti")->getFloat() * d + gmst.find("fBargainOfferBase")->getFloat(); - if (mCurrentBalance<0) + if (buying) x += abs(int(pcTerm - npcTerm)); else x += abs(int(npcTerm - pcTerm)); From 7c9c0830a9614c4b5f48c179228fa62761a65ed6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 May 2014 19:49:48 +0200 Subject: [PATCH 052/110] Fix errors due to BaseWhite material being removed --- components/terrain/chunk.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index 7ecafda5e3..57db151249 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -56,7 +57,11 @@ namespace Terrain mVertexData->vertexBufferBinding->setBinding(3, colourBuffer); // Assign a default material in case terrain material fails to be created - mMaterial = Ogre::MaterialManager::getSingleton().getByName("BaseWhite"); + // Since we are removing this material in the destructor, it must be cloned from BaseWhite + // so the original always stays available. + static int materialCount=0; + mMaterial = Ogre::MaterialManager::getSingleton().getByName("BaseWhite") + ->clone("BaseWhite"+Ogre::StringConverter::toString(++materialCount)); mIndexData = OGRE_NEW Ogre::IndexData(); mIndexData->indexStart = 0; From dcc0e2d1054178aea10ee51d151b1c4200c13af4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Jun 2014 00:21:14 +0200 Subject: [PATCH 053/110] When dialogue goodbye is forced, allow using either the red link or the goodbye button Fixes #1373 --- apps/openmw/mwgui/dialogue.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 5e3f93ab96..441e31e327 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -271,7 +271,8 @@ namespace MWGui void DialogueWindow::exit() { - if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + && !mGoodbye) return; MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } @@ -517,7 +518,7 @@ namespace MWGui MyGUI::Button* byeButton; getWidget(byeButton, "ByeButton"); - if(MWBase::Environment::get().getDialogueManager()->isInChoice()) { + if(MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye) { byeButton->setEnabled(false); } else { From cd131e7f867fbc0c9a8d28259960dab40a23f248 Mon Sep 17 00:00:00 2001 From: Fil Krynicki Date: Sat, 31 May 2014 19:51:21 -0400 Subject: [PATCH 054/110] 1196/1217 fix Fixes an issue where inputs could be processed by both GUI and gameplay systems. An enabled/disable has been added to OIS channels, and OpenMW now disables player gameplay hotkeys when a GUI element has focus. GUI hotkeys are left enabled. --- apps/openmw/mwinput/inputmanagerimp.cpp | 19 ++++++++++++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ extern/oics/ICSChannel.cpp | 13 +++++++++++-- extern/oics/ICSChannel.h | 6 +++++- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 344da5be1a..73399ee788 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -160,6 +160,20 @@ namespace MWInput delete mInputManager; } + void InputManager::setPlayerControlsEnabled(bool enabled) + { + int nPlayerChannels = 15; + int playerChannels[] = {A_Activate, A_AutoMove, A_AlwaysRun, A_ToggleWeapon, + A_ToggleSpell, A_Rest, A_QuickKey1, A_QuickKey2, + A_QuickKey3, A_QuickKey4, A_QuickKey5, A_QuickKey6, + A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10}; + + for(int i = 0; i < nPlayerChannels; i++) { + int pc = playerChannels[i]; + mInputBinder->getChannel(pc)->setEnabled(enabled); + } + } + void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { if (mDragDrop) @@ -511,7 +525,10 @@ namespace MWInput OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); if (kc != OIS::KC_UNASSIGNED) - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + { + bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + setPlayerControlsEnabled(!guiFocus); + } mInputBinder->keyPressed (arg); } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 537c3a1827..dbd13e793c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -172,6 +172,8 @@ namespace MWInput void resetIdleTime(); void updateIdleTime(float dt); + void setPlayerControlsEnabled(bool enabled); + private: void toggleMainMenu(); void toggleSpell(); diff --git a/extern/oics/ICSChannel.cpp b/extern/oics/ICSChannel.cpp index 703f2207c9..268615c920 100644 --- a/extern/oics/ICSChannel.cpp +++ b/extern/oics/ICSChannel.cpp @@ -38,6 +38,7 @@ namespace ICS , mValue(initialValue) , mSymmetricAt(symmetricAt) , mBezierStep(bezierStep) + , mEnabled(true) { mBezierMidPoint.x = bezierMidPointX; mBezierMidPoint.y = bezierMidPointY; @@ -45,6 +46,11 @@ namespace ICS setBezierFunction(bezierMidPointY, bezierMidPointX, symmetricAt, bezierStep); } + void Channel::setEnabled(bool enabled) + { + mEnabled = enabled; + } + float Channel::getValue() { if(mValue == 0 || mValue == 1) @@ -124,7 +130,10 @@ namespace ICS void Channel::update() { - if(this->getControlsCount() == 1) + if(!mEnabled) + return; + + if(this->getControlsCount() == 1) { ControlChannelBinderItem ccBinderItem = mAttachedControls.back(); float diff = ccBinderItem.control->getValue() - ccBinderItem.control->getInitialValue(); @@ -255,4 +264,4 @@ namespace ICS t += 1.0f / ((endX-startX)/step); } } -} \ No newline at end of file +} diff --git a/extern/oics/ICSChannel.h b/extern/oics/ICSChannel.h index 5ec6cd575b..3da53369c3 100644 --- a/extern/oics/ICSChannel.h +++ b/extern/oics/ICSChannel.h @@ -89,6 +89,8 @@ namespace ICS IntervalList& getIntervals(){ return mIntervals; }; + void setEnabled(bool enabled); + protected: int mNumber; @@ -112,7 +114,9 @@ namespace ICS std::vector mAttachedControls; std::list mListeners; - void notifyListeners(float previousValue); + void notifyListeners(float previousValue); + + bool mEnabled; }; From c018319940ded39892479fc4722c07cb293f0998 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Jun 2014 00:26:15 +0200 Subject: [PATCH 055/110] Addition to 7c9c0830a96: don't create useless BaseWhite clones --- components/terrain/chunk.cpp | 21 ++++++++++++++------- components/terrain/chunk.hpp | 5 +++-- components/terrain/material.cpp | 23 ++++++++--------------- components/terrain/material.hpp | 14 ++++---------- components/terrain/quadtreenode.cpp | 16 ++++++++-------- 5 files changed, 37 insertions(+), 42 deletions(-) diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index 57db151249..bb8710b872 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -16,6 +16,7 @@ namespace Terrain Chunk::Chunk(Ogre::HardwareVertexBufferSharedPtr uvBuffer, const Ogre::AxisAlignedBox& bounds, const LoadResponseData& data) : mBounds(bounds) + , mOwnMaterial(false) { mVertexData = OGRE_NEW Ogre::VertexData; mVertexData->vertexStart = 0; @@ -57,11 +58,7 @@ namespace Terrain mVertexData->vertexBufferBinding->setBinding(3, colourBuffer); // Assign a default material in case terrain material fails to be created - // Since we are removing this material in the destructor, it must be cloned from BaseWhite - // so the original always stays available. - static int materialCount=0; - mMaterial = Ogre::MaterialManager::getSingleton().getByName("BaseWhite") - ->clone("BaseWhite"+Ogre::StringConverter::toString(++materialCount)); + mMaterial = Ogre::MaterialManager::getSingleton().getByName("BaseWhite"); mIndexData = OGRE_NEW Ogre::IndexData(); mIndexData->indexStart = 0; @@ -75,7 +72,7 @@ namespace Terrain Chunk::~Chunk() { - if (!mMaterial.isNull()) + if (!mMaterial.isNull() && mOwnMaterial) { #if TERRAIN_USE_SHADER sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); @@ -86,9 +83,19 @@ namespace Terrain OGRE_DELETE mIndexData; } - void Chunk::setMaterial(const Ogre::MaterialPtr &material) + void Chunk::setMaterial(const Ogre::MaterialPtr &material, bool own) { + // Clean up the previous material, if we own it + if (!mMaterial.isNull() && mOwnMaterial) + { +#if TERRAIN_USE_SHADER + sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); +#endif + Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); + } + mMaterial = material; + mOwnMaterial = own; } const Ogre::AxisAlignedBox& Chunk::getBoundingBox(void) const diff --git a/components/terrain/chunk.hpp b/components/terrain/chunk.hpp index d037661aee..9550b30460 100644 --- a/components/terrain/chunk.hpp +++ b/components/terrain/chunk.hpp @@ -20,8 +20,8 @@ namespace Terrain virtual ~Chunk(); - /// @note Takes ownership of \a material - void setMaterial (const Ogre::MaterialPtr& material); + /// @param own Should we take ownership of the material? + void setMaterial (const Ogre::MaterialPtr& material, bool own=true); void setIndexBuffer(Ogre::HardwareIndexBufferSharedPtr buffer); @@ -43,6 +43,7 @@ namespace Terrain private: Ogre::AxisAlignedBox mBounds; Ogre::MaterialPtr mMaterial; + bool mOwnMaterial; // Should we remove mMaterial on destruction? Ogre::VertexData* mVertexData; Ogre::IndexData* mIndexData; diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index b56f706806..771dcdf91c 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -46,35 +46,28 @@ namespace Terrain } - Ogre::MaterialPtr MaterialGenerator::generate(Ogre::MaterialPtr mat) + Ogre::MaterialPtr MaterialGenerator::generate() { assert(!mLayerList.empty() && "Can't create material with no layers"); - return create(mat, false, false); + return create(false, false); } - Ogre::MaterialPtr MaterialGenerator::generateForCompositeMapRTT(Ogre::MaterialPtr mat) + Ogre::MaterialPtr MaterialGenerator::generateForCompositeMapRTT() { assert(!mLayerList.empty() && "Can't create material with no layers"); - return create(mat, true, false); + return create(true, false); } - Ogre::MaterialPtr MaterialGenerator::generateForCompositeMap(Ogre::MaterialPtr mat) + Ogre::MaterialPtr MaterialGenerator::generateForCompositeMap() { - return create(mat, false, true); + return create(false, true); } - Ogre::MaterialPtr MaterialGenerator::create(Ogre::MaterialPtr mat, bool renderCompositeMap, bool displayCompositeMap) + Ogre::MaterialPtr MaterialGenerator::create(bool renderCompositeMap, bool displayCompositeMap) { assert(!renderCompositeMap || !displayCompositeMap); - if (!mat.isNull()) - { -#if TERRAIN_USE_SHADER - sh::Factory::getInstance().destroyMaterialInstance(mat->getName()); -#endif - Ogre::MaterialManager::getSingleton().remove(mat->getName()); - } static int count = 0; std::stringstream name; @@ -82,7 +75,7 @@ namespace Terrain if (!mShaders) { - mat = Ogre::MaterialManager::getSingleton().create(name.str(), + Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(name.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); Ogre::Technique* technique = mat->getTechnique(0); technique->removeAllPasses(); diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index e7e0678991..7f607a7af8 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -29,23 +29,17 @@ namespace Terrain void enableSplitShadows(bool splitShadows) { mSplitShadows = splitShadows; } /// Creates a material suitable for displaying a chunk of terrain using alpha-blending. - /// @param mat Material that will be replaced by the generated material. May be empty as well, in which case - /// a new material is created. - Ogre::MaterialPtr generate (Ogre::MaterialPtr mat); + Ogre::MaterialPtr generate (); /// Creates a material suitable for displaying a chunk of terrain using a ready-made composite map. - /// @param mat Material that will be replaced by the generated material. May be empty as well, in which case - /// a new material is created. - Ogre::MaterialPtr generateForCompositeMap (Ogre::MaterialPtr mat); + Ogre::MaterialPtr generateForCompositeMap (); /// Creates a material suitable for rendering composite maps, i.e. for "baking" several layer textures /// into one. The main difference compared to a normal material is that no shading is applied at this point. - /// @param mat Material that will be replaced by the generated material. May be empty as well, in which case - /// a new material is created. - Ogre::MaterialPtr generateForCompositeMapRTT (Ogre::MaterialPtr mat); + Ogre::MaterialPtr generateForCompositeMapRTT (); private: - Ogre::MaterialPtr create (Ogre::MaterialPtr mat, bool renderCompositeMap, bool displayCompositeMap); + Ogre::MaterialPtr create (bool renderCompositeMap, bool displayCompositeMap); std::vector mLayerList; std::vector mBlendmapList; diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index a14fe1f842..37c638da0c 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -400,13 +400,13 @@ void QuadTreeNode::load(const LoadResponseData &data) { if (mSize == 1) { - mChunk->setMaterial(mMaterialGenerator->generate(mChunk->getMaterial())); + mChunk->setMaterial(mMaterialGenerator->generate()); } else { ensureCompositeMap(); mMaterialGenerator->setCompositeMap(mCompositeMap->getName()); - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap(mChunk->getMaterial())); + mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); } } // else: will be loaded in loadMaterials() after background thread has finished loading layers @@ -532,13 +532,13 @@ void QuadTreeNode::loadMaterials() { if (mSize == 1) { - mChunk->setMaterial(mMaterialGenerator->generate(mChunk->getMaterial())); + mChunk->setMaterial(mMaterialGenerator->generate()); } else { ensureCompositeMap(); mMaterialGenerator->setCompositeMap(mCompositeMap->getName()); - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap(mChunk->getMaterial())); + mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); } } } @@ -554,7 +554,7 @@ void QuadTreeNode::prepareForCompositeMap(Ogre::TRect area) std::vector layer; layer.push_back(mTerrain->getStorage()->getDefaultLayer()); matGen.setLayerList(layer); - makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generateForCompositeMapRTT(Ogre::MaterialPtr())); + makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generateForCompositeMapRTT()); return; } if (mSize > 1) @@ -577,7 +577,7 @@ void QuadTreeNode::prepareForCompositeMap(Ogre::TRect area) else { // TODO: when to destroy? - Ogre::MaterialPtr material = mMaterialGenerator->generateForCompositeMapRTT(Ogre::MaterialPtr()); + Ogre::MaterialPtr material = mMaterialGenerator->generateForCompositeMapRTT(); makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, material); } } @@ -612,9 +612,9 @@ void QuadTreeNode::applyMaterials() mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled()); mMaterialGenerator->enableSplitShadows(mTerrain->getSplitShadowsEnabled()); if (mSize <= 1) - mChunk->setMaterial(mMaterialGenerator->generate(Ogre::MaterialPtr())); + mChunk->setMaterial(mMaterialGenerator->generate()); else - mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap(Ogre::MaterialPtr())); + mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap()); } if (hasChildren()) for (int i=0; i<4; ++i) From f6f6b5604afd9d6269cc0aed93bb47f05107d0de Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Jun 2014 23:11:38 +0200 Subject: [PATCH 056/110] 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 3b758f8660..16c1b497cd 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 663af640b8..15ba274980 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 057/110] 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 7f349e2236..f724b4204a 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 15fde1bcb9..4633141a69 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 576c06d791fb0f08a0ba781576e8a55d4df6e9d7 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Sun, 1 Jun 2014 17:48:26 -0400 Subject: [PATCH 058/110] Fix Bug #1371 Not properly reading in the NIF file's QuaternionKeyList. --- components/nif/niffile.cpp | 2 ++ components/nif/niffile.hpp | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 0f7e658fb8..10847e8f4d 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -318,6 +318,8 @@ void NIFFile::parse() Record *r = NULL; std::string rec = nif.getString(); + if(rec.empty()) + fail("Record number " + Ogre::StringConverter::toString(i) + " out of " + Ogre::StringConverter::toString(recNum) + " is blank."); RecordFactoryEntry const * entry = lookupRecordFactory (rec.c_str ()); diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 77e0acb9e5..29fa3951e7 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -137,8 +138,8 @@ template struct KeyT { float mTime; T mValue; - T mForwardValue; // Only for Quadratic interpolation - T mBackwardValue; // Only for Quadratic interpolation + T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList + T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList float mTension; // Only for TBC interpolation float mBias; // Only for TBC interpolation float mContinuity; // Only for TBC interpolation @@ -184,8 +185,11 @@ struct KeyListT { KeyT &key = mKeys[i]; key.mTime = nif->getFloat(); key.mValue = (nif->*getValue)(); - key.mForwardValue = (nif->*getValue)(); - key.mBackwardValue = (nif->*getValue)(); + if( typeid(Ogre::Quaternion) != typeid(T) ) + { + key.mForwardValue = (nif->*getValue)(); + key.mBackwardValue = (nif->*getValue)(); + } } } else if(mInterpolationType == sTBCInterpolation) From 20dabaead97cfed145ee6e8ee2c27a057872539e Mon Sep 17 00:00:00 2001 From: slothlife Date: Mon, 2 Jun 2014 02:34:43 -0500 Subject: [PATCH 059/110] Fix CMake scripts to link static dependencies Added FindDirectX scripts from Ogre so that FindOgre.cmake doesn't fail silently to find the libraries correctly. Modified top-level CMakelists.txt: - Correctly set include dirs, preprocessor definitions, and add libraries for static Ogre plugins. - Correctly set preprocessor definitions for static MyGUI. Modified launcher, openmw, and opencs to link the static Ogre plugins. Fixed FindSDL2.cmake to set a variable that contains only the SDL2 library, so that the launcher doesn't incorrectly link against SDL2main. Fixed FindMyGUI.cmake to correctly look for static variants. Fixed FindOgre.cmake to set variables for DirectX plugins correctly. --- CMakeLists.txt | 46 +++++++++++--- apps/launcher/CMakeLists.txt | 11 +--- apps/opencs/CMakeLists.txt | 1 + apps/openmw/CMakeLists.txt | 13 ---- cmake/FindDirectX.cmake | 72 ++++++++++++++++++++++ cmake/FindDirectX11.cmake | 114 +++++++++++++++++++++++++++++++++++ cmake/FindMyGUI.cmake | 60 ++++++------------ cmake/FindOGRE.cmake | 8 ++- cmake/FindSDL2.cmake | 5 +- 9 files changed, 253 insertions(+), 77 deletions(-) create mode 100644 cmake/FindDirectX.cmake create mode 100644 cmake/FindDirectX11.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f349e2236..fb0f5816e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,16 +239,40 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) -IF(OGRE_STATIC) -find_package(Cg) -IF(WIN32) -set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_Direct3D9_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS}) -ELSE(WIN32) -set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS}) -ENDIF(WIN32) -ENDIF(OGRE_STATIC) + +set(OGRE_PLUGIN_INCLUDE_DIRS "") +set(OGRE_STATIC_PLUGINS "") + +macro(add_static_ogre_plugin PLUGIN) + if(OGRE_${PLUGIN}_FOUND) + # strip RenderSystem_ or Plugin_ prefix from plugin name + string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN}) + string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP}) + add_definitions(-DENABLE_PLUGIN_${PLUGIN_NAME}) + + list(APPEND OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIRS}) + list(APPEND OGRE_STATIC_PLUGINS ${OGRE_${PLUGIN}_LIBRARIES}) + endif(OGRE_${PLUGIN}_FOUND) +endmacro(add_static_ogre_plugin) + +if(OGRE_STATIC) + # set up OGRE_PLUGIN_INCLUDE_DIRS and OGRE_STATIC_PLUGINS + add_static_ogre_plugin(Plugin_OctreeSceneManager) + add_static_ogre_plugin(Plugin_ParticleFX) + find_package(Cg) + if(Cg_FOUND) + add_static_ogre_plugin(Plugin_CgProgramManager) + list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES}) + endif(Cg_FOUND) + + add_static_ogre_plugin(RenderSystem_GL) + if(WIN32) + add_static_ogre_plugin(RenderSystem_Direct3D9) + endif(WIN32) +endif(OGRE_STATIC) + include_directories("." - ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} + ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} @@ -260,6 +284,10 @@ include_directories("." link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) +if(MYGUI_STATIC) + add_definitions(-DMYGUI_STATIC) +endif (MYGUI_STATIC) + if (APPLE) # List used Ogre plugins SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index e4638c31b4..ec721a5e59 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -94,15 +94,6 @@ if(NOT WIN32) endif(NOT WIN32) # Main executable -IF(OGRE_STATIC) -IF(WIN32) -ADD_DEFINITIONS(-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL) -set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) -ELSE(WIN32) -ADD_DEFINITIONS(-DENABLE_PLUGIN_GL) -set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_GL_LIBRARIES}) -ENDIF(WIN32) -ENDIF(OGRE_STATIC) add_executable(omwlauncher ${GUI_TYPE} ${LAUNCHER} @@ -116,7 +107,7 @@ target_link_libraries(omwlauncher ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} - ${SDL2_LIBRARY} + ${SDL2_LIBRARY_ONLY} ${QT_LIBRARIES} components ) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4576432e1c..f18ac0bcab 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -192,6 +192,7 @@ endif(APPLE) target_link_libraries(opencs ${OGRE_LIBRARIES} + ${OGRE_STATIC_PLUGINS} ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${QT_LIBRARIES} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8496b47a4a..b76756ca07 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -89,19 +89,6 @@ endif(WIN32) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -IF(OGRE_STATIC) -ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) -set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) -IF(WIN32) -ADD_DEFINITIONS(-DENABLE_PLUGIN_Direct3D9) -list (APPEND OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_Direct3D9_LIBRARIES}) -ENDIF(WIN32) -IF (Cg_FOUND) -ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager) -list (APPEND OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${Cg_LIBRARIES}) -ENDIF (Cg_FOUND) -ENDIF(OGRE_STATIC) - add_executable(openmw ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} diff --git a/cmake/FindDirectX.cmake b/cmake/FindDirectX.cmake new file mode 100644 index 0000000000..4641b55a3d --- /dev/null +++ b/cmake/FindDirectX.cmake @@ -0,0 +1,72 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# Find DirectX9 SDK +# Define: +# DirectX9_FOUND +# DirectX9_INCLUDE_DIR +# DirectX9_LIBRARY +# DirectX9_ROOT_DIR + +if(WIN32) # The only platform it makes sense to check for DirectX9 SDK + include(FindPkgMacros) + findpkg_begin(DirectX9) + + # Get path, convert backslashes as ${ENV_DXSDK_DIR} + getenv_path(DXSDK_DIR) + getenv_path(DirectX_HOME) + getenv_path(DirectX_ROOT) + getenv_path(DirectX_BASE) + + # construct search paths + set(DirectX9_PREFIX_PATH + "${DXSDK_DIR}" "${ENV_DXSDK_DIR}" + "${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}" + "${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}" + "${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}" + "C:/apps_x86/Microsoft DirectX SDK*" + "C:/Program Files (x86)/Microsoft DirectX SDK*" + "C:/apps/Microsoft DirectX SDK*" + "C:/Program Files/Microsoft DirectX SDK*" + "$ENV{ProgramFiles}/Microsoft DirectX SDK*" + ) + + create_search_paths(DirectX9) + # redo search if prefix path changed + clear_if_changed(DirectX9_PREFIX_PATH + DirectX9_LIBRARY + DirectX9_INCLUDE_DIR + ) + + find_path(DirectX9_INCLUDE_DIR NAMES d3d9.h D3DCommon.h HINTS ${DirectX9_INC_SEARCH_PATH}) + # dlls are in DirectX9_ROOT_DIR/Developer Runtime/x64|x86 + # lib files are in DirectX9_ROOT_DIR/Lib/x64|x86 + if(CMAKE_CL_64) + set(DirectX9_LIBPATH_SUFFIX "x64") + else(CMAKE_CL_64) + set(DirectX9_LIBPATH_SUFFIX "x86") + endif(CMAKE_CL_64) + find_library(DirectX9_LIBRARY NAMES d3d9 HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) + find_library(DirectX9_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) + find_library(DirectX9_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) + find_library(DirectX9_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX9_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX9_LIBPATH_SUFFIX}) + + findpkg_finish(DirectX9) + set(DirectX9_LIBRARIES ${DirectX9_LIBRARIES} + ${DirectX9_D3DX9_LIBRARY} + ${DirectX9_DXERR_LIBRARY} + ${DirectX9_DXGUID_LIBRARY} + ) + + mark_as_advanced(DirectX9_D3DX9_LIBRARY DirectX9_DXERR_LIBRARY DirectX9_DXGUID_LIBRARY + DirectX9_DXGI_LIBRARY DirectX9_D3DCOMPILER_LIBRARY) + + +endif(WIN32) diff --git a/cmake/FindDirectX11.cmake b/cmake/FindDirectX11.cmake new file mode 100644 index 0000000000..22d5b5441f --- /dev/null +++ b/cmake/FindDirectX11.cmake @@ -0,0 +1,114 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# Find DirectX11 SDK +# Define: +# DirectX11_FOUND +# DirectX11_INCLUDE_DIR +# DirectX11_LIBRARY +# DirectX11_ROOT_DIR + +if(WIN32) # The only platform it makes sense to check for DirectX11 SDK + include(FindPkgMacros) + findpkg_begin(DirectX11) + + # Get path, convert backslashes as ${ENV_DXSDK_DIR} + getenv_path(DXSDK_DIR) + getenv_path(DIRECTX_HOME) + getenv_path(DIRECTX_ROOT) + getenv_path(DIRECTX_BASE) + + # construct search paths + set(DirectX11_PREFIX_PATH + "${DXSDK_DIR}" "${ENV_DXSDK_DIR}" + "${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}" + "${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}" + "${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}" + "C:/apps_x86/Microsoft DirectX SDK*" + "C:/Program Files (x86)/Microsoft DirectX SDK*" + "C:/apps/Microsoft DirectX SDK*" + "C:/Program Files/Microsoft DirectX SDK*" + "$ENV{ProgramFiles}/Microsoft DirectX SDK*" + ) + + if(OGRE_BUILD_PLATFORM_WINRT) + # Windows 8 SDK has custom layout + set(DirectX11_INC_SEARCH_PATH + "C:/Program Files (x86)/Windows Kits/8.0/Include/shared" + "C:/Program Files (x86)/Windows Kits/8.0/Include/um" + ) + set(DirectX11_LIB_SEARCH_PATH + "C:/Program Files (x86)/Windows Kits/8.0/Lib/win8/um" + ) + endif() + + create_search_paths(DirectX11) + # redo search if prefix path changed + clear_if_changed(DirectX11_PREFIX_PATH + DirectX11_LIBRARY + DirectX11_INCLUDE_DIR + ) + + # dlls are in DirectX11_ROOT_DIR/Developer Runtime/x64|x86 + # lib files are in DirectX11_ROOT_DIR/Lib/x64|x86 + if(CMAKE_CL_64) + set(DirectX11_LIBPATH_SUFFIX "x64") + else(CMAKE_CL_64) + set(DirectX11_LIBPATH_SUFFIX "x86") + endif(CMAKE_CL_64) + + # look for D3D11 components + find_path(DirectX11_INCLUDE_DIR NAMES D3D11Shader.h HINTS ${DirectX11_INC_SEARCH_PATH}) + find_library(DirectX11_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) + find_library(DirectX11_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) + find_library(DirectX11_DXGI_LIBRARY NAMES dxgi HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) + find_library(DirectX11_D3DCOMPILER_LIBRARY NAMES d3dcompiler HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) + + find_library(DirectX11_LIBRARY NAMES d3d11 HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) + find_library(DirectX11_D3DX11_LIBRARY NAMES d3dx11 HINTS ${DirectX11_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX11_LIBPATH_SUFFIX}) + if (DirectX11_INCLUDE_DIR AND DirectX11_LIBRARY) + set(DirectX11_D3D11_FOUND TRUE) + set(DirectX11_INCLUDE_DIR ${DirectX11_INCLUDE_DIR}) + set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} + ${DirectX11_LIBRARY} + ${DirectX11_DXGI_LIBRARY} + ${DirectX11_DXGUID_LIBRARY} + ${DirectX11_D3DCOMPILER_LIBRARY} + ) + endif () + if (DirectX11_D3DX11_LIBRARY) + set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} ${DirectX11_D3DX11_LIBRARY}) + endif () + if (DirectX11_DXERR_LIBRARY) + set(DirectX11_D3D11_LIBRARIES ${DirectX11_D3D11_LIBRARIES} ${DirectX11_DXERR_LIBRARY}) + endif () + + findpkg_finish(DirectX11) + + set(DirectX11_LIBRARIES + ${DirectX11_D3D11_LIBRARIES} + ) + + if (OGRE_BUILD_PLATFORM_WINDOWS_PHONE) + set(DirectX11_FOUND TRUE) + set(DirectX11_INCLUDE_DIR "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/WPSDK/WP80/include" CACHE STRING "" FORCE) + set(DirectX11_LIBRARY "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/WPSDK/WP80/lib" CACHE STRING "" FORCE) + set(DirectX11_LIBRARIES ${DirectX11_LIBRARY}) + set(CMAKE_CXX_FLAGS "/EHsc" CACHE STRING "" FORCE) + endif () + + mark_as_advanced(DirectX11_INCLUDE_DIR + DirectX11_D3D11_LIBRARIES + DirectX11_D3DX11_LIBRARY + DirectX11_DXERR_LIBRARY + DirectX11_DXGUID_LIBRARY + DirectX11_DXGI_LIBRARY + DirectX11_D3DCOMPILER_LIBRARY) +endif(WIN32) \ No newline at end of file diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index e2fefac7dc..ebf0694046 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -19,58 +19,34 @@ include(FindPkgMacros) IF (WIN32) #Windows MESSAGE(STATUS "Looking for MyGUI") -SET(MYGUISDK $ENV{MYGUI_HOME}) + SET(MYGUISDK $ENV{MYGUI_HOME}) IF (MYGUISDK) -findpkg_begin ( "MYGUI" ) + findpkg_begin ( "MYGUI" ) MESSAGE(STATUS "Using MyGUI in MyGUI SDK") -STRING(REGEX REPLACE "[\\]" "/" MYGUISDK "${MYGUISDK}" ) + STRING(REGEX REPLACE "[\\]" "/" MYGUISDK "${MYGUISDK}" ) -find_path ( MYGUI_INCLUDE_DIRS -MyGUI.h -"${MYGUISDK}/MyGUIEngine/include" -NO_DEFAULT_PATH ) + find_path ( MYGUI_INCLUDE_DIRS MyGUI.h "${MYGUISDK}/MyGUIEngine/include" NO_DEFAULT_PATH ) + find_path ( MYGUI_PLATFORM_INCLUDE_DIRS MyGUI_OgrePlatform.h "${MYGUISDK}/Platforms/Ogre/OgrePlatform/include" NO_DEFAULT_PATH ) -find_path ( MYGUI_PLATFORM_INCLUDE_DIRS -MyGUI_OgrePlatform.h -"${MYGUISDK}/Platforms/Ogre/OgrePlatform/include" -NO_DEFAULT_PATH ) + SET ( MYGUI_LIB_DIR ${MYGUISDK}/lib ${MYGUISDK}/*/lib ) -SET ( MYGUI_LIB_DIR ${MYGUISDK}/lib ${MYGUISDK}/*/lib ) + if ( MYGUI_STATIC ) + set(LIB_SUFFIX "Static") + endif ( MYGUI_STATIC ) -find_library ( MYGUI_LIBRARIES_REL NAMES -MyGUIEngine.lib -MyGUI.OgrePlatform.lib -HINTS -${MYGUI_LIB_DIR} -PATH_SUFFIXES "" release relwithdebinfo minsizerel ) + find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine${LIB_SUFFIX}.lib MyGUI.OgrePlatform.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) + find_library ( MYGUI_LIBRARIES_DBG NAMES MyGUIEngine${LIB_SUFFIX}_d.lib MyGUI.OgrePlatform_d.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) -find_library ( MYGUI_LIBRARIES_DBG NAMES -MyGUIEngine_d.lib -MyGUI.OgrePlatform_d.lib -HINTS -${MYGUI_LIB_DIR} -PATH_SUFFIXES "" debug ) + find_library ( MYGUI_PLATFORM_LIBRARIES_REL NAMES MyGUI.OgrePlatform.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) + find_library ( MYGUI_PLATFORM_LIBRARIES_DBG NAMES MyGUI.OgrePlatform_d.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" debug ) -find_library ( MYGUI_PLATFORM_LIBRARIES_REL NAMES -MyGUI.OgrePlatform.lib -HINTS -${MYGUI_LIB_DIR} -PATH_SUFFIXES "" release relwithdebinfo minsizerel ) + make_library_set ( MYGUI_LIBRARIES ) + make_library_set ( MYGUI_PLATFORM_LIBRARIES ) -find_library ( MYGUI_PLATFORM_LIBRARIES_DBG NAMES -MyGUI.OgrePlatform_d.lib -HINTS -${MYGUI_LIB_DIR} -PATH_SUFFIXES "" debug ) - -make_library_set ( MYGUI_LIBRARIES ) -make_library_set ( MYGUI_PLATFORM_LIBRARIES ) - -MESSAGE ("${MYGUI_LIBRARIES}") -MESSAGE ("${MYGUI_PLATFORM_LIBRARIES}") - -#findpkg_finish ( "MYGUI" ) + MESSAGE ("${MYGUI_LIBRARIES}") + MESSAGE ("${MYGUI_PLATFORM_LIBRARIES}") + #findpkg_finish ( "MYGUI" ) ENDIF (MYGUISDK) IF (OGRESOURCE) MESSAGE(STATUS "Using MyGUI in OGRE dependencies") diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake index 96f93cf34a..81b52b1b77 100644 --- a/cmake/FindOGRE.cmake +++ b/cmake/FindOGRE.cmake @@ -493,14 +493,18 @@ ogre_find_plugin(RenderSystem_Direct3D11 OgreD3D11RenderSystem.h RenderSystems/D if (OGRE_STATIC) # check if dependencies for plugins are met - if (NOT DirectX_FOUND) + if (NOT DirectX9_FOUND) set(OGRE_RenderSystem_Direct3D9_FOUND FALSE) + else () + set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${DirectX9_INCLUDE_DIR}) endif () if (NOT DirectX_D3D10_FOUND) set(OGRE_RenderSystem_Direct3D10_FOUND FALSE) endif () if (NOT DirectX_D3D11_FOUND) set(OGRE_RenderSystem_Direct3D11_FOUND FALSE) + else () + set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${DirectX_D3D11_INCLUDE_DIR}) endif () if (NOT OPENGL_FOUND) set(OGRE_RenderSystem_GL_FOUND FALSE) @@ -513,7 +517,7 @@ if (OGRE_STATIC) endif () set(OGRE_RenderSystem_Direct3D9_LIBRARIES ${OGRE_RenderSystem_Direct3D9_LIBRARIES} - ${DirectX_LIBRARIES} + ${DirectX9_LIBRARIES} ) set(OGRE_RenderSystem_Direct3D10_LIBRARIES ${OGRE_RenderSystem_Direct3D10_LIBRARIES} ${DirectX_D3D10_LIBRARIES} diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 70e607a89f..163abf4639 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -87,7 +87,7 @@ FIND_PATH(SDL2_INCLUDE_DIR SDL.h ) #MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}") -FIND_LIBRARY(SDL2_LIBRARY_TEMP +FIND_LIBRARY(SDL2_LIBRARY_PATH NAMES SDL2 HINTS $ENV{SDL2DIR} @@ -99,6 +99,9 @@ FIND_LIBRARY(SDL2_LIBRARY_TEMP /opt ) +set(SDL2_LIBRARY_ONLY ${SDL2_LIBRARY_PATH} CACHE STRING "The SDL2 library, with no other libraries.") +set(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_PATH}) + #MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}") IF(NOT SDL2_BUILDING_LIBRARY) From 929aae68696b3251155959cfe18312fa56ff625a Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 1 Jun 2014 22:21:52 +0200 Subject: [PATCH 060/110] Silence a clang warning warning: pointer is initialized by a temporary array, which will be destroyed at the end of the full-expression [-Waddress-of-array-temporary] --- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 548a871ce1..f9927537cd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2057,8 +2057,8 @@ namespace MWWorld // door to exterior if (it->mRef.getDestCell().empty()) { int x, y; - const float *pos = it->mRef.getDoorDest().pos; - positionToIndex(pos[0], pos[1], x, y); + ESM::Position doorDest = it->mRef.getDoorDest(); + positionToIndex(doorDest.pos[0], doorDest.pos[1], x, y); source = getExterior(x, y); } // door to interior From 8b33c087e0da487d8307a9c0f417bbaf22774614 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Jun 2014 14:46:41 +0200 Subject: [PATCH 061/110] 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 | 149 ++++++++++++++---------- 1 file changed, 85 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index dafb8323aa..29b5318d74 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; + 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.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; + 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()); + 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); + 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 + 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); + 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); - writer.save (stream); + writer.save (stream); - Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); - listener.setProgressRange(recordCount); - listener.setLabel("#{sNotifyMessage4}"); + Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + listener.setProgressRange(recordCount); + listener.setLabel("#{sNotifyMessage4}"); - Loading::ScopedLoad load(&listener); + Loading::ScopedLoad load(&listener); - writer.startRecord (ESM::REC_SAVE); - slot->mProfile.save (writer); - writer.endRecord (ESM::REC_SAVE); - listener.increaseProgress(); + writer.startRecord (ESM::REC_SAVE); + slot->mProfile.save (writer); + writer.endRecord (ESM::REC_SAVE); + listener.increaseProgress(); - 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); + 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); - // 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; + // 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; - writer.close(); + writer.close(); - Settings::Manager::setString ("character", "Saves", - slot->mPath.parent_path().filename().string()); + 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(); + + std::cerr << error.str() << std::endl; + + 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 062/110] 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 348b7c1df9..ef5d5858b6 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 063/110] 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 121a73a485..006be921b1 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 822e2d88e1..d773904db2 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"); + it->deleteSlot(slot); - mCharacters[index].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(); } +std::list::iterator MWState::CharacterManager::findCharacter(const MWState::Character* character) +{ + 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) { - 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"); - - 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 869d34f21c..adf9d2ef44 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 064/110] 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 235300b438..8d9ac3c228 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 065/110] 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 8dcccfdb35..3d7e7e283a 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 066/110] 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 7c915ebebf..f1bbc68cdf 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 96e0e1ed47..f198d625d7 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 32bf773bd5..f753ae1f45 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 f6a7b71e9d..47962015c2 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 281d3b4c95218da2f5cee37817e89c8a697081e6 Mon Sep 17 00:00:00 2001 From: slothlife Date: Mon, 2 Jun 2014 17:21:13 -0500 Subject: [PATCH 067/110] Fix for dereferencing past end of mGuiModes. --- apps/openmw/mwgui/windowmanagerimp.cpp | 241 +++++++++++++------------ 1 file changed, 122 insertions(+), 119 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4de3028ed4..0e4ac22a62 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -442,128 +442,131 @@ namespace MWGui return; } - GuiMode mode = mGuiModes.back(); + if(mGuiModes.size() != 0) + { + GuiMode mode = mGuiModes.back(); - switch(mode) { - case GM_QuickKeysMenu: - mQuickKeysMenu->setVisible (true); - break; - case GM_MainMenu: - mMenu->setVisible(true); - break; - case GM_Settings: - mSettingsWindow->setVisible(true); - break; - case GM_Console: - mConsole->setVisible(true); - break; - case GM_Scroll: - mScrollWindow->setVisible(true); - break; - case GM_Book: - mBookWindow->setVisible(true); - break; - case GM_Alchemy: - mAlchemyWindow->setVisible(true); - break; - case GM_Rest: - mWaitDialog->setVisible(true); - break; - case GM_RestBed: - mWaitDialog->setVisible(true); - mWaitDialog->bedActivated(); - break; - case GM_Levelup: - mLevelupDialog->setVisible(true); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - mCharGen->spawnDialog(mode); - break; - case GM_Inventory: - { - // First, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed & ~mForceHidden; + switch(mode) { + case GM_QuickKeysMenu: + mQuickKeysMenu->setVisible (true); + break; + case GM_MainMenu: + mMenu->setVisible(true); + break; + case GM_Settings: + mSettingsWindow->setVisible(true); + break; + case GM_Console: + mConsole->setVisible(true); + break; + case GM_Scroll: + mScrollWindow->setVisible(true); + break; + case GM_Book: + mBookWindow->setVisible(true); + break; + case GM_Alchemy: + mAlchemyWindow->setVisible(true); + break; + case GM_Rest: + mWaitDialog->setVisible(true); + break; + case GM_RestBed: + mWaitDialog->setVisible(true); + mWaitDialog->bedActivated(); + break; + case GM_Levelup: + mLevelupDialog->setVisible(true); + break; + case GM_Name: + case GM_Race: + case GM_Class: + case GM_ClassPick: + case GM_ClassCreate: + case GM_Birth: + case GM_ClassGenerate: + case GM_Review: + mCharGen->spawnDialog(mode); + break; + case GM_Inventory: + { + // First, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed & ~mForceHidden; - // Show the windows we want - mMap ->setVisible(eff & GW_Map); - mStatsWindow ->setVisible(eff & GW_Stats); - mInventoryWindow->setVisible(eff & GW_Inventory); - mInventoryWindow->setGuiMode(mode); - mSpellWindow ->setVisible(eff & GW_Magic); - break; + // Show the windows we want + mMap ->setVisible(eff & GW_Map); + mStatsWindow ->setVisible(eff & GW_Stats); + mInventoryWindow->setVisible(eff & GW_Inventory); + mInventoryWindow->setGuiMode(mode); + mSpellWindow ->setVisible(eff & GW_Magic); + break; + } + case GM_Container: + mContainerWindow->setVisible(true); + mInventoryWindow->setVisible(true); + mInventoryWindow->setGuiMode(mode); + break; + case GM_Companion: + mCompanionWindow->setVisible(true); + mInventoryWindow->setVisible(true); + mInventoryWindow->setGuiMode(mode); + break; + case GM_Dialogue: + mDialogueWindow->setVisible(true); + break; + case GM_Barter: + mInventoryWindow->setVisible(true); + mInventoryWindow->setTrading(true); + mInventoryWindow->setGuiMode(mode); + mTradeWindow->setVisible(true); + break; + case GM_SpellBuying: + mSpellBuyingWindow->setVisible(true); + break; + case GM_Travel: + mTravelWindow->setVisible(true); + break; + case GM_SpellCreation: + mSpellCreationDialog->setVisible(true); + break; + case GM_Recharge: + mRecharge->setVisible(true); + break; + case GM_Enchanting: + mEnchantingDialog->setVisible(true); + break; + case GM_Training: + mTrainingWindow->setVisible(true); + break; + case GM_MerchantRepair: + mMerchantRepair->setVisible(true); + break; + case GM_Repair: + mRepair->setVisible(true); + break; + case GM_Journal: + mJournal->setVisible(true); + break; + case GM_LoadingWallpaper: + mHud->setVisible(false); + setCursorVisible(false); + break; + case GM_Loading: + // Show the pinned windows + mMap->setVisible(mMap->pinned() && !(mForceHidden & GW_Map)); + mStatsWindow->setVisible(mStatsWindow->pinned() && !(mForceHidden & GW_Stats)); + mInventoryWindow->setVisible(mInventoryWindow->pinned() && !(mForceHidden & GW_Inventory)); + mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic)); + + setCursorVisible(false); + break; + default: + // Unsupported mode, switch back to game + break; } - case GM_Container: - mContainerWindow->setVisible(true); - mInventoryWindow->setVisible(true); - mInventoryWindow->setGuiMode(mode); - break; - case GM_Companion: - mCompanionWindow->setVisible(true); - mInventoryWindow->setVisible(true); - mInventoryWindow->setGuiMode(mode); - break; - case GM_Dialogue: - mDialogueWindow->setVisible(true); - break; - case GM_Barter: - mInventoryWindow->setVisible(true); - mInventoryWindow->setTrading(true); - mInventoryWindow->setGuiMode(mode); - mTradeWindow->setVisible(true); - break; - case GM_SpellBuying: - mSpellBuyingWindow->setVisible(true); - break; - case GM_Travel: - mTravelWindow->setVisible(true); - break; - case GM_SpellCreation: - mSpellCreationDialog->setVisible(true); - break; - case GM_Recharge: - mRecharge->setVisible(true); - break; - case GM_Enchanting: - mEnchantingDialog->setVisible(true); - break; - case GM_Training: - mTrainingWindow->setVisible(true); - break; - case GM_MerchantRepair: - mMerchantRepair->setVisible(true); - break; - case GM_Repair: - mRepair->setVisible(true); - break; - case GM_Journal: - mJournal->setVisible(true); - break; - case GM_LoadingWallpaper: - mHud->setVisible(false); - setCursorVisible(false); - break; - case GM_Loading: - // Show the pinned windows - mMap->setVisible(mMap->pinned() && !(mForceHidden & GW_Map)); - mStatsWindow->setVisible(mStatsWindow->pinned() && !(mForceHidden & GW_Stats)); - mInventoryWindow->setVisible(mInventoryWindow->pinned() && !(mForceHidden & GW_Inventory)); - mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic)); - - setCursorVisible(false); - break; - default: - // Unsupported mode, switch back to game - break; } } From bbc5b125abd7ccaafe7a0ce206a7c8229685f840 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Jun 2014 00:16:32 +0200 Subject: [PATCH 068/110] 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 683fe9208f..70f1569225 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 819bda0fd2..6ae2ba82a0 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 5994c6e211..1feb92b02e 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 9efdeae546..feb9457c64 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 f3c9e9c73a..0940b7fefa 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 19f20eeee7..ca2989646c 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 dcfe7931a0..acf078a2c2 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 34421d4313..c460aa41ad 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 ca6d309d79..71a2a7865b 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 4dbc3da45c..b2f9c1bef6 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 069/110] 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 548a871ce1..52ca17314e 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 070/110] 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 fb5a80cc7d..77da56fa4f 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 071/110] 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 70f1569225..7ffe9e6a42 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 6ae2ba82a0..8f87825f09 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 1feb92b02e..b9ddb7daa9 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 feb9457c64..4b827d1aba 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 0940b7fefa..fa27b4ef06 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 c460aa41ad..5524f55202 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 072/110] 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 a7859d1283..217ec4407e 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 073/110] 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 da03e009f2..0c3ccbffbf 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 074/110] 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 a7cf3791fc..8f5a699d9d 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 832169f8b7..a959e6c42e 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) }; } From c4e738677032425b6dcc0daf2db78cb6b081e5c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 4 Jun 2014 21:12:23 +0200 Subject: [PATCH 075/110] Revert "added changed reference tracking for cells" This reverts commit f4334da42ec0076c073aed1a3aec6a4a17f1ba5a. --- apps/opencs/model/world/cell.hpp | 7 ++-- apps/opencs/model/world/columnimp.hpp | 40 ----------------------- apps/opencs/model/world/refcollection.cpp | 6 ---- 3 files changed, 2 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index 8a2781590d..a47dbf45df 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -1,7 +1,7 @@ #ifndef CSM_WOLRD_CELL_H #define CSM_WOLRD_CELL_H -#include +#include #include #include @@ -16,11 +16,8 @@ namespace CSMWorld { std::string mId; - /// These are the references modified by the edited content file. These are stored in - /// mModified only. - std::set mTouchedRefs; - void load (ESM::ESMReader &esm); + }; } diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6b276d1517..6976b454d9 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -10,7 +10,6 @@ #include "columnbase.hpp" #include "columns.hpp" #include "info.hpp" -#include "cell.hpp" namespace CSMWorld { @@ -88,45 +87,6 @@ namespace CSMWorld } }; - /// \brief Specialisation that takes care of the modified reference tracking - template<> - struct RecordStateColumn : public Column - { - RecordStateColumn() - : Column (Columns::ColumnId_Modification, ColumnBase::Display_RecordState) - {} - - virtual QVariant get (const Record& record) const - { - if (record.mState==Record::State_Erased) - return static_cast (Record::State_Deleted); - - if (!record.mModified.mTouchedRefs.empty() && - !record.mState==Record::State_Deleted && - !record.mState==Record::State_ModifiedOnly) - { - static_cast (Record::State_Modified); - } - - return static_cast (record.mState); - } - - virtual void set (Record& record, const QVariant& data) - { - record.mState = static_cast (data.toInt()); - } - - virtual bool isEditable() const - { - return true; - } - - virtual bool isUserEditable() const - { - return false; - } - }; - template struct FixedRecordTypeColumn : public Column { diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 36518f0fa4..c516e2c3ec 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -53,8 +53,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool } else { - cell.mModified.mTouchedRefs.insert (Misc::StringUtils::lowerCase ( - mCells.getId (cellIndex))); record.mState = RecordBase::State_Deleted; setRecord (index, record); } @@ -62,10 +60,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool continue; } - if (!base) - cell.mModified.mTouchedRefs.insert (Misc::StringUtils::lowerCase ( - mCells.getId (cellIndex))); - if (iter==cache.end()) { // new reference From 1b9b275f30f105ea69bceec1f944b6a5afbb6147 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Jun 2014 13:39:56 +0200 Subject: [PATCH 076/110] fix for bug #1369 --- apps/opencs/model/world/refidcollection.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index f515e34d8e..cb2027880c 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -304,10 +304,17 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponReach, ColumnBase::Display_Float)); weaponColumns.mReach = &mColumns.back(); - for (int i=0; i<6; ++i) + for (int i=0; i<3; ++i) { - mColumns.push_back (RefIdColumn (Columns::ColumnId_MinChop + i, ColumnBase::Display_Integer)); - weaponColumns.mChop[i] = &mColumns.back(); + const RefIdColumn **column = + i==0 ? weaponColumns.mChop : (i==1 ? weaponColumns.mSlash : weaponColumns.mThrust); + + for (int j=0; j<2; ++j) + { + mColumns.push_back ( + RefIdColumn (Columns::ColumnId_MinChop+i*2+j, ColumnBase::Display_Integer)); + column[j] = &mColumns.back(); + } } static const struct From c0f1449004c8a609d50e5f94f0192831d3b58c0d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 14:54:07 +0200 Subject: [PATCH 077/110] Cycle with equipped items if all slots are occupied (Fixes #1395) --- apps/openmw/mwworld/actionequip.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 05677cdc7f..50da1e5e5d 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -41,6 +41,8 @@ namespace MWWorld // slots that this item can be equipped in std::pair, bool> slots_ = getTarget().getClass().getEquipmentSlots(getTarget()); + if (slots_.first.empty()) + return; // retrieve ContainerStoreIterator to the item MWWorld::ContainerStoreIterator it = invStore.begin(); @@ -55,20 +57,13 @@ namespace MWWorld assert(it != invStore.end()); // equip the item in the first free slot - for (std::vector::const_iterator slot=slots_.first.begin(); - slot!=slots_.first.end(); ++slot) + std::vector::const_iterator slot=slots_.first.begin(); + for (;slot!=slots_.first.end(); ++slot) { // if the item is equipped already, nothing to do if (invStore.getSlot(*slot) == it) return; - // if all slots are occupied, replace the last slot - if (slot == --slots_.first.end()) - { - invStore.equip(*slot, it, actor); - break; - } - if (invStore.getSlot(*slot) == invStore.end()) { // slot is not occupied @@ -76,5 +71,19 @@ namespace MWWorld break; } } + + // all slots are occupied -> cycle + // move all slots one towards begin(), then equip the item in the slot that is now free + if (slot == slots_.first.end()) + { + for (slot=slots_.first.begin();slot!=slots_.first.end(); ++slot) + { + invStore.unequipSlot(*slot, actor); + if (slot+1 != slots_.first.end()) + invStore.equip(*slot, invStore.getSlot(*(slot+1)), actor); + else + invStore.equip(*slot, it, actor); + } + } } } From cefa20bfb94a8d5d8301bdc0f8aca5109a655c53 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 15:39:08 +0200 Subject: [PATCH 078/110] Fix not reacting to quit request while video is playing --- apps/openmw/mwgui/videowidget.cpp | 5 +++++ apps/openmw/mwgui/videowidget.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 566c7cadbb..8430c1c7bc 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -42,4 +42,9 @@ bool VideoWidget::update() return mPlayer.isPlaying(); } +void VideoWidget::cleanup() +{ + mPlayer.close(); +} + } diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index 16a71d367d..9360c8359f 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -26,6 +26,9 @@ namespace MWGui /// @return Is the video still playing? bool update(); + /// Free video player resources (done automatically on destruction) + void cleanup(); + private: bool mAllowSkipping; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4de3028ed4..94001d8777 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1576,12 +1576,13 @@ namespace MWGui bool cursorWasVisible = mCursorVisible; setCursorVisible(false); - while (mVideoWidget->update()) + while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { MWBase::Environment::get().getInputManager()->update(0, true, false); mRendering->getWindow()->update(); } + mVideoWidget->cleanup(); setCursorVisible(cursorWasVisible); From 85c98711788cc68c8c1a787043b3e9c8b80152d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 16:15:47 +0200 Subject: [PATCH 079/110] Use question mark for not found glyphs in the font --- apps/openmw/mwgui/fontloader.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp index 59c2e7ca68..13270b797e 100644 --- a/apps/openmw/mwgui/fontloader.cpp +++ b/apps/openmw/mwgui/fontloader.cpp @@ -265,18 +265,30 @@ namespace MWGui cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); } + + // Question mark, use for NotDefined marker (used for glyphs not existing in the font) + if (i == 63) + { + MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code"); + cursorCode->addAttribute("index", MyGUI::FontCodeType::NotDefined); + cursorCode->addAttribute("coord", MyGUI::utility::toString(x1) + " " + + MyGUI::utility::toString(y1) + " " + + MyGUI::utility::toString(w) + " " + + MyGUI::utility::toString(h)); + cursorCode->addAttribute("advance", data[i].width); + cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + + MyGUI::utility::toString((fontSize-data[i].ascent))); + } } // These are required as well, but the fonts don't provide them - for (int i=0; i<3; ++i) + for (int i=0; i<2; ++i) { MyGUI::FontCodeType::Enum type; if(i == 0) type = MyGUI::FontCodeType::Selected; else if (i == 1) type = MyGUI::FontCodeType::SelectedBack; - else if (i == 2) - type = MyGUI::FontCodeType::NotDefined; MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code"); cursorCode->addAttribute("index", type); From 4e235516c3811f1b2f3125ff7b52e160de73257f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 16:16:16 +0200 Subject: [PATCH 080/110] Work around missing character in french morrowind font (Bug #1390) --- apps/openmw/mwgui/fontloader.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp index 13270b797e..9d47bc38d1 100644 --- a/apps/openmw/mwgui/fontloader.cpp +++ b/apps/openmw/mwgui/fontloader.cpp @@ -64,10 +64,15 @@ namespace return unicode; } + // getUtf8, aka the worst function ever written. + // This includes various hacks for dealing with Morrowind's .fnt files that are *mostly* + // in the expected win12XX encoding, but also have randomly swapped characters sometimes. + // Looks like the Morrowind developers found standard encodings too boring and threw in some twists for fun. std::string getUtf8 (unsigned char c, ToUTF8::Utf8Encoder& encoder, ToUTF8::FromType encoding) { if (encoding == ToUTF8::WINDOWS_1250) { + // Hacks for polish font unsigned char win1250; std::map conv; conv[0x80] = 0xc6; @@ -101,7 +106,8 @@ namespace conv[0xa3] = 0xbf; conv[0xa4] = 0x0; // not contained in win1250 conv[0xe1] = 0x8c; - conv[0xe1] = 0x8c; + // Can't remember if this was supposed to read 0xe2, or is it just an extraneous copypaste? + //conv[0xe1] = 0x8c; conv[0xe3] = 0x0; // not contained in win1250 conv[0xf5] = 0x0; // not contained in win1250 @@ -252,6 +258,21 @@ 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) + { + MyGUI::xml::ElementPtr code = codes->createChild("Code"); + code->addAttribute("index", 0x2019); + code->addAttribute("coord", MyGUI::utility::toString(x1) + " " + + MyGUI::utility::toString(y1) + " " + + MyGUI::utility::toString(w) + " " + + MyGUI::utility::toString(h)); + code->addAttribute("advance", data[i].width); + code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + + MyGUI::utility::toString((fontSize-data[i].ascent))); + } + // ASCII vertical bar, use this as text input cursor if (i == 124) { From b6e52ae8ab53b89635928b9def716c0b51fa0f1c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 17:01:22 +0200 Subject: [PATCH 081/110] Fix crash when loading a savegame after dying (Fixes #1389) --- apps/openmw/mwworld/worldimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 52ca17314e..5cde556ec1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1851,7 +1851,12 @@ namespace MWWorld if (!mPlayer) mPlayer = new MWWorld::Player(player, *this); else + { + // Remove the old CharacterController + MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); + mPlayer->set(player); + } Ptr ptr = mPlayer->getPlayer(); mRendering->setupPlayer(ptr); From d2e98c4de1732107a75ee93690eea4a995987b73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 17:21:02 +0200 Subject: [PATCH 082/110] Fix forced switch to third person on death not always working For instance, when dying from fall damage --- apps/openmw/mwmechanics/character.cpp | 7 +++++++ apps/openmw/mwrender/camera.cpp | 4 ++-- apps/openmw/mwrender/camera.hpp | 3 ++- apps/openmw/mwstate/statemanagerimp.cpp | 1 - apps/openmw/mwworld/worldimp.cpp | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c9da912dd2..db4e599291 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -409,6 +409,13 @@ MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::I void CharacterController::playDeath(float startpoint, CharacterState death) { + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + // The first-person animations do not include death, so we need to + // force-switch to third person before playing the death animation. + MWBase::Environment::get().getWorld()->useDeathCamera(); + } + switch (death) { case CharState_SwimDeath: diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 2942649512..9e683cc159 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -140,11 +140,11 @@ namespace MWRender } } - void Camera::toggleViewMode() + void Camera::toggleViewMode(bool force) { // Changing the view will stop all playing animations, so if we are playing // anything important, queue the view change for later - if (!mAnimation->allowSwitchViewMode()) + if (!mAnimation->allowSwitchViewMode() && !force) { mViewModeToggleQueued = true; return; diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 808f817cf5..1e86bfb481 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -75,7 +75,8 @@ namespace MWRender /// Attach camera to object void attachTo(const MWWorld::Ptr &); - void toggleViewMode(); + /// @param Force view mode switch, even if currently not allowed by the animation. + void toggleViewMode(bool force=false); bool toggleVanityMode(bool enable); void allowVanityMode(bool allow); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 29b5318d74..0e56365d60 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -144,7 +144,6 @@ void MWState::StateManager::newGame (bool bypass) void MWState::StateManager::endGame() { mState = State_Ended; - MWBase::Environment::get().getWorld()->useDeathCamera(); } void MWState::StateManager::saveGame (const std::string& description, const Slot *slot) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5cde556ec1..2bd835561d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -432,7 +432,7 @@ namespace MWWorld mRendering->getCamera()->toggleVanityMode(false); } if(mRendering->getCamera()->isFirstPerson()) - togglePOV(); + mRendering->getCamera()->toggleViewMode(true); } MWWorld::Player& World::getPlayer() From 17f8b49db640f3739c613c3eac40fb7bdd197ff1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 17:43:12 +0200 Subject: [PATCH 083/110] Add missing padding for item tooltip magic effects --- apps/openmw/mwgui/tooltips.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index aeb79a9381..faa3f5befd 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -400,7 +400,7 @@ namespace MWGui if (!info.effects.empty()) { MyGUI::Widget* effectArea = mDynamicToolTipBox->createWidget("", - MyGUI::IntCoord(0, totalSize.height, 300, 300-totalSize.height), + MyGUI::IntCoord(padding.left, totalSize.height, 300-padding.left, 300-totalSize.height), MyGUI::Align::Stretch, "ToolTipEffectArea"); MyGUI::IntCoord coord(0, 6, totalSize.width, 24); @@ -419,7 +419,7 @@ namespace MWGui { assert(enchant); MyGUI::Widget* enchantArea = mDynamicToolTipBox->createWidget("", - MyGUI::IntCoord(0, totalSize.height, 300, 300-totalSize.height), + MyGUI::IntCoord(padding.left, totalSize.height, 300-padding.left, 300-totalSize.height), MyGUI::Align::Stretch, "ToolTipEnchantArea"); MyGUI::IntCoord coord(0, 6, totalSize.width, 24); From 1173957e563ea49bc94f0babcd7bfa833b3f880f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 18:15:48 +0200 Subject: [PATCH 084/110] Fix item weight displaying as 1e+3 for Stendarr's Hammer --- apps/openmw/mwgui/tooltips.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index faa3f5befd..16b010908a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -512,7 +512,11 @@ namespace MWGui std::string ToolTips::toString(const float value) { std::ostringstream stream; - stream << std::setprecision(3) << value; + + if (value != int(value)) + stream << std::setprecision(3); + + stream << value; return stream.str(); } From e772bb88da9ddb977844116286fb827bf33a8664 Mon Sep 17 00:00:00 2001 From: dreamer-dead Date: Thu, 5 Jun 2014 18:53:12 +0400 Subject: [PATCH 085/110] Remove RTTI usage in NIF reader. --- components/nif/niffile.hpp | 111 ++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 29fa3951e7..6fa98c6101 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -113,24 +113,24 @@ public: }; /// Get a given record - Record *getRecord(size_t index) + Record *getRecord(size_t index) const { Record *res = records.at(index); assert(res != NULL); return res; } /// Number of records - size_t numRecords() { return records.size(); } + size_t numRecords() const { return records.size(); } /// Get a given root - Record *getRoot(size_t index=0) + Record *getRoot(size_t index=0) const { Record *res = roots.at(index); assert(res != NULL); return res; } /// Number of roots - size_t numRoots() { return roots.size(); } + size_t numRoots() const { return roots.size(); } }; @@ -163,45 +163,33 @@ struct KeyListT { void read(NIFStream *nif, bool force=false) { + assert(nif); size_t count = nif->getInt(); if(count == 0 && !force) return; mInterpolationType = nif->getInt(); mKeys.resize(count); + NIFStream &nifReference = *nif; if(mInterpolationType == sLinearInterpolation) { for(size_t i = 0;i < count;i++) { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); + readTimeAndValue(nifReference, mKeys[i]); } } else if(mInterpolationType == sQuadraticInterpolation) { for(size_t i = 0;i < count;i++) { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); - if( typeid(Ogre::Quaternion) != typeid(T) ) - { - key.mForwardValue = (nif->*getValue)(); - key.mBackwardValue = (nif->*getValue)(); - } + readQuadratic(nifReference, mKeys[i]); } } else if(mInterpolationType == sTBCInterpolation) { for(size_t i = 0;i < count;i++) { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); - key.mTension = nif->getFloat(); - key.mBias = nif->getFloat(); - key.mContinuity = nif->getFloat(); + readTBC(nifReference, mKeys[i]); } } //\FIXME This now reads the correct amount of data in the file, but doesn't actually do anything with it. @@ -212,30 +200,8 @@ struct KeyListT { nif->file->fail("count should always be '1' for XYZ_ROTATION_KEY. Retrieved Value: "+Ogre::StringConverter::toString(count)); return; } - //KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html) - //Chomp unknown and possibly unused float - nif->getFloat(); - for(size_t i=0;i<3;++i) - { - unsigned int numKeys = nif->getInt(); - if(numKeys != 0) - { - int interpolationTypeAgain = nif->getInt(); - if( interpolationTypeAgain != sLinearInterpolation) - { - nif->file->fail("XYZ_ROTATION_KEY's KeyGroup keyType must be '1' (Linear Interpolation). Retrieved Value: "+Ogre::StringConverter::toString(interpolationTypeAgain)); - return; - } - for(size_t j = 0;j < numKeys;j++) - { - //For now just chomp these - nif->getFloat(); - nif->getFloat(); - } - } - nif->file->warn("XYZ_ROTATION_KEY read, but not used!"); - } - } + readXYZ(nifReference); + } else if (mInterpolationType == 0) { if (count != 0) @@ -244,6 +210,61 @@ struct KeyListT { else nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); } + +private: + static void readTimeAndValue(NIFStream &nif, KeyT &key) + { + key.mTime = nif.getFloat(); + key.mValue = (nif.*getValue)(); + } + + static void readQuadratic(NIFStream &nif, KeyT &key) + { + readTimeAndValue(nif, key); + } + + template + static void readQuadratic(NIFStream &nif, KeyT &key) + { + readTimeAndValue(nif, key); + key.mForwardValue = (nif.*getValue)(); + key.mBackwardValue = (nif.*getValue)(); + } + + static void readTBC(NIFStream &nif, KeyT &key) + { + readTimeAndValue(nif, key); + key.mTension = nif.getFloat(); + key.mBias = nif.getFloat(); + key.mContinuity = nif.getFloat(); + } + + static void readXYZ(NIFStream &nif) + { + //KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html) + //Chomp unknown and possibly unused float + nif.getFloat(); + for(size_t i=0;i<3;++i) + { + const unsigned int numKeys = nif.getInt(); + if(numKeys != 0) + { + const int interpolationTypeAgain = nif.getInt(); + if( interpolationTypeAgain != sLinearInterpolation) + { + nif.file->fail("XYZ_ROTATION_KEY's KeyGroup keyType must be '1' (Linear Interpolation). Retrieved Value: "+Ogre::StringConverter::toString(interpolationTypeAgain)); + return; + } + for(size_t j = 0;j < numKeys;++j) + { + //For now just chomp these + nif.getFloat(); + nif.getFloat(); + } + } + nif.file->warn("XYZ_ROTATION_KEY read, but not used!"); + } + } }; typedef KeyListT FloatKeyList; typedef KeyListT Vector3KeyList; From f53e86cad9d1375cac64f4306245c89a49e390ac Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 21:51:57 +0200 Subject: [PATCH 086/110] Fix AiCombat being incorrectly added to player (Fixes #1356) --- apps/openmw/mwmechanics/actors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 3d7e7e283a..8fe8e19240 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -932,7 +932,7 @@ namespace MWMechanics for (std::list::iterator it = listGuards.begin(); it != listGuards.end(); ++it) { - engageCombat(iter->first, *it, false); + engageCombat(iter->first, *it, *it == player); } } From 6db936bb3a14893e9a70abd85708be3d250e976b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 22:13:18 +0200 Subject: [PATCH 087/110] Refactor item icon code into ItemWidget (Fixes #1391) - Removed duplicate code - Fixed missing magic backgrounds during item drag&drop - Change background texture used for HUD icons --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 23 +--- apps/openmw/mwgui/alchemywindow.hpp | 5 +- apps/openmw/mwgui/container.cpp | 20 +-- apps/openmw/mwgui/enchantingdialog.cpp | 144 ++++++++++---------- apps/openmw/mwgui/enchantingdialog.hpp | 10 +- apps/openmw/mwgui/hud.cpp | 51 ++----- apps/openmw/mwgui/hud.hpp | 3 +- apps/openmw/mwgui/itemview.cpp | 58 ++------ apps/openmw/mwgui/itemwidget.cpp | 105 ++++++++++++++ apps/openmw/mwgui/itemwidget.hpp | 49 +++++++ apps/openmw/mwgui/quickkeysmenu.cpp | 125 +++++++---------- apps/openmw/mwgui/quickkeysmenu.hpp | 6 +- apps/openmw/mwgui/recharge.cpp | 19 +-- apps/openmw/mwgui/recharge.hpp | 4 +- apps/openmw/mwgui/repair.cpp | 20 +-- apps/openmw/mwgui/repair.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 + files/mygui/openmw_alchemy_window.layout | 34 ++--- files/mygui/openmw_box.skin.xml | 5 + files/mygui/openmw_enchanting_dialog.layout | 6 +- files/mygui/openmw_hud.layout | 4 +- files/mygui/openmw_quickkeys_menu.layout | 20 +-- files/mygui/openmw_recharge_dialog.layout | 2 +- files/mygui/openmw_repair.layout | 2 +- files/mygui/openmw_resources.xml | 26 ++++ 26 files changed, 408 insertions(+), 341 deletions(-) create mode 100644 apps/openmw/mwgui/itemwidget.cpp create mode 100644 apps/openmw/mwgui/itemwidget.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8496b47a4a..d81276b72d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -33,7 +33,7 @@ add_openmw_dir (mwgui merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel fontloader controllers savegamedialog - recharge mode videowidget backgroundimage + recharge mode videowidget backgroundimage itemwidget ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index ab04189a68..0b3e3c1684 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -13,20 +13,7 @@ #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" #include "itemview.hpp" - -namespace -{ - std::string getIconPath(MWWorld::Ptr ptr) - { - std::string path = std::string("icons\\"); - path += ptr.getClass().getInventoryIcon(ptr); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - return path; - } - -} +#include "itemwidget.hpp" namespace MWGui { @@ -149,7 +136,7 @@ namespace MWGui { mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr"); mApparatus.at (index)->setUserData (*iter); - mApparatus.at (index)->setImageTexture (getIconPath (*iter)); + mApparatus.at (index)->setItem(*iter); } } @@ -189,7 +176,7 @@ namespace MWGui MWMechanics::Alchemy::TIngredientsIterator it = mAlchemy.beginIngredients (); for (int i=0; i<4; ++i) { - MyGUI::ImageBox* ingredient = mIngredients[i]; + ItemWidget* ingredient = mIngredients[i]; MWWorld::Ptr item; if (it != mAlchemy.endIngredients ()) @@ -204,15 +191,15 @@ namespace MWGui if (ingredient->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0)); - ingredient->setImageTexture(""); ingredient->clearUserStrings (); + ingredient->setItem(item); + if (item.isEmpty ()) continue; ingredient->setUserString("ToolTipType", "ItemPtr"); ingredient->setUserData(item); - ingredient->setImageTexture(getIconPath(item)); MyGUI::TextBox* text = ingredient->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); text->setTextAlign(MyGUI::Align::Right); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 4fd4b825c0..b538a1f808 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -11,6 +11,7 @@ namespace MWGui { class ItemView; + class ItemWidget; class SortFilterItemModel; class AlchemyWindow : public WindowBase @@ -44,8 +45,8 @@ namespace MWGui MWMechanics::Alchemy mAlchemy; - std::vector mApparatus; - std::vector mIngredients; + std::vector mApparatus; + std::vector mIngredients; }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 609dea3857..4ba454a1ca 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -20,6 +20,7 @@ #include "inventorywindow.hpp" #include "itemview.hpp" +#include "itemwidget.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" #include "pickpocketitemmodel.hpp" @@ -46,22 +47,15 @@ namespace MWGui mSourceSortModel->addDragItem(mItem.mBase, count); } - std::string path = std::string("icons\\"); - path += mItem.mBase.getClass().getInventoryIcon(mItem.mBase); - MyGUI::ImageBox* baseWidget = mDragAndDropWidget->createWidget - ("ImageBox", MyGUI::IntCoord(0, 0, 42, 42), MyGUI::Align::Default); + ItemWidget* baseWidget = mDragAndDropWidget->createWidget + ("MW_ItemIcon", MyGUI::IntCoord(0, 0, 42, 42), MyGUI::Align::Default); mDraggedWidget = baseWidget; - MyGUI::ImageBox* image = baseWidget->createWidget("ImageBox", - MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); - size_t pos = path.rfind("."); - if (pos != std::string::npos) - path.erase(pos); - path.append(".dds"); - image->setImageTexture(path); - image->setNeedMouseFocus(false); + baseWidget->setItem(mItem.mBase); + baseWidget->setNeedMouseFocus(false); // text widget that shows item count - MyGUI::TextBox* text = image->createWidget("SandBrightText", + // TODO: move to ItemWidget + MyGUI::TextBox* text = baseWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); text->setTextAlign(MyGUI::Align::Right); text->setNeedMouseFocus(false); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index ccb1fab682..92221977b1 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -14,6 +14,7 @@ #include "itemselection.hpp" #include "container.hpp" +#include "itemwidget.hpp" #include "sortfilteritemmodel.hpp" @@ -57,8 +58,45 @@ namespace MWGui void EnchantingDialog::open() { center(); - onRemoveItem(NULL); - onRemoveSoul(NULL); + + setSoulGem(MWWorld::Ptr()); + setItem(MWWorld::Ptr()); + } + + void EnchantingDialog::setSoulGem(const MWWorld::Ptr &gem) + { + if (gem.isEmpty()) + { + mSoulBox->setItem(MWWorld::Ptr()); + mSoulBox->clearUserStrings(); + mEnchanting.setSoulGem(MWWorld::Ptr()); + } + else + { + mSoulBox->setItem(gem); + mSoulBox->setUserString ("ToolTipType", "ItemPtr"); + mSoulBox->setUserData(gem); + mEnchanting.setSoulGem(gem); + } + updateLabels(); + } + + void EnchantingDialog::setItem(const MWWorld::Ptr &item) + { + if (item.isEmpty()) + { + mItemBox->setItem(MWWorld::Ptr()); + mItemBox->clearUserStrings(); + mEnchanting.setOldItem(MWWorld::Ptr()); + } + else + { + mItemBox->setItem(item); + mItemBox->setUserString ("ToolTipType", "ItemPtr"); + mItemBox->setUserData(item); + mEnchanting.setOldItem(item); + } + updateLabels(); } void EnchantingDialog::exit() @@ -122,16 +160,7 @@ namespace MWGui startEditing(); mEnchanting.setSoulGem(soulgem); - MyGUI::ImageBox* image = mSoulBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); - std::string path = std::string("icons\\"); - path += soulgem.getClass().getInventoryIcon(soulgem); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - image->setImageTexture (path); - image->setUserString ("ToolTipType", "ItemPtr"); - image->setUserData(soulgem); - image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); + setSoulGem(soulgem); mPrice->setVisible(false); mPriceText->setVisible(false); @@ -151,46 +180,31 @@ namespace MWGui void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) { - delete mItemSelectionDialog; - mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}"); - mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); - mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); - mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); - mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyEnchantable); + if (mEnchanting.getOldItem().isEmpty()) + { + delete mItemSelectionDialog; + mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}"); + mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); + mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); + mItemSelectionDialog->setVisible(true); + mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyEnchantable); + } + else + { + setItem(MWWorld::Ptr()); + } } void EnchantingDialog::onItemSelected(MWWorld::Ptr item) { mItemSelectionDialog->setVisible(false); - while (mItemBox->getChildCount ()) - MyGUI::Gui::getInstance ().destroyWidget (mItemBox->getChildAt(0)); - - MyGUI::ImageBox* image = mItemBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); - std::string path = std::string("icons\\"); - path += item.getClass().getInventoryIcon(item); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - image->setImageTexture (path); - image->setUserString ("ToolTipType", "ItemPtr"); - image->setUserData(item); - image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem); - - mEnchanting.setOldItem(item); + setItem(item); mEnchanting.nextCastStyle(); updateLabels(); } - void EnchantingDialog::onRemoveItem(MyGUI::Widget *sender) - { - while (mItemBox->getChildCount ()) - MyGUI::Gui::getInstance ().destroyWidget (mItemBox->getChildAt(0)); - mEnchanting.setOldItem(MWWorld::Ptr()); - updateLabels(); - } - void EnchantingDialog::onItemCancel() { mItemSelectionDialog->setVisible(false); @@ -207,28 +221,7 @@ namespace MWGui return; } - while (mSoulBox->getChildCount ()) - MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); - - MyGUI::ImageBox* image = mSoulBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); - std::string path = std::string("icons\\"); - path += item.getClass().getInventoryIcon(item); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - image->setImageTexture (path); - image->setUserString ("ToolTipType", "ItemPtr"); - image->setUserData(item); - image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); - updateLabels(); - } - - void EnchantingDialog::onRemoveSoul(MyGUI::Widget *sender) - { - while (mSoulBox->getChildCount ()) - MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); - mEnchanting.setSoulGem(MWWorld::Ptr()); - updateLabels(); + setSoulGem(item); } void EnchantingDialog::onSoulCancel() @@ -238,15 +231,22 @@ namespace MWGui void EnchantingDialog::onSelectSoul(MyGUI::Widget *sender) { - delete mItemSelectionDialog; - mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}"); - mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); - mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); - mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); - mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyChargedSoulstones); + if (mEnchanting.getGem().isEmpty()) + { + delete mItemSelectionDialog; + mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}"); + mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); + mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); + mItemSelectionDialog->setVisible(true); + mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyChargedSoulstones); - //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); + //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); + } + else + { + setSoulGem(MWWorld::Ptr()); + } } void EnchantingDialog::notifyEffectsChanged () diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 7e641702e1..b75ae82803 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -11,6 +11,7 @@ namespace MWGui { class ItemSelectionDialog; + class ItemWidget; class EnchantingDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { @@ -22,6 +23,9 @@ namespace MWGui virtual void exit(); + void setSoulGem (const MWWorld::Ptr& gem); + void setItem (const MWWorld::Ptr& item); + void startEnchanting(MWWorld::Ptr actor); void startSelfEnchanting(MWWorld::Ptr soulgem); @@ -32,8 +36,6 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* sender); void onSelectItem (MyGUI::Widget* sender); void onSelectSoul (MyGUI::Widget* sender); - void onRemoveItem (MyGUI::Widget* sender); - void onRemoveSoul (MyGUI::Widget* sender); void onItemSelected(MWWorld::Ptr item); void onItemCancel(); @@ -46,8 +48,8 @@ namespace MWGui ItemSelectionDialog* mItemSelectionDialog; MyGUI::Button* mCancelButton; - MyGUI::ImageBox* mItemBox; - MyGUI::ImageBox* mSoulBox; + ItemWidget* mItemBox; + ItemWidget* mSoulBox; MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ede5750a56..d87ac7ec59 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -18,6 +18,7 @@ #include "container.hpp" #include "itemmodel.hpp" +#include "itemwidget.hpp" namespace MWGui { @@ -423,9 +424,6 @@ namespace MWGui mSpellStatus->setProgressRange(100); mSpellStatus->setProgressPosition(successChancePercent); - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - mSpellBox->setUserString("ToolTipType", "Spell"); mSpellBox->setUserString("Spell", spellId); @@ -438,7 +436,9 @@ namespace MWGui icon.insert(slashPos+1, "b_"); icon = std::string("icons\\") + icon; Widgets::fixTexturePath(icon); - mSpellImage->setImageTexture(icon); + + mSpellImage->setItem(MWWorld::Ptr()); + mSpellImage->setIcon(icon); } void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) @@ -455,21 +455,10 @@ namespace MWGui mSpellStatus->setProgressRange(100); mSpellStatus->setProgressPosition(chargePercent); - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - mSpellBox->setUserString("ToolTipType", "ItemPtr"); mSpellBox->setUserData(item); - mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = mSpellImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) - , MyGUI::Align::Stretch); - - std::string path = std::string("icons\\"); - path+=item.getClass().getInventoryIcon(item); - Widgets::fixTexturePath(path); - itemBox->setImageTexture(path); - itemBox->setNeedMouseFocus(false); + mSpellImage->setItem(item); } void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) @@ -489,23 +478,7 @@ namespace MWGui mWeapStatus->setProgressRange(100); mWeapStatus->setProgressPosition(durabilityPercent); - if (mWeapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); - - std::string path = std::string("icons\\"); - path+=item.getClass().getInventoryIcon(item); - Widgets::fixTexturePath(path); - - if (item.getClass().getEnchantment(item) != "") - { - mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) - , MyGUI::Align::Stretch); - itemBox->setImageTexture(path); - itemBox->setNeedMouseFocus(false); - } - else - mWeapImage->setImageTexture(path); + mWeapImage->setItem(item); } void HUD::unsetSelectedSpell() @@ -519,11 +492,9 @@ namespace MWGui mWeaponSpellBox->setVisible(true); } - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); mSpellStatus->setProgressRange(100); mSpellStatus->setProgressPosition(0); - mSpellImage->setImageTexture(""); + mSpellImage->setItem(MWWorld::Ptr()); mSpellBox->clearUserStrings(); } @@ -538,17 +509,17 @@ namespace MWGui mWeaponSpellBox->setVisible(true); } - if (mWeapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); mWeapStatus->setProgressRange(100); mWeapStatus->setProgressPosition(0); MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); + + mWeapImage->setItem(MWWorld::Ptr()); if (player.getClass().getNpcStats(player).isWerewolf()) - mWeapImage->setImageTexture("icons\\k\\tx_werewolf_hand.dds"); + mWeapImage->setIcon("icons\\k\\tx_werewolf_hand.dds"); else - mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); + mWeapImage->setIcon("icons\\k\\stealth_handtohand.dds"); mWeapBox->clearUserStrings(); } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 973ac07457..f451ea4d2d 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -10,6 +10,7 @@ namespace MWGui { class DragAndDrop; class SpellIcons; + class ItemWidget; class HUD : public OEngine::GUI::Layout, public LocalMapBase { @@ -63,7 +64,7 @@ namespace MWGui MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; MyGUI::Widget* mHealthFrame; MyGUI::Widget *mWeapBox, *mSpellBox, *mSneakBox; - MyGUI::ImageBox *mWeapImage, *mSpellImage; + ItemWidget *mWeapImage, *mSpellImage; MyGUI::ProgressBar *mWeapStatus, *mSpellStatus; MyGUI::Widget *mEffectBox, *mMinimapBox; MyGUI::Button* mMinimapButton; diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 24bc3fd630..fdaf930399 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -12,6 +12,7 @@ #include "../mwworld/class.hpp" #include "itemmodel.hpp" +#include "itemwidget.hpp" namespace MWGui { @@ -80,53 +81,24 @@ void ItemView::update() const ItemStack& item = mModel->getItem(i); /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them - std::string path = std::string("icons\\"); - path += item.mBase.getClass().getInventoryIcon(item.mBase); - - // background widget (for the "equipped" frame and magic item background image) - bool isMagic = (item.mFlags & ItemStack::Flag_Enchanted); - MyGUI::ImageBox* backgroundWidget = dragArea->createWidget("ImageBox", + ItemWidget* itemWidget = dragArea->createWidget("MW_ItemIcon", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); - backgroundWidget->setUserString("ToolTipType", "ItemModelIndex"); - backgroundWidget->setUserData(std::make_pair(i, mModel)); + itemWidget->setUserString("ToolTipType", "ItemModelIndex"); + itemWidget->setUserData(std::make_pair(i, mModel)); + ItemWidget::ItemState state = ItemWidget::None; + if (item.mType == ItemStack::Type_Barter) + state = ItemWidget::Barter; + if (item.mType == ItemStack::Type_Equipped) + state = ItemWidget::Equip; + itemWidget->setItem(item.mBase, state); - std::string backgroundTex = "textures\\menu_icon"; - if (isMagic) - backgroundTex += "_magic"; - if (item.mType == ItemStack::Type_Normal) - { - if (!isMagic) - backgroundTex = ""; - } - else if (item.mType == ItemStack::Type_Equipped) - backgroundTex += "_equip"; - else if (item.mType == ItemStack::Type_Barter) - backgroundTex += "_barter"; - - if (backgroundTex != "") - backgroundTex += ".dds"; - - backgroundWidget->setImageTexture(backgroundTex); - if ((item.mType == ItemStack::Type_Barter) && !isMagic) - backgroundWidget->setProperty("ImageCoord", "2 2 42 42"); - else - backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); - backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemView::onSelectedItem); - backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheel); - - // image - MyGUI::ImageBox* image = backgroundWidget->createWidget("ImageBox", - MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); - std::string::size_type pos = path.rfind("."); - if(pos != std::string::npos) - path.erase(pos); - path.append(".dds"); - image->setImageTexture(path); - image->setNeedMouseFocus(false); + itemWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemView::onSelectedItem); + itemWidget->eventMouseWheel += MyGUI::newDelegate(this, &ItemView::onMouseWheel); // text widget that shows item count - MyGUI::TextBox* text = image->createWidget("SandBrightText", - MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); + // TODO: move to ItemWidget + MyGUI::TextBox* text = itemWidget->createWidget("SandBrightText", + MyGUI::IntCoord(5, 19, 32, 18), MyGUI::Align::Default, std::string("Label")); text->setTextAlign(MyGUI::Align::Right); text->setNeedMouseFocus(false); text->setTextShadow(true); diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp new file mode 100644 index 0000000000..a1ca5cb6c9 --- /dev/null +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -0,0 +1,105 @@ +#include "itemwidget.hpp" + +#include +#include + +#include "../mwworld/class.hpp" + +namespace MWGui +{ + + ItemWidget::ItemWidget() + : mItem(NULL) + { + + } + + void ItemWidget::registerComponents() + { + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + } + + void ItemWidget::initialiseOverride() + { + assignWidget(mItem, "Item"); + if (mItem) + mItem->setNeedMouseFocus(false); + assignWidget(mFrame, "Frame"); + if (mFrame) + mFrame->setNeedMouseFocus(false); + + Base::initialiseOverride(); + } + + void ItemWidget::setIcon(const std::string &icon) + { + if (mItem) + mItem->setImageTexture(icon); + } + + void ItemWidget::setFrame(const std::string &frame, const MyGUI::IntCoord &coord) + { + if (mFrame) + { + mFrame->setImageTexture(frame); + mFrame->setImageTile(MyGUI::IntSize(coord.width, coord.height)); // Why is this needed? MyGUI bug? + mFrame->setImageCoord(coord); + } + } + + void ItemWidget::setIcon(const MWWorld::Ptr &ptr) + { + // image + std::string path = std::string("icons\\"); + path += ptr.getClass().getInventoryIcon(ptr); + + std::string::size_type pos = path.rfind("."); + if(pos != std::string::npos) + path.erase(pos); + path.append(".dds"); + setIcon(path); + } + + + void ItemWidget::setItem(const MWWorld::Ptr &ptr, ItemState state) + { + if (!mItem) + return; + + if (ptr.isEmpty()) + { + if (mFrame) + mFrame->setImageTexture(""); + mItem->setImageTexture(""); + return; + } + + bool isMagic = !ptr.getClass().getEnchantment(ptr).empty(); + + std::string backgroundTex = "textures\\menu_icon"; + if (isMagic) + backgroundTex += "_magic"; + if (state == None) + { + if (!isMagic) + backgroundTex = ""; + } + else if (state == Equip) + { + backgroundTex += "_equip"; + } + else if (state == Barter) + backgroundTex += "_barter"; + + if (backgroundTex != "") + backgroundTex += ".dds"; + + if (state == Barter && !isMagic) + setFrame(backgroundTex, MyGUI::IntCoord(2,2,42,42)); + else + setFrame(backgroundTex, MyGUI::IntCoord(0,0,42,42)); + + setIcon(ptr); + } + +} diff --git a/apps/openmw/mwgui/itemwidget.hpp b/apps/openmw/mwgui/itemwidget.hpp new file mode 100644 index 0000000000..3de98489d0 --- /dev/null +++ b/apps/openmw/mwgui/itemwidget.hpp @@ -0,0 +1,49 @@ +#ifndef OPENMW_MWGUI_ITEMWIDGET_H +#define OPENMW_MWGUI_ITEMWIDGET_H + +#include + +namespace MWWorld +{ + class Ptr; +} + +namespace MWGui +{ + + /// @brief A widget that shows an icon for an MWWorld::Ptr + class ItemWidget : public MyGUI::Widget + { + MYGUI_RTTI_DERIVED(ItemWidget) + public: + ItemWidget(); + + /// Register needed components with MyGUI's factory manager + static void registerComponents (); + + enum ItemState + { + None, + Equip, + Barter, + Magic + }; + + /// \a ptr may be empty + void setItem (const MWWorld::Ptr& ptr, ItemState state = None); + + // Set icon and frame manually + void setIcon (const std::string& icon); + void setIcon (const MWWorld::Ptr& ptr); + void setFrame (const std::string& frame, const MyGUI::IntCoord& coord); + + private: + virtual void initialiseOverride(); + + MyGUI::ImageBox* mItem; + MyGUI::ImageBox* mFrame; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index af4e20ca4a..e142171770 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -23,6 +23,8 @@ #include "spellwindow.hpp" +#include "itemwidget.hpp" + namespace MWGui { @@ -46,14 +48,16 @@ namespace MWGui for (int i = 0; i < 10; ++i) { - MyGUI::Button* button; + ItemWidget* button; getWidget(button, "QuickKey" + boost::lexical_cast(i+1)); button->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); - unassign(button, i); - mQuickKeyButtons.push_back(button); + + mAssigned.push_back(Type_Unassigned); + + unassign(button, i); } } @@ -77,12 +81,14 @@ namespace MWGui delete mMagicSelectionDialog; } - void QuickKeysMenu::unassign(MyGUI::Widget* key, int index) + void QuickKeysMenu::unassign(ItemWidget* key, int index) { - while (key->getChildCount ()) - MyGUI::Gui::getInstance ().destroyWidget (key->getChildAt(0)); + key->clearUserStrings(); + key->setItem(MWWorld::Ptr()); + while (key->getChildCount()) // Destroy number label + MyGUI::Gui::getInstance().destroyWidget(key->getChildAt(0)); - key->setUserData(Type_Unassigned); + mAssigned[index] = Type_Unassigned; MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); textBox->setTextAlign (MyGUI::Align::Center); @@ -156,27 +162,16 @@ namespace MWGui void QuickKeysMenu::onAssignItem(MWWorld::Ptr item) { - MyGUI::Button* button = mQuickKeyButtons[mSelectedIndex]; - while (button->getChildCount ()) - MyGUI::Gui::getInstance ().destroyWidget (button->getChildAt(0)); + assert (mSelectedIndex > 0); + ItemWidget* button = mQuickKeyButtons[mSelectedIndex]; + while (button->getChildCount()) // Destroy number label + MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0)); - button->setUserData(Type_Item); + mAssigned[mSelectedIndex] = Type_Item; - MyGUI::ImageBox* frame = button->createWidget("ImageBox", MyGUI::IntCoord(9, 8, 42, 42), MyGUI::Align::Default); - std::string backgroundTex = "textures\\menu_icon_barter.dds"; - frame->setImageTexture (backgroundTex); - frame->setImageCoord (MyGUI::IntCoord(4, 4, 40, 40)); - frame->setUserString ("ToolTipType", "ItemPtr"); - frame->setUserData(item); - frame->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); - MyGUI::ImageBox* image = frame->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); - std::string path = std::string("icons\\"); - path += item.getClass().getInventoryIcon(item); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - image->setImageTexture (path); - image->setNeedMouseFocus (false); + button->setItem(item, ItemWidget::Barter); + button->setUserString ("ToolTipType", "ItemPtr"); + button->setUserData(item); if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); @@ -189,28 +184,18 @@ namespace MWGui void QuickKeysMenu::onAssignMagicItem (MWWorld::Ptr item) { - MyGUI::Button* button = mQuickKeyButtons[mSelectedIndex]; - while (button->getChildCount ()) - MyGUI::Gui::getInstance ().destroyWidget (button->getChildAt(0)); + assert (mSelectedIndex > 0); + ItemWidget* button = mQuickKeyButtons[mSelectedIndex]; + while (button->getChildCount()) // Destroy number label + MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0)); - button->setUserData(Type_MagicItem); + mAssigned[mSelectedIndex] = Type_MagicItem; - MyGUI::ImageBox* frame = button->createWidget("ImageBox", MyGUI::IntCoord(9, 8, 42, 42), MyGUI::Align::Default); - std::string backgroundTex = "textures\\menu_icon_select_magic_magic.dds"; - frame->setImageTexture (backgroundTex); - frame->setImageCoord (MyGUI::IntCoord(2, 2, 40, 40)); - frame->setUserString ("ToolTipType", "ItemPtr"); - frame->setUserData(item); - frame->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); + button->setFrame("textures\\menu_icon_select_magic_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); + button->setIcon(item); - MyGUI::ImageBox* image = frame->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); - std::string path = std::string("icons\\"); - path += item.getClass().getInventoryIcon(item); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - image->setImageTexture (path); - image->setNeedMouseFocus (false); + button->setUserString ("ToolTipType", "ItemPtr"); + button->setUserData(item); if (mMagicSelectionDialog) mMagicSelectionDialog->setVisible(false); @@ -218,21 +203,16 @@ namespace MWGui void QuickKeysMenu::onAssignMagic (const std::string& spellId) { - MyGUI::Button* button = mQuickKeyButtons[mSelectedIndex]; - while (button->getChildCount ()) - MyGUI::Gui::getInstance ().destroyWidget (button->getChildAt(0)); + assert (mSelectedIndex > 0); + ItemWidget* button = mQuickKeyButtons[mSelectedIndex]; + while (button->getChildCount()) // Destroy number label + MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0)); - button->setUserData(Type_Magic); + mAssigned[mSelectedIndex] = Type_Magic; - MyGUI::ImageBox* frame = button->createWidget("ImageBox", MyGUI::IntCoord(9, 8, 42, 42), MyGUI::Align::Default); - std::string backgroundTex = "textures\\menu_icon_select_magic.dds"; - frame->setImageTexture (backgroundTex); - frame->setImageCoord (MyGUI::IntCoord(2, 2, 40, 40)); - frame->setUserString ("ToolTipType", "Spell"); - frame->setUserString ("Spell", spellId); - frame->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); - - MyGUI::ImageBox* image = frame->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); + button->setItem(MWWorld::Ptr()); + button->setUserString ("ToolTipType", "Spell"); + button->setUserString ("Spell", spellId); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -251,8 +231,8 @@ namespace MWGui path.erase(pos); path.append(".dds"); - image->setImageTexture (path); - image->setNeedMouseFocus (false); + button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); + button->setIcon(path); if (mMagicSelectionDialog) mMagicSelectionDialog->setVisible(false); @@ -265,16 +245,17 @@ namespace MWGui void QuickKeysMenu::activateQuickKey(int index) { - MyGUI::Button* button = mQuickKeyButtons[index-1]; + assert (index-1 > 0); + ItemWidget* button = mQuickKeyButtons[index-1]; - QuickKeyType type = *button->getUserData(); + QuickKeyType type = mAssigned[index-1]; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); if (type == Type_Item || type == Type_MagicItem) { - MWWorld::Ptr item = *button->getChildAt (0)->getUserData(); + MWWorld::Ptr item = *button->getUserData(); // make sure the item is available if (item.getRefData ().getCount() < 1) { @@ -286,7 +267,7 @@ namespace MWGui if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) { item = *it; - button->getChildAt(0)->setUserData(item); + button->setUserData(item); break; } } @@ -303,7 +284,7 @@ namespace MWGui if (type == Type_Magic) { - std::string spellId = button->getChildAt(0)->getUserString("Spell"); + std::string spellId = button->getUserString("Spell"); // Make sure the player still has this spell MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); @@ -315,13 +296,13 @@ namespace MWGui } else if (type == Type_Item) { - MWWorld::Ptr item = *button->getChildAt (0)->getUserData(); + MWWorld::Ptr item = *button->getUserData(); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); } else if (type == Type_MagicItem) { - MWWorld::Ptr item = *button->getChildAt (0)->getUserData(); + MWWorld::Ptr item = *button->getUserData(); // retrieve ContainerStoreIterator to the item MWWorld::ContainerStoreIterator it = store.begin(); @@ -403,9 +384,9 @@ namespace MWGui for (int i=0; i<10; ++i) { - MyGUI::Button* button = mQuickKeyButtons[i]; + ItemWidget* button = mQuickKeyButtons[i]; - int type = *button->getUserData(); + int type = mAssigned[i]; ESM::QuickKeys::QuickKey key; key.mType = type; @@ -417,12 +398,12 @@ namespace MWGui case Type_Item: case Type_MagicItem: { - MWWorld::Ptr item = *button->getChildAt(0)->getUserData(); + MWWorld::Ptr item = *button->getUserData(); key.mId = item.getCellRef().getRefId(); break; } case Type_Magic: - std::string spellId = button->getChildAt(0)->getUserString("Spell"); + std::string spellId = button->getUserString("Spell"); key.mId = spellId; break; } @@ -452,7 +433,7 @@ namespace MWGui mSelectedIndex = i; int keyType = it->mType; std::string id = it->mId; - MyGUI::Button* button = mQuickKeyButtons[i]; + ItemWidget* button = mQuickKeyButtons[i]; switch (keyType) { diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 40c5dab565..dc088d3c9a 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -11,6 +11,7 @@ namespace MWGui class QuickKeysMenuAssign; class ItemSelectionDialog; class MagicSelectionDialog; + class ItemWidget; class QuickKeysMenu : public WindowBase { @@ -51,7 +52,8 @@ namespace MWGui MyGUI::EditBox* mInstructionLabel; MyGUI::Button* mOkButton; - std::vector mQuickKeyButtons; + std::vector mQuickKeyButtons; + std::vector mAssigned; QuickKeysMenuAssign* mAssignDialog; ItemSelectionDialog* mItemSelectionDialog; @@ -63,7 +65,7 @@ namespace MWGui void onQuickKeyButtonClicked(MyGUI::Widget* sender); void onOkButtonClicked(MyGUI::Widget* sender); - void unassign(MyGUI::Widget* key, int index); + void unassign(ItemWidget* key, int index); }; class QuickKeysMenuAssign : public WindowModal diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index e5ea545917..0795642736 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -14,6 +14,7 @@ #include "../mwmechanics/npcstats.hpp" #include "widgets.hpp" +#include "itemwidget.hpp" namespace MWGui { @@ -45,12 +46,7 @@ void Recharge::exit() void Recharge::start (const MWWorld::Ptr &item) { - std::string path = std::string("icons\\"); - path += item.getClass().getInventoryIcon(item); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - mGemIcon->setImageTexture (path); + mGemIcon->setItem(item); mGemIcon->setUserString("ToolTipType", "ItemPtr"); mGemIcon->setUserData(item); @@ -108,14 +104,9 @@ void Recharge::updateView() text->setNeedMouseFocus(false); currentY += 19; - MyGUI::ImageBox* icon = mView->createWidget ( - "ImageBox", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); - std::string path = std::string("icons\\"); - path += iter->getClass().getInventoryIcon(*iter); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - icon->setImageTexture (path); + ItemWidget* icon = mView->createWidget ( + "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); + icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); icon->setUserData(*iter); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked); diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 5558b197e0..17d700649b 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -8,6 +8,8 @@ namespace MWGui { +class ItemWidget; + class Recharge : public WindowBase { public: @@ -25,7 +27,7 @@ protected: MyGUI::Widget* mGemBox; - MyGUI::ImageBox* mGemIcon; + ItemWidget* mGemIcon; MyGUI::TextBox* mChargeLabel; diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 29ec62887a..986e27243a 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -13,6 +13,8 @@ #include "widgets.hpp" +#include "itemwidget.hpp" + namespace MWGui { @@ -44,12 +46,7 @@ void Repair::startRepairItem(const MWWorld::Ptr &item) { mRepair.setTool(item); - std::string path = std::string("icons\\"); - path += item.getClass().getInventoryIcon(item); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - mToolIcon->setImageTexture (path); + mToolIcon->setItem(item); mToolIcon->setUserString("ToolTipType", "ItemPtr"); mToolIcon->setUserData(item); @@ -113,14 +110,9 @@ void Repair::updateRepairView() text->setNeedMouseFocus(false); currentY += 19; - MyGUI::ImageBox* icon = mRepairView->createWidget ( - "ImageBox", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); - std::string path = std::string("icons\\"); - path += iter->getClass().getInventoryIcon(*iter); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - icon->setImageTexture (path); + ItemWidget* icon = mRepairView->createWidget ( + "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); + icon->setItem(*iter); icon->setUserString("ToolTipType", "ItemPtr"); icon->setUserData(*iter); icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 42539ad9e0..439ee1169a 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -8,6 +8,8 @@ namespace MWGui { +class ItemWidget; + class Repair : public WindowBase { public: @@ -25,7 +27,7 @@ protected: MyGUI::Widget* mToolBox; - MyGUI::ImageBox* mToolIcon; + ItemWidget* mToolIcon; MyGUI::TextBox* mUsesLabel; MyGUI::TextBox* mQualityLabel; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 94001d8777..588235db96 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -64,6 +64,7 @@ #include "fontloader.hpp" #include "videowidget.hpp" #include "backgroundimage.hpp" +#include "itemwidget.hpp" namespace MWGui { @@ -166,6 +167,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); + ItemWidget::registerComponents(); MyGUI::FactoryManager::getInstance().registerFactory("Controller"); diff --git a/files/mygui/openmw_alchemy_window.layout b/files/mygui/openmw_alchemy_window.layout index 4b15ac1bd5..e098800afb 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -23,21 +23,13 @@ - - - + - - - + - - - + - - - + @@ -51,21 +43,13 @@ - - - + - - - + - - - + - - - + @@ -106,4 +90,4 @@ - \ No newline at end of file + diff --git a/files/mygui/openmw_box.skin.xml b/files/mygui/openmw_box.skin.xml index 620f49e2b3..af3a05d31b 100644 --- a/files/mygui/openmw_box.skin.xml +++ b/files/mygui/openmw_box.skin.xml @@ -73,4 +73,9 @@ as around the sections of the stats window, or around popup info windows --> + + + + + diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index f64d21deaa..2a3cb7c1db 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -26,8 +26,7 @@ - - + @@ -35,8 +34,7 @@ - - + diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 90fa1c8a56..e1f8af7bf3 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -59,7 +59,7 @@ - + @@ -71,7 +71,7 @@ - + diff --git a/files/mygui/openmw_quickkeys_menu.layout b/files/mygui/openmw_quickkeys_menu.layout index dcb10404df..d7e976d455 100644 --- a/files/mygui/openmw_quickkeys_menu.layout +++ b/files/mygui/openmw_quickkeys_menu.layout @@ -17,16 +17,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index 49e7357645..1b2ad947bf 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index 2881a5853a..09a3724408 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 3901ab8252..a37d3335c2 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -319,4 +319,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + From 0063b63ae441edeed34258e40d81b1fcf22a47ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 22:23:57 +0200 Subject: [PATCH 088/110] Don't use armor mitigation for fall damage --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7405292b4b..5ec192ab20 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -680,7 +680,7 @@ namespace MWClass else getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur? - if(ishealth) + if(ishealth && !attacker.isEmpty()) // Don't use armor mitigation for fall damage { // Hit percentages: // cuirass = 30% From 3d103f37856074052e3047fa4bbd8d6e02165a4e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Jun 2014 22:27:46 +0200 Subject: [PATCH 089/110] Don't block hits when in hand-to-hand combat (shield not visible) --- apps/openmw/mwmechanics/combat.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 69c3c08f76..be62e8315f 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -73,9 +73,16 @@ namespace MWMechanics return false; MWMechanics::CreatureStats& blockerStats = blocker.getClass().getCreatureStats(blocker); + + // Don't block when in spellcasting state (shield is equipped, but not visible) if (blockerStats.getDrawState() == DrawState_Spell) return false; + // Don't block when in hand-to-hand combat (shield is equipped, but not visible) + if (blockerStats.getDrawState() == DrawState_Weapon && + inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight) == inv.end()) + return false; + MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2 * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() From c36decb8555aa7c0d755628ad6f67efde572932e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 00:43:07 +0200 Subject: [PATCH 090/110] Fix being able to place items on top of actors (Fixes #1403) --- apps/openmw/mwworld/physicssystem.cpp | 4 +++- apps/openmw/mwworld/physicssystem.hpp | 3 ++- apps/openmw/mwworld/worldimp.cpp | 12 ++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index e93d9e640f..b0b00c6dbd 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -492,7 +492,7 @@ namespace MWWorld return std::make_pair(true, ray.getPoint(len * test.second)); } - std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal) + std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit) { Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( mouseX, @@ -510,6 +510,8 @@ namespace MWWorld return std::make_pair(false, Ogre::Vector3()); else { + if (hit != NULL) + *hit = result.first; return std::make_pair(true, ray.getPoint(200*result.second)); /// \todo make this distance (ray length) configurable } } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 899d7144d9..c590b40c87 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -70,9 +70,10 @@ namespace MWWorld std::pair castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); - std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal = NULL); + std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal = NULL, std::string* hit = NULL); ///< cast ray from the mouse, return true if it hit something and the first result /// @param normal if non-NULL, the hit normal will be written there (if there is a hit) + /// @param hit if non-NULL, the string handle of the hit object will be written there (if there is a hit) OEngine::Physic::PhysicEngine* getEngine(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2bd835561d..0939f01be5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1624,12 +1624,20 @@ namespace MWWorld bool World::canPlaceObject(float cursorX, float cursorY) { Ogre::Vector3 normal(0,0,0); - std::pair result = mPhysics->castRay(cursorX, cursorY, &normal); + std::string handle; + std::pair result = mPhysics->castRay(cursorX, cursorY, &normal, &handle); if (result.first) { // check if the wanted position is on a flat surface, and not e.g. against a vertical wall - return (normal.angleBetween(Ogre::Vector3(0.f,0.f,1.f)).valueDegrees() < 30); + if (normal.angleBetween(Ogre::Vector3(0.f,0.f,1.f)).valueDegrees() >= 30) + return false; + + MWWorld::Ptr hitObject = searchPtrViaHandle(handle); + if (!hitObject.isEmpty() && hitObject.getClass().isActor()) + return false; + + return true; } else return false; From d442853b3e67b6f0cde3fb28382b83060b14a24b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 01:30:23 +0200 Subject: [PATCH 091/110] Allow opposite gender's parts as fallback (Fixes #1404) --- apps/openmw/mwrender/npcanimation.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 03ccde388b..fcbf3805b9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -408,8 +408,6 @@ void NpcAnimation::updateParts() if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) continue; - if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) - continue; if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace)) continue; @@ -435,6 +433,20 @@ void NpcAnimation::updateParts() } continue; } + + if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + { + // Allow opposite gender's parts as fallback if parts for our gender are missing + BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); + while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart) + { + if(!parts[bIt->second]) + parts[bIt->second] = &*it; + ++bIt; + } + continue; + } + BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart) { From 40d6c8abf717b3112cc26c8d7be016974deb6a0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 02:24:51 +0200 Subject: [PATCH 092/110] Remove horizontal messagebox layout, not used in vanilla (Fixes #1402) --- apps/openmw/mwgui/messagebox.cpp | 132 ++++++++++--------------------- 1 file changed, 41 insertions(+), 91 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 1ce167c339..c5c46cba8e 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -232,102 +232,52 @@ namespace MWGui buttonsWidth += buttonLeftPadding; MyGUI::IntSize mainWidgetSize; - if(buttonsWidth < fixedWidth) - { - // on one line - if(textSize.width + 2*textPadding < buttonsWidth) - { - mainWidgetSize.width = buttonsWidth; - } - else - { - mainWidgetSize.width = textSize.width + 3*textPadding; - } - mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; - - MyGUI::IntPoint absPos; - absPos.left = (gameWindowSize.width - mainWidgetSize.width)/2; - absPos.top = (gameWindowSize.height - mainWidgetSize.height)/2; - - mMainWidget->setPosition(absPos); - mMainWidget->setSize(mainWidgetSize); - - MyGUI::IntCoord messageWidgetCoord; - messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; - messageWidgetCoord.top = textPadding; - mMessageWidget->setCoord(messageWidgetCoord); - - mMessageWidget->setSize(textSize); - - MyGUI::IntCoord buttonCord; - MyGUI::IntSize buttonSize(0, buttonHeight); - int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; - - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) - { - buttonCord.left = left; - buttonCord.top = textSize.height + textButtonPadding; - - buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; - - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); - - left += buttonSize.width + buttonLeftPadding; - } + // among each other + if(biggestButtonWidth > textSize.width) { + mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; } - else - { - // among each other - if(biggestButtonWidth > textSize.width) { - mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; - } - else { - mainWidgetSize.width = textSize.width + 3*textPadding; - } - - MyGUI::IntCoord buttonCord; - MyGUI::IntSize buttonSize(0, buttonHeight); - - int top = textButtonPadding + buttonTopPadding + textSize.height; - - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) - { - buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; - - buttonCord.top = top; - buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ - - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); - - top += buttonSize.height + 2*buttonTopPadding; - } - - mainWidgetSize.height = top + buttonMainPadding; - mMainWidget->setSize(mainWidgetSize); - - MyGUI::IntPoint absPos; - absPos.left = (gameWindowSize.width - mainWidgetSize.width)/2; - absPos.top = (gameWindowSize.height - mainWidgetSize.height)/2; - - mMainWidget->setPosition(absPos); - - MyGUI::IntCoord messageWidgetCoord; - messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; - messageWidgetCoord.top = textPadding; - messageWidgetCoord.width = textSize.width; - messageWidgetCoord.height = textSize.height; - mMessageWidget->setCoord(messageWidgetCoord); + else { + mainWidgetSize.width = textSize.width + 3*textPadding; } + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + + int top = textButtonPadding + buttonTopPadding + textSize.height; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; + buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; + + buttonCord.top = top; + buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + top += buttonSize.height + 2*buttonTopPadding; + } + + mainWidgetSize.height = top + buttonMainPadding; + mMainWidget->setSize(mainWidgetSize); + + MyGUI::IntPoint absPos; + absPos.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absPos.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + mMainWidget->setPosition(absPos); + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + messageWidgetCoord.width = textSize.width; + messageWidgetCoord.height = textSize.height; + mMessageWidget->setCoord(messageWidgetCoord); + // Set key focus to "Ok" button std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { if(Misc::StringUtils::ciEqual((*button)->getCaption(), ok)) From b90e4db8718b0a41de179214a9c7b0cb9f9b7440 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 6 Jun 2014 01:26:28 -0400 Subject: [PATCH 093/110] Actually read in XYZ_ROTATION_KEY data instead of discarding it. --- components/nif/data.hpp | 13 ++++++ components/nif/niffile.hpp | 92 ++++++++++++++------------------------ 2 files changed, 46 insertions(+), 59 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index f1f34184ba..998c887486 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -413,12 +413,25 @@ struct NiMorphData : public Record struct NiKeyframeData : public Record { QuaternionKeyList mRotations; + //\FIXME mXYZ_Keys are read, but not used. + FloatKeyList mXYZ_Keys; Vector3KeyList mTranslations; FloatKeyList mScales; void read(NIFStream *nif) { mRotations.read(nif); + if(mRotations.mInterpolationType == mRotations.sXYZInterpolation) + { + //Chomp unused float + nif->getFloat(); + for(size_t i=0;i<3;++i) + { + //Read concatenates items together. + mXYZ_keys.read(nif,true); + } + nif->file->warn("XYZ_ROTATION_KEY read, but not used!"); + } mTranslations.read(nif); mScales.read(nif); } diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 6fa98c6101..5ef8179d5c 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -158,57 +158,58 @@ struct KeyListT { static const int sTBCInterpolation = 3; static const int sXYZInterpolation = 4; - int mInterpolationType; + unsigned int mInterpolationType; VecType mKeys; void read(NIFStream *nif, bool force=false) { assert(nif); - size_t count = nif->getInt(); + size_t count = nif->getUInt(); if(count == 0 && !force) return; - mInterpolationType = nif->getInt(); - mKeys.resize(count); + //If we aren't forcing things, make sure that read clears any previous keys + if(!force) + mKeys.clear(); + + mInterpolationType = nif->getUInt(); + + KeyT key; NIFStream &nifReference = *nif; - if(mInterpolationType == sLinearInterpolation) + for(size_t i = 0;i < count;i++) { - for(size_t i = 0;i < count;i++) + if(mInterpolationType == sLinearInterpolation) { - readTimeAndValue(nifReference, mKeys[i]); + readTimeAndValue(nifReference, key); + mKeys.push_back(key); } - } - else if(mInterpolationType == sQuadraticInterpolation) - { - for(size_t i = 0;i < count;i++) + else if(mInterpolationType == sQuadraticInterpolation) { - readQuadratic(nifReference, mKeys[i]); + readQuadratic(nifReference, key); + mKeys.push_back(key); } - } - else if(mInterpolationType == sTBCInterpolation) - { - for(size_t i = 0;i < count;i++) + else if(mInterpolationType == sTBCInterpolation) { - readTBC(nifReference, mKeys[i]); + readTBC(nifReference, key); + mKeys.push_back(key); } - } - //\FIXME This now reads the correct amount of data in the file, but doesn't actually do anything with it. - else if(mInterpolationType == sXYZInterpolation) - { - if (count != 1) + else if(mInterpolationType == sXYZInterpolation) { - nif->file->fail("count should always be '1' for XYZ_ROTATION_KEY. Retrieved Value: "+Ogre::StringConverter::toString(count)); - return; + //Don't try to read XYZ keys into the wrong part + if(force) + { + readTimeAndValue(nifReference, key); + mKeys.push_back(key); + } + else if ( count != 1 ) + nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count)); } - readXYZ(nifReference); + else if ((0 == mInterpolationType)) + if (count != 0) + nif->file->fail("Interpolation type 0 doesn't work with keys"); + else + nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); } - else if (mInterpolationType == 0) - { - if (count != 0) - nif->file->fail("Interpolation type 0 doesn't work with keys"); - } - else - nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); } private: @@ -238,33 +239,6 @@ private: key.mBias = nif.getFloat(); key.mContinuity = nif.getFloat(); } - - static void readXYZ(NIFStream &nif) - { - //KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html) - //Chomp unknown and possibly unused float - nif.getFloat(); - for(size_t i=0;i<3;++i) - { - const unsigned int numKeys = nif.getInt(); - if(numKeys != 0) - { - const int interpolationTypeAgain = nif.getInt(); - if( interpolationTypeAgain != sLinearInterpolation) - { - nif.file->fail("XYZ_ROTATION_KEY's KeyGroup keyType must be '1' (Linear Interpolation). Retrieved Value: "+Ogre::StringConverter::toString(interpolationTypeAgain)); - return; - } - for(size_t j = 0;j < numKeys;++j) - { - //For now just chomp these - nif.getFloat(); - nif.getFloat(); - } - } - nif.file->warn("XYZ_ROTATION_KEY read, but not used!"); - } - } }; typedef KeyListT FloatKeyList; typedef KeyListT Vector3KeyList; From f9f278f6450a80bebbc50cc459054a4e113d2677 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 6 Jun 2014 07:00:04 -0400 Subject: [PATCH 094/110] Fixed a capitalization error. Changed Interpolations to unsigned. Also explained what's happening in the comments. --- components/nif/data.hpp | 2 +- components/nif/niffile.hpp | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 998c887486..e943887682 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -428,7 +428,7 @@ struct NiKeyframeData : public Record for(size_t i=0;i<3;++i) { //Read concatenates items together. - mXYZ_keys.read(nif,true); + mXYZ_Keys.read(nif,true); } nif->file->warn("XYZ_ROTATION_KEY read, but not used!"); } diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 5ef8179d5c..daec80ea1c 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -153,14 +153,15 @@ template struct KeyListT { typedef std::vector< KeyT > VecType; - static const int sLinearInterpolation = 1; - static const int sQuadraticInterpolation = 2; - static const int sTBCInterpolation = 3; - static const int sXYZInterpolation = 4; + static const unsigned int sLinearInterpolation = 1; + static const unsigned int sQuadraticInterpolation = 2; + static const unsigned int sTBCInterpolation = 3; + static const unsigned int sXYZInterpolation = 4; unsigned int mInterpolationType; VecType mKeys; + //Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html) void read(NIFStream *nif, bool force=false) { assert(nif); @@ -193,20 +194,22 @@ struct KeyListT { readTBC(nifReference, key); mKeys.push_back(key); } + //XYZ keys aren't actually read here. + //data.hpp sees that the last type read was sXYZInterpolation and: + // Eats a floating point number, then + // Re-runs the read function 3 more times, with force enabled so that the previous values aren't cleared. + // When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation. else if(mInterpolationType == sXYZInterpolation) { //Don't try to read XYZ keys into the wrong part - if(force) - { - readTimeAndValue(nifReference, key); - mKeys.push_back(key); - } - else if ( count != 1 ) + if ( count != 1 ) nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count)); } - else if ((0 == mInterpolationType)) + else if (0 == mInterpolationType) + { if (count != 0) nif->file->fail("Interpolation type 0 doesn't work with keys"); + } else nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); } From f3cece8dec04e230bc6a3cf91b8a1c4b0ca383a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 14:12:50 +0200 Subject: [PATCH 095/110] Fix alchemy allowing same item ID in different slots (Fixes #1407) --- apps/openmw/mwmechanics/alchemy.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 64b358b96c..2e03122d5b 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -395,7 +395,8 @@ int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) return -1; for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) - if (!iter->isEmpty() && ingredient.get()==iter->get()) + if (!iter->isEmpty() && Misc::StringUtils::ciEqual(ingredient.getClass().getId(ingredient), + iter->getClass().getId(*iter))) return -1; mIngredients[slot] = ingredient; From 9627146bf49c99ba5e4e99f871fb182f468b3e88 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 15:08:44 +0200 Subject: [PATCH 096/110] Another fix for trade exploit (hopefully the last: Fixes #1408) --- apps/openmw/mwgui/tradewindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 73f48c8cf4..7ef472282f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -345,7 +345,7 @@ namespace MWGui x += abs(int(npcTerm - pcTerm)); int roll = std::rand()%100 + 1; - if(roll > x) //trade refused + if(roll > x || (mCurrentMerchantOffer < 0) != (mCurrentBalance < 0)) //trade refused { MWBase::Environment::get().getWindowManager()-> messageBox("#{sNotifyMessage9}"); From 01283f531eeb71cbef1a01b7e1a0da41a895520e Mon Sep 17 00:00:00 2001 From: Hallfaer Tuilinn Date: Fri, 6 Jun 2014 15:13:25 +0200 Subject: [PATCH 097/110] Fix for Bug #1409 --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 3d7e7e283a..48218f9de6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1088,10 +1088,10 @@ namespace MWMechanics CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - float healthHours = healthPerHour >= 0 + float healthHours = healthPerHour > 0 ? (stats.getHealth().getModified() - stats.getHealth().getCurrent()) / healthPerHour : 1.0f; - float magickaHours = magickaPerHour >= 0 + float magickaHours = magickaPerHour > 0 ? (stats.getMagicka().getModified() - stats.getMagicka().getCurrent()) / magickaPerHour : 1.0f; From 54a5dba3f546cad38af44707a8f5fb7f106df72a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 15:20:56 +0200 Subject: [PATCH 098/110] Don't reserve Pauldron parts for robes (Fixes #1396) --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index fcbf3805b9..7277cc1872 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -308,7 +308,7 @@ void NpcAnimation::updateParts() ESM::PartReferenceType parts[] = { ESM::PRT_Groin, ESM::PRT_Skirt, ESM::PRT_RLeg, ESM::PRT_LLeg, ESM::PRT_RUpperarm, ESM::PRT_LUpperarm, ESM::PRT_RKnee, ESM::PRT_LKnee, - ESM::PRT_RForearm, ESM::PRT_LForearm, ESM::PRT_RPauldron, ESM::PRT_LPauldron + ESM::PRT_RForearm, ESM::PRT_LForearm }; size_t parts_size = sizeof(parts)/sizeof(parts[0]); for(size_t p = 0;p < parts_size;++p) From b68a8e38cdbbd04fb6e89c8231c00005ac851c23 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 15:24:06 +0200 Subject: [PATCH 099/110] Remove unused map --- apps/openmw/mwrender/npcanimation.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7277cc1872..be2b262fc2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -351,8 +351,6 @@ void NpcAnimation::updateParts() // Remember body parts so we only have to search through the store once for each race/gender/viewmode combination static std::map< std::pair,std::vector > sRaceMapping; - static std::map , std::vector > sVampireMapping; - static const int Flag_Female = 1<<0; static const int Flag_FirstPerson = 1<<1; From 58d963d6e665de48300dc4ebdc3725a5fe61c495 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Jun 2014 18:43:30 +0200 Subject: [PATCH 100/110] Fix warning --- apps/openmw/mwgui/messagebox.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index c5c46cba8e..d73a0e1223 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -179,7 +179,6 @@ namespace MWGui { WindowModal::open(); - int fixedWidth = 500; int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 20; // padding between the text-widget und the button-widget int buttonLeftPadding = 10; // padding between the buttons if horizontal From 13c953cbb290433b7f9dbbd04e5191b67a84f60a Mon Sep 17 00:00:00 2001 From: Fil Krynicki Date: Fri, 6 Jun 2014 16:21:28 -0400 Subject: [PATCH 101/110] Made recommended changes Maybe introduced a bug not allowing punching. Testing. --- apps/openmw/mwinput/inputmanagerimp.cpp | 46 ++++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 80cd834d5d..12e3cdbf78 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -168,11 +168,12 @@ namespace MWInput void InputManager::setPlayerControlsEnabled(bool enabled) { - int nPlayerChannels = 15; + int nPlayerChannels = 17; int playerChannels[] = {A_Activate, A_AutoMove, A_AlwaysRun, A_ToggleWeapon, A_ToggleSpell, A_Rest, A_QuickKey1, A_QuickKey2, A_QuickKey3, A_QuickKey4, A_QuickKey5, A_QuickKey6, - A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10}; + A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10, + A_Use}; for(int i = 0; i < nPlayerChannels; i++) { int pc = playerChannels[i]; @@ -558,41 +559,49 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { - mInputBinder->keyReleased (arg); - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)); + if (kc != OIS::KC_UNASSIGNED) + { + bool guiFocus = MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)); + setPlayerControlsEnabled(!guiFocus); + } + mInputBinder->keyReleased (arg); + } void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { - mInputBinder->mousePressed (arg, id); + bool guiFocus = false; - if (id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT) - return; // MyGUI has no use for these events - - MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); - if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + if (!(id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT)) // MyGUI has no use for these events { - MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); - if (b && b->getEnabled()) + guiFocus = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); + if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { - MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); + if (b && b->getEnabled()) + { + MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + } } } + setPlayerControlsEnabled(!guiFocus); + + mInputBinder->mousePressed (arg, id); } void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) { + bool guiFocus = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); + setPlayerControlsEnabled(!guiFocus); mInputBinder->mouseReleased (arg, id); - MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); } void InputManager::mouseMoved(const SFO::MouseMotionEvent &arg ) { - mInputBinder->mouseMoved (arg); + bool guiFocus = false; resetIdleTime (); @@ -610,7 +619,7 @@ namespace MWInput mMouseWheel = int(arg.z); - MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); + guiFocus = MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); } if (mMouseLookEnabled) @@ -638,6 +647,9 @@ namespace MWInput MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); } } + + setPlayerControlsEnabled(!guiFocus); + mInputBinder->mouseMoved (arg); } void InputManager::windowFocusChange(bool have_focus) From 97caa1f8a40d2b94046198c9216dca160c5f3a5f Mon Sep 17 00:00:00 2001 From: Fil Krynicki Date: Fri, 6 Jun 2014 22:25:23 -0400 Subject: [PATCH 102/110] Alternative fix strategy by checking for binding state --- apps/openmw/mwinput/inputmanagerimp.cpp | 45 ++++++++++++++++--------- extern/oics/ICSInputControlSystem.cpp | 5 +++ extern/oics/ICSInputControlSystem.h | 1 + 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 80cd834d5d..ec1c0aa92a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -558,36 +558,51 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { - mInputBinder->keyReleased (arg); - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + mInputBinder->keyReleased (arg); } void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { - mInputBinder->mousePressed (arg, id); + bool guiMode = false; - if (id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT) - return; // MyGUI has no use for these events - - MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); - if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI has no use for these events { - MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); - if (b && b->getEnabled()) + MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); + guiMode = guiMode && MWBase::Environment::get().getWindowManager()->isGuiMode(); + if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { - MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); + if (b && b->getEnabled()) + { + MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + } } } + + setPlayerControlsEnabled(!guiMode); + mInputBinder->mousePressed (arg, id); + + } void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) - { - mInputBinder->mouseReleased (arg, id); + { - MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); + if(mInputBinder->detectingBindingState()) + { + mInputBinder->mouseReleased (arg, id); + } else { + bool guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); + guiMode = guiMode && MWBase::Environment::get().getWindowManager()->isGuiMode(); + + if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind + + setPlayerControlsEnabled(!guiMode); + mInputBinder->mouseReleased (arg, id); + } } void InputManager::mouseMoved(const SFO::MouseMotionEvent &arg ) diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index cdf8fbfe2f..a053bbab4e 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -796,6 +796,11 @@ namespace ICS mMouseAxisBindingInitialValues[0] = ICS_MOUSE_AXIS_BINDING_NULL_VALUE; } + bool InputControlSystem::detectingBindingState() + { + return mDetectingBindingControl != NULL; + } + void InputControlSystem::cancelDetectingBindingState() { mDetectingBindingControl = NULL; diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index a83ae539ef..4aaecdea9f 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -146,6 +146,7 @@ namespace ICS void enableDetectingBindingState(Control* control, Control::ControlChangingDirection direction); void cancelDetectingBindingState(); + bool detectingBindingState(); bool save(std::string fileName = ""); From 1d3a220d947a6cf44f5e3dfc7c588a53f3aec232 Mon Sep 17 00:00:00 2001 From: Fil Krynicki Date: Fri, 6 Jun 2014 22:35:16 -0400 Subject: [PATCH 103/110] Added A_Use command to player controls. --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ec1c0aa92a..0ca55ea580 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -168,11 +168,12 @@ namespace MWInput void InputManager::setPlayerControlsEnabled(bool enabled) { - int nPlayerChannels = 15; + int nPlayerChannels = 17; int playerChannels[] = {A_Activate, A_AutoMove, A_AlwaysRun, A_ToggleWeapon, A_ToggleSpell, A_Rest, A_QuickKey1, A_QuickKey2, A_QuickKey3, A_QuickKey4, A_QuickKey5, A_QuickKey6, - A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10}; + A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10, + A_Use}; for(int i = 0; i < nPlayerChannels; i++) { int pc = playerChannels[i]; From cd693b6d37dc6a5b0413e500d0fb1570449156e6 Mon Sep 17 00:00:00 2001 From: Fil Krynicki Date: Sat, 7 Jun 2014 20:08:29 -0400 Subject: [PATCH 104/110] Fixed mouse closing containers, and injection/gui test order Called setEnabled on channels now effects whether those channels notify listeners, rather than whether they register changes to their controls. This was making channels get stuck on "1" when the GUI was activated. Also ensured GUI activity can invalidate player controls even if that activity is closing the GUI, by re-ordering a check. And fixed a comment. --- apps/openmw/mwinput/inputmanagerimp.cpp | 10 +++++----- extern/oics/ICSChannel.cpp | 5 +---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0ca55ea580..85d5cdb8e1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -569,10 +569,10 @@ namespace MWInput { bool guiMode = false; - if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI has no use for these events + if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events { - MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); - guiMode = guiMode && MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); @@ -596,8 +596,8 @@ namespace MWInput { mInputBinder->mouseReleased (arg, id); } else { - bool guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); - guiMode = guiMode && MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind diff --git a/extern/oics/ICSChannel.cpp b/extern/oics/ICSChannel.cpp index 268615c920..178fe5aa35 100644 --- a/extern/oics/ICSChannel.cpp +++ b/extern/oics/ICSChannel.cpp @@ -84,7 +84,7 @@ namespace ICS mValue = value; - if(previousValue != value) + if(previousValue != value && mEnabled) { notifyListeners(previousValue); } @@ -130,9 +130,6 @@ namespace ICS void Channel::update() { - if(!mEnabled) - return; - if(this->getControlsCount() == 1) { ControlChannelBinderItem ccBinderItem = mAttachedControls.back(); From 51c45796b183a5b4d71323602045674a0c4be71c Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 7 Jun 2014 19:26:12 -0500 Subject: [PATCH 105/110] Fix physics to not trigger Bullet assert in Debug When physics attempts to move by a very small amount, precision losses caused Bullet to trigger an assert in debug from normalizing a zero length vector. --- apps/openmw/mwworld/physicssystem.cpp | 28 +++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b0b00c6dbd..fde774662e 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -299,17 +299,33 @@ namespace MWWorld continue; // velocity updated, calculate nextpos again } - // trace to where character would go if there were no obstructions - tracer.doTrace(colobj, newPosition, nextpos, engine); - - // check for obstructions - if(tracer.mFraction >= 1.0f) + if(!newPosition.positionCloses(nextpos, 0.00000001)) { - newPosition = tracer.mEndPos; // ok to move, so set newPosition + // trace to where character would go if there were no obstructions + tracer.doTrace(colobj, newPosition, nextpos, engine); + + // check for obstructions + if(tracer.mFraction >= 1.0f) + { + newPosition = tracer.mEndPos; // ok to move, so set newPosition + remainingTime *= (1.0f-tracer.mFraction); // FIXME: remainingTime is no longer used so don't set it? + break; + } + } + else + { + // The current position and next position are nearly the same, so just exit. + // Note: Bullet can trigger an assert in debug modes if the positions + // are the same, since that causes it to attempt to normalize a zero + // length vector (which can also happen with nearly identical vectors, since + // precision can be lost due to any math Bullet does internally). Since we + // aren't performing any collision detection, we want to reject the next + // position, so that we don't slowly move inside another object. remainingTime *= (1.0f-tracer.mFraction); // FIXME: remainingTime is no longer used so don't set it? break; } + Ogre::Vector3 oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful From 803a7514dfbfabd58678ad3a551deebb0c6f628e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Jun 2014 11:33:39 +0200 Subject: [PATCH 106/110] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index da54170345..092f5c15e8 100644 --- a/credits.txt +++ b/credits.txt @@ -36,6 +36,7 @@ Eli2 Emanuel Guével (potatoesmaster) Fil Krynicki (filkry) gugus/gus +Hallfaer Tuilinn Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) From 67abc60264a6aec4d5b9080150bb22e76cde02f5 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Sun, 8 Jun 2014 20:59:26 +0400 Subject: [PATCH 107/110] aiming to moving target in ranged combat ai 1) Taking into account target move vector and speed. However aiming is not ideal, since attack strength can't be controlled directly. I did achieve almost 100% accuracy updating it everyframe but then thought it would be unfair, cause AI should mimic human targetting. 2) Also added in this commit func to measure real attack durations for weapon. --- apps/openmw/mwmechanics/aicombat.cpp | 346 +++++++++++++++++------ apps/openmw/mwmechanics/aicombat.hpp | 9 +- apps/openmw/mwrender/animation.cpp | 19 +- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/weaponanimation.cpp | 2 +- 5 files changed, 278 insertions(+), 100 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 8f81885597..7a846e00d9 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -1,8 +1,6 @@ #include "aicombat.hpp" #include -#include - #include "../mwworld/class.hpp" #include "../mwworld/timestamp.hpp" @@ -14,6 +12,8 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" +#include "../mwrender/animation.hpp" + #include "creaturestats.hpp" #include "steering.hpp" @@ -30,7 +30,12 @@ namespace } //chooses an attack depending on probability to avoid uniformity - void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement); + ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement); + + void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]); + + Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, + float duration, int weapType, float strength); float getZAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f) { @@ -76,18 +81,20 @@ namespace namespace MWMechanics { - static const float MAX_ATTACK_DURATION = 0.35f; static const float DOOR_CHECK_INTERVAL = 1.5f; // same as AiWander // NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp AiCombat::AiCombat(const MWWorld::Ptr& actor) : mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId()), + mLastTargetPos(actor.getRefData().getPosition().pos), mTimerAttack(0), mTimerReact(0), mTimerCombatMove(0), mFollowTarget(false), mReadyToAttack(false), mAttack(false), + mStrength(0), + mMinMaxAttackDuration(), mCombatMove(false), mMovement(), mForceNoShortcut(false), @@ -158,9 +165,9 @@ namespace MWMechanics return true; if (!actor.getClass().isNpc() && target == MWBase::Environment::get().getWorld()->getPlayerPtr() && - (actor.getClass().canSwim(actor) && !actor.getClass().canWalk(actor) // pure water creature - && !MWBase::Environment::get().getWorld()->isSwimming(target)) // Player moved out of water - || (!actor.getClass().canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(target))) // creature can't swim to Player + (actor.getClass().canSwim(actor) && !actor.getClass().canWalk(actor) // 1. pure water creature and Player moved out of water + && !MWBase::Environment::get().getWorld()->isSwimming(target)) + || (!actor.getClass().canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(target))) // 2. creature can't swim to Player { actor.getClass().getCreatureStats(actor).setHostile(false); actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false); @@ -194,6 +201,27 @@ namespace MWMechanics } mTimerAttack -= duration; + + //TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f + float attacksPeriod = 1.0f; + + ESM::Weapon::AttackType attackType; + + if(mReadyToAttack) + { + if (mMinMaxAttackDuration[0][0] == 0) + { + getMinMaxAttackDuration(actor, mMinMaxAttackDuration); + } + + if (mTimerAttack <= 0) mAttack = false; + } + else + { + mTimerAttack = -attacksPeriod; + mAttack = false; + } + actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mAttack); float tReaction = 0.25f; @@ -213,40 +241,6 @@ namespace MWMechanics mCell = actor.getCell(); } - //actual attacking logic - //TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f - float attacksPeriod = 1.0f; - if(mReadyToAttack) - { - if(mTimerAttack <= -attacksPeriod) - { - //TODO: should depend on time between 'start' to 'min attack' - //for better controlling of NPCs' attack strength. - //Also it seems that this time is different for slash/thrust/chop - mTimerAttack = MAX_ATTACK_DURATION * static_cast(rand())/RAND_MAX; - mAttack = true; - - //say a provoking combat phrase - if (actor.getClass().isNpc()) - { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - int chance = store.get().find("iVoiceAttackOdds")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (roll < chance) - { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); - } - } - } - else if (mTimerAttack <= 0) - mAttack = false; - } - else - { - mTimerAttack = -attacksPeriod; - mAttack = false; - } - const MWWorld::Class &actorCls = actor.getClass(); const ESM::Weapon *weapon = NULL; MWMechanics::WeaponType weaptype; @@ -270,9 +264,9 @@ namespace MWMechanics if (weaptype == WeapType_HandToHand) { - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - weapRange = gmst.find("fHandToHandReach")->getFloat(); + static float fHandToHandReach = + MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->getFloat(); + weapRange = fHandToHandReach; } else if (weaptype != WeapType_PickProbe && weaptype != WeapType_Spell) { @@ -289,6 +283,49 @@ namespace MWMechanics weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit) } + float rangeAttack; + float rangeFollow; + bool distantCombat = false; + if (weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow || weaptype == WeapType_Thrown) + { + rangeAttack = 1000; // TODO: should depend on archer skill + rangeFollow = 0; // not needed in ranged combat + distantCombat = true; + } + else + { + rangeAttack = weapRange; + rangeFollow = 300; + } + + // start new attack + if(mReadyToAttack) + { + if(mTimerAttack <= -attacksPeriod) + { + mAttack = true; // attack starts just now + + if (!distantCombat) attackType = chooseBestAttack(weapon, mMovement); + else attackType = ESM::Weapon::AT_Chop; // cause it's =0 + + mStrength = static_cast(rand()) / RAND_MAX; + mTimerAttack = mMinMaxAttackDuration[attackType][0] + + (mMinMaxAttackDuration[attackType][1] - mMinMaxAttackDuration[attackType][0]) * mStrength; + + //say a provoking combat phrase + if (actor.getClass().isNpc()) + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + int chance = store.get().find("iVoiceAttackOdds")->getInt(); + int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + if (roll < chance) + { + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); + } + } + } + } + /* * Some notes on meanings of variables: @@ -319,21 +356,6 @@ namespace MWMechanics * target even if LOS is not achieved) */ - float rangeAttack; - float rangeFollow; - bool distantCombat = false; - if (weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow || weaptype == WeapType_Thrown) - { - rangeAttack = 1000; // TODO: should depend on archer skill - rangeFollow = 0; // not needed in ranged combat - distantCombat = true; - } - else - { - rangeAttack = weapRange; - rangeFollow = 300; - } - ESM::Position pos = actor.getRefData().getPosition(); Ogre::Vector3 vActorPos(pos.pos); Ogre::Vector3 vTargetPos(target.getRefData().getPosition().pos); @@ -342,40 +364,46 @@ namespace MWMechanics bool isStuck = false; float speed = 0.0f; - if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = actorCls.getSpeed(actor)) * tReaction / 2) + if(mMovement.mPosition[1] && (mLastActorPos - vActorPos).length() < (speed = actorCls.getSpeed(actor)) * tReaction / 2) isStuck = true; - mLastPos = pos; + mLastActorPos = vActorPos; // check if actor can move along z-axis bool canMoveByZ = (actorCls.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) || MWBase::Environment::get().getWorld()->isFlying(actor); - // determine vertical angle to target - // if actor can move along z-axis it will control movement dir - // if can't - it will control correct aiming - mMovement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); - - // (within strike dist) || (not quite strike dist while following) + // (within attack dist) || (not quite attack dist while following) if(distToTarget < rangeAttack || (distToTarget <= rangeFollow && mFollowTarget && !isStuck) ) { //Melee and Close-up combat - // if we preserve dir.z then horizontal angle can be inaccurate - mMovement.mRotation[2] = getZAngleToDir(Ogre::Vector3(vDirToTarget.x, vDirToTarget.y, 0)); + // getXAngleToDir determines vertical angle to target: + // if actor can move along z-axis it will control movement dir + // if can't - it will control correct aiming. + // note: in getZAngleToDir if we preserve dir.z then horizontal angle can be inaccurate + if (distantCombat) + { + Ogre::Vector3 vAimDir = AimDirToMovingTarget(actor, target, mLastTargetPos, tReaction, weaptype, mStrength); + mLastTargetPos = vTargetPos; + mMovement.mRotation[0] = getXAngleToDir(vAimDir); + mMovement.mRotation[2] = getZAngleToDir(Ogre::Vector3(vAimDir.x, vAimDir.y, 0)); + } + else + { + mMovement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); + mMovement.mRotation[2] = getZAngleToDir(Ogre::Vector3(vDirToTarget.x, vDirToTarget.y, 0)); + } - // (not quite strike dist while following) + // (not quite attack dist while following) if (mFollowTarget && distToTarget > rangeAttack) { //Close-up combat: just run up on target mMovement.mPosition[1] = 1; } - else // (within strike dist) + else // (within attack dist) { - mMovement.mPosition[1] = 0; - - // set slash/thrust/chop attack - if (mAttack && !distantCombat) chooseBestAttack(weapon, mMovement); + if (!mAttack) mMovement.mPosition[1] = 0; if(mMovement.mPosition[0] || mMovement.mPosition[1]) { @@ -479,9 +507,9 @@ namespace MWMechanics //special run attack; it shouldn't affect melee combat tactics if(actorCls.getMovementSettings(actor).mPosition[1] == 1) { - //check if actor can overcome the distance = distToTarget - attackerWeapRange - //less than in time of playing weapon anim from 'start' to 'hit' tags (t_swing) - //then start attacking + /* check if actor can overcome the distance = distToTarget - attackerWeapRange + less than in time of swinging with weapon (t_swing), then start attacking + */ float speed1 = actorCls.getSpeed(actor); float speed2 = target.getClass().getSpeed(target); if(target.getClass().getMovementSettings(target).mPosition[0] == 0 @@ -491,13 +519,16 @@ namespace MWMechanics float s1 = distToTarget - weapRange; float t = s1/speed1; float s2 = speed2 * t; - float t_swing = (MAX_ATTACK_DURATION/2) / weapSpeed;//instead of 0.17 should be the time of playing weapon anim from 'start' to 'hit' tags + float t_swing = + mMinMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + + (mMinMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - mMinMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * static_cast(rand()) / RAND_MAX; + if (t + s2/speed1 <= t_swing) { mReadyToAttack = true; if(mTimerAttack <= -attacksPeriod) { - mTimerAttack = MAX_ATTACK_DURATION * static_cast(rand())/RAND_MAX; + mTimerAttack = t_swing; mAttack = true; } } @@ -650,8 +681,10 @@ namespace MWMechanics namespace { -void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement) +ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement) { + ESM::Weapon::AttackType attackType; + if (weapon == NULL) { //hand-to-hand deal equal damage for each type @@ -660,34 +693,161 @@ void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement { movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; movement.mPosition[1] = 0; + attackType = ESM::Weapon::AT_Slash; } else if(roll <= 0.666f) //forward punch + { movement.mPosition[1] = 1; + attackType = ESM::Weapon::AT_Thrust; + } else { movement.mPosition[1] = movement.mPosition[0] = 0; + attackType = ESM::Weapon::AT_Chop; } + } + else + { + //the more damage attackType deals the more probability it has + int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; + int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; + int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; + + float total = slash + chop + thrust; + + float roll = static_cast(rand())/RAND_MAX; + if(roll <= static_cast(slash)/total) + { + movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; + movement.mPosition[1] = 0; + attackType = ESM::Weapon::AT_Slash; + } + else if(roll <= (static_cast(slash) + static_cast(thrust))/total) + { + movement.mPosition[1] = 1; + attackType = ESM::Weapon::AT_Thrust; + } + else + { + movement.mPosition[1] = movement.mPosition[0] = 0; + attackType = ESM::Weapon::AT_Chop; + } + } + + return attackType; +} + +void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]) +{ + if (!actor.getClass().hasInventoryStore(actor)) // creatures + { + fMinMaxDurations[0][0] = fMinMaxDurations[0][1] = 0.1f; + fMinMaxDurations[1][0] = fMinMaxDurations[1][1] = 0.1f; + fMinMaxDurations[2][0] = fMinMaxDurations[2][1] = 0.1f; return; } - //the more damage attackType deals the more probability it has - int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; - int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; - int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; + // get weapon information: type and speed + const ESM::Weapon *weapon = NULL; + MWMechanics::WeaponType weaptype; - float total = slash + chop + thrust; + MWWorld::ContainerStoreIterator weaponSlot = + MWMechanics::getActiveWeapon(actor.getClass().getCreatureStats(actor), actor.getClass().getInventoryStore(actor), &weaptype); - float roll = static_cast(rand())/RAND_MAX; - if(roll <= static_cast(slash)/total) + float weapSpeed; + if (weaptype != MWMechanics::WeapType_HandToHand) { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; - movement.mPosition[1] = 0; + weapon = weaponSlot->get()->mBase; + weapSpeed = weapon->mData.mSpeed; + } + else weapSpeed = 1.0f; + + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(actor); + + std::string weapGroup; + MWMechanics::getWeaponGroup(weaptype, weapGroup); + weapGroup = weapGroup + ": "; + + bool bRangedWeap = (weaptype >= MWMechanics::WeapType_BowAndArrow && weaptype <= MWMechanics::WeapType_Thrown); + + const char *attackType[] = {"chop ", "slash ", "thrust ", "shoot "}; + + std::string textKey = "start"; + std::string textKey2; + + // get durations for each attack type + for (int i = 0; i < (bRangedWeap ? 1 : 3); i++) + { + float start1 = anim->getStartTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey, false); + + textKey2 = "min attack"; + float start2 = anim->getStartTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2, false); + + fMinMaxDurations[i][0] = (start2 - start1) / weapSpeed; + + textKey2 = "max attack"; + start1 = anim->getStartTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2, false); + + fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed; + } + +} + +Ogre::Vector3 AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const Ogre::Vector3& vLastTargetPos, + float duration, int weapType, float strength) +{ + float projSpeed; + + // get projectile speed (depending on weapon type) + if (weapType == ESM::Weapon::MarksmanThrown) + { + static float fThrownWeaponMinSpeed = + MWBase::Environment::get().getWorld()->getStore().get().find("fThrownWeaponMinSpeed")->getFloat(); + static float fThrownWeaponMaxSpeed = + MWBase::Environment::get().getWorld()->getStore().get().find("fThrownWeaponMaxSpeed")->getFloat(); + + projSpeed = + fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * strength; } - else if(roll <= (static_cast(slash) + static_cast(thrust))/total) - movement.mPosition[1] = 1; else - movement.mPosition[1] = movement.mPosition[0] = 0; + { + static float fProjectileMinSpeed = + MWBase::Environment::get().getWorld()->getStore().get().find("fProjectileMinSpeed")->getFloat(); + static float fProjectileMaxSpeed = + MWBase::Environment::get().getWorld()->getStore().get().find("fProjectileMaxSpeed")->getFloat(); + + projSpeed = + fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * strength; + } + + // idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same + + Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); + Ogre::Vector3 vTargetPos = Ogre::Vector3(target.getRefData().getPosition().pos); + Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos; + float distToTarget = vDirToTarget.length(); + + Ogre::Vector3 vTargetMoveDir = vTargetPos - vLastTargetPos; + vTargetMoveDir /= duration; // |vTargetMoveDir| is target real speed in units/sec now + + Ogre::Vector3 vPerpToDir = vDirToTarget.crossProduct(Ogre::Vector3::UNIT_Z); + + float velPerp = vTargetMoveDir.dotProduct(vPerpToDir.normalisedCopy()); + float velDir = vTargetMoveDir.dotProduct(vDirToTarget.normalisedCopy()); + + // time to collision between target and projectile + float t_collision; + + float projVelDirSquared = projSpeed * projSpeed - velPerp * velPerp; + float projDistDiff = vDirToTarget.dotProduct(vTargetMoveDir.normalisedCopy()); + projDistDiff = sqrt(distToTarget * distToTarget - projDistDiff * projDistDiff); + + if (projVelDirSquared > 0) + t_collision = projDistDiff / (sqrt(projVelDirSquared) - velDir); + else t_collision = 0; // speed of projectile is not enough to reach moving target + + return vTargetPos + vTargetMoveDir * t_collision - vActorPos; } } diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 4b728ff221..e168dfc957 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -8,6 +8,8 @@ #include "movement.hpp" #include "obstacle.hpp" +#include + #include "../mwworld/cellstore.hpp" // for Doors #include "../mwbase/world.hpp" @@ -48,12 +50,17 @@ namespace MWMechanics bool mCombatMove; bool mBackOffDoor; + float mStrength; // this is actually make sense only in ranged combat + float mMinMaxAttackDuration[3][2]; // slash, thrust, chop has different durations + bool mForceNoShortcut; ESM::Position mShortcutFailPos; - ESM::Position mLastPos; + Ogre::Vector3 mLastActorPos; MWMechanics::Movement mMovement; + int mTargetActorId; + Ogre::Vector3 mLastTargetPos; const MWWorld::CellStore* mCell; ObstacleCheck mObstacleCheck; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3b8b91b0e4..641ddb43e5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -896,15 +896,26 @@ bool Animation::getInfo(const std::string &groupname, float *complete, float *sp return true; } -float Animation::getStartTime(const std::string &groupname) const +float Animation::getStartTime(const std::string &groupname, bool onlyGroup) const { AnimSourceList::const_iterator iter(mAnimSources.begin()); for(;iter != mAnimSources.end();iter++) { const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; - NifOgre::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); - if(found != keys.end()) - return found->first; + if (onlyGroup) + { + NifOgre::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); + if(found != keys.end()) + return found->first; + } + else + { + for(NifOgre::TextKeyMap::const_iterator iter(keys.begin()); iter != keys.end(); ++iter) + { + if(iter->second.compare(0, groupname.size(), groupname) == 0) + return iter->first; + } + } } return -1.f; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 564bb73ef1..2fc57f0e91 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -275,7 +275,7 @@ public: bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; /// Get the absolute position in the animation track of the first text key with the given group. - float getStartTime(const std::string &groupname) const; + float getStartTime(const std::string &groupname, bool onlyGroup) const; /// Get the current absolute position in the animation track for the animation that is currently playing from the given group. float getCurrentTime(const std::string& groupname) const; diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 5f953bd838..3d4886ceac 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -32,7 +32,7 @@ float WeaponAnimationTime::getValue() const void WeaponAnimationTime::setGroup(const std::string &group) { mWeaponGroup = group; - mStartTime = mAnimation->getStartTime(mWeaponGroup); + mStartTime = mAnimation->getStartTime(mWeaponGroup, true); } void WeaponAnimationTime::updateStartTime() From 698cbba6ef6bb3e139da218b001686f0583d0a54 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Mon, 9 Jun 2014 23:02:06 +0400 Subject: [PATCH 108/110] old bug + comment fix --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 5727996d95..76a84cc9e1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -928,7 +928,7 @@ namespace MWMechanics if (timerUpdateAITargets == 0 && iter->first.getTypeName() == typeid(ESM::Creature).name() && !listGuards.empty()) { sBasePoint = Ogre::Vector3(iter->first.getRefData().getPosition().pos); - listGuards.sort(comparePtrDist); // try to engage combat starting from the nearest creature + listGuards.sort(comparePtrDist); // try to engage combat starting from the nearest guard for (std::list::iterator it = listGuards.begin(); it != listGuards.end(); ++it) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index db4e599291..b487ffb21f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -975,7 +975,7 @@ 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) && animPlaying) { if( mMovementState != CharState_None || mJumpState != JumpState_None || From 979128b2c55f3c38a5160cf82222aa5325824916 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Tue, 10 Jun 2014 14:20:29 +0400 Subject: [PATCH 109/110] Combat music; some minor combat fixes --- apps/openmw/mwmechanics/actors.cpp | 19 +++++++++++++++++++ apps/openmw/mwmechanics/aicombat.cpp | 8 ++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 76a84cc9e1..7102fc0eeb 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -970,6 +970,9 @@ namespace MWMechanics } // Kill dead actors, update some variables + + int hostilesCount = 0; // need to know this to play Battle music + for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); @@ -988,6 +991,8 @@ namespace MWMechanics if(!stats.isDead()) { + if (stats.isHostile()) hostilesCount++; + if(iter->second->isDead()) { // Actor has been resurrected. Notify the CharacterController and re-enable collision. @@ -1045,6 +1050,20 @@ namespace MWMechanics } } + // check if we still have any player enemies to switch music + static bool isBattleMusic = false; + + if (isBattleMusic && hostilesCount == 0) + { + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); + isBattleMusic = false; + } + else if (!isBattleMusic && hostilesCount > 0) + { + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); + isBattleMusic = true; + } + // if player is in sneak state see if anyone detects him if (player.getClass().getCreatureStats(player).getMovementFlag(MWMechanics::CreatureStats::Flag_Sneak)) { diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5e2847ed2f..2218623da7 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -405,8 +405,6 @@ namespace MWMechanics } else // (within attack dist) { - if (!mAttack) mMovement.mPosition[1] = 0; - if(mMovement.mPosition[0] || mMovement.mPosition[1]) { mTimerCombatMove = 0.1f + 0.1f * static_cast(rand())/RAND_MAX; @@ -501,6 +499,12 @@ namespace MWMechanics } mMovement.mPosition[1] = 1; + if (mReadyToAttack) + { + // to stop possible sideway moving after target moved out of attack range + mCombatMove = true; + mTimerCombatMove = 0; + } mReadyToAttack = false; } From d6d9df6cec4c3c5e1dc02bc756f4174243caff56 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Wed, 11 Jun 2014 00:20:46 +0400 Subject: [PATCH 110/110] split getStartTime --- apps/openmw/mwmechanics/aicombat.cpp | 12 ++++++-- apps/openmw/mwrender/animation.cpp | 35 ++++++++++++++---------- apps/openmw/mwrender/animation.hpp | 5 +++- apps/openmw/mwrender/weaponanimation.cpp | 2 +- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2218623da7..4a3c724d59 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -785,15 +785,21 @@ void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations // get durations for each attack type for (int i = 0; i < (bRangedWeap ? 1 : 3); i++) { - float start1 = anim->getStartTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey, false); + float start1 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey); + + if (start1 < 0) + { + fMinMaxDurations[i][0] = fMinMaxDurations[i][1] = 0.1f; + continue; + } textKey2 = "min attack"; - float start2 = anim->getStartTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2, false); + float start2 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2); fMinMaxDurations[i][0] = (start2 - start1) / weapSpeed; textKey2 = "max attack"; - start1 = anim->getStartTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2, false); + start1 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2); fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6c27465577..1c86fab891 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -903,27 +903,32 @@ bool Animation::getInfo(const std::string &groupname, float *complete, float *sp return true; } -float Animation::getStartTime(const std::string &groupname, bool onlyGroup) const +float Animation::getStartTime(const std::string &groupname) const { - AnimSourceList::const_iterator iter(mAnimSources.begin()); - for(;iter != mAnimSources.end();iter++) + for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) { const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; - if (onlyGroup) + + NifOgre::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); + if(found != keys.end()) + return found->first; + } + return -1.f; +} + +float Animation::getTextKeyTime(const std::string &textKey) const +{ + for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + { + const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; + + for(NifOgre::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey) { - NifOgre::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); - if(found != keys.end()) - return found->first; - } - else - { - for(NifOgre::TextKeyMap::const_iterator iter(keys.begin()); iter != keys.end(); ++iter) - { - if(iter->second.compare(0, groupname.size(), groupname) == 0) - return iter->first; - } + if(iterKey->second.compare(0, textKey.size(), textKey) == 0) + return iterKey->first; } } + return -1.f; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2fc57f0e91..b2d69b79a4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -275,7 +275,10 @@ public: bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; /// Get the absolute position in the animation track of the first text key with the given group. - float getStartTime(const std::string &groupname, bool onlyGroup) const; + float getStartTime(const std::string &groupname) const; + + /// Get the absolute position in the animation track of the text key + float getTextKeyTime(const std::string &textKey) const; /// Get the current absolute position in the animation track for the animation that is currently playing from the given group. float getCurrentTime(const std::string& groupname) const; diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 3d4886ceac..5f953bd838 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -32,7 +32,7 @@ float WeaponAnimationTime::getValue() const void WeaponAnimationTime::setGroup(const std::string &group) { mWeaponGroup = group; - mStartTime = mAnimation->getStartTime(mWeaponGroup, true); + mStartTime = mAnimation->getStartTime(mWeaponGroup); } void WeaponAnimationTime::updateStartTime()